diff --git a/.gitignore b/.gitignore index 9dacde0..57af07c 100644 --- a/.gitignore +++ b/.gitignore @@ -46,6 +46,11 @@ modules.builtin /Module.symvers # +# Debian directory (make deb-pkg) +# +/debian/ + +# # git files that we don't want to ignore even it they are dot-files # !.gitignore diff --git a/.mailmap b/.mailmap index 353ad56..a4806f0 100644 --- a/.mailmap +++ b/.mailmap @@ -73,8 +73,7 @@ Linas Vepstas Mark Brown Matthieu CASTET Mayuresh Janorkar -Michael Buesch -Michael Buesch +Michael Buesch Michel Dänzer Mitesh shah Morten Welinder diff --git a/Documentation/ABI/obsolete/proc-pid-oom_adj b/Documentation/ABI/obsolete/proc-pid-oom_adj index cf63f26..9a3cb88 100644 --- a/Documentation/ABI/obsolete/proc-pid-oom_adj +++ b/Documentation/ABI/obsolete/proc-pid-oom_adj @@ -14,7 +14,7 @@ Why: /proc//oom_adj allows userspace to influence the oom killer's A much more powerful interface, /proc//oom_score_adj, was introduced with the oom killer rewrite that allows users to increase or - decrease the badness() score linearly. This interface will replace + decrease the badness score linearly. This interface will replace /proc//oom_adj. A warning will be emitted to the kernel log if an application uses this diff --git a/Documentation/ABI/stable/firewire-cdev b/Documentation/ABI/stable/firewire-cdev new file mode 100644 index 0000000..16d0308 --- /dev/null +++ b/Documentation/ABI/stable/firewire-cdev @@ -0,0 +1,103 @@ +What: /dev/fw[0-9]+ +Date: May 2007 +KernelVersion: 2.6.22 +Contact: linux1394-devel@lists.sourceforge.net +Description: + The character device files /dev/fw* are the interface between + firewire-core and IEEE 1394 device drivers implemented in + userspace. The ioctl(2)- and read(2)-based ABI is defined and + documented in . + + This ABI offers most of the features which firewire-core also + exposes to kernelspace IEEE 1394 drivers. + + Each /dev/fw* is associated with one IEEE 1394 node, which can + be remote or local nodes. Operations on a /dev/fw* file have + different scope: + - The 1394 node which is associated with the file: + - Asynchronous request transmission + - Get the Configuration ROM + - Query node ID + - Query maximum speed of the path between this node + and local node + - The 1394 bus (i.e. "card") to which the node is attached to: + - Isochronous stream transmission and reception + - Asynchronous stream transmission and reception + - Asynchronous broadcast request transmission + - PHY packet transmission and reception + - Allocate, reallocate, deallocate isochronous + resources (channels, bandwidth) at the bus's IRM + - Query node IDs of local node, root node, IRM, bus + manager + - Query cycle time + - Bus reset initiation, bus reset event reception + - All 1394 buses: + - Allocation of IEEE 1212 address ranges on the local + link layers, reception of inbound requests to such + an address range, asynchronous response transmission + to inbound requests + - Addition of descriptors or directories to the local + nodes' Configuration ROM + + Due to the different scope of operations and in order to let + userland implement different access permission models, some + operations are restricted to /dev/fw* files that are associated + with a local node: + - Addition of descriptors or directories to the local + nodes' Configuration ROM + - PHY packet transmission and reception + + A /dev/fw* file remains associated with one particular node + during its entire life time. Bus topology changes, and hence + node ID changes, are tracked by firewire-core. ABI users do not + need to be aware of topology. + + The following file operations are supported: + + open(2) + Currently the only useful flags are O_RDWR. + + ioctl(2) + Initiate various actions. Some take immediate effect, others + are performed asynchronously while or after the ioctl returns. + See the inline documentation in for + descriptions of all ioctls. + + poll(2), select(2), epoll_wait(2) etc. + Watch for events to become available to be read. + + read(2) + Receive various events. There are solicited events like + outbound asynchronous transaction completion or isochronous + buffer completion, and unsolicited events such as bus resets, + request reception, or PHY packet reception. Always use a read + buffer which is large enough to receive the largest event that + could ever arrive. See for descriptions + of all event types and for which ioctls affect reception of + events. + + mmap(2) + Allocate a DMA buffer for isochronous reception or transmission + and map it into the process address space. The arguments should + be used as follows: addr = NULL, length = the desired buffer + size, i.e. number of packets times size of largest packet, + prot = at least PROT_READ for reception and at least PROT_WRITE + for transmission, flags = MAP_SHARED, fd = the handle to the + /dev/fw*, offset = 0. + + Isochronous reception works in packet-per-buffer fashion except + for multichannel reception which works in buffer-fill mode. + + munmap(2) + Unmap the isochronous I/O buffer from the process address space. + + close(2) + Besides stopping and freeing I/O contexts that were associated + with the file descriptor, back out any changes to the local + nodes' Configuration ROM. Deallocate isochronous channels and + bandwidth at the IRM that were marked for kernel-assisted + re- and deallocation. + +Users: libraw1394 + libdc1394 + tools like jujuutils, fwhack, ... diff --git a/Documentation/ABI/stable/sysfs-bus-firewire b/Documentation/ABI/stable/sysfs-bus-firewire new file mode 100644 index 0000000..3d484e5 --- /dev/null +++ b/Documentation/ABI/stable/sysfs-bus-firewire @@ -0,0 +1,122 @@ +What: /sys/bus/firewire/devices/fw[0-9]+/ +Date: May 2007 +KernelVersion: 2.6.22 +Contact: linux1394-devel@lists.sourceforge.net +Description: + IEEE 1394 node device attributes. + Read-only. Mutable during the node device's lifetime. + See IEEE 1212 for semantic definitions. + + config_rom + Contents of the Configuration ROM register. + Binary attribute; an array of host-endian u32. + + guid + The node's EUI-64 in the bus information block of + Configuration ROM. + Hexadecimal string representation of an u64. + + +What: /sys/bus/firewire/devices/fw[0-9]+/units +Date: June 2009 +KernelVersion: 2.6.31 +Contact: linux1394-devel@lists.sourceforge.net +Description: + IEEE 1394 node device attribute. + Read-only. Mutable during the node device's lifetime. + See IEEE 1212 for semantic definitions. + + units + Summary of all units present in an IEEE 1394 node. + Contains space-separated tuples of specifier_id and + version of each unit present in the node. Specifier_id + and version are hexadecimal string representations of + u24 of the respective unit directory entries. + Specifier_id and version within each tuple are separated + by a colon. + +Users: udev rules to set ownership and access permissions or ACLs of + /dev/fw[0-9]+ character device files + + +What: /sys/bus/firewire/devices/fw[0-9]+[.][0-9]+/ +Date: May 2007 +KernelVersion: 2.6.22 +Contact: linux1394-devel@lists.sourceforge.net +Description: + IEEE 1394 unit device attributes. + Read-only. Immutable during the unit device's lifetime. + See IEEE 1212 for semantic definitions. + + modalias + Same as MODALIAS in the uevent at device creation. + + rom_index + Offset of the unit directory within the parent device's + (node device's) Configuration ROM, in quadlets. + Decimal string representation. + + +What: /sys/bus/firewire/devices/*/ +Date: May 2007 +KernelVersion: 2.6.22 +Contact: linux1394-devel@lists.sourceforge.net +Description: + Attributes common to IEEE 1394 node devices and unit devices. + Read-only. Mutable during the node device's lifetime. + Immutable during the unit device's lifetime. + See IEEE 1212 for semantic definitions. + + These attributes are only created if the root directory of an + IEEE 1394 node or the unit directory of an IEEE 1394 unit + actually contains according entries. + + hardware_version + Hexadecimal string representation of an u24. + + hardware_version_name + Contents of a respective textual descriptor leaf. + + model + Hexadecimal string representation of an u24. + + model_name + Contents of a respective textual descriptor leaf. + + specifier_id + Hexadecimal string representation of an u24. + Mandatory in unit directories according to IEEE 1212. + + vendor + Hexadecimal string representation of an u24. + Mandatory in the root directory according to IEEE 1212. + + vendor_name + Contents of a respective textual descriptor leaf. + + version + Hexadecimal string representation of an u24. + Mandatory in unit directories according to IEEE 1212. + + +What: /sys/bus/firewire/drivers/sbp2/fw*/host*/target*/*:*:*:*/ieee1394_id + formerly + /sys/bus/ieee1394/drivers/sbp2/fw*/host*/target*/*:*:*:*/ieee1394_id +Date: Feb 2004 +KernelVersion: 2.6.4 +Contact: linux1394-devel@lists.sourceforge.net +Description: + SCSI target port identifier and logical unit identifier of a + logical unit of an SBP-2 target. The identifiers are specified + in SAM-2...SAM-4 annex A. They are persistent and world-wide + unique properties the SBP-2 attached target. + + Read-only attribute, immutable during the target's lifetime. + Format, as exposed by firewire-sbp2 since 2.6.22, May 2007: + Colon-separated hexadecimal string representations of + u64 EUI-64 : u24 directory_ID : u16 LUN + without 0x prefixes, without whitespace. The former sbp2 driver + (removed in 2.6.37 after being superseded by firewire-sbp2) used + a somewhat shorter format which was not as close to SAM. + +Users: udev rules to create /dev/disk/by-id/ symlinks diff --git a/Documentation/ABI/stable/vdso b/Documentation/ABI/stable/vdso new file mode 100644 index 0000000..8a1cbb5 --- /dev/null +++ b/Documentation/ABI/stable/vdso @@ -0,0 +1,27 @@ +On some architectures, when the kernel loads any userspace program it +maps an ELF DSO into that program's address space. This DSO is called +the vDSO and it often contains useful and highly-optimized alternatives +to real syscalls. + +These functions are called just like ordinary C function according to +your platform's ABI. Call them from a sensible context. (For example, +if you set CS on x86 to something strange, the vDSO functions are +within their rights to crash.) In addition, if you pass a bad +pointer to a vDSO function, you might get SIGSEGV instead of -EFAULT. + +To find the DSO, parse the auxiliary vector passed to the program's +entry point. The AT_SYSINFO_EHDR entry will point to the vDSO. + +The vDSO uses symbol versioning; whenever you request a symbol from the +vDSO, specify the version you are expecting. + +Programs that dynamically link to glibc will use the vDSO automatically. +Otherwise, you can use the reference parser in Documentation/vDSO/parse_vdso.c. + +Unless otherwise noted, the set of symbols with any given version and the +ABI of those symbols is considered stable. It may vary across architectures, +though. + +(As of this writing, this ABI documentation as been confirmed for x86_64. + The maintainers of the other vDSO-using architectures should confirm + that it is correct for their architecture.) \ No newline at end of file diff --git a/Documentation/ABI/testing/sysfs-bus-i2c-devices-fsa9480 b/Documentation/ABI/testing/sysfs-bus-i2c-devices-fsa9480 new file mode 100644 index 0000000..9de269b --- /dev/null +++ b/Documentation/ABI/testing/sysfs-bus-i2c-devices-fsa9480 @@ -0,0 +1,21 @@ +What: /sys/bus/i2c/devices/.../device +Date: February 2011 +Contact: Minkyu Kang +Description: + show what device is attached + NONE - no device + USB - USB device is attached + UART - UART is attached + CHARGER - Charger is attaced + JIG - JIG is attached + +What: /sys/bus/i2c/devices/.../switch +Date: February 2011 +Contact: Minkyu Kang +Description: + show or set the state of manual switch + VAUDIO - switch to VAUDIO path + UART - switch to UART path + AUDIO - switch to AUDIO path + DHOST - switch to DHOST path + AUTO - switch automatically by device diff --git a/Documentation/ABI/testing/sysfs-driver-hid-roccat-koneplus b/Documentation/ABI/testing/sysfs-driver-hid-roccat-koneplus index c1b53b8..65e6e5d 100644 --- a/Documentation/ABI/testing/sysfs-driver-hid-roccat-koneplus +++ b/Documentation/ABI/testing/sysfs-driver-hid-roccat-koneplus @@ -92,6 +92,14 @@ Description: The mouse has a tracking- and a distance-control-unit. These This file is writeonly. Users: http://roccat.sourceforge.net +What: /sys/bus/usb/devices/-:./::./koneplus/roccatkoneplus/talk +Date: May 2011 +Contact: Stefan Achatz +Description: Used to active some easy* functions of the mouse from outside. + The data has to be 16 bytes long. + This file is writeonly. +Users: http://roccat.sourceforge.net + What: /sys/bus/usb/devices/-:./::./koneplus/roccatkoneplus/tcu Date: October 2010 Contact: Stefan Achatz diff --git a/Documentation/ABI/testing/sysfs-driver-hid-wiimote b/Documentation/ABI/testing/sysfs-driver-hid-wiimote new file mode 100644 index 0000000..5d5a16e --- /dev/null +++ b/Documentation/ABI/testing/sysfs-driver-hid-wiimote @@ -0,0 +1,10 @@ +What: /sys/bus/hid/drivers/wiimote//led1 +What: /sys/bus/hid/drivers/wiimote//led2 +What: /sys/bus/hid/drivers/wiimote//led3 +What: /sys/bus/hid/drivers/wiimote//led4 +Date: July 2011 +KernelVersion: 3.1 +Contact: David Herrmann +Description: Make it possible to set/get current led state. Reading from it + returns 0 if led is off and 1 if it is on. Writing 0 to it + disables the led, writing 1 enables it. diff --git a/Documentation/ABI/testing/sysfs-module b/Documentation/ABI/testing/sysfs-module index cfcec3b..9489ea8 100644 --- a/Documentation/ABI/testing/sysfs-module +++ b/Documentation/ABI/testing/sysfs-module @@ -10,3 +10,26 @@ KernelVersion: 2.6.35 Contact: masa-korg@dsn.okisemi.com Description: Write/read Option ROM data. + +What: /sys/module/ehci_hcd/drivers/.../uframe_periodic_max +Date: July 2011 +KernelVersion: 3.1 +Contact: Kirill Smelkov +Description: Maximum time allowed for periodic transfers per microframe (μs) + + [ USB 2.0 sets maximum allowed time for periodic transfers per + microframe to be 80%, that is 100 microseconds out of 125 + microseconds (full microframe). + + However there are cases, when 80% max isochronous bandwidth is + too limiting. For example two video streams could require 110 + microseconds of isochronous bandwidth per microframe to work + together. ] + + Through this setting it is possible to raise the limit so that + the host controller would allow allocating more than 100 + microseconds of periodic bandwidth per microframe. + + Beware, non-standard modes are usually not thoroughly tested by + hardware designers, and the hardware can malfunction when this + setting differ from default 100. diff --git a/Documentation/DMA-API-HOWTO.txt b/Documentation/DMA-API-HOWTO.txt index d568bc2..a0b6250 100644 --- a/Documentation/DMA-API-HOWTO.txt +++ b/Documentation/DMA-API-HOWTO.txt @@ -613,13 +613,13 @@ to use the dma_sync_*() interfaces. pass_to_upper_layers(cp->rx_buf); make_and_setup_new_rx_buf(cp); } else { - /* Just sync the buffer and give it back - * to the card. + /* CPU should not write to + * DMA_FROM_DEVICE-mapped area, + * so dma_sync_single_for_device() is + * not needed here. It would be required + * for DMA_BIDIRECTIONAL mapping if + * the memory was modified. */ - dma_sync_single_for_device(&cp->dev, - cp->rx_dma, - cp->rx_len, - DMA_FROM_DEVICE); give_rx_buf_to_card(cp); } } diff --git a/Documentation/DocBook/80211.tmpl b/Documentation/DocBook/80211.tmpl index 8906648..445289c 100644 --- a/Documentation/DocBook/80211.tmpl +++ b/Documentation/DocBook/80211.tmpl @@ -402,8 +402,9 @@ !Finclude/net/mac80211.h set_key_cmd !Finclude/net/mac80211.h ieee80211_key_conf !Finclude/net/mac80211.h ieee80211_key_flags -!Finclude/net/mac80211.h ieee80211_tkip_key_type -!Finclude/net/mac80211.h ieee80211_get_tkip_key +!Finclude/net/mac80211.h ieee80211_get_tkip_p1k +!Finclude/net/mac80211.h ieee80211_get_tkip_p1k_iv +!Finclude/net/mac80211.h ieee80211_get_tkip_p2k !Finclude/net/mac80211.h ieee80211_key_removed diff --git a/Documentation/DocBook/kernel-hacking.tmpl b/Documentation/DocBook/kernel-hacking.tmpl index 7b3f493..07a9c48 100644 --- a/Documentation/DocBook/kernel-hacking.tmpl +++ b/Documentation/DocBook/kernel-hacking.tmpl @@ -409,7 +409,7 @@ cond_resched(); /* Will sleep */ You should always compile your kernel - CONFIG_DEBUG_SPINLOCK_SLEEP on, and it will warn + CONFIG_DEBUG_ATOMIC_SLEEP on, and it will warn you if you break these rules. If you do break the rules, you will eventually lock up your box. diff --git a/Documentation/DocBook/v4l/io.xml b/Documentation/DocBook/v4l/io.xml index 227e7ac..c57d1ec 100644 --- a/Documentation/DocBook/v4l/io.xml +++ b/Documentation/DocBook/v4l/io.xml @@ -210,7 +210,7 @@ for (i = 0; i < reqbuf.count; i++) &v4l2-requestbuffers; reqbuf; /* Our current format uses 3 planes per buffer */ -#define FMT_NUM_PLANES = 3; +#define FMT_NUM_PLANES = 3 struct { void *start[FMT_NUM_PLANES]; diff --git a/Documentation/DocBook/writing-an-alsa-driver.tmpl b/Documentation/DocBook/writing-an-alsa-driver.tmpl index 58ced23..598c22f 100644 --- a/Documentation/DocBook/writing-an-alsa-driver.tmpl +++ b/Documentation/DocBook/writing-an-alsa-driver.tmpl @@ -1164,7 +1164,7 @@ } chip->port = pci_resource_start(pci, 0); if (request_irq(pci->irq, snd_mychip_interrupt, - IRQF_SHARED, "My Chip", chip)) { + IRQF_SHARED, KBUILD_MODNAME, chip)) { printk(KERN_ERR "cannot grab irq %d\n", pci->irq); snd_mychip_free(chip); return -EBUSY; @@ -1197,7 +1197,7 @@ /* pci_driver definition */ static struct pci_driver driver = { - .name = "My Own Chip", + .name = KBUILD_MODNAME, .id_table = snd_mychip_ids, .probe = snd_mychip_probe, .remove = __devexit_p(snd_mychip_remove), @@ -1340,7 +1340,7 @@ irq, snd_mychip_interrupt, - IRQF_SHARED, "My Chip", chip)) { + IRQF_SHARED, KBUILD_MODNAME, chip)) { printk(KERN_ERR "cannot grab irq %d\n", pci->irq); snd_mychip_free(chip); return -EBUSY; @@ -1616,7 +1616,7 @@ = 1 (from kernel version 2.6.12). + +kuser_cmpxchg +------------- + +Location: 0xffff0fc0 + +Reference prototype: + + int __kuser_cmpxchg(int32_t oldval, int32_t newval, volatile int32_t *ptr); + +Input: + + r0 = oldval + r1 = newval + r2 = ptr + lr = return address + +Output: + + r0 = success code (zero or non-zero) + C flag = set if r0 == 0, clear if r0 != 0 + +Clobbered registers: + + r3, ip, flags + +Definition: + + Atomically store newval in *ptr only if *ptr is equal to oldval. + Return zero if *ptr was changed or non-zero if no exchange happened. + The C flag is also set if *ptr was changed to allow for assembly + optimization in the calling code. + +Usage example: + +typedef int (__kuser_cmpxchg_t)(int oldval, int newval, volatile int *ptr); +#define __kuser_cmpxchg (*(__kuser_cmpxchg_t *)0xffff0fc0) + +int atomic_add(volatile int *ptr, int val) +{ + int old, new; + + do { + old = *ptr; + new = old + val; + } while(__kuser_cmpxchg(old, new, ptr)); + + return new; +} + +Notes: + + - This routine already includes memory barriers as needed. + + - Valid only if __kuser_helper_version >= 2 (from kernel version 2.6.12). + +kuser_memory_barrier +-------------------- + +Location: 0xffff0fa0 + +Reference prototype: + + void __kuser_memory_barrier(void); + +Input: + + lr = return address + +Output: + + none + +Clobbered registers: + + none + +Definition: + + Apply any needed memory barrier to preserve consistency with data modified + manually and __kuser_cmpxchg usage. + +Usage example: + +typedef void (__kuser_dmb_t)(void); +#define __kuser_dmb (*(__kuser_dmb_t *)0xffff0fa0) + +Notes: + + - Valid only if __kuser_helper_version >= 3 (from kernel version 2.6.15). + +kuser_cmpxchg64 +--------------- + +Location: 0xffff0f60 + +Reference prototype: + + int __kuser_cmpxchg64(const int64_t *oldval, + const int64_t *newval, + volatile int64_t *ptr); + +Input: + + r0 = pointer to oldval + r1 = pointer to newval + r2 = pointer to target value + lr = return address + +Output: + + r0 = success code (zero or non-zero) + C flag = set if r0 == 0, clear if r0 != 0 + +Clobbered registers: + + r3, lr, flags + +Definition: + + Atomically store the 64-bit value pointed by *newval in *ptr only if *ptr + is equal to the 64-bit value pointed by *oldval. Return zero if *ptr was + changed or non-zero if no exchange happened. + + The C flag is also set if *ptr was changed to allow for assembly + optimization in the calling code. + +Usage example: + +typedef int (__kuser_cmpxchg64_t)(const int64_t *oldval, + const int64_t *newval, + volatile int64_t *ptr); +#define __kuser_cmpxchg64 (*(__kuser_cmpxchg64_t *)0xffff0f60) + +int64_t atomic_add64(volatile int64_t *ptr, int64_t val) +{ + int64_t old, new; + + do { + old = *ptr; + new = old + val; + } while(__kuser_cmpxchg64(&old, &new, ptr)); + + return new; +} + +Notes: + + - This routine already includes memory barriers as needed. + + - Due to the length of this sequence, this spans 2 conventional kuser + "slots", therefore 0xffff0f80 is not used as a valid entry point. + + - Valid only if __kuser_helper_version >= 5 (from kernel version 3.1). diff --git a/Documentation/blackfin/bfin-spi-notes.txt b/Documentation/blackfin/bfin-spi-notes.txt index 556fa87..eae6eaf 100644 --- a/Documentation/blackfin/bfin-spi-notes.txt +++ b/Documentation/blackfin/bfin-spi-notes.txt @@ -9,6 +9,8 @@ the entire SPI transfer. - And not just bits_per_word duration. In most cases you can utilize SPI MODE_3 instead of MODE_0 to work-around this behavior. If your SPI slave device in question requires SPI MODE_0 or MODE_2 timing, you can utilize the GPIO controlled SPI Slave Select option instead. +In this case, you should use GPIO based CS for all of your slaves and not just +the ones using mode 0 or 2 in order to guarantee correct CS toggling behavior. You can even use the same pin whose peripheral role is a SSEL, but use it as a GPIO instead. diff --git a/Documentation/block/queue-sysfs.txt b/Documentation/block/queue-sysfs.txt index f652740..d8147b3 100644 --- a/Documentation/block/queue-sysfs.txt +++ b/Documentation/block/queue-sysfs.txt @@ -45,9 +45,13 @@ device. rq_affinity (RW) ---------------- -If this option is enabled, the block layer will migrate request completions -to the CPU that originally submitted the request. For some workloads -this provides a significant reduction in CPU cycles due to caching effects. +If this option is '1', the block layer will migrate request completions to the +cpu "group" that originally submitted the request. For some workloads this +provides a significant reduction in CPU cycles due to caching effects. + +For storage configurations that need to maximize distribution of completion +processing setting this option to '2' forces the completion to run on the +requesting cpu (bypassing the "group" aggregation logic). scheduler (RW) -------------- diff --git a/Documentation/blockdev/README.DAC960 b/Documentation/blockdev/README.DAC960 index 0e8f618..bd85fb9 100644 --- a/Documentation/blockdev/README.DAC960 +++ b/Documentation/blockdev/README.DAC960 @@ -214,7 +214,7 @@ replacing "/usr/src" with wherever you keep your Linux kernel source tree: make config make bzImage (or zImage) -Then install "arch/i386/boot/bzImage" or "arch/i386/boot/zImage" as your +Then install "arch/x86/boot/bzImage" or "arch/x86/boot/zImage" as your standard kernel, run lilo if appropriate, and reboot. To create the necessary devices in /dev, the "make_rd" script included in diff --git a/Documentation/blockdev/ramdisk.txt b/Documentation/blockdev/ramdisk.txt index 6c820ba..fa72e97 100644 --- a/Documentation/blockdev/ramdisk.txt +++ b/Documentation/blockdev/ramdisk.txt @@ -64,9 +64,9 @@ the RAM disk dynamically grows as data is being written into it, a size field is not required. Bits 11 to 13 are not currently used and may as well be zero. These numbers are no magical secrets, as seen below: -./arch/i386/kernel/setup.c:#define RAMDISK_IMAGE_START_MASK 0x07FF -./arch/i386/kernel/setup.c:#define RAMDISK_PROMPT_FLAG 0x8000 -./arch/i386/kernel/setup.c:#define RAMDISK_LOAD_FLAG 0x4000 +./arch/x86/kernel/setup.c:#define RAMDISK_IMAGE_START_MASK 0x07FF +./arch/x86/kernel/setup.c:#define RAMDISK_PROMPT_FLAG 0x8000 +./arch/x86/kernel/setup.c:#define RAMDISK_LOAD_FLAG 0x4000 Consider a typical two floppy disk setup, where you will have the kernel on disk one, and have already put a RAM disk image onto disk #2. @@ -85,7 +85,7 @@ The command line equivalent is: "prompt_ramdisk=1" Putting that together gives 2^15 + 2^14 + 0 = 49152 for an rdev word. So to create disk one of the set, you would do: - /usr/src/linux# cat arch/i386/boot/zImage > /dev/fd0 + /usr/src/linux# cat arch/x86/boot/zImage > /dev/fd0 /usr/src/linux# rdev /dev/fd0 /dev/fd0 /usr/src/linux# rdev -r /dev/fd0 49152 diff --git a/Documentation/cgroups/cpuacct.txt b/Documentation/cgroups/cpuacct.txt index 9ad85df..9d73cc0 100644 --- a/Documentation/cgroups/cpuacct.txt +++ b/Documentation/cgroups/cpuacct.txt @@ -23,7 +23,7 @@ New accounting groups can be created under the parent group /sys/fs/cgroup. # cd /sys/fs/cgroup # mkdir g1 -# echo $$ > g1 +# echo $$ > g1/tasks The above steps create a new group g1 and move the current shell process (bash) into it. CPU time consumed by this bash and its children diff --git a/Documentation/cgroups/cpusets.txt b/Documentation/cgroups/cpusets.txt index 5b0d78e..5c51ed4 100644 --- a/Documentation/cgroups/cpusets.txt +++ b/Documentation/cgroups/cpusets.txt @@ -180,7 +180,7 @@ files describing that cpuset: - cpuset.sched_load_balance flag: if set, load balance within CPUs on that cpuset - cpuset.sched_relax_domain_level: the searching range when migrating tasks -In addition, the root cpuset only has the following file: +In addition, only the root cpuset has the following file: - cpuset.memory_pressure_enabled flag: compute memory_pressure? New cpusets are created using the mkdir system call or shell diff --git a/Documentation/cgroups/memory.txt b/Documentation/cgroups/memory.txt index 06eb6d9..6f3c598 100644 --- a/Documentation/cgroups/memory.txt +++ b/Documentation/cgroups/memory.txt @@ -380,7 +380,7 @@ will be charged as a new owner of it. 5.2 stat file -memory.stat file includes following statistics +5.2.1 memory.stat file includes following statistics # per-memory cgroup local status cache - # of bytes of page cache memory. @@ -438,6 +438,89 @@ Note: file_mapped is accounted only when the memory cgroup is owner of page cache.) +5.2.2 memory.vmscan_stat + +memory.vmscan_stat includes statistics information for memory scanning and +freeing, reclaiming. The statistics shows memory scanning information since +memory cgroup creation and can be reset to 0 by writing 0 as + + #echo 0 > ../memory.vmscan_stat + +This file contains following statistics. + +[param]_[file_or_anon]_pages_by_[reason]_[under_heararchy] +[param]_elapsed_ns_by_[reason]_[under_hierarchy] + +For example, + + scanned_file_pages_by_limit indicates the number of scanned + file pages at vmscan. + +Now, 3 parameters are supported + + scanned - the number of pages scanned by vmscan + rotated - the number of pages activated at vmscan + freed - the number of pages freed by vmscan + +If "rotated" is high against scanned/freed, the memcg seems busy. + +Now, 2 reason are supported + + limit - the memory cgroup's limit + system - global memory pressure + softlimit + (global memory pressure not under softlimit is not handled now) + +When under_hierarchy is added in the tail, the number indicates the +total memcg scan of its children and itself. + +elapsed_ns is a elapsed time in nanosecond. This may include sleep time +and not indicates CPU usage. So, please take this as just showing +latency. + +Here is an example. + +# cat /cgroup/memory/A/memory.vmscan_stat +scanned_pages_by_limit 9471864 +scanned_anon_pages_by_limit 6640629 +scanned_file_pages_by_limit 2831235 +rotated_pages_by_limit 4243974 +rotated_anon_pages_by_limit 3971968 +rotated_file_pages_by_limit 272006 +freed_pages_by_limit 2318492 +freed_anon_pages_by_limit 962052 +freed_file_pages_by_limit 1356440 +elapsed_ns_by_limit 351386416101 +scanned_pages_by_system 0 +scanned_anon_pages_by_system 0 +scanned_file_pages_by_system 0 +rotated_pages_by_system 0 +rotated_anon_pages_by_system 0 +rotated_file_pages_by_system 0 +freed_pages_by_system 0 +freed_anon_pages_by_system 0 +freed_file_pages_by_system 0 +elapsed_ns_by_system 0 +scanned_pages_by_limit_under_hierarchy 9471864 +scanned_anon_pages_by_limit_under_hierarchy 6640629 +scanned_file_pages_by_limit_under_hierarchy 2831235 +rotated_pages_by_limit_under_hierarchy 4243974 +rotated_anon_pages_by_limit_under_hierarchy 3971968 +rotated_file_pages_by_limit_under_hierarchy 272006 +freed_pages_by_limit_under_hierarchy 2318492 +freed_anon_pages_by_limit_under_hierarchy 962052 +freed_file_pages_by_limit_under_hierarchy 1356440 +elapsed_ns_by_limit_under_hierarchy 351386416101 +scanned_pages_by_system_under_hierarchy 0 +scanned_anon_pages_by_system_under_hierarchy 0 +scanned_file_pages_by_system_under_hierarchy 0 +rotated_pages_by_system_under_hierarchy 0 +rotated_anon_pages_by_system_under_hierarchy 0 +rotated_file_pages_by_system_under_hierarchy 0 +freed_pages_by_system_under_hierarchy 0 +freed_anon_pages_by_system_under_hierarchy 0 +freed_file_pages_by_system_under_hierarchy 0 +elapsed_ns_by_system_under_hierarchy 0 + 5.3 swappiness Similar to /proc/sys/vm/swappiness, but affecting a hierarchy of groups only. diff --git a/Documentation/cpu-freq/cpu-drivers.txt b/Documentation/cpu-freq/cpu-drivers.txt index 6c30e93..c436096 100644 --- a/Documentation/cpu-freq/cpu-drivers.txt +++ b/Documentation/cpu-freq/cpu-drivers.txt @@ -168,7 +168,7 @@ in-chipset dynamic frequency switching to policy->min, the upper limit to policy->max, and -if supported- select a performance-oriented setting when policy->policy is CPUFREQ_POLICY_PERFORMANCE, and a powersaving-oriented setting when CPUFREQ_POLICY_POWERSAVE. Also check -the reference implementation in arch/i386/kernel/cpu/cpufreq/longrun.c +the reference implementation in drivers/cpufreq/longrun.c diff --git a/Documentation/development-process/4.Coding b/Documentation/development-process/4.Coding index f3f1a46..83f5f5b 100644 --- a/Documentation/development-process/4.Coding +++ b/Documentation/development-process/4.Coding @@ -244,7 +244,7 @@ testing purposes. In particular, you should turn on: - DEBUG_SLAB can find a variety of memory allocation and use errors; it should be used on most development kernels. - - DEBUG_SPINLOCK, DEBUG_SPINLOCK_SLEEP, and DEBUG_MUTEXES will find a + - DEBUG_SPINLOCK, DEBUG_ATOMIC_SLEEP, and DEBUG_MUTEXES will find a number of common locking errors. There are quite a few other debugging options, some of which will be diff --git a/Documentation/devicetree/bindings/arm/pmu.txt b/Documentation/devicetree/bindings/arm/pmu.txt new file mode 100644 index 0000000..1c044eb --- /dev/null +++ b/Documentation/devicetree/bindings/arm/pmu.txt @@ -0,0 +1,21 @@ +* ARM Performance Monitor Units + +ARM cores often have a PMU for counting cpu and cache events like cache misses +and hits. The interface to the PMU is part of the ARM ARM. The ARM PMU +representation in the device tree should be done as under:- + +Required properties: + +- compatible : should be one of + "arm,cortex-a9-pmu" + "arm,cortex-a8-pmu" + "arm,arm1176-pmu" + "arm,arm1136-pmu" +- interrupts : 1 combined interrupt or 1 per core. + +Example: + +pmu { + compatible = "arm,cortex-a9-pmu"; + interrupts = <100 101>; +}; diff --git a/Documentation/devicetree/bindings/arm/primecell.txt b/Documentation/devicetree/bindings/arm/primecell.txt new file mode 100644 index 0000000..1d5d7a8 --- /dev/null +++ b/Documentation/devicetree/bindings/arm/primecell.txt @@ -0,0 +1,21 @@ +* ARM Primecell Peripherals + +ARM, Ltd. Primecell peripherals have a standard id register that can be used to +identify the peripheral type, vendor, and revision. This value can be used for +driver matching. + +Required properties: + +- compatible : should be a specific value for peripheral and "arm,primecell" + +Optional properties: + +- arm,primecell-periphid : Value to override the h/w value with + +Example: + +serial@fff36000 { + compatible = "arm,pl011", "arm,primecell"; + arm,primecell-periphid = <0x00341011>; +}; + diff --git a/Documentation/devicetree/bindings/arm/sirf.txt b/Documentation/devicetree/bindings/arm/sirf.txt new file mode 100644 index 0000000..6b07f65 --- /dev/null +++ b/Documentation/devicetree/bindings/arm/sirf.txt @@ -0,0 +1,3 @@ +prima2 "cb" evalutation board +Required root node properties: + - compatible = "sirf,prima2-cb", "sirf,prima2"; diff --git a/Documentation/devicetree/bindings/arm/xilinx.txt b/Documentation/devicetree/bindings/arm/xilinx.txt new file mode 100644 index 0000000..6f1ed830 --- /dev/null +++ b/Documentation/devicetree/bindings/arm/xilinx.txt @@ -0,0 +1,7 @@ +Xilinx Zynq EP107 Emulation Platform board + +This board is an emulation platform for the Zynq product which is +based on an ARM Cortex A9 processor. + +Required root node properties: + - compatible = "xlnx,zynq-ep107"; diff --git a/Documentation/devicetree/bindings/crypto/fsl-sec2.txt b/Documentation/devicetree/bindings/crypto/fsl-sec2.txt new file mode 100644 index 0000000..38988ef --- /dev/null +++ b/Documentation/devicetree/bindings/crypto/fsl-sec2.txt @@ -0,0 +1,68 @@ +Freescale SoC SEC Security Engines versions 2.x-3.x + +Required properties: + +- compatible : Should contain entries for this and backward compatible + SEC versions, high to low, e.g., "fsl,sec2.1", "fsl,sec2.0" +- reg : Offset and length of the register set for the device +- interrupts : the SEC's interrupt number +- fsl,num-channels : An integer representing the number of channels + available. +- fsl,channel-fifo-len : An integer representing the number of + descriptor pointers each channel fetch fifo can hold. +- fsl,exec-units-mask : The bitmask representing what execution units + (EUs) are available. It's a single 32-bit cell. EU information + should be encoded following the SEC's Descriptor Header Dword + EU_SEL0 field documentation, i.e. as follows: + + bit 0 = reserved - should be 0 + bit 1 = set if SEC has the ARC4 EU (AFEU) + bit 2 = set if SEC has the DES/3DES EU (DEU) + bit 3 = set if SEC has the message digest EU (MDEU/MDEU-A) + bit 4 = set if SEC has the random number generator EU (RNG) + bit 5 = set if SEC has the public key EU (PKEU) + bit 6 = set if SEC has the AES EU (AESU) + bit 7 = set if SEC has the Kasumi EU (KEU) + bit 8 = set if SEC has the CRC EU (CRCU) + bit 11 = set if SEC has the message digest EU extended alg set (MDEU-B) + +remaining bits are reserved for future SEC EUs. + +- fsl,descriptor-types-mask : The bitmask representing what descriptors + are available. It's a single 32-bit cell. Descriptor type information + should be encoded following the SEC's Descriptor Header Dword DESC_TYPE + field documentation, i.e. as follows: + + bit 0 = set if SEC supports the aesu_ctr_nonsnoop desc. type + bit 1 = set if SEC supports the ipsec_esp descriptor type + bit 2 = set if SEC supports the common_nonsnoop desc. type + bit 3 = set if SEC supports the 802.11i AES ccmp desc. type + bit 4 = set if SEC supports the hmac_snoop_no_afeu desc. type + bit 5 = set if SEC supports the srtp descriptor type + bit 6 = set if SEC supports the non_hmac_snoop_no_afeu desc.type + bit 7 = set if SEC supports the pkeu_assemble descriptor type + bit 8 = set if SEC supports the aesu_key_expand_output desc.type + bit 9 = set if SEC supports the pkeu_ptmul descriptor type + bit 10 = set if SEC supports the common_nonsnoop_afeu desc. type + bit 11 = set if SEC supports the pkeu_ptadd_dbl descriptor type + + ..and so on and so forth. + +Optional properties: + +- interrupt-parent : the phandle for the interrupt controller that + services interrupts for this device. + +Example: + + /* MPC8548E */ + crypto@30000 { + compatible = "fsl,sec2.1", "fsl,sec2.0"; + reg = <0x30000 0x10000>; + interrupts = <29 2>; + interrupt-parent = <&mpic>; + fsl,num-channels = <4>; + fsl,channel-fifo-len = <24>; + fsl,exec-units-mask = <0xfe>; + fsl,descriptor-types-mask = <0x12b0ebf>; + }; diff --git a/Documentation/devicetree/bindings/gpio/fsl-imx-gpio.txt b/Documentation/devicetree/bindings/gpio/fsl-imx-gpio.txt new file mode 100644 index 0000000..4363ae4 --- /dev/null +++ b/Documentation/devicetree/bindings/gpio/fsl-imx-gpio.txt @@ -0,0 +1,22 @@ +* Freescale i.MX/MXC GPIO controller + +Required properties: +- compatible : Should be "fsl,-gpio" +- reg : Address and length of the register set for the device +- interrupts : Should be the port interrupt shared by all 32 pins, if + one number. If two numbers, the first one is the interrupt shared + by low 16 pins and the second one is for high 16 pins. +- gpio-controller : Marks the device node as a gpio controller. +- #gpio-cells : Should be two. The first cell is the pin number and + the second cell is used to specify optional parameters (currently + unused). + +Example: + +gpio0: gpio@73f84000 { + compatible = "fsl,imx51-gpio", "fsl,imx31-gpio"; + reg = <0x73f84000 0x4000>; + interrupts = <50 51>; + gpio-controller; + #gpio-cells = <2>; +}; diff --git a/Documentation/devicetree/bindings/gpio/gpio.txt b/Documentation/devicetree/bindings/gpio/gpio.txt index edaa84d..4e16ba4 100644 --- a/Documentation/devicetree/bindings/gpio/gpio.txt +++ b/Documentation/devicetree/bindings/gpio/gpio.txt @@ -4,17 +4,45 @@ Specifying GPIO information for devices 1) gpios property ----------------- -Nodes that makes use of GPIOs should define them using `gpios' property, -format of which is: <&gpio-controller1-phandle gpio1-specifier - &gpio-controller2-phandle gpio2-specifier - 0 /* holes are permitted, means no GPIO 3 */ - &gpio-controller4-phandle gpio4-specifier - ...>; +Nodes that makes use of GPIOs should specify them using one or more +properties, each containing a 'gpio-list': -Note that gpio-specifier length is controller dependent. + gpio-list ::= [gpio-list] + single-gpio ::= + gpio-phandle : phandle to gpio controller node + gpio-specifier : Array of #gpio-cells specifying specific gpio + (controller specific) + +GPIO properties should be named "[-]gpios". Exact +meaning of each gpios property must be documented in the device tree +binding for each device. + +For example, the following could be used to describe gpios pins to use +as chip select lines; with chip selects 0, 1 and 3 populated, and chip +select 2 left empty: + + gpio1: gpio1 { + gpio-controller + #gpio-cells = <2>; + }; + gpio2: gpio2 { + gpio-controller + #gpio-cells = <1>; + }; + [...] + chipsel-gpios = <&gpio1 12 0>, + <&gpio1 13 0>, + <0>, /* holes are permitted, means no GPIO 2 */ + <&gpio2 2>; + +Note that gpio-specifier length is controller dependent. In the +above example, &gpio1 uses 2 cells to specify a gpio, while &gpio2 +only uses one. gpio-specifier may encode: bank, pin position inside the bank, whether pin is open-drain and whether pin is logically inverted. +Exact meaning of each specifier cell is controller specific, and must +be documented in the device tree binding for the device. Example of the node using GPIOs: @@ -28,8 +56,8 @@ and empty GPIO flags as accepted by the "qe_pio_e" gpio-controller. 2) gpio-controller nodes ------------------------ -Every GPIO controller node must have #gpio-cells property defined, -this information will be used to translate gpio-specifiers. +Every GPIO controller node must both an empty "gpio-controller" +property, and have #gpio-cells contain the size of the gpio-specifier. Example of two SOC GPIO banks defined as gpio-controller nodes: diff --git a/Documentation/devicetree/bindings/gpio/gpio_keys.txt b/Documentation/devicetree/bindings/gpio/gpio_keys.txt new file mode 100644 index 0000000..7190c99 --- /dev/null +++ b/Documentation/devicetree/bindings/gpio/gpio_keys.txt @@ -0,0 +1,36 @@ +Device-Tree bindings for input/gpio_keys.c keyboard driver + +Required properties: + - compatible = "gpio-keys"; + +Optional properties: + - autorepeat: Boolean, Enable auto repeat feature of Linux input + subsystem. + +Each button (key) is represented as a sub-node of "gpio-keys": +Subnode properties: + + - gpios: OF devcie-tree gpio specificatin. + - label: Descriptive name of the key. + - linux,code: Keycode to emit. + +Optional subnode-properties: + - linux,input-type: Specify event type this button/key generates. + If not specified defaults to <1> == EV_KEY. + - debounce-interval: Debouncing interval time in milliseconds. + If not specified defaults to 5. + - gpio-key,wakeup: Boolean, button can wake-up the system. + +Example nodes: + + gpio_keys { + compatible = "gpio-keys"; + #address-cells = <1>; + #size-cells = <0>; + autorepeat; + button@21 { + label = "GPIO Key UP"; + linux,code = <103>; + gpios = <&gpio1 0 1>; + }; + ... diff --git a/Documentation/devicetree/bindings/gpio/gpio_nvidia.txt b/Documentation/devicetree/bindings/gpio/gpio_nvidia.txt new file mode 100644 index 0000000..eb4b530 --- /dev/null +++ b/Documentation/devicetree/bindings/gpio/gpio_nvidia.txt @@ -0,0 +1,8 @@ +NVIDIA Tegra 2 GPIO controller + +Required properties: +- compatible : "nvidia,tegra20-gpio" +- #gpio-cells : Should be two. The first cell is the pin number and the + second cell is used to specify optional parameters: + - bit 0 specifies polarity (0 for normal, 1 for inverted) +- gpio-controller : Marks the device node as a GPIO controller. diff --git a/Documentation/devicetree/bindings/net/can/fsl-flexcan.txt b/Documentation/devicetree/bindings/net/can/fsl-flexcan.txt old mode 100755 new mode 100644 diff --git a/Documentation/devicetree/bindings/powerpc/fsl/sec.txt b/Documentation/devicetree/bindings/powerpc/fsl/sec.txt deleted file mode 100644 index 2b6f2d4..0000000 --- a/Documentation/devicetree/bindings/powerpc/fsl/sec.txt +++ /dev/null @@ -1,68 +0,0 @@ -Freescale SoC SEC Security Engines - -Required properties: - -- compatible : Should contain entries for this and backward compatible - SEC versions, high to low, e.g., "fsl,sec2.1", "fsl,sec2.0" -- reg : Offset and length of the register set for the device -- interrupts : the SEC's interrupt number -- fsl,num-channels : An integer representing the number of channels - available. -- fsl,channel-fifo-len : An integer representing the number of - descriptor pointers each channel fetch fifo can hold. -- fsl,exec-units-mask : The bitmask representing what execution units - (EUs) are available. It's a single 32-bit cell. EU information - should be encoded following the SEC's Descriptor Header Dword - EU_SEL0 field documentation, i.e. as follows: - - bit 0 = reserved - should be 0 - bit 1 = set if SEC has the ARC4 EU (AFEU) - bit 2 = set if SEC has the DES/3DES EU (DEU) - bit 3 = set if SEC has the message digest EU (MDEU/MDEU-A) - bit 4 = set if SEC has the random number generator EU (RNG) - bit 5 = set if SEC has the public key EU (PKEU) - bit 6 = set if SEC has the AES EU (AESU) - bit 7 = set if SEC has the Kasumi EU (KEU) - bit 8 = set if SEC has the CRC EU (CRCU) - bit 11 = set if SEC has the message digest EU extended alg set (MDEU-B) - -remaining bits are reserved for future SEC EUs. - -- fsl,descriptor-types-mask : The bitmask representing what descriptors - are available. It's a single 32-bit cell. Descriptor type information - should be encoded following the SEC's Descriptor Header Dword DESC_TYPE - field documentation, i.e. as follows: - - bit 0 = set if SEC supports the aesu_ctr_nonsnoop desc. type - bit 1 = set if SEC supports the ipsec_esp descriptor type - bit 2 = set if SEC supports the common_nonsnoop desc. type - bit 3 = set if SEC supports the 802.11i AES ccmp desc. type - bit 4 = set if SEC supports the hmac_snoop_no_afeu desc. type - bit 5 = set if SEC supports the srtp descriptor type - bit 6 = set if SEC supports the non_hmac_snoop_no_afeu desc.type - bit 7 = set if SEC supports the pkeu_assemble descriptor type - bit 8 = set if SEC supports the aesu_key_expand_output desc.type - bit 9 = set if SEC supports the pkeu_ptmul descriptor type - bit 10 = set if SEC supports the common_nonsnoop_afeu desc. type - bit 11 = set if SEC supports the pkeu_ptadd_dbl descriptor type - - ..and so on and so forth. - -Optional properties: - -- interrupt-parent : the phandle for the interrupt controller that - services interrupts for this device. - -Example: - - /* MPC8548E */ - crypto@30000 { - compatible = "fsl,sec2.1", "fsl,sec2.0"; - reg = <0x30000 0x10000>; - interrupts = <29 2>; - interrupt-parent = <&mpic>; - fsl,num-channels = <4>; - fsl,channel-fifo-len = <24>; - fsl,exec-units-mask = <0xfe>; - fsl,descriptor-types-mask = <0x12b0ebf>; - }; diff --git a/Documentation/devicetree/bindings/rtc/olpc-xo1-rtc.txt b/Documentation/devicetree/bindings/rtc/olpc-xo1-rtc.txt new file mode 100644 index 0000000..a2891ce --- /dev/null +++ b/Documentation/devicetree/bindings/rtc/olpc-xo1-rtc.txt @@ -0,0 +1,5 @@ +OLPC XO-1 RTC +~~~~~~~~~~~~~ + +Required properties: + - compatible : "olpc,xo1-rtc" diff --git a/Documentation/devicetree/bindings/spi/fsl-imx-cspi.txt b/Documentation/devicetree/bindings/spi/fsl-imx-cspi.txt new file mode 100644 index 0000000..9841057 --- /dev/null +++ b/Documentation/devicetree/bindings/spi/fsl-imx-cspi.txt @@ -0,0 +1,22 @@ +* Freescale (Enhanced) Configurable Serial Peripheral Interface + (CSPI/eCSPI) for i.MX + +Required properties: +- compatible : Should be "fsl,-cspi" or "fsl,-ecspi" +- reg : Offset and length of the register set for the device +- interrupts : Should contain CSPI/eCSPI interrupt +- fsl,spi-num-chipselects : Contains the number of the chipselect +- cs-gpios : Specifies the gpio pins to be used for chipselects. + +Example: + +ecspi@70010000 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "fsl,imx51-ecspi"; + reg = <0x70010000 0x4000>; + interrupts = <36>; + fsl,spi-num-chipselects = <2>; + cs-gpios = <&gpio3 24 0>, /* GPIO4_24 */ + <&gpio3 25 0>; /* GPIO4_25 */ +}; diff --git a/Documentation/devicetree/bindings/spi/spi_nvidia.txt b/Documentation/devicetree/bindings/spi/spi_nvidia.txt new file mode 100644 index 0000000..6b9e518 --- /dev/null +++ b/Documentation/devicetree/bindings/spi/spi_nvidia.txt @@ -0,0 +1,5 @@ +NVIDIA Tegra 2 SPI device + +Required properties: +- compatible : should be "nvidia,tegra20-spi". +- gpios : should specify GPIOs used for chipselect. diff --git a/Documentation/devicetree/bindings/tty/serial/of-serial.txt b/Documentation/devicetree/bindings/tty/serial/of-serial.txt new file mode 100644 index 0000000..b8b27b0 --- /dev/null +++ b/Documentation/devicetree/bindings/tty/serial/of-serial.txt @@ -0,0 +1,36 @@ +* UART (Universal Asynchronous Receiver/Transmitter) + +Required properties: +- compatible : one of: + - "ns8250" + - "ns16450" + - "ns16550a" + - "ns16550" + - "ns16750" + - "ns16850" + - "nvidia,tegra20-uart" + - "ibm,qpace-nwp-serial" + - "serial" if the port type is unknown. +- reg : offset and length of the register set for the device. +- interrupts : should contain uart interrupt. +- clock-frequency : the input clock frequency for the UART. + +Optional properties: +- current-speed : the current active speed of the UART. +- reg-offset : offset to apply to the mapbase from the start of the registers. +- reg-shift : quantity to shift the register offsets by. +- reg-io-width : the size (in bytes) of the IO accesses that should be + performed on the device. There are some systems that require 32-bit + accesses to the UART (e.g. TI davinci). +- used-by-rtas : set to indicate that the port is in use by the OpenFirmware + RTAS and should not be registered. + +Example: + + uart@80230000 { + compatible = "ns8250"; + reg = <0x80230000 0x100>; + clock-frequency = <3686400>; + interrupts = <10>; + reg-shift = <2>; + }; diff --git a/Documentation/driver-model/device.txt b/Documentation/driver-model/device.txt index b2ff426..bdefe72 100644 --- a/Documentation/driver-model/device.txt +++ b/Documentation/driver-model/device.txt @@ -104,4 +104,4 @@ Then in the module init function is would do: And assuming 'dev' is the struct device passed into the probe hook, the driver probe function would do something like: - create_device(&mydriver_class, dev, chrdev, &private_data, "my_name"); + device_create(&mydriver_class, dev, chrdev, &private_data, "my_name"); diff --git a/Documentation/driver-model/overview.txt b/Documentation/driver-model/overview.txt index 07236ed..6a8f9a8 100644 --- a/Documentation/driver-model/overview.txt +++ b/Documentation/driver-model/overview.txt @@ -30,7 +30,7 @@ management, and hot plug. In particular, the model dictated by Intel and Microsoft (namely ACPI) ensures that almost every device on almost any bus on an x86-compatible system can work within this paradigm. Of course, not every bus is able to support all such operations, although most -buses support a most of those operations. +buses support most of those operations. Downstream Access @@ -46,25 +46,29 @@ struct pci_dev now looks like this: struct pci_dev { ... - struct device dev; + struct device dev; /* Generic device interface */ + ... }; -Note first that it is statically allocated. This means only one allocation on -device discovery. Note also that it is at the _end_ of struct pci_dev. This is -to make people think about what they're doing when switching between the bus -driver and the global driver; and to prevent against mindless casts between -the two. +Note first that the struct device dev within the struct pci_dev is +statically allocated. This means only one allocation on device discovery. + +Note also that that struct device dev is not necessarily defined at the +front of the pci_dev structure. This is to make people think about what +they're doing when switching between the bus driver and the global driver, +and to discourage meaningless and incorrect casts between the two. The PCI bus layer freely accesses the fields of struct device. It knows about the structure of struct pci_dev, and it should know the structure of struct device. Individual PCI device drivers that have been converted to the current driver model generally do not and should not touch the fields of struct device, -unless there is a strong compelling reason to do so. +unless there is a compelling reason to do so. -This abstraction is prevention of unnecessary pain during transitional phases. -If the name of the field changes or is removed, then every downstream driver -will break. On the other hand, if only the bus layer (and not the device -layer) accesses struct device, it is only that layer that needs to change. +The above abstraction prevents unnecessary pain during transitional phases. +If it were not done this way, then when a field was renamed or removed, every +downstream driver would break. On the other hand, if only the bus layer +(and not the device layer) accesses the struct device, it is only the bus +layer that needs to change. User Interface @@ -73,15 +77,27 @@ User Interface By virtue of having a complete hierarchical view of all the devices in the system, exporting a complete hierarchical view to userspace becomes relatively easy. This has been accomplished by implementing a special purpose virtual -file system named sysfs. It is hence possible for the user to mount the -whole sysfs filesystem anywhere in userspace. +file system named sysfs. + +Almost all mainstream Linux distros mount this filesystem automatically; you +can see some variation of the following in the output of the "mount" command: + +$ mount +... +none on /sys type sysfs (rw,noexec,nosuid,nodev) +... +$ + +The auto-mounting of sysfs is typically accomplished by an entry similar to +the following in the /etc/fstab file: + +none /sys sysfs defaults 0 0 -This can be done permanently by providing the following entry into the -/etc/fstab (under the provision that the mount point does exist, of course): +or something similar in the /lib/init/fstab file on Debian-based systems: -none /sys sysfs defaults 0 0 +none /sys sysfs nodev,noexec,nosuid 0 0 -Or by hand on the command line: +If sysfs is not automatically mounted, you can always do it manually with: # mount -t sysfs sysfs /sys diff --git a/Documentation/fb/modedb.txt b/Documentation/fb/modedb.txt index ec4dee7..16aa084 100644 --- a/Documentation/fb/modedb.txt +++ b/Documentation/fb/modedb.txt @@ -20,7 +20,7 @@ in a video= option, fbmem considers that to be a global video mode option. Valid mode specifiers (mode_option argument): - x[M][R][-][@][i][m] + x[M][R][-][@][i][m][eDd] [-][@] with , , and decimal numbers and a string. @@ -36,6 +36,21 @@ pixels and 1.8% of yres). Sample usage: 1024x768M@60m - CVT timing with margins +DRM drivers also add options to enable or disable outputs: + +'e' will force the display to be enabled, i.e. it will override the detection +if a display is connected. 'D' will force the display to be enabled and use +digital output. This is useful for outputs that have both analog and digital +signals (e.g. HDMI and DVI-I). For other outputs it behaves like 'e'. If 'd' +is specified the output is disabled. + +You can additionally specify which output the options matches to. +To force the VGA output to be enabled and drive a specific mode say: + video=VGA-1:1280x1024@60me + +Specifying the option multiple times for different ports is possible, e.g.: + video=LVDS-1:d video=HDMI-1:D + ***** oOo ***** oOo ***** oOo ***** oOo ***** oOo ***** oOo ***** oOo ***** What is the VESA(TM) Coordinated Video Timings (CVT)? @@ -132,5 +147,5 @@ There may be more modes. tridentfb - Trident (Cyber)blade chipset frame buffer vt8623fb - VIA 8623 frame buffer -BTW, only a few drivers use this at the moment. Others are to follow -(feel free to send patches). +BTW, only a few fb drivers use this at the moment. Others are to follow +(feel free to send patches). The DRM drivers also support this. diff --git a/Documentation/feature-removal-schedule.txt b/Documentation/feature-removal-schedule.txt index b1c921c..dfd6a9f 100644 --- a/Documentation/feature-removal-schedule.txt +++ b/Documentation/feature-removal-schedule.txt @@ -184,7 +184,7 @@ Why: /proc//oom_adj allows userspace to influence the oom killer's A much more powerful interface, /proc//oom_score_adj, was introduced with the oom killer rewrite that allows users to increase or - decrease the badness() score linearly. This interface will replace + decrease the badness score linearly. This interface will replace /proc//oom_adj. A warning will be emitted to the kernel log if an application uses this @@ -193,20 +193,6 @@ Why: /proc//oom_adj allows userspace to influence the oom killer's --------------------------- -What: CS5535/CS5536 obsolete GPIO driver -When: June 2011 -Files: drivers/staging/cs5535_gpio/* -Check: drivers/staging/cs5535_gpio/cs5535_gpio.c -Why: A newer driver replaces this; it is drivers/gpio/cs5535-gpio.c, and - integrates with the Linux GPIO subsystem. The old driver has been - moved to staging, and will be removed altogether around 2.6.40. - Please test the new driver, and ensure that the functionality you - need and any bugfixes from the old driver are available in the new - one. -Who: Andres Salomon - --------------------------- - What: remove EXPORT_SYMBOL(kernel_thread) When: August 2006 Files: arch/*/kernel/*_ksyms.c @@ -294,7 +280,7 @@ When: The schedule was July 2008, but it was decided that we are going to keep t Why: The support code for the old firmware hurts code readability/maintainability and slightly hurts runtime performance. Bugfixes for the old firmware are not provided by Broadcom anymore. -Who: Michael Buesch +Who: Michael Buesch --------------------------- @@ -430,7 +416,7 @@ Who: Avi Kivity ---------------------------- What: iwlwifi 50XX module parameters -When: 2.6.40 +When: 3.0 Why: The "..50" modules parameters were used to configure 5000 series and up devices; different set of module parameters also available for 4965 with same functionalities. Consolidate both set into single place @@ -441,7 +427,7 @@ Who: Wey-Yi Guy ---------------------------- What: iwl4965 alias support -When: 2.6.40 +When: 3.0 Why: Internal alias support has been present in module-init-tools for some time, the MODULE_ALIAS("iwl4965") boilerplate aliases can be removed with no impact. @@ -474,15 +460,8 @@ Who: FUJITA Tomonori ---------------------------- -What: DMA_xxBIT_MASK macros -When: Jun 2011 -Why: DMA_xxBIT_MASK macros were replaced with DMA_BIT_MASK() macros. -Who: FUJITA Tomonori - ----------------------------- - What: iwlwifi disable_hw_scan module parameters -When: 2.6.40 +When: 3.0 Why: Hareware scan is the prefer method for iwlwifi devices for scanning operation. Remove software scan support for all the iwlwifi devices. @@ -491,26 +470,6 @@ Who: Wey-Yi Guy ---------------------------- -What: access to nfsd auth cache through sys_nfsservctl or '.' files - in the 'nfsd' filesystem. -When: 2.6.40 -Why: This is a legacy interface which have been replaced by a more - dynamic cache. Continuing to maintain this interface is an - unnecessary burden. -Who: NeilBrown - ----------------------------- - -What: cancel_rearming_delayed_work[queue]() -When: 2.6.39 - -Why: The functions have been superceded by cancel_delayed_work_sync() - quite some time ago. The conversion is trivial and there is no - in-kernel user left. -Who: Tejun Heo - ----------------------------- - What: Legacy, non-standard chassis intrusion detection interface. When: June 2011 Why: The adm9240, w83792d and w83793 hardware monitoring drivers have @@ -528,22 +487,6 @@ Files: net/netfilter/xt_connlimit.c ---------------------------- -What: noswapaccount kernel command line parameter -When: 2.6.40 -Why: The original implementation of memsw feature enabled by - CONFIG_CGROUP_MEM_RES_CTLR_SWAP could be disabled by the noswapaccount - kernel parameter (introduced in 2.6.29-rc1). Later on, this decision - turned out to be not ideal because we cannot have the feature compiled - in and disabled by default and let only interested to enable it - (e.g. general distribution kernels might need it). Therefore we have - added swapaccount[=0|1] parameter (introduced in 2.6.37) which provides - the both possibilities. If we remove noswapaccount we will have - less command line parameters with the same functionality and we - can also cleanup the parameter handling a bit (). -Who: Michal Hocko - ----------------------------- - What: ipt_addrtype match include file When: 2012 Why: superseded by xt_addrtype @@ -562,7 +505,7 @@ Who: Jean Delvare ---------------------------- What: Support for UVCIOC_CTRL_ADD in the uvcvideo driver -When: 2.6.42 +When: 3.2 Why: The information passed to the driver by this ioctl is now queried dynamically from the device. Who: Laurent Pinchart @@ -570,7 +513,7 @@ Who: Laurent Pinchart ---------------------------- What: Support for UVCIOC_CTRL_MAP_OLD in the uvcvideo driver -When: 2.6.42 +When: 3.2 Why: Used only by applications compiled against older driver versions. Superseded by UVCIOC_CTRL_MAP which supports V4L2 menu controls. Who: Laurent Pinchart @@ -578,7 +521,7 @@ Who: Laurent Pinchart ---------------------------- What: Support for UVCIOC_CTRL_GET and UVCIOC_CTRL_SET in the uvcvideo driver -When: 2.6.42 +When: 3.2 Why: Superseded by the UVCIOC_CTRL_QUERY ioctl. Who: Laurent Pinchart @@ -605,3 +548,10 @@ Why: Just opening a V4L device should not change the state of the hardware Who: Hans Verkuil ---------------------------- + +What: g_file_storage driver +When: 3.8 +Why: This driver has been superseded by g_mass_storage. +Who: Alan Stern + +---------------------------- diff --git a/Documentation/filesystems/Locking b/Documentation/filesystems/Locking index 57d827d..6533807 100644 --- a/Documentation/filesystems/Locking +++ b/Documentation/filesystems/Locking @@ -52,7 +52,7 @@ ata *); void (*put_link) (struct dentry *, struct nameidata *, void *); void (*truncate) (struct inode *); int (*permission) (struct inode *, int, unsigned int); - int (*check_acl)(struct inode *, int, unsigned int); + int (*get_acl)(struct inode *, int); int (*setattr) (struct dentry *, struct iattr *); int (*getattr) (struct vfsmount *, struct dentry *, struct kstat *); int (*setxattr) (struct dentry *, const char *,const void *,size_t,int); @@ -80,7 +80,7 @@ put_link: no truncate: yes (see below) setattr: yes permission: no (may not block if called in rcu-walk mode) -check_acl: no +get_acl: no getattr: no setxattr: yes getxattr: no @@ -338,21 +338,21 @@ fl_release_private: maybe no ----------------------- lock_manager_operations --------------------------- prototypes: - int (*fl_compare_owner)(struct file_lock *, struct file_lock *); - void (*fl_notify)(struct file_lock *); /* unblock callback */ - int (*fl_grant)(struct file_lock *, struct file_lock *, int); - void (*fl_release_private)(struct file_lock *); - void (*fl_break)(struct file_lock *); /* break_lease callback */ - int (*fl_change)(struct file_lock **, int); + int (*lm_compare_owner)(struct file_lock *, struct file_lock *); + void (*lm_notify)(struct file_lock *); /* unblock callback */ + int (*lm_grant)(struct file_lock *, struct file_lock *, int); + void (*lm_release_private)(struct file_lock *); + void (*lm_break)(struct file_lock *); /* break_lease callback */ + int (*lm_change)(struct file_lock **, int); locking rules: file_lock_lock may block -fl_compare_owner: yes no -fl_notify: yes no -fl_grant: no no -fl_release_private: maybe no -fl_break: yes no -fl_change yes no +lm_compare_owner: yes no +lm_notify: yes no +lm_grant: no no +lm_release_private: maybe no +lm_break: yes no +lm_change yes no --------------------------- buffer_head ----------------------------------- prototypes: @@ -412,7 +412,7 @@ prototypes: int (*open) (struct inode *, struct file *); int (*flush) (struct file *); int (*release) (struct inode *, struct file *); - int (*fsync) (struct file *, int datasync); + int (*fsync) (struct file *, loff_t start, loff_t end, int datasync); int (*aio_fsync) (struct kiocb *, int datasync); int (*fasync) (int, struct file *, int); int (*lock) (struct file *, int, struct file_lock *); @@ -438,9 +438,7 @@ prototypes: locking rules: All may block except for ->setlease. - No VFS locks held on entry except for ->fsync and ->setlease. - -->fsync() has i_mutex on inode. + No VFS locks held on entry except for ->setlease. ->setlease has the file_list_lock held and must not sleep. diff --git a/Documentation/filesystems/debugfs.txt b/Documentation/filesystems/debugfs.txt index ed52af6..742cc06 100644 --- a/Documentation/filesystems/debugfs.txt +++ b/Documentation/filesystems/debugfs.txt @@ -73,8 +73,8 @@ the following functions can be used instead: struct dentry *parent, u16 *value); struct dentry *debugfs_create_x32(const char *name, mode_t mode, struct dentry *parent, u32 *value); - -Note that there is no debugfs_create_x64(). + struct dentry *debugfs_create_x64(const char *name, mode_t mode, + struct dentry *parent, u64 *value); These functions are useful as long as the developer knows the size of the value to be exported. Some types can have different widths on different diff --git a/Documentation/filesystems/ext3.txt b/Documentation/filesystems/ext3.txt index 272f80d..22f3a0e 100644 --- a/Documentation/filesystems/ext3.txt +++ b/Documentation/filesystems/ext3.txt @@ -147,15 +147,6 @@ grpjquota= during journal replay. They replace the above package for more details (http://sourceforge.net/projects/linuxquota). -bh (*) ext3 associates buffer heads to data pages to -nobh (a) cache disk block mapping information - (b) link pages into transaction to provide - ordering guarantees. - "bh" option forces use of buffer heads. - "nobh" option tries to avoid associating buffer - heads (supported only for "writeback" mode). - - Specification ============= Ext3 shares all disk implementation with the ext2 filesystem, and adds @@ -227,5 +218,5 @@ kernel source: programs: http://e2fsprogs.sourceforge.net/ http://ext2resize.sourceforge.net -useful links: http://www.ibm.com/developerworks/library/l-fs7.html - http://www.ibm.com/developerworks/library/l-fs8.html +useful links: http://www.ibm.com/developerworks/library/l-fs7/index.html + http://www.ibm.com/developerworks/library/l-fs8/index.html diff --git a/Documentation/filesystems/ext4.txt b/Documentation/filesystems/ext4.txt index 3ae9bc9..232a575 100644 --- a/Documentation/filesystems/ext4.txt +++ b/Documentation/filesystems/ext4.txt @@ -68,12 +68,12 @@ Note: More extensive information for getting started with ext4 can be '-o barriers=[0|1]' mount option for both ext3 and ext4 filesystems for a fair comparison. When tuning ext3 for best benchmark numbers, it is often worthwhile to try changing the data journaling mode; '-o - data=writeback,nobh' can be faster for some workloads. (Note - however that running mounted with data=writeback can potentially - leave stale data exposed in recently written files in case of an - unclean shutdown, which could be a security exposure in some - situations.) Configuring the filesystem with a large journal can - also be helpful for metadata-intensive workloads. + data=writeback' can be faster for some workloads. (Note however that + running mounted with data=writeback can potentially leave stale data + exposed in recently written files in case of an unclean shutdown, + which could be a security exposure in some situations.) Configuring + the filesystem with a large journal can also be helpful for + metadata-intensive workloads. 2. Features =========== @@ -272,14 +272,6 @@ grpjquota= during journal replay. They replace the above package for more details (http://sourceforge.net/projects/linuxquota). -bh (*) ext4 associates buffer heads to data pages to -nobh (a) cache disk block mapping information - (b) link pages into transaction to provide - ordering guarantees. - "bh" option forces use of buffer heads. - "nobh" option tries to avoid associating buffer - heads (supported only for "writeback" mode). - stripe=n Number of filesystem blocks that mballoc will try to use for allocation size and alignment. For RAID5/6 systems this should be the number of data @@ -393,8 +385,7 @@ dioread_nolock locking. If the dioread_nolock option is specified write and convert the extent to initialized after IO completes. This approach allows ext4 code to avoid using inode mutex, which improves scalability on high - speed storages. However this does not work with nobh - option and the mount will fail. Nor does it work with + speed storages. However this does not work with data journaling and dioread_nolock option will be ignored with kernel warning. Note that dioread_nolock code path is only used for extent-based files. diff --git a/Documentation/filesystems/nfs/Exporting b/Documentation/filesystems/nfs/Exporting index 87019d2..09994c2 100644 --- a/Documentation/filesystems/nfs/Exporting +++ b/Documentation/filesystems/nfs/Exporting @@ -92,7 +92,14 @@ For a filesystem to be exportable it must: 1/ provide the filehandle fragment routines described below. 2/ make sure that d_splice_alias is used rather than d_add when ->lookup finds an inode for a given parent and name. - Typically the ->lookup routine will end with a: + + If inode is NULL, d_splice_alias(inode, dentry) is eqivalent to + + d_add(dentry, inode), NULL + + Similarly, d_splice_alias(ERR_PTR(err), dentry) = ERR_PTR(err) + + Typically the ->lookup routine will simply end with a: return d_splice_alias(inode, dentry); } diff --git a/Documentation/filesystems/nfs/nfs41-server.txt b/Documentation/filesystems/nfs/nfs41-server.txt index 0488491..092fad9 100644 --- a/Documentation/filesystems/nfs/nfs41-server.txt +++ b/Documentation/filesystems/nfs/nfs41-server.txt @@ -39,27 +39,17 @@ interoperability problems with future clients. Known issues: from a linux client are possible, but we aren't really conformant with the spec (for example, we don't use kerberos on the backchannel correctly). - - no trunking support: no clients currently take advantage of - trunking, but this is a mandatory feature, and its use is - recommended to clients in a number of places. (E.g. to ensure - timely renewal in case an existing connection's retry timeouts - have gotten too long; see section 8.3 of the RFC.) - Therefore, lack of this feature may cause future clients to - fail. - Incomplete backchannel support: incomplete backchannel gss support and no support for BACKCHANNEL_CTL mean that callbacks (hence delegations and layouts) may not be available and clients confused by the incomplete implementation may fail. - - Server reboot recovery is unsupported; if the server reboots, - clients may fail. - We do not support SSV, which provides security for shared client-server state (thus preventing unauthorized tampering with locks and opens, for example). It is mandatory for servers to support this, though no clients use it yet. - Mandatory operations which we do not support, such as - DESTROY_CLIENTID, FREE_STATEID, SECINFO_NO_NAME, and - TEST_STATEID, are not currently used by clients, but will be + DESTROY_CLIENTID, are not currently used by clients, but will be (and the spec recommends their uses in common cases), and clients should not be expected to know how to recover from the case where they are not supported. This will eventually cause @@ -69,8 +59,9 @@ In addition, some limitations are inherited from the current NFSv4 implementation: - Incomplete delegation enforcement: if a file is renamed or - unlinked, a client holding a delegation may continue to - indefinitely allow opens of the file under the old name. + unlinked by a local process, a client holding a delegation may + continue to indefinitely allow opens of the file under the old + name. The table below, taken from the NFSv4.1 document, lists the operations that are mandatory to implement (REQ), optional @@ -99,7 +90,7 @@ Operations +----------------------+------------+--------------+----------------+ | ACCESS | REQ | | Section 18.1 | NS | BACKCHANNEL_CTL | REQ | | Section 18.33 | -NS | BIND_CONN_TO_SESSION | REQ | | Section 18.34 | +I | BIND_CONN_TO_SESSION | REQ | | Section 18.34 | | CLOSE | REQ | | Section 18.2 | | COMMIT | REQ | | Section 18.3 | | CREATE | REQ | | Section 18.4 | @@ -111,7 +102,7 @@ NS*| DELEGPURGE | OPT | FDELG (REQ) | Section 18.5 | NS | DESTROY_CLIENTID | REQ | | Section 18.50 | I | DESTROY_SESSION | REQ | | Section 18.37 | I | EXCHANGE_ID | REQ | | Section 18.35 | -NS | FREE_STATEID | REQ | | Section 18.38 | +I | FREE_STATEID | REQ | | Section 18.38 | | GETATTR | REQ | | Section 18.7 | P | GETDEVICEINFO | OPT | pNFS (REQ) | Section 18.40 | P | GETDEVICELIST | OPT | pNFS (OPT) | Section 18.41 | @@ -145,14 +136,14 @@ NS*| OPENATTR | OPT | | Section 18.17 | | RESTOREFH | REQ | | Section 18.27 | | SAVEFH | REQ | | Section 18.28 | | SECINFO | REQ | | Section 18.29 | -NS | SECINFO_NO_NAME | REC | pNFS files | Section 18.45, | +I | SECINFO_NO_NAME | REC | pNFS files | Section 18.45, | | | | layout (REQ) | Section 13.12 | I | SEQUENCE | REQ | | Section 18.46 | | SETATTR | REQ | | Section 18.30 | | SETCLIENTID | MNI | | N/A | | SETCLIENTID_CONFIRM | MNI | | N/A | NS | SET_SSV | REQ | | Section 18.47 | -NS | TEST_STATEID | REQ | | Section 18.48 | +I | TEST_STATEID | REQ | | Section 18.48 | | VERIFY | REQ | | Section 18.31 | NS*| WANT_DELEGATION | OPT | FDELG (OPT) | Section 18.49 | | WRITE | REQ | | Section 18.32 | @@ -206,12 +197,6 @@ CREATE_SESSION: SEQUENCE: * no support for dynamic slot table renegotiation (optional) -nfsv4.1 COMPOUND rules: -The following cases aren't supported yet: -* Enforcing of NFS4ERR_NOT_ONLY_OP for: BIND_CONN_TO_SESSION, CREATE_SESSION, - DESTROY_CLIENTID, DESTROY_SESSION, EXCHANGE_ID. -* DESTROY_SESSION MUST be the final operation in the COMPOUND request. - Nonstandard compound limitations: * No support for a sessions fore channel RPC compound that requires both a ca_maxrequestsize request and a ca_maxresponsesize reply, so we may @@ -219,3 +204,5 @@ Nonstandard compound limitations: negotiation. * No more than one IO operation (read, write, readdir) allowed per compound. + +See also http://wiki.linux-nfs.org/wiki/index.php/Server_4.0_and_4.1_issues. diff --git a/Documentation/filesystems/nfs/nfsroot.txt b/Documentation/filesystems/nfs/nfsroot.txt index 90c71c6..ffdd9d8 100644 --- a/Documentation/filesystems/nfs/nfsroot.txt +++ b/Documentation/filesystems/nfs/nfsroot.txt @@ -226,7 +226,7 @@ They depend on various facilities being available: cdrecord. e.g. - cdrecord dev=ATAPI:1,0,0 arch/i386/boot/image.iso + cdrecord dev=ATAPI:1,0,0 arch/x86/boot/image.iso For more information on isolinux, including how to create bootdisks for prebuilt kernels, see http://syslinux.zytor.com/ diff --git a/Documentation/filesystems/porting b/Documentation/filesystems/porting index 6e29954..b4a3d76 100644 --- a/Documentation/filesystems/porting +++ b/Documentation/filesystems/porting @@ -400,10 +400,32 @@ a file off. -- [mandatory] - --- -[mandatory] ->get_sb() is gone. Switch to use of ->mount(). Typically it's just a matter of switching from calling get_sb_... to mount_... and changing the function type. If you were doing it manually, just switch from setting ->mnt_root to some pointer to returning that pointer. On errors return ERR_PTR(...). + +-- +[mandatory] + ->permission() and generic_permission()have lost flags +argument; instead of passing IPERM_FLAG_RCU we add MAY_NOT_BLOCK into mask. + generic_permission() has also lost the check_acl argument; ACL checking +has been taken to VFS and filesystems need to provide a non-NULL ->i_op->get_acl +to read an ACL from disk. + +-- +[mandatory] + If you implement your own ->llseek() you must handle SEEK_HOLE and +SEEK_DATA. You can hanle this by returning -EINVAL, but it would be nicer to +support it in some way. The generic handler assumes that the entire file is +data and there is a virtual hole at the end of the file. So if the provided +offset is less than i_size and SEEK_DATA is specified, return the same offset. +If the above is true for the offset and you are given SEEK_HOLE, return the end +of the file. If the offset is i_size or greater return -ENXIO in either case. + +[mandatory] + If you have your own ->fsync() you must make sure to call +filemap_write_and_wait_range() so that all dirty pages are synced out properly. +You must also keep in mind that ->fsync() is not called with i_mutex held +anymore, so if you require i_mutex locking you must make sure to take it and +release it yourself. diff --git a/Documentation/filesystems/squashfs.txt b/Documentation/filesystems/squashfs.txt index d4d4146..7db3ebd 100644 --- a/Documentation/filesystems/squashfs.txt +++ b/Documentation/filesystems/squashfs.txt @@ -2,7 +2,7 @@ SQUASHFS 4.0 FILESYSTEM ======================= Squashfs is a compressed read-only filesystem for Linux. -It uses zlib/lzo compression to compress files, inodes and directories. +It uses zlib/lzo/xz compression to compress files, inodes and directories. Inodes in the system are very small and all blocks are packed to minimise data overhead. Block sizes greater than 4K are supported up to a maximum of 1Mbytes (default block size 128K). @@ -55,6 +55,8 @@ create populated squashfs filesystems. This and other squashfs utilities can be obtained from http://www.squashfs.org. Usage instructions can be obtained from this site also. +The squashfs-tools development tree is now located on kernel.org + git://git.kernel.org/pub/scm/fs/squashfs/squashfs-tools.git 3. SQUASHFS FILESYSTEM DESIGN ----------------------------- diff --git a/Documentation/filesystems/ubifs.txt b/Documentation/filesystems/ubifs.txt index 8e4fab6..a0a61d2 100644 --- a/Documentation/filesystems/ubifs.txt +++ b/Documentation/filesystems/ubifs.txt @@ -111,34 +111,6 @@ The following is an example of the kernel boot arguments to attach mtd0 to UBI and mount volume "rootfs": ubi.mtd=0 root=ubi0:rootfs rootfstype=ubifs - -Module Parameters for Debugging -=============================== - -When UBIFS has been compiled with debugging enabled, there are 2 module -parameters that are available to control aspects of testing and debugging. - -debug_chks Selects extra checks that UBIFS can do while running: - - Check Flag value - - General checks 1 - Check Tree Node Cache (TNC) 2 - Check indexing tree size 4 - Check orphan area 8 - Check old indexing tree 16 - Check LEB properties (lprops) 32 - Check leaf nodes and inodes 64 - -debug_tsts Selects a mode of testing, as follows: - - Test mode Flag value - - Failure mode for recovery testing 4 - -For example, set debug_chks to 3 to enable general and TNC checks. - - References ========== diff --git a/Documentation/filesystems/vfs.txt b/Documentation/filesystems/vfs.txt index 88b9f55..52d8fb8 100644 --- a/Documentation/filesystems/vfs.txt +++ b/Documentation/filesystems/vfs.txt @@ -229,6 +229,8 @@ struct super_operations { ssize_t (*quota_read)(struct super_block *, int, char *, size_t, loff_t); ssize_t (*quota_write)(struct super_block *, int, const char *, size_t, loff_t); + int (*nr_cached_objects)(struct super_block *); + void (*free_cached_objects)(struct super_block *, int); }; All methods are called without any locks being held, unless otherwise @@ -301,6 +303,26 @@ or bottom half). quota_write: called by the VFS to write to filesystem quota file. + nr_cached_objects: called by the sb cache shrinking function for the + filesystem to return the number of freeable cached objects it contains. + Optional. + + free_cache_objects: called by the sb cache shrinking function for the + filesystem to scan the number of objects indicated to try to free them. + Optional, but any filesystem implementing this method needs to also + implement ->nr_cached_objects for it to be called correctly. + + We can't do anything with any errors that the filesystem might + encountered, hence the void return type. This will never be called if + the VM is trying to reclaim under GFP_NOFS conditions, hence this + method does not need to handle that situation itself. + + Implementations must include conditional reschedule calls inside any + scanning loop that is done. This allows the VFS to determine + appropriate scan batch sizes without having to worry about whether + implementations will cause holdoff problems due to large scan batch + sizes. + Whoever sets up the inode is responsible for filling in the "i_op" field. This is a pointer to a "struct inode_operations" which describes the methods that can be performed on individual inodes. @@ -333,8 +355,8 @@ struct inode_operations { void * (*follow_link) (struct dentry *, struct nameidata *); void (*put_link) (struct dentry *, struct nameidata *, void *); void (*truncate) (struct inode *); - int (*permission) (struct inode *, int, unsigned int); - int (*check_acl)(struct inode *, int, unsigned int); + int (*permission) (struct inode *, int); + int (*get_acl)(struct inode *, int); int (*setattr) (struct dentry *, struct iattr *); int (*getattr) (struct vfsmount *mnt, struct dentry *, struct kstat *); int (*setxattr) (struct dentry *, const char *,const void *,size_t,int); @@ -423,7 +445,7 @@ otherwise noted. permission: called by the VFS to check for access rights on a POSIX-like filesystem. - May be called in rcu-walk mode (flags & IPERM_FLAG_RCU). If in rcu-walk + May be called in rcu-walk mode (mask & MAY_NOT_BLOCK). If in rcu-walk mode, the filesystem must check the permission without blocking or storing to the inode. @@ -755,7 +777,7 @@ struct file_operations { int (*open) (struct inode *, struct file *); int (*flush) (struct file *); int (*release) (struct inode *, struct file *); - int (*fsync) (struct file *, int datasync); + int (*fsync) (struct file *, loff_t, loff_t, int datasync); int (*aio_fsync) (struct kiocb *, int datasync); int (*fasync) (int, struct file *, int); int (*lock) (struct file *, int, struct file_lock *); diff --git a/Documentation/hwmon/it87 b/Documentation/hwmon/it87 index 38425f0..6f496a5 100644 --- a/Documentation/hwmon/it87 +++ b/Documentation/hwmon/it87 @@ -76,7 +76,8 @@ IT8718F, IT8720F, IT8721F, IT8726F, IT8758E and SiS950 chips. These chips are 'Super I/O chips', supporting floppy disks, infrared ports, joysticks and other miscellaneous stuff. For hardware monitoring, they include an 'environment controller' with 3 temperature sensors, 3 fan -rotation speed sensors, 8 voltage sensors, and associated alarms. +rotation speed sensors, 8 voltage sensors, associated alarms, and chassis +intrusion detection. The IT8712F and IT8716F additionally feature VID inputs, used to report the Vcore voltage of the processor. The early IT8712F have 5 VID pins, diff --git a/Documentation/hwmon/lm78 b/Documentation/hwmon/lm78 index 60932e2..2bdc881 100644 --- a/Documentation/hwmon/lm78 +++ b/Documentation/hwmon/lm78 @@ -13,7 +13,8 @@ Supported chips: Datasheet: Publicly available at the National Semiconductor website http://www.national.com/ -Author: Frodo Looijaard +Authors: Frodo Looijaard + Jean Delvare Description ----------- diff --git a/Documentation/hwmon/sch5636 b/Documentation/hwmon/sch5636 new file mode 100644 index 0000000..f83bd1c --- /dev/null +++ b/Documentation/hwmon/sch5636 @@ -0,0 +1,31 @@ +Kernel driver sch5636 +===================== + +Supported chips: + * SMSC SCH5636 + Prefix: 'sch5636' + Addresses scanned: none, address read from Super I/O config space + +Author: Hans de Goede + + +Description +----------- + +SMSC SCH5636 Super I/O chips include an embedded microcontroller for +hardware monitoring solutions, allowing motherboard manufacturers to create +their own custom hwmon solution based upon the SCH5636. + +Currently the sch5636 driver only supports the Fujitsu Theseus SCH5636 based +hwmon solution. The sch5636 driver runs a sanity check on loading to ensure +it is dealing with a Fujitsu Theseus and not with another custom SCH5636 based +hwmon solution. + +The Fujitsu Theseus can monitor up to 5 voltages, 8 fans and 16 +temperatures. Note that the driver detects how many fan headers / +temperature sensors are actually implemented on the motherboard, so you will +likely see fewer temperature and fan inputs. + +An application note describing the Theseus' registers, as well as an +application note describing the protocol for communicating with the +microcontroller is available upon request. Please mail me if you want a copy. diff --git a/Documentation/i2o/ioctl b/Documentation/i2o/ioctl index 1e77fac..22ca53a 100644 --- a/Documentation/i2o/ioctl +++ b/Documentation/i2o/ioctl @@ -110,7 +110,7 @@ V. Getting Logical Configuration Table ENOBUFS Buffer not large enough. If this occurs, the required buffer length is written into *(lct->reslen) -VI. Settting Parameters +VI. Setting Parameters SYNOPSIS diff --git a/Documentation/ioctl/ioctl-number.txt b/Documentation/ioctl/ioctl-number.txt index 3a46e36..72ba8d5 100644 --- a/Documentation/ioctl/ioctl-number.txt +++ b/Documentation/ioctl/ioctl-number.txt @@ -301,6 +301,7 @@ Code Seq#(hex) Include File Comments 0xAE all linux/kvm.h Kernel-based Virtual Machine +0xAF 00-1F linux/fsl_hypervisor.h Freescale hypervisor 0xB0 all RATIO devices in development: 0xB1 00-1F PPPoX diff --git a/Documentation/isdn/README.HiSax b/Documentation/isdn/README.HiSax index 99e87a6..b1a573c 100644 --- a/Documentation/isdn/README.HiSax +++ b/Documentation/isdn/README.HiSax @@ -506,7 +506,7 @@ to e.g. the Internet: make clean; make zImage; make modules; make modules_install 2. Install the new kernel - cp /usr/src/linux/arch/i386/boot/zImage /etc/kernel/linux.isdn + cp /usr/src/linux/arch/x86/boot/zImage /etc/kernel/linux.isdn vi /etc/lilo.conf lilo diff --git a/Documentation/ja_JP/SubmitChecklist b/Documentation/ja_JP/SubmitChecklist index 2df4576..cb5507b 100644 --- a/Documentation/ja_JP/SubmitChecklist +++ b/Documentation/ja_JP/SubmitChecklist @@ -68,7 +68,7 @@ Linux カーネルパッチ投稿者向けチェックリスト 12: CONFIG_PREEMPT, CONFIG_DEBUG_PREEMPT, CONFIG_DEBUG_SLAB, CONFIG_DEBUG_PAGEALLOC, CONFIG_DEBUG_MUTEXES, CONFIG_DEBUG_SPINLOCK, - CONFIG_DEBUG_SPINLOCK_SLEEP これら全てを同時に有効にして動作確認を + CONFIG_DEBUG_ATOMIC_SLEEP これら全てを同時に有効にして動作確認を 行ってください。 13: CONFIG_SMP, CONFIG_PREEMPT を有効にした場合と無効にした場合の両方で diff --git a/Documentation/ja_JP/SubmittingPatches b/Documentation/ja_JP/SubmittingPatches index f107c83..97f78dd 100644 --- a/Documentation/ja_JP/SubmittingPatches +++ b/Documentation/ja_JP/SubmittingPatches @@ -11,16 +11,18 @@ for non English (read: Japanese) speakers and is not intended as a fork. So if you have any comments or updates of this file, please try to update the original English file first. -Last Updated: 2007/10/24 +Last Updated: 2011/06/09 + ================================== これは、 -linux-2.6.23/Documentation/SubmittingPatches の和訳 +linux-2.6.39/Documentation/SubmittingPatches の和訳 です。 翻訳団体: JF プロジェクト < http://www.linux.or.jp/JF/ > -翻訳日: 2007/10/17 +翻訳日: 2011/06/09 翻訳者: Keiichi Kii 校正者: Masanari Kobayashi さん Matsukura さん + Takeshi Hamasaki さん ================================== Linux カーネルに変更を加えるための Howto @@ -97,7 +99,7 @@ Quilt: http://savannah.nongnu.org/projects/quilt Andrew Morton's patch scripts: -http://userweb.kernel.org/~akpm/stuff/tpp.txt +http://userweb.kernel.org/~akpm/stuff/patch-scripts.tar.gz このリンクの先のスクリプトの代わりとして、quilt がパッチマネジメント ツールとして推奨されています(上のリンクを見てください)。 @@ -109,9 +111,25 @@ http://userweb.kernel.org/~akpm/stuff/tpp.txt 「ドライバー X に対するバグフィックス」あるいは「このパッチはサブシス テム X に対する更新を含んでいます。どうか取り入れてください。」などです。 +パッチの説明を Linux カーネルのソースコードマネジメントシステム「 git 」の +コミットログとして簡単に引用できる形で書けば、メンテナから感謝されるでしょう。 +以下の #15 を見てください。 + 説明が長くなりだしたのであれば、おそらくそれはパッチを分ける必要がある という兆候です。次の #3 を見てください。 +パッチ(シリーズ)を(再)投稿する時、十分なパッチの説明とそのパッチが必要な理由を +パッチに含めてください。ただ「これはパッチ(シリーズ)のバージョン N」とだけ +書かないでください。そして、パッチをマージする人にパッチの説明を探させそれを +パッチに追記させるため、過去のバージョンのパッチやそのパッチの URL を参照する +手間をかけさせないでください。 +つまり、パッチシリーズとその説明は一緒にあるべきです。これはパッチをマージする +人、レビューする人、どちらのためにもなります。レビューする人の中には、おそらく +過去のバージョンのパッチを受け取ってもいない人がいます。 + +登録済みのバグエントリを修正するパッチであれば、そのバグエントリを示すバグ ID +や URL を明記してください。 + 3) パッチの分割 意味のあるひとまとまりごとに変更を個々のパッチファイルに分けてください。 @@ -141,7 +159,7 @@ http://userweb.kernel.org/~akpm/stuff/tpp.txt 拒否されるでしょう。 あなたはパッチを投稿する前に最低限パッチスタイルチェッカー -( scripts/patchcheck.pl )を利用してパッチをチェックすべきです。 +( scripts/checkpatch.pl )を利用してパッチをチェックすべきです。 もしパッチに違反がのこっているならば、それらの全てについてあなたは正当な 理由を示せるようにしておく必要があります。 @@ -192,13 +210,13 @@ VGER.KERNEL.ORG でホスティングされているメーリングリストの 情報がマニュアルページの中に入ってくるように、変更が起きたという 通知を送ってください。 -たとえ、メンテナが #4 で反応がなかったとしても、メンテナのコードに変更を +たとえ、メンテナが #5 で反応がなかったとしても、メンテナのコードに変更を 加えたときには、いつもメンテナに CC するのを忘れないようにしてください。 -小さなパッチであれば、Adrian Bunk が管理している Trivial Patch Monkey -(ちょっとしたパッチを集めている)に CC してもいい -です。ちょっとしたパッチとは以下のルールのどれか1つを満たしていなけ -ればなりません。 +小さなパッチであれば、Trivial Patch Monkey(ちょっとしたパッチを集めている) +に CC してもいいです。その現管理者については MAINTAINERS +ファイルを見てください。ちょっとしたパッチとは以下のルールのどれか1つを満たして +いなければなりません。 ・ドキュメントのスペルミスの修正 ・grep(1) コマンドによる検索を困難にしているスペルの修正 ・コンパイル時の警告の修正(無駄な警告が散乱することは好ましくないた @@ -210,7 +228,6 @@ VGER.KERNEL.ORG でホスティングされているメーリングリストの ・移植性のないコードから移植性のあるコードへの置き換え(小さい範囲で あればアーキテクチャ特有のことでも他の人がコピーできます) ・作者やメンテナによる修正(すなわち patch monkey の再転送モード) -EMAIL: 7) MIME やリンクや圧縮ファイルや添付ファイルではなくプレインテキストのみ @@ -233,26 +250,15 @@ MIME 形式の添付ファイルは Linus に手間を取らせることにな 例外:お使いの電子メールクライアントがパッチをめちゃくちゃにするので あれば、誰かが MIME 形式のパッチを再送するよう求めるかもしれません。 -警告: Mozilla のような特定の電子メールクライアントは電子メールの -ヘッダに以下のものを付加して送ります。 ----- message header ---- -Content-Type: text/plain; charset=us-ascii; format=flowed ----- message header ---- -問題は、「 format=flowed 」が付いた電子メールを特定の受信側の電子メール -クライアントがタブをスペースに置き換えるというような変更をすることです。 -したがって送られてきたパッチは壊れているように見えるでしょう。 - -これを修正するには、mozilla の defaults/pref/mailnews.js ファイルを -以下のように修正します。 -pref("mailnews.send_plaintext_flowed", false); // RFC 2646======= -pref("mailnews.display.disable_format_flowed_support", true); +余計な変更を加えずにあなたのパッチを送信するための電子メールクライアントの設定 +のヒントについては Documentation/email-clients.txt を参照してください。 8) 電子メールのサイズ パッチを Linus へ送るときは常に #7 の手順に従ってください。 大きなパッチはメーリングリストやメンテナにとって不親切です。パッチが -未圧縮で 40KB を超えるようであるなら、インターネット上のアクセス可能な +未圧縮で 300KB を超えるようであるなら、インターネット上のアクセス可能な サーバに保存し、保存場所を示す URL を伝えるほうが適切です。 9) カーネルバージョンの明記 @@ -324,7 +330,7 @@ Linus や LKML への大量の電子メールのために、サブジェクト (c) 本寄与は(a)、(b)、(c)を証明する第3者から私へ直接提供された ものであり、私はそれに変更を加えていない。 - (d) 私はこのプロジェクトと本寄与が公のものであることに理解及び同意す + (d) 私はこのプロジェクトと本寄与が公のものであることに理解及び同意す る。同時に、関与した記録(投稿の際の全ての個人情報と sign-off を 含む)が無期限に保全されることと、当該プロジェクト又は関連する オープンソースライセンスに沿った形で再配布されることに理解及び @@ -340,7 +346,51 @@ Linus や LKML への大量の電子メールのために、サブジェクト 無視されますが、あなたはそのタグを社内の手続きに利用したり、sign-off に特別 な情報を示したりすることができます。 -13) いつ Acked-by: を使うのか +あなたがサブシステムまたはブランチのメンテナであれば、受け取ったパッチを自身の +ツリーにマージするために、わずかに変更が必要となる場合があります。なぜなら +あなたのツリーの中のコードと投稿者のツリーの中のコードは同一ではないためです。 +もし、あなたが厳密に上記ルール(c)にこだわるのであれば、投稿者に再度差分を +とるよう依頼すべきです。しかし、これは時間とエネルギーを非生産的に浪費する +ことになります。ルール(b)はあなたにコードを修正する権利を与えてくれます。 +しかし、投稿者のコードを修正し、その修正によるバグを投稿者に押し付けてしまう +ことはとても失礼なことです。この問題を解決するために、末尾の投稿者の +Signed-off-by とあなたがその末尾に追加する Signed-off-by の間に、修正を +加えたことを示す1行を追加することが推奨されています。 +(その1行の書き方に)決まりはありませんが、大括弧の中に電子メールアドレスや氏名 +と修正内容を記載するやり方は目につきやすく、最終段階での変更の責任があなたに +あることを明確にするのに十分な方法のようです。例えば、 + + Signed-off-by: Random J Developer + [lucky@maintainer.example.org: struct foo moved from foo.c to foo.h] + Signed-off-by: Lucky K Maintainer + +あなたが安定版のブランチを管理しており、作成者のクレジット、変更の追跡、 +修正のマージ、と同時に苦情からの投稿者の保護を行いたい場合、この慣習は特に +有用となります。いかなる事情があってもチェンジログに出てくる作成者の +アイデンティティ情報(From ヘッダ)は変更できないことに注意してください。 + +バックポートする人のための特別な注意事項。追跡を容易に行うために、コミット +メッセージのトップ(サブジェクト行のすぐ後)にパッチの起源を示す情報を記述する +ことは一般的で有用な慣習です。例えば、これは 2.6-stable ツリーでの一例です。 + + Date: Tue May 13 19:10:30 2008 +0000 + + SCSI: libiscsi regression in 2.6.25: fix nop timer handling + + commit 4cf1043593db6a337f10e006c23c69e5fc93e722 upstream + +そして、これは 2.4 ツリーでの一例です。 + + Date: Tue May 13 22:12:27 2008 +0200 + + wireless, airo: waitbusy() won't delay + + [backport of 2.6 commit b7acbdfbd1f277c1eb23f344f899cfa4cd0bf36a] + +どんな形式であれ、この情報はあなたのツリーを追跡する人やあなたのツリーのバグを +解決しようとしている人にとって価値のある支援となります。 + +13) いつ Acked-by: と Cc: を使うのか 「 Signed-off-by: 」タグはその署名者がパッチの開発に関わっていたことやパッチ の伝播パスにいたことを示しています。 @@ -354,7 +404,7 @@ Linus や LKML への大量の電子メールのために、サブジェクト Acked-by: は Signed-off-by: のように公式なタグではありません。それはメンテナが 少なくともパッチをレビューし、同意を示しているという記録です。そのような -ことからパッチの統合者がメンテナの「うん、良いと思うよ」という発言を +ことからパッチをマージする人がメンテナの「うん、良いと思うよ」という発言を Acked-by: へ置き換えることがあります。 Acked-by: が必ずしもパッチ全体の承認を示しているわけではありません。例えば、 @@ -364,7 +414,62 @@ Acked-by: が必ずしもパッチ全体の承認を示しているわけでは この点は、ご自分で判断してください。(その Acked-by: が)疑わしい場合は、 メーリングリストアーカイブの中の大元の議論を参照すべきです。 -14) 標準的なパッチのフォーマット +パッチにコメントする機会を持っていたが、その時にコメントしなかった人がいれば、 +その人を指す「Cc:」タグを任意で追加してもかまいません。これは指定された人からの +明確なアクションなしに付与できる唯一のタグです。 +このタグはパッチに関心があると思われる人達がそのパッチの議論に含まれていたこと +を明文化します。 + +14) Reported-by と Tested-by: と Reviewed-by: の利用 + +他の誰かによって報告された問題を修正するパッチであれば、問題報告者という寄与を +クレジットするために、Reported-by: タグを追加することを検討してください。 +こまめにバグ報告者をクレジットしていくことで、うまくいけばその人たちが将来再び +コミュニティの力となってくれるでしょう。 +ただし、報告者の許可無くこのタグを追加しないように注意してください。特に、 +問題が公の場で報告されていなかったのであれば。 + +Tested-by: タグはタグで指定された人によって(ある環境下で)パッチのテストに成功 +していることを示します。このタグはメンテナにテストが実施済みであることを +知らせ、将来の関連パッチのテスト協力者を見つける方法を提供し、テスト実施者に +対するクレジットを保証します。 + +Reviewed-by: タグは、それとは異なり、下記のレビューア宣言の下にレビューされ、 +受け入れ可能とみなされたパッチであることを示します。 + + レビューアによる監督宣言 + + 私は Reviewed-by: タグを提示することによって、以下のことを明言する。 + + (a) 私はメインラインカーネルへの統合に向け、その妥当性及び「即応性 + (訳注)」を検証し、技術的側面からパッチをレビュー済みである。 + + 訳注: + 「即応性」の原文は "readiness"。 + パッチが十分な品質を持っており、メインラインカーネルへの統合を即座に + 行うことができる状態であるかどうかを "readiness" という単語で表現 + している。 + + (b) パッチに関するあらゆる問題、懸念、あるいは、疑問は投稿者へ伝達済み + である。私はそれらのコメントに対する投稿者の返答に満足している。 + + (c) 投稿に伴い改良されるコードがある一方で、現時点で、私は(1)それが + カーネルにとって価値のある変更であること、そして、(2)統合に際して + 議論になり得るような問題はないものと確信している。 + + (d) 私はパッチをレビューし適切であると確信している一方で、あらゆる + 状況においてその宣言した目的や機能が正しく実現することに関して、 + いかなる保証もしない(特にどこかで明示しない限り)。 + +Reviewd-by タグはそのパッチがカーネルに対して適切な修正であって、深刻な技術的 +問題を残していないという意見の宣言です。興味のあるレビューアは誰でも(レビュー +作業を終えたら)パッチに対して Reviewed-by タグを提示できます。このタグは +レビューアの寄与をクレジットする働き、レビューの進捗の度合いをメンテナに +知らせる働きを持ちます。そのパッチの領域に詳しく、そして、しっかりとした +レビューを実施したレビューアによって提供される時、Reviewed-by: タグがあなたの +パッチをカーネルにマージする可能性を高めるでしょう。 + +15) 標準的なパッチのフォーマット 標準的なパッチのサブジェクトは以下のとおりです。 @@ -396,18 +501,37 @@ Acked-by: が必ずしもパッチ全体の承認を示しているわけでは 電子メールのサブジェクト内のサブシステム表記は、パッチが適用される 分野またはサブシステムを識別できるようにすべきです。 -電子メールのサブジェクトの「概要の言い回し」はそのパッチの概要を正確 -に表現しなければなりません。「概要の言い回し」をファイル名にしてはい -けません。一連のパッチ中でそれぞれのパッチは同じ「概要の言い回し」を -使ってはいけません(「一連のパッチ」とは順序付けられた関連のある複数の +電子メールのサブジェクトの「summary phrase」はそのパッチの概要を正確 +に表現しなければなりません。「summary phrase」をファイル名にしてはい +けません。パッチシリーズ中でそれぞれのパッチは同じ「summary phrase」を +使ってはいけません(「パッチシリーズ」とは順序付けられた関連のある複数の パッチ群です)。 -あなたの電子メールの「概要の言い回し」がそのパッチにとって世界で唯 -一の識別子になるように心がけてください。「概要の言い回し」は git の -チェンジログの中へずっと伝播していきます。「概要の言い回し」は、開 -発者が後でパッチを参照するために議論の中で利用するかもしれません。 -人々はそのパッチに関連した議論を読むために「概要の言い回し」を使って -google で検索したがるでしょう。 +あなたの電子メールの「summary phrase」がそのパッチにとって世界で唯一の識別子に +なるように心がけてください。「summary phrase」は git のチェンジログの中へ +ずっと伝播していきます。「summary phrase」は、開発者が後でパッチを参照する +ために議論の中で利用するかもしれません。 +人々はそのパッチに関連した議論を読むために「summary phrase」を使って google で +検索したがるでしょう。それはまた2、3ヶ月あとで、人々が「gitk」や +「git log --oneline」のようなツールを使用して何千ものパッチに目を通す時、 +唯一目にとまる情報となるでしょう。 + +これらの理由のため、「summary phrase」はなぜパッチが必要であるか、パッチが何を +変更するかの2つの情報をせいぜい70〜75文字で表現していなければなりません。 +「summary phrase」は簡潔であり説明的である表現を目指しつつ、うまく +まとめられている概要となるべきです。 + +「summary phrase」は「Subject: [PATCH tag] 」のように、 +大括弧で閉じられたタグを接頭辞として付加してもかまいません。このタグは +「summary phrase」の一部とは考えませんが、パッチをどのように取り扱うべきかを +表現します。 +一般的には「v1, v2, v3」のようなバージョン情報を表すタグ(過去のパッチに対する +コメントを反映するために複数のバージョンのパッチが投稿されているのであれば)、 +「RFC」のようなコメントを要求するタグが挙げられます。パッチシリーズとして4つの +パッチがあれば、個々のパッチに「1/4, 2/4, 3/4, 4/4」のように番号を付けても +かまいません。これは開発者がパッチを適用する順番を確実に把握するためです。 +そして、開発者がパッチシリーズの中のすべてのパッチをもらさずレビュー或いは +適用するのを保証するためです。 サブジェクトの例を二つ @@ -426,7 +550,12 @@ google で検索したがるでしょう。 説明本体は無期限のソースのチェンジログにコミットされます。なので、説明 本体はそのパッチに至った議論の詳細を忘れているある程度の技量を持っている人 -がその詳細を思い出すことができるものでなければなりません。 +がその詳細を思い出すことができるものでなければなりません。パッチが対処する +障害の症状(カーネルログメッセージや oops メッセージ等)を記載することは問題に +対処可能なパッチを求めてコミットログを検索する人々にとって特に有用です。 +パッチがコンパイル問題を解決するのであれば、そのパッチを探している人が見つける +ことができる情報だけで十分であり、コンパイル時の全てのエラーを含める必要は +ありません。「summary phrase」と同様に、簡潔であり説明的であることが重要です。 「 --- 」マーカー行はパッチ処理ツールに対して、チェンジログメッセージの終端 部分を認識させるという重要な役目を果たします。 @@ -436,14 +565,46 @@ google で検索したがるでしょう。 追加され何行消されたかを示すものです。diffstat コマンドは特に大きなパッチに おいて役立ちます。その時点でだけ又はメンテナにとってのみ関係のあるコメント は無期限に保存されるチェンジログにとって適切ではありません。そのため、この -ようなコメントもマーカー行の後に書かれるべきです。ファイル名はカーネルソー -スツリーのトップディレクトリからの表記でリストされるため、横方向のスペース -をとり過ぎないように、diffstat コマンドにオプション「 -p 1 -w 70 」を指定し -てください(インデントを含めてちょうど80列に合うでしょう)。 +ようなコメントもマーカー行の後に書かれるべきです。 +このようなコメントの良い例として、v1 と v2 のバージョン間で何が変更されたかを +表す「パッチの変更履歴」が挙げられます。 + +「 --- 」マーカー行の後に diffstat コマンドの結果を含めるのであれば、ファイル +名はカーネルソースツリーのトップディレクトリからの表記で列記されるため、横方向 +のスペースをとり過ぎないように、diffstat コマンドにオプション「 -p 1 -w 70 」 +を指定してください(インデントを含めてちょうど80列に合うでしょう)。 適切なパッチのフォーマットの詳細についてはセクション3の参考文献を参照して ください。 +16) 「git pull」要求の送り方(Linus の電子メールから) + +間違ったブランチから引っ張るのを防ぐために、git リポジトリのアドレスと +ブランチ名を同じ行に1行で記載してください。そうすることで、3回の連続クリック +で全て選択できます。 + +正しい形式は下記の通りです。 + + "Please pull from + + git://jdelvare.pck.nerim.net/jdelvare-2.6 i2c-for-linus + + to get these changes:" + +その結果、アドレスを自分自身でタイピングして間違えることはなくなります(実際に、 +何度か間違ったブランチから引っ張ってきてしまい、その時に diffstat の結果を +検証して間違っていることに気づいたことがあります。どこから何を引っ張るべきかを +「探したり」、正しいブランチ名かどうかを重ねてチェックしたりする必要が +なくなればより快適になるでしょう)。 + +diffstat の結果を生成するために「 git diff -M --stat --summary 」を使って +ください。-M オプションはファイル名の変更を検知でき、--summary オプションは +新規ファイル、削除されたファイル、名前が変更されたファイルの概要を生成します。 + +-M オプション(ファイル名の変更検知)を指定すると、diffstat の結果はかなり +異なってきます。git は大規模な変更(追加と削除のペア)をファイル名の変更と +判断するためです。 + ------------------------------------ セクション2 - ヒントとTIPSと小技 ------------------------------------ @@ -459,7 +620,7 @@ google で検索したがるでしょう。 も逸脱していると、レビューやコメントなしに受け取ってもらえないかもし れません。 -唯一の特筆すべき例外は、コードをあるファイルから別のファイルに移動 +特筆すべき例外は、コードをあるファイルから別のファイルに移動 するときです。この場合、コードを移動するパッチでは、移動されるコード に関して移動以外の変更を一切加えるべきではありません。これにより、 コードの移動とあなたが行ったコードの修正を明確に区別できるようにな @@ -553,4 +714,11 @@ Kernel Documentation/CodingStyle: Linus Torvalds's mail on the canonical patch format: + +Andi Kleen, "On submitting kernel patches" + Some strategies to get difficult or controversial changes in. + http://halobates.de/on-submitting-patches.pdf + -- + + diff --git a/Documentation/kbuild/makefiles.txt b/Documentation/kbuild/makefiles.txt index 47435e5..f47cdef 100644 --- a/Documentation/kbuild/makefiles.txt +++ b/Documentation/kbuild/makefiles.txt @@ -441,7 +441,7 @@ more details, with real examples. specified if first option are not supported. Example: - #arch/i386/kernel/Makefile + #arch/x86/kernel/Makefile vsyscall-flags += $(call cc-ldoption, -Wl$(comma)--hash-style=sysv) In the above example, vsyscall-flags will be assigned the option @@ -460,7 +460,7 @@ more details, with real examples. supported to use an optional second option. Example: - #arch/i386/Makefile + #arch/x86/Makefile cflags-y += $(call cc-option,-march=pentium-mmx,-march=i586) In the above example, cflags-y will be assigned the option @@ -522,7 +522,7 @@ more details, with real examples. even though the option was accepted by gcc. Example: - #arch/i386/Makefile + #arch/x86/Makefile cflags-y += $(shell \ if [ $(call cc-version) -ge 0300 ] ; then \ echo "-mregparm=3"; fi ;) @@ -802,7 +802,7 @@ but in the architecture makefiles where the kbuild infrastructure is not sufficient this sometimes needs to be explicit. Example: - #arch/i386/boot/Makefile + #arch/x86/boot/Makefile subdir- := compressed/ The above assignment instructs kbuild to descend down in the @@ -812,12 +812,12 @@ To support the clean infrastructure in the Makefiles that builds the final bootimage there is an optional target named archclean: Example: - #arch/i386/Makefile + #arch/x86/Makefile archclean: - $(Q)$(MAKE) $(clean)=arch/i386/boot + $(Q)$(MAKE) $(clean)=arch/x86/boot -When "make clean" is executed, make will descend down in arch/i386/boot, -and clean as usual. The Makefile located in arch/i386/boot/ may use +When "make clean" is executed, make will descend down in arch/x86/boot, +and clean as usual. The Makefile located in arch/x86/boot/ may use the subdir- trick to descend further down. Note 1: arch/$(ARCH)/Makefile cannot use "subdir-", because that file is @@ -882,7 +882,7 @@ When kbuild executes, the following steps are followed (roughly): LDFLAGS_vmlinux uses the LDFLAGS_$@ support. Example: - #arch/i386/Makefile + #arch/x86/Makefile LDFLAGS_vmlinux := -e stext OBJCOPYFLAGS objcopy flags @@ -920,14 +920,14 @@ When kbuild executes, the following steps are followed (roughly): Often, the KBUILD_CFLAGS variable depends on the configuration. Example: - #arch/i386/Makefile + #arch/x86/Makefile cflags-$(CONFIG_M386) += -march=i386 KBUILD_CFLAGS += $(cflags-y) Many arch Makefiles dynamically run the target C compiler to probe supported options: - #arch/i386/Makefile + #arch/x86/Makefile ... cflags-$(CONFIG_MPENTIUMII) += $(call cc-option,\ @@ -1038,8 +1038,8 @@ When kbuild executes, the following steps are followed (roughly): into the arch/$(ARCH)/boot/Makefile. Example: - #arch/i386/Makefile - boot := arch/i386/boot + #arch/x86/Makefile + boot := arch/x86/boot bzImage: vmlinux $(Q)$(MAKE) $(build)=$(boot) $(boot)/$@ @@ -1051,7 +1051,7 @@ When kbuild executes, the following steps are followed (roughly): To support this, $(archhelp) must be defined. Example: - #arch/i386/Makefile + #arch/x86/Makefile define archhelp echo '* bzImage - Image (arch/$(ARCH)/boot/bzImage)' endif @@ -1065,7 +1065,7 @@ When kbuild executes, the following steps are followed (roughly): from vmlinux. Example: - #arch/i386/Makefile + #arch/x86/Makefile all: bzImage When "make" is executed without arguments, bzImage will be built. @@ -1083,7 +1083,7 @@ When kbuild executes, the following steps are followed (roughly): 2) kbuild knows what files to delete during "make clean" Example: - #arch/i386/kernel/Makefile + #arch/x86/kernel/Makefile extra-y := head.o init_task.o In this example, extra-y is used to list object files that @@ -1133,7 +1133,7 @@ When kbuild executes, the following steps are followed (roughly): Compress target. Use maximum compression to compress target. Example: - #arch/i386/boot/Makefile + #arch/x86/boot/Makefile LDFLAGS_bootsect := -Ttext 0x0 -s --oformat binary LDFLAGS_setup := -Ttext 0x0 -s --oformat binary -e begtext @@ -1193,7 +1193,7 @@ When kbuild executes, the following steps are followed (roughly): When updating the $(obj)/bzImage target, the line - BUILD arch/i386/boot/bzImage + BUILD arch/x86/boot/bzImage will be displayed with "make KBUILD_VERBOSE=0". @@ -1207,7 +1207,7 @@ When kbuild executes, the following steps are followed (roughly): kbuild knows .lds files and includes a rule *lds.S -> *lds. Example: - #arch/i386/kernel/Makefile + #arch/x86/kernel/Makefile always := vmlinux.lds #Makefile diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt index aa47be7..4ca9389 100644 --- a/Documentation/kernel-parameters.txt +++ b/Documentation/kernel-parameters.txt @@ -1159,10 +1159,6 @@ bytes respectively. Such letter suffixes can also be entirely omitted. for all guests. Default is 1 (enabled) if in 64bit or 32bit-PAE mode - kvm-intel.bypass_guest_pf= - [KVM,Intel] Disables bypassing of guest page faults - on Intel chips. Default is 1 (enabled) - kvm-intel.ept= [KVM,Intel] Disable extended page tables (virtualized MMU) support on capable Intel chips. Default is 1 (enabled) @@ -1737,6 +1733,10 @@ bytes respectively. Such letter suffixes can also be entirely omitted. no-kvmapf [X86,KVM] Disable paravirtualized asynchronous page fault handling. + no-steal-acc [X86,KVM] Disable paravirtualized steal time accounting. + steal time is computed, but won't influence scheduler + behaviour + nolapic [X86-32,APIC] Do not enable or use the local APIC. nolapic_timer [X86-32,APIC] Do not use the local APIC timer. @@ -1846,7 +1846,9 @@ bytes respectively. Such letter suffixes can also be entirely omitted. See Documentation/sound/oss/oss-parameters.txt panic= [KNL] Kernel behaviour on panic: delay - seconds before rebooting + timeout > 0: seconds before rebooting + timeout = 0: wait forever + timeout < 0: reboot immediately Format: parkbd.port= [HW] Parallel port number the keyboard adapter is @@ -2526,6 +2528,11 @@ bytes respectively. Such letter suffixes can also be entirely omitted. ,,,,,,, See also Documentation/input/joystick-parport.txt + udbg-immortal [PPC] When debugging early kernel crashes that + happen after console_init() and before a proper + console driver takes over, this boot options might + help "seeing" what's going on. + uhash_entries= [KNL,NET] Set number of hash buckets for UDP/UDP-Lite connections @@ -2540,6 +2547,11 @@ bytes respectively. Such letter suffixes can also be entirely omitted. unknown_nmi_panic [X86] Cause panic on unknown NMI. + usbcore.authorized_default= + [USB] Default USB device authorization: + (default -1 = authorized except for wireless USB, + 0 = not authorized, 1 = authorized) + usbcore.autosuspend= [USB] The autosuspend time delay (in seconds) used for newly-detected USB devices (default 2). This diff --git a/Documentation/magic-number.txt b/Documentation/magic-number.txt index 4b12abc..abf481f 100644 --- a/Documentation/magic-number.txt +++ b/Documentation/magic-number.txt @@ -66,7 +66,7 @@ MKISS_DRIVER_MAGIC 0x04bf mkiss_channel drivers/net/mkiss.h RISCOM8_MAGIC 0x0907 riscom_port drivers/char/riscom8.h SPECIALIX_MAGIC 0x0907 specialix_port drivers/char/specialix_io8.h HDLC_MAGIC 0x239e n_hdlc drivers/char/n_hdlc.c -APM_BIOS_MAGIC 0x4101 apm_user arch/i386/kernel/apm.c +APM_BIOS_MAGIC 0x4101 apm_user arch/x86/kernel/apm_32.c CYCLADES_MAGIC 0x4359 cyclades_port include/linux/cyclades.h DB_MAGIC 0x4442 fc_info drivers/net/iph5526_novram.c DL_MAGIC 0x444d fc_info drivers/net/iph5526_novram.c diff --git a/Documentation/mca.txt b/Documentation/mca.txt index 510375d..dfd130c 100644 --- a/Documentation/mca.txt +++ b/Documentation/mca.txt @@ -11,7 +11,7 @@ Adapter Detection The ideal MCA adapter detection is done through the use of the Programmable Option Select registers. Generic functions for doing -this have been added in include/linux/mca.h and arch/i386/kernel/mca.c. +this have been added in include/linux/mca.h and arch/x86/kernel/mca_32.c. Everything needed to detect adapters and read (and write) configuration information is there. A number of MCA-specific drivers already use this. The typical probe code looks like the following: @@ -81,7 +81,7 @@ more people use shared IRQs on PCI machines. In general, an interrupt must be acknowledged not only at the ICU (which is done automagically by the kernel), but at the device level. In particular, IRQ 0 must be reset after a timer interrupt (now done in -arch/i386/kernel/time.c) or the first timer interrupt hangs the system. +arch/x86/kernel/time.c) or the first timer interrupt hangs the system. There were also problems with the 1.3.x floppy drivers, but that seems to have been fixed. diff --git a/Documentation/md.txt b/Documentation/md.txt index f0eee83..fc94770 100644 --- a/Documentation/md.txt +++ b/Documentation/md.txt @@ -360,18 +360,20 @@ Each directory contains: A file recording the current state of the device in the array which can be a comma separated list of faulty - device has been kicked from active use due to - a detected fault + a detected fault or it has unacknowledged bad + blocks in_sync - device is a fully in-sync member of the array writemostly - device will only be subject to read requests if there are no other options. This applies only to raid1 arrays. - blocked - device has failed, metadata is "external", - and the failure hasn't been acknowledged yet. + blocked - device has failed, and the failure hasn't been + acknowledged yet by the metadata handler. Writes that would write to this device if it were not faulty are blocked. spare - device is working, but not a full member. This includes spares that are in the process of being recovered to + write_error - device has ever seen a write error. This list may grow in future. This can be written to. Writing "faulty" simulates a failure on the device. @@ -379,9 +381,11 @@ Each directory contains: Writing "writemostly" sets the writemostly flag. Writing "-writemostly" clears the writemostly flag. Writing "blocked" sets the "blocked" flag. - Writing "-blocked" clears the "blocked" flag and allows writes - to complete. + Writing "-blocked" clears the "blocked" flags and allows writes + to complete and possibly simulates an error. Writing "in_sync" sets the in_sync flag. + Writing "write_error" sets writeerrorseen flag. + Writing "-write_error" clears writeerrorseen flag. This file responds to select/poll. Any change to 'faulty' or 'blocked' causes an event. @@ -419,7 +423,6 @@ Each directory contains: written, it will be rejected. recovery_start - When the device is not 'in_sync', this records the number of sectors from the start of the device which are known to be correct. This is normally zero, but during a recovery @@ -435,6 +438,20 @@ Each directory contains: Setting this to 'none' is equivalent to setting 'in_sync'. Setting to any other value also clears the 'in_sync' flag. + bad_blocks + This gives the list of all known bad blocks in the form of + start address and length (in sectors respectively). If output + is too big to fit in a page, it will be truncated. Writing + "sector length" to this file adds new acknowledged (i.e. + recorded to disk safely) bad blocks. + + unacknowledged_bad_blocks + This gives the list of known-but-not-yet-saved-to-disk bad + blocks in the same form of 'bad_blocks'. If output is too big + to fit in a page, it will be truncated. Writing to this file + adds bad blocks without acknowledging them. This is largely + for testing. + An active md device will also contain and entry for each active device diff --git a/Documentation/mmc/00-INDEX b/Documentation/mmc/00-INDEX index 93dd7a7..a9ba672 100644 --- a/Documentation/mmc/00-INDEX +++ b/Documentation/mmc/00-INDEX @@ -4,3 +4,5 @@ mmc-dev-attrs.txt - info on SD and MMC device attributes mmc-dev-parts.txt - info on SD and MMC device partitions +mmc-async-req.txt + - info on mmc asynchronous requests diff --git a/Documentation/mmc/mmc-async-req.txt b/Documentation/mmc/mmc-async-req.txt new file mode 100644 index 0000000..ae1907b --- /dev/null +++ b/Documentation/mmc/mmc-async-req.txt @@ -0,0 +1,87 @@ +Rationale +========= + +How significant is the cache maintenance overhead? +It depends. Fast eMMC and multiple cache levels with speculative cache +pre-fetch makes the cache overhead relatively significant. If the DMA +preparations for the next request are done in parallel with the current +transfer, the DMA preparation overhead would not affect the MMC performance. +The intention of non-blocking (asynchronous) MMC requests is to minimize the +time between when an MMC request ends and another MMC request begins. +Using mmc_wait_for_req(), the MMC controller is idle while dma_map_sg and +dma_unmap_sg are processing. Using non-blocking MMC requests makes it +possible to prepare the caches for next job in parallel with an active +MMC request. + +MMC block driver +================ + +The mmc_blk_issue_rw_rq() in the MMC block driver is made non-blocking. +The increase in throughput is proportional to the time it takes to +prepare (major part of preparations are dma_map_sg() and dma_unmap_sg()) +a request and how fast the memory is. The faster the MMC/SD is the +more significant the prepare request time becomes. Roughly the expected +performance gain is 5% for large writes and 10% on large reads on a L2 cache +platform. In power save mode, when clocks run on a lower frequency, the DMA +preparation may cost even more. As long as these slower preparations are run +in parallel with the transfer performance won't be affected. + +Details on measurements from IOZone and mmc_test +================================================ + +https://wiki.linaro.org/WorkingGroups/Kernel/Specs/StoragePerfMMC-async-req + +MMC core API extension +====================== + +There is one new public function mmc_start_req(). +It starts a new MMC command request for a host. The function isn't +truly non-blocking. If there is an ongoing async request it waits +for completion of that request and starts the new one and returns. It +doesn't wait for the new request to complete. If there is no ongoing +request it starts the new request and returns immediately. + +MMC host extensions +=================== + +There are two optional members in the mmc_host_ops -- pre_req() and +post_req() -- that the host driver may implement in order to move work +to before and after the actual mmc_host_ops.request() function is called. +In the DMA case pre_req() may do dma_map_sg() and prepare the DMA +descriptor, and post_req() runs the dma_unmap_sg(). + +Optimize for the first request +============================== + +The first request in a series of requests can't be prepared in parallel +with the previous transfer, since there is no previous request. +The argument is_first_req in pre_req() indicates that there is no previous +request. The host driver may optimize for this scenario to minimize +the performance loss. A way to optimize for this is to split the current +request in two chunks, prepare the first chunk and start the request, +and finally prepare the second chunk and start the transfer. + +Pseudocode to handle is_first_req scenario with minimal prepare overhead: + +if (is_first_req && req->size > threshold) + /* start MMC transfer for the complete transfer size */ + mmc_start_command(MMC_CMD_TRANSFER_FULL_SIZE); + + /* + * Begin to prepare DMA while cmd is being processed by MMC. + * The first chunk of the request should take the same time + * to prepare as the "MMC process command time". + * If prepare time exceeds MMC cmd time + * the transfer is delayed, guesstimate max 4k as first chunk size. + */ + prepare_1st_chunk_for_dma(req); + /* flush pending desc to the DMAC (dmaengine.h) */ + dma_issue_pending(req->dma_desc); + + prepare_2nd_chunk_for_dma(req); + /* + * The second issue_pending should be called before MMC runs out + * of the first chunk. If the MMC runs out of the first data chunk + * before this call, the transfer is delayed. + */ + dma_issue_pending(req->dma_desc); diff --git a/Documentation/networking/ifenslave.c b/Documentation/networking/ifenslave.c index 2bac961..65968fb 100644 --- a/Documentation/networking/ifenslave.c +++ b/Documentation/networking/ifenslave.c @@ -260,7 +260,7 @@ int main(int argc, char *argv[]) case 'V': opt_V++; exclusive++; break; case '?': - fprintf(stderr, usage_msg); + fprintf(stderr, "%s", usage_msg); res = 2; goto out; } @@ -268,13 +268,13 @@ int main(int argc, char *argv[]) /* options check */ if (exclusive > 1) { - fprintf(stderr, usage_msg); + fprintf(stderr, "%s", usage_msg); res = 2; goto out; } if (opt_v || opt_V) { - printf(version); + printf("%s", version); if (opt_V) { res = 0; goto out; @@ -282,14 +282,14 @@ int main(int argc, char *argv[]) } if (opt_u) { - printf(usage_msg); + printf("%s", usage_msg); res = 0; goto out; } if (opt_h) { - printf(usage_msg); - printf(help_msg); + printf("%s", usage_msg); + printf("%s", help_msg); res = 0; goto out; } @@ -309,7 +309,7 @@ int main(int argc, char *argv[]) goto out; } else { /* Just show usage */ - fprintf(stderr, usage_msg); + fprintf(stderr, "%s", usage_msg); res = 2; goto out; } @@ -320,7 +320,7 @@ int main(int argc, char *argv[]) master_ifname = *spp++; if (master_ifname == NULL) { - fprintf(stderr, usage_msg); + fprintf(stderr, "%s", usage_msg); res = 2; goto out; } @@ -339,7 +339,7 @@ int main(int argc, char *argv[]) if (slave_ifname == NULL) { if (opt_d || opt_c) { - fprintf(stderr, usage_msg); + fprintf(stderr, "%s", usage_msg); res = 2; goto out; } diff --git a/Documentation/networking/ip-sysctl.txt b/Documentation/networking/ip-sysctl.txt index bfe9242..db2a406 100644 --- a/Documentation/networking/ip-sysctl.txt +++ b/Documentation/networking/ip-sysctl.txt @@ -106,16 +106,6 @@ inet_peer_maxttl - INTEGER when the number of entries in the pool is very small). Measured in seconds. -inet_peer_gc_mintime - INTEGER - Minimum interval between garbage collection passes. This interval is - in effect under high memory pressure on the pool. - Measured in seconds. - -inet_peer_gc_maxtime - INTEGER - Minimum interval between garbage collection passes. This interval is - in effect under low (or absent) memory pressure on the pool. - Measured in seconds. - TCP variables: somaxconn - INTEGER @@ -394,7 +384,7 @@ tcp_rmem - vector of 3 INTEGERs: min, default, max min: Minimal size of receive buffer used by TCP sockets. It is guaranteed to each TCP socket, even under moderate memory pressure. - Default: 8K + Default: 1 page default: initial size of receive buffer used by TCP sockets. This value overrides net.core.rmem_default used by other protocols. @@ -483,7 +473,7 @@ tcp_window_scaling - BOOLEAN tcp_wmem - vector of 3 INTEGERs: min, default, max min: Amount of memory reserved for send buffers for TCP sockets. Each TCP socket has rights to use it due to fact of its birth. - Default: 4K + Default: 1 page default: initial size of send buffer used by TCP sockets. This value overrides net.core.wmem_default used by other protocols. @@ -553,13 +543,13 @@ udp_rmem_min - INTEGER Minimal size of receive buffer used by UDP sockets in moderation. Each UDP socket is able to use the size for receiving data, even if total pages of UDP sockets exceed udp_mem pressure. The unit is byte. - Default: 4096 + Default: 1 page udp_wmem_min - INTEGER Minimal size of send buffer used by UDP sockets in moderation. Each UDP socket is able to use the size for sending data, even if total pages of UDP sockets exceed udp_mem pressure. The unit is byte. - Default: 4096 + Default: 1 page CIPSOv4 Variables: @@ -1465,10 +1455,17 @@ sctp_mem - vector of 3 INTEGERs: min, pressure, max Default is calculated at boot time from amount of available memory. sctp_rmem - vector of 3 INTEGERs: min, default, max - See tcp_rmem for a description. + Only the first value ("min") is used, "default" and "max" are + ignored. + + min: Minimal size of receive buffer used by SCTP socket. + It is guaranteed to each SCTP socket (but not association) even + under moderate memory pressure. + + Default: 1 page sctp_wmem - vector of 3 INTEGERs: min, default, max - See tcp_wmem for a description. + Currently this tunable has no effect. addr_scope_policy - INTEGER Control IPv4 address scoping - draft-stewart-tsvwg-sctp-ipv4-00 diff --git a/Documentation/networking/netdev-features.txt b/Documentation/networking/netdev-features.txt new file mode 100644 index 0000000..4b1c0dc --- /dev/null +++ b/Documentation/networking/netdev-features.txt @@ -0,0 +1,154 @@ +Netdev features mess and how to get out from it alive +===================================================== + +Author: + Michał Mirosław + + + + Part I: Feature sets +====================== + +Long gone are the days when a network card would just take and give packets +verbatim. Today's devices add multiple features and bugs (read: offloads) +that relieve an OS of various tasks like generating and checking checksums, +splitting packets, classifying them. Those capabilities and their state +are commonly referred to as netdev features in Linux kernel world. + +There are currently three sets of features relevant to the driver, and +one used internally by network core: + + 1. netdev->hw_features set contains features whose state may possibly + be changed (enabled or disabled) for a particular device by user's + request. This set should be initialized in ndo_init callback and not + changed later. + + 2. netdev->features set contains features which are currently enabled + for a device. This should be changed only by network core or in + error paths of ndo_set_features callback. + + 3. netdev->vlan_features set contains features whose state is inherited + by child VLAN devices (limits netdev->features set). This is currently + used for all VLAN devices whether tags are stripped or inserted in + hardware or software. + + 4. netdev->wanted_features set contains feature set requested by user. + This set is filtered by ndo_fix_features callback whenever it or + some device-specific conditions change. This set is internal to + networking core and should not be referenced in drivers. + + + + Part II: Controlling enabled features +======================================= + +When current feature set (netdev->features) is to be changed, new set +is calculated and filtered by calling ndo_fix_features callback +and netdev_fix_features(). If the resulting set differs from current +set, it is passed to ndo_set_features callback and (if the callback +returns success) replaces value stored in netdev->features. +NETDEV_FEAT_CHANGE notification is issued after that whenever current +set might have changed. + +The following events trigger recalculation: + 1. device's registration, after ndo_init returned success + 2. user requested changes in features state + 3. netdev_update_features() is called + +ndo_*_features callbacks are called with rtnl_lock held. Missing callbacks +are treated as always returning success. + +A driver that wants to trigger recalculation must do so by calling +netdev_update_features() while holding rtnl_lock. This should not be done +from ndo_*_features callbacks. netdev->features should not be modified by +driver except by means of ndo_fix_features callback. + + + + Part III: Implementation hints +================================ + + * ndo_fix_features: + +All dependencies between features should be resolved here. The resulting +set can be reduced further by networking core imposed limitations (as coded +in netdev_fix_features()). For this reason it is safer to disable a feature +when its dependencies are not met instead of forcing the dependency on. + +This callback should not modify hardware nor driver state (should be +stateless). It can be called multiple times between successive +ndo_set_features calls. + +Callback must not alter features contained in NETIF_F_SOFT_FEATURES or +NETIF_F_NEVER_CHANGE sets. The exception is NETIF_F_VLAN_CHALLENGED but +care must be taken as the change won't affect already configured VLANs. + + * ndo_set_features: + +Hardware should be reconfigured to match passed feature set. The set +should not be altered unless some error condition happens that can't +be reliably detected in ndo_fix_features. In this case, the callback +should update netdev->features to match resulting hardware state. +Errors returned are not (and cannot be) propagated anywhere except dmesg. +(Note: successful return is zero, >0 means silent error.) + + + + Part IV: Features +=================== + +For current list of features, see include/linux/netdev_features.h. +This section describes semantics of some of them. + + * Transmit checksumming + +For complete description, see comments near the top of include/linux/skbuff.h. + +Note: NETIF_F_HW_CSUM is a superset of NETIF_F_IP_CSUM + NETIF_F_IPV6_CSUM. +It means that device can fill TCP/UDP-like checksum anywhere in the packets +whatever headers there might be. + + * Transmit TCP segmentation offload + +NETIF_F_TSO_ECN means that hardware can properly split packets with CWR bit +set, be it TCPv4 (when NETIF_F_TSO is enabled) or TCPv6 (NETIF_F_TSO6). + + * Transmit DMA from high memory + +On platforms where this is relevant, NETIF_F_HIGHDMA signals that +ndo_start_xmit can handle skbs with frags in high memory. + + * Transmit scatter-gather + +Those features say that ndo_start_xmit can handle fragmented skbs: +NETIF_F_SG --- paged skbs (skb_shinfo()->frags), NETIF_F_FRAGLIST --- +chained skbs (skb->next/prev list). + + * Software features + +Features contained in NETIF_F_SOFT_FEATURES are features of networking +stack. Driver should not change behaviour based on them. + + * LLTX driver (deprecated for hardware drivers) + +NETIF_F_LLTX should be set in drivers that implement their own locking in +transmit path or don't need locking at all (e.g. software tunnels). +In ndo_start_xmit, it is recommended to use a try_lock and return +NETDEV_TX_LOCKED when the spin lock fails. The locking should also properly +protect against other callbacks (the rules you need to find out). + +Don't use it for new drivers. + + * netns-local device + +NETIF_F_NETNS_LOCAL is set for devices that are not allowed to move between +network namespaces (e.g. loopback). + +Don't use it in drivers. + + * VLAN challenged + +NETIF_F_VLAN_CHALLENGED should be set for devices which can't cope with VLAN +headers. Some drivers set this because the cards can't handle the bigger MTU. +[FIXME: Those cases could be fixed in VLAN code by allowing only reduced-MTU +VLANs. This may be not useful, though.] diff --git a/Documentation/networking/nfc.txt b/Documentation/networking/nfc.txt new file mode 100644 index 0000000..b24c29b --- /dev/null +++ b/Documentation/networking/nfc.txt @@ -0,0 +1,128 @@ +Linux NFC subsystem +=================== + +The Near Field Communication (NFC) subsystem is required to standardize the +NFC device drivers development and to create an unified userspace interface. + +This document covers the architecture overview, the device driver interface +description and the userspace interface description. + +Architecture overview +--------------------- + +The NFC subsystem is responsible for: + - NFC adapters management; + - Polling for targets; + - Low-level data exchange; + +The subsystem is divided in some parts. The 'core' is responsible for +providing the device driver interface. On the other side, it is also +responsible for providing an interface to control operations and low-level +data exchange. + +The control operations are available to userspace via generic netlink. + +The low-level data exchange interface is provided by the new socket family +PF_NFC. The NFC_SOCKPROTO_RAW performs raw communication with NFC targets. + + + +--------------------------------------+ + | USER SPACE | + +--------------------------------------+ + ^ ^ + | low-level | control + | data exchange | operations + | | + | v + | +-----------+ + | AF_NFC | netlink | + | socket +-----------+ + | raw ^ + | | + v v + +---------+ +-----------+ + | rawsock | <--------> | core | + +---------+ +-----------+ + ^ + | + v + +-----------+ + | driver | + +-----------+ + +Device Driver Interface +----------------------- + +When registering on the NFC subsystem, the device driver must inform the core +of the set of supported NFC protocols and the set of ops callbacks. The ops +callbacks that must be implemented are the following: + +* start_poll - setup the device to poll for targets +* stop_poll - stop on progress polling operation +* activate_target - select and initialize one of the targets found +* deactivate_target - deselect and deinitialize the selected target +* data_exchange - send data and receive the response (transceive operation) + +Userspace interface +-------------------- + +The userspace interface is divided in control operations and low-level data +exchange operation. + +CONTROL OPERATIONS: + +Generic netlink is used to implement the interface to the control operations. +The operations are composed by commands and events, all listed below: + +* NFC_CMD_GET_DEVICE - get specific device info or dump the device list +* NFC_CMD_START_POLL - setup a specific device to polling for targets +* NFC_CMD_STOP_POLL - stop the polling operation in a specific device +* NFC_CMD_GET_TARGET - dump the list of targets found by a specific device + +* NFC_EVENT_DEVICE_ADDED - reports an NFC device addition +* NFC_EVENT_DEVICE_REMOVED - reports an NFC device removal +* NFC_EVENT_TARGETS_FOUND - reports START_POLL results when 1 or more targets +are found + +The user must call START_POLL to poll for NFC targets, passing the desired NFC +protocols through NFC_ATTR_PROTOCOLS attribute. The device remains in polling +state until it finds any target. However, the user can stop the polling +operation by calling STOP_POLL command. In this case, it will be checked if +the requester of STOP_POLL is the same of START_POLL. + +If the polling operation finds one or more targets, the event TARGETS_FOUND is +sent (including the device id). The user must call GET_TARGET to get the list of +all targets found by such device. Each reply message has target attributes with +relevant information such as the supported NFC protocols. + +All polling operations requested through one netlink socket are stopped when +it's closed. + +LOW-LEVEL DATA EXCHANGE: + +The userspace must use PF_NFC sockets to perform any data communication with +targets. All NFC sockets use AF_NFC: + +struct sockaddr_nfc { + sa_family_t sa_family; + __u32 dev_idx; + __u32 target_idx; + __u32 nfc_protocol; +}; + +To establish a connection with one target, the user must create an +NFC_SOCKPROTO_RAW socket and call the 'connect' syscall with the sockaddr_nfc +struct correctly filled. All information comes from NFC_EVENT_TARGETS_FOUND +netlink event. As a target can support more than one NFC protocol, the user +must inform which protocol it wants to use. + +Internally, 'connect' will result in an activate_target call to the driver. +When the socket is closed, the target is deactivated. + +The data format exchanged through the sockets is NFC protocol dependent. For +instance, when communicating with MIFARE tags, the data exchanged are MIFARE +commands and their responses. + +The first received package is the response to the first sent package and so +on. In order to allow valid "empty" responses, every data received has a NULL +header of 1 byte. diff --git a/Documentation/networking/stmmac.txt b/Documentation/networking/stmmac.txt index 80a7a34..57a2410 100644 --- a/Documentation/networking/stmmac.txt +++ b/Documentation/networking/stmmac.txt @@ -7,7 +7,7 @@ This is the driver for the MAC 10/100/1000 on-chip Ethernet controllers (Synopsys IP blocks); it has been fully tested on STLinux platforms. Currently this network device driver is for all STM embedded MAC/GMAC -(7xxx SoCs). Other platforms start using it i.e. ARM SPEAr. +(i.e. 7xxx/5xxx SoCs) and it's known working on other platforms i.e. ARM SPEAr. DWC Ether MAC 10/100/1000 Universal version 3.41a and DWC Ether MAC 10/100 Universal version 4.0 have been used for developing the first code @@ -71,7 +71,7 @@ Several performance tests on STM platforms showed this optimisation allows to sp the CPU while having the maximum throughput. 4.4) WOL -Wake up on Lan feature through Magic Frame is only supported for the GMAC +Wake up on Lan feature through Magic and Unicast frames are supported for the GMAC core. 4.5) DMA descriptors @@ -91,11 +91,15 @@ LRO is not supported. The driver is compatible with PAL to work with PHY and GPHY devices. 4.9) Platform information -Several information came from the platform; please refer to the -driver's Header file in include/linux directory. +Several driver's information can be passed through the platform +These are included in the include/linux/stmmac.h header file +and detailed below as well: -struct plat_stmmacenet_data { + struct plat_stmmacenet_data { int bus_id; + int phy_addr; + int interface; + struct stmmac_mdio_bus_data *mdio_bus_data; int pbl; int clk_csr; int has_gmac; @@ -103,67 +107,135 @@ struct plat_stmmacenet_data { int tx_coe; int bugged_jumbo; int pmt; - void (*fix_mac_speed)(void *priv, unsigned int speed); - void (*bus_setup)(unsigned long ioaddr); -#ifdef CONFIG_STM_DRIVERS - struct stm_pad_config *pad_config; -#endif - void *bsp_priv; -}; + int force_sf_dma_mode; + void (*fix_mac_speed)(void *priv, unsigned int speed); + void (*bus_setup)(void __iomem *ioaddr); + int (*init)(struct platform_device *pdev); + void (*exit)(struct platform_device *pdev); + void *bsp_priv; + }; Where: -- pbl (Programmable Burst Length) is maximum number of - beats to be transferred in one DMA transaction. - GMAC also enables the 4xPBL by default. -- fix_mac_speed and bus_setup are used to configure internal target - registers (on STM platforms); -- has_gmac: GMAC core is on board (get it at run-time in the next step); -- bus_id: bus identifier. -- tx_coe: core is able to perform the tx csum in HW. -- enh_desc: if sets the MAC will use the enhanced descriptor structure. -- clk_csr: CSR Clock range selection. -- bugged_jumbo: some HWs are not able to perform the csum in HW for - over-sized frames due to limited buffer sizes. Setting this - flag the csum will be done in SW on JUMBO frames. - -struct plat_stmmacphy_data { - int bus_id; - int phy_addr; - unsigned int phy_mask; - int interface; - int (*phy_reset)(void *priv); - void *priv; -}; + o bus_id: bus identifier. + o phy_addr: the physical address can be passed from the platform. + If it is set to -1 the driver will automatically + detect it at run-time by probing all the 32 addresses. + o interface: PHY device's interface. + o mdio_bus_data: specific platform fields for the MDIO bus. + o pbl: the Programmable Burst Length is maximum number of beats to + be transferred in one DMA transaction. + GMAC also enables the 4xPBL by default. + o clk_csr: CSR Clock range selection. + o has_gmac: uses the GMAC core. + o enh_desc: if sets the MAC will use the enhanced descriptor structure. + o tx_coe: core is able to perform the tx csum in HW. + o bugged_jumbo: some HWs are not able to perform the csum in HW for + over-sized frames due to limited buffer sizes. + Setting this flag the csum will be done in SW on + JUMBO frames. + o pmt: core has the embedded power module (optional). + o force_sf_dma_mode: force DMA to use the Store and Forward mode + instead of the Threshold. + o fix_mac_speed: this callback is used for modifying some syscfg registers + (on ST SoCs) according to the link speed negotiated by the + physical layer . + o bus_setup: perform HW setup of the bus. For example, on some ST platforms + this field is used to configure the AMBA bridge to generate more + efficient STBus traffic. + o init/exit: callbacks used for calling a custom initialisation; + this is sometime necessary on some platforms (e.g. ST boxes) + where the HW needs to have set some PIO lines or system cfg + registers. + o custom_cfg: this is a custom configuration that can be passed while + initialising the resources. + +The we have: + + struct stmmac_mdio_bus_data { + int bus_id; + int (*phy_reset)(void *priv); + unsigned int phy_mask; + int *irqs; + int probed_phy_irq; + }; Where: -- bus_id: bus identifier; -- phy_addr: physical address used for the attached phy device; - set it to -1 to get it at run-time; -- interface: physical MII interface mode; -- phy_reset: hook to reset HW function. - -SOURCES: -- Kconfig -- Makefile -- stmmac_main.c: main network device driver; -- stmmac_mdio.c: mdio functions; -- stmmac_ethtool.c: ethtool support; -- stmmac_timer.[ch]: timer code used for mitigating the driver dma interrupts - Only tested on ST40 platforms based. -- stmmac.h: private driver structure; -- common.h: common definitions and VFTs; -- descs.h: descriptor structure definitions; -- dwmac1000_core.c: GMAC core functions; -- dwmac1000_dma.c: dma functions for the GMAC chip; -- dwmac1000.h: specific header file for the GMAC; -- dwmac100_core: MAC 100 core and dma code; -- dwmac100_dma.c: dma funtions for the MAC chip; -- dwmac1000.h: specific header file for the MAC; -- dwmac_lib.c: generic DMA functions shared among chips -- enh_desc.c: functions for handling enhanced descriptors -- norm_desc.c: functions for handling normal descriptors - -TODO: -- XGMAC controller is not supported. -- Review the timer optimisation code to use an embedded device that seems to be + o bus_id: bus identifier; + o phy_reset: hook to reset the phy device attached to the bus. + o phy_mask: phy mask passed when register the MDIO bus within the driver. + o irqs: list of IRQs, one per PHY. + o probed_phy_irq: if irqs is NULL, use this for probed PHY. + +Below an example how the structures above are using on ST platforms. + + static struct plat_stmmacenet_data stxYYY_ethernet_platform_data = { + .pbl = 32, + .has_gmac = 0, + .enh_desc = 0, + .fix_mac_speed = stxYYY_ethernet_fix_mac_speed, + | + |-> to write an internal syscfg + | on this platform when the + | link speed changes from 10 to + | 100 and viceversa + .init = &stmmac_claim_resource, + | + |-> On ST SoC this calls own "PAD" + | manager framework to claim + | all the resources necessary + | (GPIO ...). The .custom_cfg field + | is used to pass a custom config. +}; + +Below the usage of the stmmac_mdio_bus_data: on this SoC, in fact, +there are two MAC cores: one MAC is for MDIO Bus/PHY emulation +with fixed_link support. + +static struct stmmac_mdio_bus_data stmmac1_mdio_bus = { + .bus_id = 1, + | + |-> phy device on the bus_id 1 + .phy_reset = phy_reset; + | + |-> function to provide the phy_reset on this board + .phy_mask = 0, +}; + +static struct fixed_phy_status stmmac0_fixed_phy_status = { + .link = 1, + .speed = 100, + .duplex = 1, +}; + +During the board's device_init we can configure the first +MAC for fixed_link by calling: + fixed_phy_add(PHY_POLL, 1, &stmmac0_fixed_phy_status));) +and the second one, with a real PHY device attached to the bus, +by using the stmmac_mdio_bus_data structure (to provide the id, the +reset procedure etc). + +4.10) List of source files: + o Kconfig + o Makefile + o stmmac_main.c: main network device driver; + o stmmac_mdio.c: mdio functions; + o stmmac_ethtool.c: ethtool support; + o stmmac_timer.[ch]: timer code used for mitigating the driver dma interrupts + Only tested on ST40 platforms based. + o stmmac.h: private driver structure; + o common.h: common definitions and VFTs; + o descs.h: descriptor structure definitions; + o dwmac1000_core.c: GMAC core functions; + o dwmac1000_dma.c: dma functions for the GMAC chip; + o dwmac1000.h: specific header file for the GMAC; + o dwmac100_core: MAC 100 core and dma code; + o dwmac100_dma.c: dma funtions for the MAC chip; + o dwmac1000.h: specific header file for the MAC; + o dwmac_lib.c: generic DMA functions shared among chips + o enh_desc.c: functions for handling enhanced descriptors + o norm_desc.c: functions for handling normal descriptors + +5) TODO: + o XGMAC is not supported. + o Review the timer optimisation code to use an embedded device that will be available in new chip generations. diff --git a/Documentation/power/devices.txt b/Documentation/power/devices.txt index 64565aa..3384d59 100644 --- a/Documentation/power/devices.txt +++ b/Documentation/power/devices.txt @@ -506,8 +506,8 @@ routines. Nevertheless, different callback pointers are used in case there is a situation where it actually matters. -Device Power Domains --------------------- +Device Power Management Domains +------------------------------- Sometimes devices share reference clocks or other power resources. In those cases it generally is not possible to put devices into low-power states individually. Instead, a set of devices sharing a power resource can be put @@ -516,8 +516,8 @@ power resource. Of course, they also need to be put into the full-power state together, by turning the shared power resource on. A set of devices with this property is often referred to as a power domain. -Support for power domains is provided through the pwr_domain field of struct -device. This field is a pointer to an object of type struct dev_power_domain, +Support for power domains is provided through the pm_domain field of struct +device. This field is a pointer to an object of type struct dev_pm_domain, defined in include/linux/pm.h, providing a set of power management callbacks analogous to the subsystem-level and device driver callbacks that are executed for the given device during all power transitions, instead of the respective @@ -604,7 +604,7 @@ state temporarily, for example so that its system wakeup capability can be disabled. This all depends on the hardware and the design of the subsystem and device driver in question. -During system-wide resume from a sleep state it's best to put devices into the -full-power state, as explained in Documentation/power/runtime_pm.txt. Refer to -that document for more information regarding this particular issue as well as +During system-wide resume from a sleep state it's easiest to put devices into +the full-power state, as explained in Documentation/power/runtime_pm.txt. Refer +to that document for more information regarding this particular issue as well as for information on the device runtime power management framework in general. diff --git a/Documentation/power/opp.txt b/Documentation/power/opp.txt index 5ae70a12..3035d00 100644 --- a/Documentation/power/opp.txt +++ b/Documentation/power/opp.txt @@ -321,6 +321,8 @@ opp_init_cpufreq_table - cpufreq framework typically is initialized with addition to CONFIG_PM as power management feature is required to dynamically scale voltage and frequency in a system. +opp_free_cpufreq_table - Free up the table allocated by opp_init_cpufreq_table + 7. Data Structures ================== Typically an SoC contains multiple voltage domains which are variable. Each diff --git a/Documentation/power/runtime_pm.txt b/Documentation/power/runtime_pm.txt index b24875b..14dd3c6 100644 --- a/Documentation/power/runtime_pm.txt +++ b/Documentation/power/runtime_pm.txt @@ -1,39 +1,39 @@ -Run-time Power Management Framework for I/O Devices +Runtime Power Management Framework for I/O Devices (C) 2009-2011 Rafael J. Wysocki , Novell Inc. (C) 2010 Alan Stern 1. Introduction -Support for run-time power management (run-time PM) of I/O devices is provided +Support for runtime power management (runtime PM) of I/O devices is provided at the power management core (PM core) level by means of: * The power management workqueue pm_wq in which bus types and device drivers can put their PM-related work items. It is strongly recommended that pm_wq be - used for queuing all work items related to run-time PM, because this allows + used for queuing all work items related to runtime PM, because this allows them to be synchronized with system-wide power transitions (suspend to RAM, hibernation and resume from system sleep states). pm_wq is declared in include/linux/pm_runtime.h and defined in kernel/power/main.c. -* A number of run-time PM fields in the 'power' member of 'struct device' (which +* A number of runtime PM fields in the 'power' member of 'struct device' (which is of the type 'struct dev_pm_info', defined in include/linux/pm.h) that can - be used for synchronizing run-time PM operations with one another. + be used for synchronizing runtime PM operations with one another. -* Three device run-time PM callbacks in 'struct dev_pm_ops' (defined in +* Three device runtime PM callbacks in 'struct dev_pm_ops' (defined in include/linux/pm.h). * A set of helper functions defined in drivers/base/power/runtime.c that can be - used for carrying out run-time PM operations in such a way that the + used for carrying out runtime PM operations in such a way that the synchronization between them is taken care of by the PM core. Bus types and device drivers are encouraged to use these functions. -The run-time PM callbacks present in 'struct dev_pm_ops', the device run-time PM +The runtime PM callbacks present in 'struct dev_pm_ops', the device runtime PM fields of 'struct dev_pm_info' and the core helper functions provided for -run-time PM are described below. +runtime PM are described below. -2. Device Run-time PM Callbacks +2. Device Runtime PM Callbacks -There are three device run-time PM callbacks defined in 'struct dev_pm_ops': +There are three device runtime PM callbacks defined in 'struct dev_pm_ops': struct dev_pm_ops { ... @@ -72,11 +72,11 @@ knows what to do to handle the device). not mean that the device has been put into a low power state. It is supposed to mean, however, that the device will not process data and will not communicate with the CPU(s) and RAM until the subsystem-level resume - callback is executed for it. The run-time PM status of a device after + callback is executed for it. The runtime PM status of a device after successful execution of the subsystem-level suspend callback is 'suspended'. * If the subsystem-level suspend callback returns -EBUSY or -EAGAIN, - the device's run-time PM status is 'active', which means that the device + the device's runtime PM status is 'active', which means that the device _must_ be fully operational afterwards. * If the subsystem-level suspend callback returns an error code different @@ -104,7 +104,7 @@ the device). * Once the subsystem-level resume callback has completed successfully, the PM core regards the device as fully operational, which means that the device - _must_ be able to complete I/O operations as needed. The run-time PM status + _must_ be able to complete I/O operations as needed. The runtime PM status of the device is then 'active'. * If the subsystem-level resume callback returns an error code, the PM core @@ -130,7 +130,7 @@ device in that case. The value returned by this callback is ignored by the PM core. The helper functions provided by the PM core, described in Section 4, guarantee -that the following constraints are met with respect to the bus type's run-time +that the following constraints are met with respect to the bus type's runtime PM callbacks: (1) The callbacks are mutually exclusive (e.g. it is forbidden to execute @@ -142,7 +142,7 @@ PM callbacks: (2) ->runtime_idle() and ->runtime_suspend() can only be executed for 'active' devices (i.e. the PM core will only execute ->runtime_idle() or - ->runtime_suspend() for the devices the run-time PM status of which is + ->runtime_suspend() for the devices the runtime PM status of which is 'active'). (3) ->runtime_idle() and ->runtime_suspend() can only be executed for a device @@ -151,7 +151,7 @@ PM callbacks: flag of which is set. (4) ->runtime_resume() can only be executed for 'suspended' devices (i.e. the - PM core will only execute ->runtime_resume() for the devices the run-time + PM core will only execute ->runtime_resume() for the devices the runtime PM status of which is 'suspended'). Additionally, the helper functions provided by the PM core obey the following @@ -171,9 +171,9 @@ rules: scheduled requests to execute the other callbacks for the same device, except for scheduled autosuspends. -3. Run-time PM Device Fields +3. Runtime PM Device Fields -The following device run-time PM fields are present in 'struct dev_pm_info', as +The following device runtime PM fields are present in 'struct dev_pm_info', as defined in include/linux/pm.h: struct timer_list suspend_timer; @@ -205,7 +205,7 @@ defined in include/linux/pm.h: unsigned int disable_depth; - used for disabling the helper funcions (they work normally if this is - equal to zero); the initial value of it is 1 (i.e. run-time PM is + equal to zero); the initial value of it is 1 (i.e. runtime PM is initially disabled for all devices) unsigned int runtime_error; @@ -229,10 +229,10 @@ defined in include/linux/pm.h: suspend to complete; means "start a resume as soon as you've suspended" unsigned int run_wake; - - set if the device is capable of generating run-time wake-up events + - set if the device is capable of generating runtime wake-up events enum rpm_status runtime_status; - - the run-time PM status of the device; this field's initial value is + - the runtime PM status of the device; this field's initial value is RPM_SUSPENDED, which means that each device is initially regarded by the PM core as 'suspended', regardless of its real hardware status @@ -243,7 +243,7 @@ defined in include/linux/pm.h: and pm_runtime_forbid() helper functions unsigned int no_callbacks; - - indicates that the device does not use the run-time PM callbacks (see + - indicates that the device does not use the runtime PM callbacks (see Section 8); it may be modified only by the pm_runtime_no_callbacks() helper function @@ -270,16 +270,16 @@ defined in include/linux/pm.h: All of the above fields are members of the 'power' member of 'struct device'. -4. Run-time PM Device Helper Functions +4. Runtime PM Device Helper Functions -The following run-time PM helper functions are defined in +The following runtime PM helper functions are defined in drivers/base/power/runtime.c and include/linux/pm_runtime.h: void pm_runtime_init(struct device *dev); - - initialize the device run-time PM fields in 'struct dev_pm_info' + - initialize the device runtime PM fields in 'struct dev_pm_info' void pm_runtime_remove(struct device *dev); - - make sure that the run-time PM of the device will be disabled after + - make sure that the runtime PM of the device will be disabled after removing the device from device hierarchy int pm_runtime_idle(struct device *dev); @@ -289,9 +289,10 @@ drivers/base/power/runtime.c and include/linux/pm_runtime.h: int pm_runtime_suspend(struct device *dev); - execute the subsystem-level suspend callback for the device; returns 0 on - success, 1 if the device's run-time PM status was already 'suspended', or + success, 1 if the device's runtime PM status was already 'suspended', or error code on failure, where -EAGAIN or -EBUSY means it is safe to attempt - to suspend the device again in future + to suspend the device again in future and -EACCES means that + 'power.disable_depth' is different from 0 int pm_runtime_autosuspend(struct device *dev); - same as pm_runtime_suspend() except that the autosuspend delay is taken @@ -301,10 +302,11 @@ drivers/base/power/runtime.c and include/linux/pm_runtime.h: int pm_runtime_resume(struct device *dev); - execute the subsystem-level resume callback for the device; returns 0 on - success, 1 if the device's run-time PM status was already 'active' or + success, 1 if the device's runtime PM status was already 'active' or error code on failure, where -EAGAIN means it may be safe to attempt to resume the device again in future, but 'power.runtime_error' should be - checked additionally + checked additionally, and -EACCES means that 'power.disable_depth' is + different from 0 int pm_request_idle(struct device *dev); - submit a request to execute the subsystem-level idle callback for the @@ -321,7 +323,7 @@ drivers/base/power/runtime.c and include/linux/pm_runtime.h: device in future, where 'delay' is the time to wait before queuing up a suspend work item in pm_wq, in milliseconds (if 'delay' is zero, the work item is queued up immediately); returns 0 on success, 1 if the device's PM - run-time status was already 'suspended', or error code if the request + runtime status was already 'suspended', or error code if the request hasn't been scheduled (or queued up if 'delay' is 0); if the execution of ->runtime_suspend() is already scheduled and not yet expired, the new value of 'delay' will be used as the time to wait @@ -329,7 +331,7 @@ drivers/base/power/runtime.c and include/linux/pm_runtime.h: int pm_request_resume(struct device *dev); - submit a request to execute the subsystem-level resume callback for the device (the request is represented by a work item in pm_wq); returns 0 on - success, 1 if the device's run-time PM status was already 'active', or + success, 1 if the device's runtime PM status was already 'active', or error code if the request hasn't been queued up void pm_runtime_get_noresume(struct device *dev); @@ -367,22 +369,32 @@ drivers/base/power/runtime.c and include/linux/pm_runtime.h: pm_runtime_autosuspend(dev) and return its result void pm_runtime_enable(struct device *dev); - - enable the run-time PM helper functions to run the device bus type's - run-time PM callbacks described in Section 2 + - decrement the device's 'power.disable_depth' field; if that field is equal + to zero, the runtime PM helper functions can execute subsystem-level + callbacks described in Section 2 for the device int pm_runtime_disable(struct device *dev); - - prevent the run-time PM helper functions from running subsystem-level - run-time PM callbacks for the device, make sure that all of the pending - run-time PM operations on the device are either completed or canceled; + - increment the device's 'power.disable_depth' field (if the value of that + field was previously zero, this prevents subsystem-level runtime PM + callbacks from being run for the device), make sure that all of the pending + runtime PM operations on the device are either completed or canceled; returns 1 if there was a resume request pending and it was necessary to execute the subsystem-level resume callback for the device to satisfy that request, otherwise 0 is returned + int pm_runtime_barrier(struct device *dev); + - check if there's a resume request pending for the device and resume it + (synchronously) in that case, cancel any other pending runtime PM requests + regarding it and wait for all runtime PM operations on it in progress to + complete; returns 1 if there was a resume request pending and it was + necessary to execute the subsystem-level resume callback for the device to + satisfy that request, otherwise 0 is returned + void pm_suspend_ignore_children(struct device *dev, bool enable); - set/unset the power.ignore_children flag of the device int pm_runtime_set_active(struct device *dev); - - clear the device's 'power.runtime_error' flag, set the device's run-time + - clear the device's 'power.runtime_error' flag, set the device's runtime PM status to 'active' and update its parent's counter of 'active' children as appropriate (it is only valid to use this function if 'power.runtime_error' is set or 'power.disable_depth' is greater than @@ -390,7 +402,7 @@ drivers/base/power/runtime.c and include/linux/pm_runtime.h: which is not active and the 'power.ignore_children' flag of which is unset void pm_runtime_set_suspended(struct device *dev); - - clear the device's 'power.runtime_error' flag, set the device's run-time + - clear the device's 'power.runtime_error' flag, set the device's runtime PM status to 'suspended' and update its parent's counter of 'active' children as appropriate (it is only valid to use this function if 'power.runtime_error' is set or 'power.disable_depth' is greater than @@ -400,6 +412,9 @@ drivers/base/power/runtime.c and include/linux/pm_runtime.h: - return true if the device's runtime PM status is 'suspended' and its 'power.disable_depth' field is equal to zero, or false otherwise + bool pm_runtime_status_suspended(struct device *dev); + - return true if the device's runtime PM status is 'suspended' + void pm_runtime_allow(struct device *dev); - set the power.runtime_auto flag for the device and decrease its usage counter (used by the /sys/devices/.../power/control interface to @@ -411,7 +426,7 @@ drivers/base/power/runtime.c and include/linux/pm_runtime.h: effectively prevent the device from being power managed at run time) void pm_runtime_no_callbacks(struct device *dev); - - set the power.no_callbacks flag for the device and remove the run-time + - set the power.no_callbacks flag for the device and remove the runtime PM attributes from /sys/devices/.../power (or prevent them from being added when the device is registered) @@ -431,7 +446,7 @@ drivers/base/power/runtime.c and include/linux/pm_runtime.h: void pm_runtime_set_autosuspend_delay(struct device *dev, int delay); - set the power.autosuspend_delay value to 'delay' (expressed in - milliseconds); if 'delay' is negative then run-time suspends are + milliseconds); if 'delay' is negative then runtime suspends are prevented unsigned long pm_runtime_autosuspend_expiration(struct device *dev); @@ -470,35 +485,35 @@ pm_runtime_resume() pm_runtime_get_sync() pm_runtime_put_sync_suspend() -5. Run-time PM Initialization, Device Probing and Removal +5. Runtime PM Initialization, Device Probing and Removal -Initially, the run-time PM is disabled for all devices, which means that the -majority of the run-time PM helper funtions described in Section 4 will return +Initially, the runtime PM is disabled for all devices, which means that the +majority of the runtime PM helper funtions described in Section 4 will return -EAGAIN until pm_runtime_enable() is called for the device. -In addition to that, the initial run-time PM status of all devices is +In addition to that, the initial runtime PM status of all devices is 'suspended', but it need not reflect the actual physical state of the device. Thus, if the device is initially active (i.e. it is able to process I/O), its -run-time PM status must be changed to 'active', with the help of +runtime PM status must be changed to 'active', with the help of pm_runtime_set_active(), before pm_runtime_enable() is called for the device. -However, if the device has a parent and the parent's run-time PM is enabled, +However, if the device has a parent and the parent's runtime PM is enabled, calling pm_runtime_set_active() for the device will affect the parent, unless the parent's 'power.ignore_children' flag is set. Namely, in that case the parent won't be able to suspend at run time, using the PM core's helper functions, as long as the child's status is 'active', even if the child's -run-time PM is still disabled (i.e. pm_runtime_enable() hasn't been called for +runtime PM is still disabled (i.e. pm_runtime_enable() hasn't been called for the child yet or pm_runtime_disable() has been called for it). For this reason, once pm_runtime_set_active() has been called for the device, pm_runtime_enable() -should be called for it too as soon as reasonably possible or its run-time PM +should be called for it too as soon as reasonably possible or its runtime PM status should be changed back to 'suspended' with the help of pm_runtime_set_suspended(). -If the default initial run-time PM status of the device (i.e. 'suspended') +If the default initial runtime PM status of the device (i.e. 'suspended') reflects the actual state of the device, its bus type's or its driver's ->probe() callback will likely need to wake it up using one of the PM core's 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 +should be used. Of course, for this purpose the device's runtime PM has to be enabled earlier by calling pm_runtime_enable(). If the device bus type's or driver's ->probe() callback runs @@ -529,33 +544,33 @@ 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 attribute to "on", which causes pm_runtime_forbid() to be called. In principle, this mechanism may also be used by the driver to effectively turn off the -run-time power management of the device until the user space turns it on. -Namely, during the initialization the driver can make sure that the run-time PM +runtime power management of the device until the user space turns it on. +Namely, during the initialization the driver can make sure that the runtime PM status of the device is 'active' and call pm_runtime_forbid(). It should be noted, however, that if the user space has already intentionally changed the value of /sys/devices/.../power/control to "auto" to allow the driver to power manage the device at run time, the driver may confuse it by using pm_runtime_forbid() this way. -6. Run-time PM and System Sleep +6. Runtime PM and System Sleep -Run-time PM and system sleep (i.e., system suspend and hibernation, also known +Runtime PM and system sleep (i.e., system suspend and hibernation, also known as suspend-to-RAM and suspend-to-disk) interact with each other in a couple of ways. If a device is active when a system sleep starts, everything is straightforward. But what should happen if the device is already suspended? -The device may have different wake-up settings for run-time PM and system sleep. -For example, remote wake-up may be enabled for run-time suspend but disallowed +The device may have different wake-up settings for runtime PM and system sleep. +For example, remote wake-up may be enabled for runtime suspend but disallowed for system sleep (device_may_wakeup(dev) returns 'false'). When this happens, the subsystem-level system suspend callback is responsible for changing the device's wake-up setting (it may leave that to the device driver's system suspend routine). It may be necessary to resume the device and suspend it again in order to do so. The same is true if the driver uses different power levels -or other settings for run-time suspend and system sleep. +or other settings for runtime suspend and system sleep. -During system resume, devices generally should be brought back to full power, -even if they were suspended before the system sleep began. There are several -reasons for this, including: +During system resume, the simplest approach is to bring all devices back to full +power, even if they had been suspended before the system suspend began. There +are several reasons for this, including: * The device might need to switch power levels, wake-up settings, etc. @@ -570,18 +585,50 @@ reasons for this, including: * The device might need to be reset. * Even though the device was suspended, if its usage counter was > 0 then most - likely it would need a run-time resume in the near future anyway. - - * Always going back to full power is simplest. + likely it would need a runtime resume in the near future anyway. -If the device was suspended before the sleep began, then its run-time PM status -will have to be updated to reflect the actual post-system sleep status. The way -to do this is: +If the device had been suspended before the system suspend began and it's +brought back to full power during resume, then its runtime PM status will have +to be updated to reflect the actual post-system sleep status. The way to do +this is: pm_runtime_disable(dev); pm_runtime_set_active(dev); pm_runtime_enable(dev); +The PM core always increments the runtime usage counter before calling the +->suspend() callback and decrements it after calling the ->resume() callback. +Hence disabling runtime PM temporarily like this will not cause any runtime +suspend attempts to be permanently lost. If the usage count goes to zero +following the return of the ->resume() callback, the ->runtime_idle() callback +will be invoked as usual. + +On some systems, however, system sleep is not entered through a global firmware +or hardware operation. Instead, all hardware components are put into low-power +states directly by the kernel in a coordinated way. Then, the system sleep +state effectively follows from the states the hardware components end up in +and the system is woken up from that state by a hardware interrupt or a similar +mechanism entirely under the kernel's control. As a result, the kernel never +gives control away and the states of all devices during resume are precisely +known to it. If that is the case and none of the situations listed above takes +place (in particular, if the system is not waking up from hibernation), it may +be more efficient to leave the devices that had been suspended before the system +suspend began in the suspended state. + +The PM core does its best to reduce the probability of race conditions between +the runtime PM and system suspend/resume (and hibernation) callbacks by carrying +out the following operations: + + * During system suspend it calls pm_runtime_get_noresume() and + pm_runtime_barrier() for every device right before executing the + subsystem-level .suspend() callback for it. In addition to that it calls + pm_runtime_disable() for every device right after executing the + subsystem-level .suspend() callback for it. + + * During system resume it calls pm_runtime_enable() and pm_runtime_put_sync() + for every device right before and right after executing the subsystem-level + .resume() callback for it, respectively. + 7. Generic subsystem callbacks Subsystems may wish to conserve code space by using the set of generic power @@ -606,40 +653,68 @@ driver/base/power/generic_ops.c: callback provided by its driver and return its result, or return 0 if not defined + int pm_generic_suspend_noirq(struct device *dev); + - if pm_runtime_suspended(dev) returns "false", invoke the ->suspend_noirq() + callback provided by the device's driver and return its result, or return + 0 if not defined + int pm_generic_resume(struct device *dev); - invoke the ->resume() callback provided by the driver of this device and, if successful, change the device's runtime PM status to 'active' + int pm_generic_resume_noirq(struct device *dev); + - invoke the ->resume_noirq() callback provided by the driver of this device + int pm_generic_freeze(struct device *dev); - if the device has not been suspended at run time, invoke the ->freeze() callback provided by its driver and return its result, or return 0 if not defined + int pm_generic_freeze_noirq(struct device *dev); + - if pm_runtime_suspended(dev) returns "false", invoke the ->freeze_noirq() + callback provided by the device's driver and return its result, or return + 0 if not defined + int pm_generic_thaw(struct device *dev); - if the device has not been suspended at run time, invoke the ->thaw() callback provided by its driver and return its result, or return 0 if not defined + int pm_generic_thaw_noirq(struct device *dev); + - if pm_runtime_suspended(dev) returns "false", invoke the ->thaw_noirq() + callback provided by the device's driver and return its result, or return + 0 if not defined + int pm_generic_poweroff(struct device *dev); - if the device has not been suspended at run time, invoke the ->poweroff() callback provided by its driver and return its result, or return 0 if not defined + int pm_generic_poweroff_noirq(struct device *dev); + - if pm_runtime_suspended(dev) returns "false", run the ->poweroff_noirq() + callback provided by the device's driver and return its result, or return + 0 if not defined + int pm_generic_restore(struct device *dev); - invoke the ->restore() callback provided by the driver of this device and, if successful, change the device's runtime PM status to 'active' + int pm_generic_restore_noirq(struct device *dev); + - invoke the ->restore_noirq() callback provided by the device's driver + These functions can be assigned to the ->runtime_idle(), ->runtime_suspend(), -->runtime_resume(), ->suspend(), ->resume(), ->freeze(), ->thaw(), ->poweroff(), -or ->restore() callback pointers in the subsystem-level dev_pm_ops structures. +->runtime_resume(), ->suspend(), ->suspend_noirq(), ->resume(), +->resume_noirq(), ->freeze(), ->freeze_noirq(), ->thaw(), ->thaw_noirq(), +->poweroff(), ->poweroff_noirq(), ->restore(), ->restore_noirq() callback +pointers in the subsystem-level dev_pm_ops structures. If a subsystem wishes to use all of them at the same time, it can simply assign the GENERIC_SUBSYS_PM_OPS macro, defined in include/linux/pm.h, to its dev_pm_ops structure pointer. Device drivers that wish to use the same function as a system suspend, freeze, -poweroff and run-time suspend callback, and similarly for system resume, thaw, -restore, and run-time resume, can achieve this with the help of the +poweroff and runtime suspend callback, and similarly for system resume, thaw, +restore, and runtime resume, can achieve this with the help of the UNIVERSAL_DEV_PM_OPS macro defined in include/linux/pm.h (possibly setting its last argument to NULL). @@ -649,7 +724,7 @@ Some "devices" are only logical sub-devices of their parent and cannot be power-managed on their own. (The prototype example is a USB interface. Entire USB devices can go into low-power mode or send wake-up requests, but neither is possible for individual interfaces.) The drivers for these devices have no -need of run-time PM callbacks; if the callbacks did exist, ->runtime_suspend() +need of runtime PM callbacks; if the callbacks did exist, ->runtime_suspend() and ->runtime_resume() would always return 0 without doing anything else and ->runtime_idle() would always call pm_runtime_suspend(). @@ -657,7 +732,7 @@ Subsystems can tell the PM core about these devices by calling pm_runtime_no_callbacks(). This should be done after the device structure is initialized and before it is registered (although after device registration is also okay). The routine will set the device's power.no_callbacks flag and -prevent the non-debugging run-time PM sysfs attributes from being created. +prevent the non-debugging runtime PM sysfs attributes from being created. When power.no_callbacks is set, the PM core will not invoke the ->runtime_idle(), ->runtime_suspend(), or ->runtime_resume() callbacks. @@ -665,7 +740,7 @@ Instead it will assume that suspends and resumes always succeed and that idle devices should be suspended. As a consequence, the PM core will never directly inform the device's subsystem -or driver about run-time power changes. Instead, the driver for the device's +or driver about runtime power changes. Instead, the driver for the device's parent must take responsibility for telling the device's driver when the parent's power state changes. @@ -676,13 +751,13 @@ A device should be put in a low-power state only when there's some reason to think it will remain in that state for a substantial time. A common heuristic says that a device which hasn't been used for a while is liable to remain unused; following this advice, drivers should not allow devices to be suspended -at run-time until they have been inactive for some minimum period. Even when +at runtime until they have been inactive for some minimum period. Even when the heuristic ends up being non-optimal, it will still prevent devices from "bouncing" too rapidly between low-power and full-power states. The term "autosuspend" is an historical remnant. It doesn't mean that the device is automatically suspended (the subsystem or driver still has to call -the appropriate PM routines); rather it means that run-time suspends will +the appropriate PM routines); rather it means that runtime suspends will automatically be delayed until the desired period of inactivity has elapsed. Inactivity is determined based on the power.last_busy field. Drivers should diff --git a/Documentation/rbtree.txt b/Documentation/rbtree.txt index 19f8278..8d32d85 100644 --- a/Documentation/rbtree.txt +++ b/Documentation/rbtree.txt @@ -196,15 +196,20 @@ Support for Augmented rbtrees Augmented rbtree is an rbtree with "some" additional data stored in each node. This data can be used to augment some new functionality to rbtree. Augmented rbtree is an optional feature built on top of basic rbtree -infrastructure. rbtree user who wants this feature will have an augment -callback function in rb_root initialized. - -This callback function will be called from rbtree core routines whenever -a node has a change in one or both of its children. It is the responsibility -of the callback function to recalculate the additional data that is in the -rb node using new children information. Note that if this new additional -data affects the parent node's additional data, then callback function has -to handle it and do the recursive updates. +infrastructure. An rbtree user who wants this feature will have to call the +augmentation functions with the user provided augmentation callback +when inserting and erasing nodes. + +On insertion, the user must call rb_augment_insert() once the new node is in +place. This will cause the augmentation function callback to be called for +each node between the new node and the root which has been affected by the +insertion. + +When erasing a node, the user must call rb_augment_erase_begin() first to +retrieve the deepest node on the rebalance path. Then, after erasing the +original node, the user must call rb_augment_erase_end() with the deepest +node found earlier. This will cause the augmentation function to be called +for each affected node between the deepest node and the root. Interval tree is an example of augmented rb tree. Reference - diff --git a/Documentation/s390/TAPE b/Documentation/s390/TAPE deleted file mode 100644 index c639aa5..0000000 --- a/Documentation/s390/TAPE +++ /dev/null @@ -1,122 +0,0 @@ -Channel attached Tape device driver - ------------------------------WARNING----------------------------------------- -This driver is considered to be EXPERIMENTAL. Do NOT use it in -production environments. Feel free to test it and report problems back to us. ------------------------------------------------------------------------------ - -The LINUX for zSeries tape device driver manages channel attached tape drives -which are compatible to IBM 3480 or IBM 3490 magnetic tape subsystems. This -includes various models of these devices (for example the 3490E). - - -Tape driver features - -The device driver supports a maximum of 128 tape devices. -No official LINUX device major number is assigned to the zSeries tape device -driver. It allocates major numbers dynamically and reports them on system -startup. -Typically it will get major number 254 for both the character device front-end -and the block device front-end. - -The tape device driver needs no kernel parameters. All supported devices -present are detected on driver initialization at system startup or module load. -The devices detected are ordered by their subchannel numbers. The device with -the lowest subchannel number becomes device 0, the next one will be device 1 -and so on. - - -Tape character device front-end - -The usual way to read or write to the tape device is through the character -device front-end. The zSeries tape device driver provides two character devices -for each physical device -- the first of these will rewind automatically when -it is closed, the second will not rewind automatically. - -The character device nodes are named /dev/rtibm0 (rewinding) and /dev/ntibm0 -(non-rewinding) for the first device, /dev/rtibm1 and /dev/ntibm1 for the -second, and so on. - -The character device front-end can be used as any other LINUX tape device. You -can write to it and read from it using LINUX facilities such as GNU tar. The -tool mt can be used to perform control operations, such as rewinding the tape -or skipping a file. - -Most LINUX tape software should work with either tape character device. - - -Tape block device front-end - -The tape device may also be accessed as a block device in read-only mode. -This could be used for software installation in the same way as it is used with -other operation systems on the zSeries platform (and most LINUX -distributions are shipped on compact disk using ISO9660 filesystems). - -One block device node is provided for each physical device. These are named -/dev/btibm0 for the first device, /dev/btibm1 for the second and so on. -You should only use the ISO9660 filesystem on LINUX for zSeries tapes because -the physical tape devices cannot perform fast seeks and the ISO9660 system is -optimized for this situation. - - -Tape block device example - -In this example a tape with an ISO9660 filesystem is created using the first -tape device. ISO9660 filesystem support must be built into your system kernel -for this. -The mt command is used to issue tape commands and the mkisofs command to -create an ISO9660 filesystem: - -- create a LINUX directory (somedir) with the contents of the filesystem - mkdir somedir - cp contents somedir - -- insert a tape - -- ensure the tape is at the beginning - mt -f /dev/ntibm0 rewind - -- set the blocksize of the character driver. The blocksize 2048 bytes - is commonly used on ISO9660 CD-Roms - mt -f /dev/ntibm0 setblk 2048 - -- write the filesystem to the character device driver - mkisofs -o /dev/ntibm0 somedir - -- rewind the tape again - mt -f /dev/ntibm0 rewind - -- Now you can mount your new filesystem as a block device: - mount -t iso9660 -o ro,block=2048 /dev/btibm0 /mnt - -TODO List - - - Driver has to be stabilized still - -BUGS - -This driver is considered BETA, which means some weaknesses may still -be in it. -If an error occurs which cannot be handled by the code you will get a -sense-data dump.In that case please do the following: - -1. set the tape driver debug level to maximum: - echo 6 >/proc/s390dbf/tape/level - -2. re-perform the actions which produced the bug. (Hopefully the bug will - reappear.) - -3. get a snapshot from the debug-feature: - cat /proc/s390dbf/tape/hex_ascii >somefile - -4. Now put the snapshot together with a detailed description of the situation - that led to the bug: - - Which tool did you use? - - Which hardware do you have? - - Was your tape unit online? - - Is it a shared tape unit? - -5. Send an email with your bug report to: - mailto:Linux390@de.ibm.com - - diff --git a/Documentation/scheduler/sched-arch.txt b/Documentation/scheduler/sched-arch.txt index d43dbcb..28aa107 100644 --- a/Documentation/scheduler/sched-arch.txt +++ b/Documentation/scheduler/sched-arch.txt @@ -66,7 +66,7 @@ Your cpu_idle routines need to obey the following rules: barrier issued (followed by a test of need_resched with interrupts disabled, as explained in 3). -arch/i386/kernel/process.c has examples of both polling and +arch/x86/kernel/process.c has examples of both polling and sleeping idle functions. diff --git a/Documentation/scsi/BusLogic.txt b/Documentation/scsi/BusLogic.txt index d7fbc94..48e982c 100644 --- a/Documentation/scsi/BusLogic.txt +++ b/Documentation/scsi/BusLogic.txt @@ -553,7 +553,7 @@ replacing "/usr/src" with wherever you keep your Linux kernel source tree: make config make zImage -Then install "arch/i386/boot/zImage" as your standard kernel, run lilo if +Then install "arch/x86/boot/zImage" as your standard kernel, run lilo if appropriate, and reboot. diff --git a/Documentation/security/keys-ecryptfs.txt b/Documentation/security/keys-ecryptfs.txt new file mode 100644 index 0000000..c3bbeba --- /dev/null +++ b/Documentation/security/keys-ecryptfs.txt @@ -0,0 +1,68 @@ + Encrypted keys for the eCryptfs filesystem + +ECryptfs is a stacked filesystem which transparently encrypts and decrypts each +file using a randomly generated File Encryption Key (FEK). + +Each FEK is in turn encrypted with a File Encryption Key Encryption Key (FEFEK) +either in kernel space or in user space with a daemon called 'ecryptfsd'. In +the former case the operation is performed directly by the kernel CryptoAPI +using a key, the FEFEK, derived from a user prompted passphrase; in the latter +the FEK is encrypted by 'ecryptfsd' with the help of external libraries in order +to support other mechanisms like public key cryptography, PKCS#11 and TPM based +operations. + +The data structure defined by eCryptfs to contain information required for the +FEK decryption is called authentication token and, currently, can be stored in a +kernel key of the 'user' type, inserted in the user's session specific keyring +by the userspace utility 'mount.ecryptfs' shipped with the package +'ecryptfs-utils'. + +The 'encrypted' key type has been extended with the introduction of the new +format 'ecryptfs' in order to be used in conjunction with the eCryptfs +filesystem. Encrypted keys of the newly introduced format store an +authentication token in its payload with a FEFEK randomly generated by the +kernel and protected by the parent master key. + +In order to avoid known-plaintext attacks, the datablob obtained through +commands 'keyctl print' or 'keyctl pipe' does not contain the overall +authentication token, which content is well known, but only the FEFEK in +encrypted form. + +The eCryptfs filesystem may really benefit from using encrypted keys in that the +required key can be securely generated by an Administrator and provided at boot +time after the unsealing of a 'trusted' key in order to perform the mount in a +controlled environment. Another advantage is that the key is not exposed to +threats of malicious software, because it is available in clear form only at +kernel level. + +Usage: + keyctl add encrypted name "new ecryptfs key-type:master-key-name keylen" ring + keyctl add encrypted name "load hex_blob" ring + keyctl update keyid "update key-type:master-key-name" + +name:= '<16 hexadecimal characters>' +key-type:= 'trusted' | 'user' +keylen:= 64 + + +Example of encrypted key usage with the eCryptfs filesystem: + +Create an encrypted key "1000100010001000" of length 64 bytes with format +'ecryptfs' and save it using a previously loaded user key "test": + + $ keyctl add encrypted 1000100010001000 "new ecryptfs user:test 64" @u + 19184530 + + $ keyctl print 19184530 + ecryptfs user:test 64 490045d4bfe48c99f0d465fbbbb79e7500da954178e2de0697 + dd85091f5450a0511219e9f7cd70dcd498038181466f78ac8d4c19504fcc72402bfc41c2 + f253a41b7507ccaa4b2b03fff19a69d1cc0b16e71746473f023a95488b6edfd86f7fdd40 + 9d292e4bacded1258880122dd553a661 + + $ keyctl pipe 19184530 > ecryptfs.blob + +Mount an eCryptfs filesystem using the created encrypted key "1000100010001000" +into the '/secret' directory: + + $ mount -i -t ecryptfs -oecryptfs_sig=1000100010001000,\ + ecryptfs_cipher=aes,ecryptfs_key_bytes=32 /secret /secret diff --git a/Documentation/security/keys-trusted-encrypted.txt b/Documentation/security/keys-trusted-encrypted.txt index 8fb79bc..5f50cca 100644 --- a/Documentation/security/keys-trusted-encrypted.txt +++ b/Documentation/security/keys-trusted-encrypted.txt @@ -53,12 +53,19 @@ they are only as secure as the user key encrypting them. The master user key should therefore be loaded in as secure a way as possible, preferably early in boot. +The decrypted portion of encrypted keys can contain either a simple symmetric +key or a more complex structure. The format of the more complex structure is +application specific, which is identified by 'format'. + Usage: - keyctl add encrypted name "new key-type:master-key-name keylen" ring - keyctl add encrypted name "load hex_blob" ring - keyctl update keyid "update key-type:master-key-name" + keyctl add encrypted name "new [format] key-type:master-key-name keylen" + ring + keyctl add encrypted name "load hex_blob" ring + keyctl update keyid "update key-type:master-key-name" + +format:= 'default | ecryptfs' +key-type:= 'trusted' | 'user' -where 'key-type' is either 'trusted' or 'user'. Examples of trusted and encrypted key usage: @@ -114,15 +121,25 @@ Reseal a trusted key under new pcr values: 7ef6a24defe4846104209bf0c3eced7fa1a672ed5b125fc9d8cd88b476a658a4434644ef df8ae9a178e9f83ba9f08d10fa47e4226b98b0702f06b3b8 -Create and save an encrypted key "evm" using the above trusted key "kmk": +The initial consumer of trusted keys is EVM, which at boot time needs a high +quality symmetric key for HMAC protection of file metadata. The use of a +trusted key provides strong guarantees that the EVM key has not been +compromised by a user level problem, and when sealed to specific boot PCR +values, protects against boot and offline attacks. Create and save an +encrypted key "evm" using the above trusted key "kmk": +option 1: omitting 'format' $ keyctl add encrypted evm "new trusted:kmk 32" @u 159771175 +option 2: explicitly defining 'format' as 'default' + $ keyctl add encrypted evm "new default trusted:kmk 32" @u + 159771175 + $ keyctl print 159771175 - trusted:kmk 32 2375725ad57798846a9bbd240de8906f006e66c03af53b1b382dbbc55 - be2a44616e4959430436dc4f2a7a9659aa60bb4652aeb2120f149ed197c564e024717c64 - 5972dcb82ab2dde83376d82b2e3c09ffc + default trusted:kmk 32 2375725ad57798846a9bbd240de8906f006e66c03af53b1b3 + 82dbbc55be2a44616e4959430436dc4f2a7a9659aa60bb4652aeb2120f149ed197c564e0 + 24717c64 5972dcb82ab2dde83376d82b2e3c09ffc $ keyctl pipe 159771175 > evm.blob @@ -132,14 +149,11 @@ Load an encrypted key "evm" from saved blob: 831684262 $ keyctl print 831684262 - trusted:kmk 32 2375725ad57798846a9bbd240de8906f006e66c03af53b1b382dbbc55 - be2a44616e4959430436dc4f2a7a9659aa60bb4652aeb2120f149ed197c564e024717c64 - 5972dcb82ab2dde83376d82b2e3c09ffc - - -The initial consumer of trusted keys is EVM, which at boot time needs a high -quality symmetric key for HMAC protection of file metadata. The use of a -trusted key provides strong guarantees that the EVM key has not been -compromised by a user level problem, and when sealed to specific boot PCR -values, protects against boot and offline attacks. Other uses for trusted and -encrypted keys, such as for disk and file encryption are anticipated. + default trusted:kmk 32 2375725ad57798846a9bbd240de8906f006e66c03af53b1b3 + 82dbbc55be2a44616e4959430436dc4f2a7a9659aa60bb4652aeb2120f149ed197c564e0 + 24717c64 5972dcb82ab2dde83376d82b2e3c09ffc + +Other uses for trusted and encrypted keys, such as for disk and file encryption +are anticipated. In particular the new format 'ecryptfs' has been defined in +in order to use encrypted keys to mount an eCryptfs filesystem. More details +about the usage can be found in the file 'Documentation/keys-ecryptfs.txt'. diff --git a/Documentation/serial/computone.txt b/Documentation/serial/computone.txt index c57ea47..60a6f65 100644 --- a/Documentation/serial/computone.txt +++ b/Documentation/serial/computone.txt @@ -87,7 +87,7 @@ c) Set address on ISA cards then: edit /usr/src/linux/drivers/char/ip2.c (Optional - may be specified on kernel command line now) d) Run "make zImage" or whatever target you prefer. -e) mv /usr/src/linux/arch/i386/boot/zImage to /boot. +e) mv /usr/src/linux/arch/x86/boot/zImage to /boot. f) Add new config for this kernel into /etc/lilo.conf, run "lilo" or copy to a floppy disk and boot from that floppy disk. g) Reboot using this kernel diff --git a/Documentation/sound/alsa/HD-Audio-Controls.txt b/Documentation/sound/alsa/HD-Audio-Controls.txt new file mode 100644 index 0000000..1482035 --- /dev/null +++ b/Documentation/sound/alsa/HD-Audio-Controls.txt @@ -0,0 +1,100 @@ +This file explains the codec-specific mixer controls. + +Realtek codecs +-------------- + +* Channel Mode + This is an enum control to change the surround-channel setup, + appears only when the surround channels are available. + It gives the number of channels to be used, "2ch", "4ch", "6ch", + and "8ch". According to the configuration, this also controls the + jack-retasking of multi-I/O jacks. + +* Auto-Mute Mode + This is an enum control to change the auto-mute behavior of the + headphone and line-out jacks. If built-in speakers and headphone + and/or line-out jacks are available on a machine, this controls + appears. + When there are only either headphones or line-out jacks, it gives + "Disabled" and "Enabled" state. When enabled, the speaker is muted + automatically when a jack is plugged. + + When both headphone and line-out jacks are present, it gives + "Disabled", "Speaker Only" and "Line-Out+Speaker". When + speaker-only is chosen, plugging into a headphone or a line-out jack + mutes the speakers, but not line-outs. When line-out+speaker is + selected, plugging to a headphone jack mutes both speakers and + line-outs. + + +IDT/Sigmatel codecs +------------------- + +* Analog Loopback + This control enables/disables the analog-loopback circuit. This + appears only when "loopback" is set to true in a codec hint + (see HD-Audio.txt). Note that on some codecs the analog-loopback + and the normal PCM playback are exclusive, i.e. when this is on, you + won't hear any PCM stream. + +* Swap Center/LFE + Swaps the center and LFE channel order. Normally, the left + corresponds to the center and the right to the LFE. When this is + ON, the left to the LFE and the right to the center. + +* Headphone as Line Out + When this control is ON, treat the headphone jacks as line-out + jacks. That is, the headphone won't auto-mute the other line-outs, + and no HP-amp is set to the pins. + +* Mic Jack Mode, Line Jack Mode, etc + These enum controls the direction and the bias of the input jack + pins. Depending on the jack type, it can set as "Mic In" and "Line + In", for determining the input bias, or it can be set to "Line Out" + when the pin is a multi-I/O jack for surround channels. + + +VIA codecs +---------- + +* Smart 5.1 + An enum control to re-task the multi-I/O jacks for surround outputs. + When it's ON, the corresponding input jacks (usually a line-in and a + mic-in) are switched as the surround and the CLFE output jacks. + +* Independent HP + When this enum control is enabled, the headphone output is routed + from an individual stream (the third PCM such as hw:0,2) instead of + the primary stream. In the case the headphone DAC is shared with a + side or a CLFE-channel DAC, the DAC is switched to the headphone + automatically. + +* Loopback Mixing + An enum control to determine whether the analog-loopback route is + enabled or not. When it's enabled, the analog-loopback is mixed to + the front-channel. Also, the same route is used for the headphone + and speaker outputs. As a side-effect, when this mode is set, the + individual volume controls will be no longer available for + headphones and speakers because there is only one DAC connected to a + mixer widget. + +* Dynamic Power-Control + This control determines whether the dynamic power-control per jack + detection is enabled or not. When enabled, the widgets power state + (D0/D3) are changed dynamically depending on the jack plugging + state for saving power consumptions. However, if your system + doesn't provide a proper jack-detection, this won't work; in such a + case, turn this control OFF. + +* Jack Detect + This control is provided only for VT1708 codec which gives no proper + unsolicited event per jack plug. When this is on, the driver polls + the jack detection so that the headphone auto-mute can work, while + turning this off would reduce the power consumption. + + +Conexant codecs +--------------- + +* Auto-Mute Mode + See Reatek codecs. diff --git a/Documentation/spi/ep93xx_spi b/Documentation/spi/ep93xx_spi index 6325f5b..d8eb01c 100644 --- a/Documentation/spi/ep93xx_spi +++ b/Documentation/spi/ep93xx_spi @@ -88,6 +88,16 @@ static void __init ts72xx_init_machine(void) ARRAY_SIZE(ts72xx_spi_devices)); } +The driver can use DMA for the transfers also. In this case ts72xx_spi_info +becomes: + +static struct ep93xx_spi_info ts72xx_spi_info = { + .num_chipselect = ARRAY_SIZE(ts72xx_spi_devices), + .use_dma = true; +}; + +Note that CONFIG_EP93XX_DMA should be enabled as well. + Thanks to ========= Martin Guy, H. Hartley Sweeten and others who helped me during development of diff --git a/Documentation/spi/pxa2xx b/Documentation/spi/pxa2xx index 493dada..00511e0 100644 --- a/Documentation/spi/pxa2xx +++ b/Documentation/spi/pxa2xx @@ -22,15 +22,11 @@ Typically a SPI master is defined in the arch/.../mach-*/board-*.c as a found in include/linux/spi/pxa2xx_spi.h: struct pxa2xx_spi_master { - enum pxa_ssp_type ssp_type; u32 clock_enable; u16 num_chipselect; u8 enable_dma; }; -The "pxa2xx_spi_master.ssp_type" field must have a value between 1 and 3 and -informs the driver which features a particular SSP supports. - The "pxa2xx_spi_master.clock_enable" field is used to enable/disable the corresponding SSP peripheral block in the "Clock Enable Register (CKEN"). See the "PXA2xx Developer Manual" section "Clocks and Power Management". @@ -61,7 +57,6 @@ static struct resource pxa_spi_nssp_resources[] = { }; static struct pxa2xx_spi_master pxa_nssp_master_info = { - .ssp_type = PXA25x_NSSP, /* Type of SSP */ .clock_enable = CKEN_NSSP, /* NSSP Peripheral clock */ .num_chipselect = 1, /* Matches the number of chips attached to NSSP */ .enable_dma = 1, /* Enables NSSP DMA */ diff --git a/Documentation/sysctl/kernel.txt b/Documentation/sysctl/kernel.txt index 5e7cb39..704e474 100644 --- a/Documentation/sysctl/kernel.txt +++ b/Documentation/sysctl/kernel.txt @@ -17,23 +17,21 @@ before actually making adjustments. Currently, these files might (depending on your configuration) show up in /proc/sys/kernel: -- acpi_video_flags + - acct +- acpi_video_flags +- auto_msgmni - bootloader_type [ X86 only ] - bootloader_version [ X86 only ] - callhome [ S390 only ] -- auto_msgmni - core_pattern - core_pipe_limit - core_uses_pid - ctrl-alt-del -- dentry-state - dmesg_restrict - domainname - hostname - hotplug -- java-appletviewer [ binfmt_java, obsolete ] -- java-interpreter [ binfmt_java, obsolete ] - kptr_restrict - kstack_depth_to_print [ X86 only ] - l2cr [ PPC only ] @@ -48,10 +46,14 @@ show up in /proc/sys/kernel: - overflowgid - overflowuid - panic +- panic_on_oops +- panic_on_unrecovered_nmi - pid_max - powersave-nap [ PPC only ] -- panic_on_unrecovered_nmi - printk +- printk_delay +- printk_ratelimit +- printk_ratelimit_burst - randomize_va_space - real-root-dev ==> Documentation/initrd.txt - reboot-cmd [ SPARC only ] @@ -59,9 +61,11 @@ show up in /proc/sys/kernel: - rtsig-nr - sem - sg-big-buff [ generic SCSI device (sg) ] +- shm_rmid_forced - shmall - shmmax [ sysv ipc ] - shmmni +- softlockup_thresh - stop-a [ SPARC only ] - sysrq ==> Documentation/sysrq.txt - tainted @@ -71,15 +75,6 @@ show up in /proc/sys/kernel: ============================================================== -acpi_video_flags: - -flags - -See Doc*/kernel/power/video.txt, it allows mode of video boot to be -set during run time. - -============================================================== - acct: highwater lowwater frequency @@ -97,6 +92,25 @@ valid for 30 seconds. ============================================================== +acpi_video_flags: + +flags + +See Doc*/kernel/power/video.txt, it allows mode of video boot to be +set during run time. + +============================================================== + +auto_msgmni: + +Enables/Disables automatic recomputing of msgmni upon memory add/remove +or upon ipc namespace creation/removal (see the msgmni description +above). Echoing "1" into this file enables msgmni automatic recomputing. +Echoing "0" turns it off. auto_msgmni default value is 1. + + +============================================================== + bootloader_type: x86 bootloader identification @@ -172,22 +186,24 @@ core_pattern is used to specify a core dumpfile pattern name. core_pipe_limit: -This sysctl is only applicable when core_pattern is configured to pipe core -files to a user space helper (when the first character of core_pattern is a '|', -see above). When collecting cores via a pipe to an application, it is -occasionally useful for the collecting application to gather data about the -crashing process from its /proc/pid directory. In order to do this safely, the -kernel must wait for the collecting process to exit, so as not to remove the -crashing processes proc files prematurely. This in turn creates the possibility -that a misbehaving userspace collecting process can block the reaping of a -crashed process simply by never exiting. This sysctl defends against that. It -defines how many concurrent crashing processes may be piped to user space -applications in parallel. If this value is exceeded, then those crashing -processes above that value are noted via the kernel log and their cores are -skipped. 0 is a special value, indicating that unlimited processes may be -captured in parallel, but that no waiting will take place (i.e. the collecting -process is not guaranteed access to /proc//). This value defaults -to 0. +This sysctl is only applicable when core_pattern is configured to pipe +core files to a user space helper (when the first character of +core_pattern is a '|', see above). When collecting cores via a pipe +to an application, it is occasionally useful for the collecting +application to gather data about the crashing process from its +/proc/pid directory. In order to do this safely, the kernel must wait +for the collecting process to exit, so as not to remove the crashing +processes proc files prematurely. This in turn creates the +possibility that a misbehaving userspace collecting process can block +the reaping of a crashed process simply by never exiting. This sysctl +defends against that. It defines how many concurrent crashing +processes may be piped to user space applications in parallel. If +this value is exceeded, then those crashing processes above that value +are noted via the kernel log and their cores are skipped. 0 is a +special value, indicating that unlimited processes may be captured in +parallel, but that no waiting will take place (i.e. the collecting +process is not guaranteed access to /proc//). This +value defaults to 0. ============================================================== @@ -218,14 +234,14 @@ to decide what to do with it. dmesg_restrict: -This toggle indicates whether unprivileged users are prevented from using -dmesg(8) to view messages from the kernel's log buffer. When -dmesg_restrict is set to (0) there are no restrictions. When +This toggle indicates whether unprivileged users are prevented +from using dmesg(8) to view messages from the kernel's log buffer. +When dmesg_restrict is set to (0) there are no restrictions. When dmesg_restrict is set set to (1), users must have CAP_SYSLOG to use dmesg(8). -The kernel config option CONFIG_SECURITY_DMESG_RESTRICT sets the default -value of dmesg_restrict. +The kernel config option CONFIG_SECURITY_DMESG_RESTRICT sets the +default value of dmesg_restrict. ============================================================== @@ -256,13 +272,6 @@ Default value is "/sbin/hotplug". ============================================================== -l2cr: (PPC only) - -This flag controls the L2 cache of G3 processor boards. If -0, the cache is disabled. Enabled if nonzero. - -============================================================== - kptr_restrict: This toggle indicates whether restrictions are placed on @@ -283,6 +292,13 @@ kernel stack. ============================================================== +l2cr: (PPC only) + +This flag controls the L2 cache of G3 processor boards. If +0, the cache is disabled. Enabled if nonzero. + +============================================================== + modules_disabled: A toggle value indicating if modules are allowed to be loaded @@ -293,6 +309,21 @@ to false. ============================================================== +nmi_watchdog: + +Enables/Disables the NMI watchdog on x86 systems. When the value is +non-zero the NMI watchdog is enabled and will continuously test all +online cpus to determine whether or not they are still functioning +properly. Currently, passing "nmi_watchdog=" parameter at boot time is +required for this function to work. + +If LAPIC NMI watchdog method is in use (nmi_watchdog=2 kernel +parameter), the NMI watchdog shares registers with oprofile. By +disabling the NMI watchdog, oprofile may have more registers to +utilize. + +============================================================== + osrelease, ostype & version: # cat osrelease @@ -312,10 +343,10 @@ The only way to tune these values is to rebuild the kernel :-) overflowgid & overflowuid: -if your architecture did not always support 32-bit UIDs (i.e. arm, i386, -m68k, sh, and sparc32), a fixed UID and GID will be returned to -applications that use the old 16-bit UID/GID system calls, if the actual -UID or GID would exceed 65535. +if your architecture did not always support 32-bit UIDs (i.e. arm, +i386, m68k, sh, and sparc32), a fixed UID and GID will be returned to +applications that use the old 16-bit UID/GID system calls, if the +actual UID or GID would exceed 65535. These sysctls allow you to change the value of the fixed UID and GID. The default is 65534. @@ -324,9 +355,22 @@ The default is 65534. panic: -The value in this file represents the number of seconds the -kernel waits before rebooting on a panic. When you use the -software watchdog, the recommended setting is 60. +The value in this file represents the number of seconds the kernel +waits before rebooting on a panic. When you use the software watchdog, +the recommended setting is 60. + +============================================================== + +panic_on_unrecovered_nmi: + +The default Linux behaviour on an NMI of either memory or unknown is +to continue operation. For many environments such as scientific +computing it is preferable that the box is taken out and the error +dealt with than an uncorrected parity/ECC error get propagated. + +A small number of systems do generate NMI's for bizarre random reasons +such as power management so the default is off. That sysctl works like +the existing panic controls already in that directory. ============================================================== @@ -376,6 +420,14 @@ the different loglevels. ============================================================== +printk_delay: + +Delay each printk message in printk_delay milliseconds + +Value from 0 - 10000 is allowed. + +============================================================== + printk_ratelimit: Some warning messages are rate limited. printk_ratelimit specifies @@ -395,15 +447,7 @@ send before ratelimiting kicks in. ============================================================== -printk_delay: - -Delay each printk message in printk_delay milliseconds - -Value from 0 - 10000 is allowed. - -============================================================== - -randomize-va-space: +randomize_va_space: This option can be used to select the type of process address space randomization that is used in the system, for architectures @@ -466,15 +510,36 @@ are doing anyway :) ============================================================== -shmmax: +shmmax: This value can be used to query and set the run time limit on the maximum shared memory segment size that can be created. -Shared memory segments up to 1Gb are now supported in the +Shared memory segments up to 1Gb are now supported in the kernel. This value defaults to SHMMAX. ============================================================== +shm_rmid_forced: + +Linux lets you set resource limits, including how much memory one +process can consume, via setrlimit(2). Unfortunately, shared memory +segments are allowed to exist without association with any process, and +thus might not be counted against any resource limits. If enabled, +shared memory segments are automatically destroyed when their attach +count becomes zero after a detach or a process termination. It will +also destroy segments that were created, but never attached to, on exit +from the process. The only use left for IPC_RMID is to immediately +destroy an unattached segment. Of course, this breaks the way things are +defined, so some applications might stop working. Note that this +feature will do you no good unless you also configure your resource +limits (in particular, RLIMIT_AS and RLIMIT_NPROC). Most systems don't +need this. + +Note that if you change this from 0 to 1, already created segments +without users and with a dead originative process will be destroyed. + +============================================================== + softlockup_thresh: This value can be used to lower the softlockup tolerance threshold. The @@ -484,7 +549,7 @@ tunable to zero will disable the softlockup detection altogether. ============================================================== -tainted: +tainted: Non-zero if the kernel has been tainted. Numeric values, which can be ORed together: @@ -509,49 +574,11 @@ can be ORed together: ============================================================== -auto_msgmni: - -Enables/Disables automatic recomputing of msgmni upon memory add/remove or -upon ipc namespace creation/removal (see the msgmni description above). -Echoing "1" into this file enables msgmni automatic recomputing. -Echoing "0" turns it off. -auto_msgmni default value is 1. - -============================================================== - -nmi_watchdog: - -Enables/Disables the NMI watchdog on x86 systems. When the value is non-zero -the NMI watchdog is enabled and will continuously test all online cpus to -determine whether or not they are still functioning properly. Currently, -passing "nmi_watchdog=" parameter at boot time is required for this function -to work. - -If LAPIC NMI watchdog method is in use (nmi_watchdog=2 kernel parameter), the -NMI watchdog shares registers with oprofile. By disabling the NMI watchdog, -oprofile may have more registers to utilize. - -============================================================== - unknown_nmi_panic: -The value in this file affects behavior of handling NMI. When the value is -non-zero, unknown NMI is trapped and then panic occurs. At that time, kernel -debugging information is displayed on console. - -NMI switch that most IA32 servers have fires unknown NMI up, for example. -If a system hangs up, try pressing the NMI switch. - -============================================================== - -panic_on_unrecovered_nmi: - -The default Linux behaviour on an NMI of either memory or unknown is to continue -operation. For many environments such as scientific computing it is preferable -that the box is taken out and the error dealt with than an uncorrected -parity/ECC error get propogated. - -A small number of systems do generate NMI's for bizarre random reasons such as -power management so the default is off. That sysctl works like the existing -panic controls already in that directory. +The value in this file affects behavior of handling NMI. When the +value is non-zero, unknown NMI is trapped and then panic occurs. At +that time, kernel debugging information is displayed on console. +NMI switch that most IA32 servers have fires unknown NMI up, for +example. If a system hangs up, try pressing the NMI switch. diff --git a/Documentation/trace/kprobetrace.txt b/Documentation/trace/kprobetrace.txt index c83bd6b..d0d0bb9 100644 --- a/Documentation/trace/kprobetrace.txt +++ b/Documentation/trace/kprobetrace.txt @@ -22,14 +22,15 @@ current_tracer. Instead of that, add probe points via Synopsis of kprobe_events ------------------------- - p[:[GRP/]EVENT] SYMBOL[+offs]|MEMADDR [FETCHARGS] : Set a probe - r[:[GRP/]EVENT] SYMBOL[+0] [FETCHARGS] : Set a return probe + p[:[GRP/]EVENT] [MOD:]SYM[+offs]|MEMADDR [FETCHARGS] : Set a probe + r[:[GRP/]EVENT] [MOD:]SYM[+0] [FETCHARGS] : Set a return probe -:[GRP/]EVENT : Clear a probe GRP : Group name. If omitted, use "kprobes" for it. EVENT : Event name. If omitted, the event name is generated - based on SYMBOL+offs or MEMADDR. - SYMBOL[+offs] : Symbol+offset where the probe is inserted. + based on SYM+offs or MEMADDR. + MOD : Module name which has given SYM. + SYM[+offs] : Symbol+offset where the probe is inserted. MEMADDR : Address where the probe is inserted. FETCHARGS : Arguments. Each probe can have up to 128 args. diff --git a/Documentation/usb/ehci.txt b/Documentation/usb/ehci.txt index 9dcafa7..160bd6c 100644 --- a/Documentation/usb/ehci.txt +++ b/Documentation/usb/ehci.txt @@ -210,3 +210,5 @@ TBD: Interrupt and ISO transfer performance issues. Those periodic transfers are fully scheduled, so the main issue is likely to be how to trigger "high bandwidth" modes. +TBD: More than standard 80% periodic bandwidth allocation is possible +through sysfs uframe_periodic_max parameter. Describe that. diff --git a/Documentation/usb/gadget_hid.txt b/Documentation/usb/gadget_hid.txt index f4a51f5..12696c2 100644 --- a/Documentation/usb/gadget_hid.txt +++ b/Documentation/usb/gadget_hid.txt @@ -81,8 +81,8 @@ Send and receive HID reports to do this. hid_gadget_test is a small interactive program to test the HID - gadget driver. To use, point it at a hidg device and set the - device type (keyboard / mouse / joystick) - E.G.: + gadget driver. To use, point it at a hidg device and set the + device type (keyboard / mouse / joystick) - E.G.: # hid_gadget_test /dev/hidg0 keyboard @@ -97,7 +97,7 @@ Send and receive HID reports HID gadget. Another interesting example is the caps lock test. Type - -–caps-lock and hit return. A report is then sent by the + --caps-lock and hit return. A report is then sent by the gadget and you should receive the host answer, corresponding to the caps lock LED status. diff --git a/Documentation/vDSO/parse_vdso.c b/Documentation/vDSO/parse_vdso.c new file mode 100644 index 0000000..8587020 --- /dev/null +++ b/Documentation/vDSO/parse_vdso.c @@ -0,0 +1,256 @@ +/* + * parse_vdso.c: Linux reference vDSO parser + * Written by Andrew Lutomirski, 2011. + * + * This code is meant to be linked in to various programs that run on Linux. + * As such, it is available with as few restrictions as possible. This file + * is licensed under the Creative Commons Zero License, version 1.0, + * available at http://creativecommons.org/publicdomain/zero/1.0/legalcode + * + * The vDSO is a regular ELF DSO that the kernel maps into user space when + * it starts a program. It works equally well in statically and dynamically + * linked binaries. + * + * This code is tested on x86_64. In principle it should work on any 64-bit + * architecture that has a vDSO. + */ + +#include +#include +#include +#include + +/* + * To use this vDSO parser, first call one of the vdso_init_* functions. + * If you've already parsed auxv, then pass the value of AT_SYSINFO_EHDR + * to vdso_init_from_sysinfo_ehdr. Otherwise pass auxv to vdso_init_from_auxv. + * Then call vdso_sym for each symbol you want. For example, to look up + * gettimeofday on x86_64, use: + * + * = vdso_sym("LINUX_2.6", "gettimeofday"); + * or + * = vdso_sym("LINUX_2.6", "__vdso_gettimeofday"); + * + * vdso_sym will return 0 if the symbol doesn't exist or if the init function + * failed or was not called. vdso_sym is a little slow, so its return value + * should be cached. + * + * vdso_sym is threadsafe; the init functions are not. + * + * These are the prototypes: + */ +extern void vdso_init_from_auxv(void *auxv); +extern void vdso_init_from_sysinfo_ehdr(uintptr_t base); +extern void *vdso_sym(const char *version, const char *name); + + +/* And here's the code. */ + +#ifndef __x86_64__ +# error Not yet ported to non-x86_64 architectures +#endif + +static struct vdso_info +{ + bool valid; + + /* Load information */ + uintptr_t load_addr; + uintptr_t load_offset; /* load_addr - recorded vaddr */ + + /* Symbol table */ + Elf64_Sym *symtab; + const char *symstrings; + Elf64_Word *bucket, *chain; + Elf64_Word nbucket, nchain; + + /* Version table */ + Elf64_Versym *versym; + Elf64_Verdef *verdef; +} vdso_info; + +/* Straight from the ELF specification. */ +static unsigned long elf_hash(const unsigned char *name) +{ + unsigned long h = 0, g; + while (*name) + { + h = (h << 4) + *name++; + if (g = h & 0xf0000000) + h ^= g >> 24; + h &= ~g; + } + return h; +} + +void vdso_init_from_sysinfo_ehdr(uintptr_t base) +{ + size_t i; + bool found_vaddr = false; + + vdso_info.valid = false; + + vdso_info.load_addr = base; + + Elf64_Ehdr *hdr = (Elf64_Ehdr*)base; + Elf64_Phdr *pt = (Elf64_Phdr*)(vdso_info.load_addr + hdr->e_phoff); + Elf64_Dyn *dyn = 0; + + /* + * We need two things from the segment table: the load offset + * and the dynamic table. + */ + for (i = 0; i < hdr->e_phnum; i++) + { + if (pt[i].p_type == PT_LOAD && !found_vaddr) { + found_vaddr = true; + vdso_info.load_offset = base + + (uintptr_t)pt[i].p_offset + - (uintptr_t)pt[i].p_vaddr; + } else if (pt[i].p_type == PT_DYNAMIC) { + dyn = (Elf64_Dyn*)(base + pt[i].p_offset); + } + } + + if (!found_vaddr || !dyn) + return; /* Failed */ + + /* + * Fish out the useful bits of the dynamic table. + */ + Elf64_Word *hash = 0; + vdso_info.symstrings = 0; + vdso_info.symtab = 0; + vdso_info.versym = 0; + vdso_info.verdef = 0; + for (i = 0; dyn[i].d_tag != DT_NULL; i++) { + switch (dyn[i].d_tag) { + case DT_STRTAB: + vdso_info.symstrings = (const char *) + ((uintptr_t)dyn[i].d_un.d_ptr + + vdso_info.load_offset); + break; + case DT_SYMTAB: + vdso_info.symtab = (Elf64_Sym *) + ((uintptr_t)dyn[i].d_un.d_ptr + + vdso_info.load_offset); + break; + case DT_HASH: + hash = (Elf64_Word *) + ((uintptr_t)dyn[i].d_un.d_ptr + + vdso_info.load_offset); + break; + case DT_VERSYM: + vdso_info.versym = (Elf64_Versym *) + ((uintptr_t)dyn[i].d_un.d_ptr + + vdso_info.load_offset); + break; + case DT_VERDEF: + vdso_info.verdef = (Elf64_Verdef *) + ((uintptr_t)dyn[i].d_un.d_ptr + + vdso_info.load_offset); + break; + } + } + if (!vdso_info.symstrings || !vdso_info.symtab || !hash) + return; /* Failed */ + + if (!vdso_info.verdef) + vdso_info.versym = 0; + + /* Parse the hash table header. */ + vdso_info.nbucket = hash[0]; + vdso_info.nchain = hash[1]; + vdso_info.bucket = &hash[2]; + vdso_info.chain = &hash[vdso_info.nbucket + 2]; + + /* That's all we need. */ + vdso_info.valid = true; +} + +static bool vdso_match_version(Elf64_Versym ver, + const char *name, Elf64_Word hash) +{ + /* + * This is a helper function to check if the version indexed by + * ver matches name (which hashes to hash). + * + * The version definition table is a mess, and I don't know how + * to do this in better than linear time without allocating memory + * to build an index. I also don't know why the table has + * variable size entries in the first place. + * + * For added fun, I can't find a comprehensible specification of how + * to parse all the weird flags in the table. + * + * So I just parse the whole table every time. + */ + + /* First step: find the version definition */ + ver &= 0x7fff; /* Apparently bit 15 means "hidden" */ + Elf64_Verdef *def = vdso_info.verdef; + while(true) { + if ((def->vd_flags & VER_FLG_BASE) == 0 + && (def->vd_ndx & 0x7fff) == ver) + break; + + if (def->vd_next == 0) + return false; /* No definition. */ + + def = (Elf64_Verdef *)((char *)def + def->vd_next); + } + + /* Now figure out whether it matches. */ + Elf64_Verdaux *aux = (Elf64_Verdaux*)((char *)def + def->vd_aux); + return def->vd_hash == hash + && !strcmp(name, vdso_info.symstrings + aux->vda_name); +} + +void *vdso_sym(const char *version, const char *name) +{ + unsigned long ver_hash; + if (!vdso_info.valid) + return 0; + + ver_hash = elf_hash(version); + Elf64_Word chain = vdso_info.bucket[elf_hash(name) % vdso_info.nbucket]; + + for (; chain != STN_UNDEF; chain = vdso_info.chain[chain]) { + Elf64_Sym *sym = &vdso_info.symtab[chain]; + + /* Check for a defined global or weak function w/ right name. */ + if (ELF64_ST_TYPE(sym->st_info) != STT_FUNC) + continue; + if (ELF64_ST_BIND(sym->st_info) != STB_GLOBAL && + ELF64_ST_BIND(sym->st_info) != STB_WEAK) + continue; + if (sym->st_shndx == SHN_UNDEF) + continue; + if (strcmp(name, vdso_info.symstrings + sym->st_name)) + continue; + + /* Check symbol version. */ + if (vdso_info.versym + && !vdso_match_version(vdso_info.versym[chain], + version, ver_hash)) + continue; + + return (void *)(vdso_info.load_offset + sym->st_value); + } + + return 0; +} + +void vdso_init_from_auxv(void *auxv) +{ + Elf64_auxv_t *elf_auxv = auxv; + for (int i = 0; elf_auxv[i].a_type != AT_NULL; i++) + { + if (elf_auxv[i].a_type == AT_SYSINFO_EHDR) { + vdso_init_from_sysinfo_ehdr(elf_auxv[i].a_un.a_val); + return; + } + } + + vdso_info.valid = false; +} diff --git a/Documentation/vDSO/vdso_test.c b/Documentation/vDSO/vdso_test.c new file mode 100644 index 0000000..fff6334 --- /dev/null +++ b/Documentation/vDSO/vdso_test.c @@ -0,0 +1,111 @@ +/* + * vdso_test.c: Sample code to test parse_vdso.c on x86_64 + * Copyright (c) 2011 Andy Lutomirski + * Subject to the GNU General Public License, version 2 + * + * You can amuse yourself by compiling with: + * gcc -std=gnu99 -nostdlib + * -Os -fno-asynchronous-unwind-tables -flto + * vdso_test.c parse_vdso.c -o vdso_test + * to generate a small binary with no dependencies at all. + */ + +#include +#include +#include +#include + +extern void *vdso_sym(const char *version, const char *name); +extern void vdso_init_from_sysinfo_ehdr(uintptr_t base); +extern void vdso_init_from_auxv(void *auxv); + +/* We need a libc functions... */ +int strcmp(const char *a, const char *b) +{ + /* This implementation is buggy: it never returns -1. */ + while (*a || *b) { + if (*a != *b) + return 1; + if (*a == 0 || *b == 0) + return 1; + a++; + b++; + } + + return 0; +} + +/* ...and two syscalls. This is x86_64-specific. */ +static inline long linux_write(int fd, const void *data, size_t len) +{ + + long ret; + asm volatile ("syscall" : "=a" (ret) : "a" (__NR_write), + "D" (fd), "S" (data), "d" (len) : + "cc", "memory", "rcx", + "r8", "r9", "r10", "r11" ); + return ret; +} + +static inline void linux_exit(int code) +{ + asm volatile ("syscall" : : "a" (__NR_exit), "D" (code)); +} + +void to_base10(char *lastdig, uint64_t n) +{ + while (n) { + *lastdig = (n % 10) + '0'; + n /= 10; + lastdig--; + } +} + +__attribute__((externally_visible)) void c_main(void **stack) +{ + /* Parse the stack */ + long argc = (long)*stack; + stack += argc + 2; + + /* Now we're pointing at the environment. Skip it. */ + while(*stack) + stack++; + stack++; + + /* Now we're pointing at auxv. Initialize the vDSO parser. */ + vdso_init_from_auxv((void *)stack); + + /* Find gettimeofday. */ + typedef long (*gtod_t)(struct timeval *tv, struct timezone *tz); + gtod_t gtod = (gtod_t)vdso_sym("LINUX_2.6", "__vdso_gettimeofday"); + + if (!gtod) + linux_exit(1); + + struct timeval tv; + long ret = gtod(&tv, 0); + + if (ret == 0) { + char buf[] = "The time is .000000\n"; + to_base10(buf + 31, tv.tv_sec); + to_base10(buf + 38, tv.tv_usec); + linux_write(1, buf, sizeof(buf) - 1); + } else { + linux_exit(ret); + } + + linux_exit(0); +} + +/* + * This is the real entry point. It passes the initial stack into + * the C entry point. + */ +asm ( + ".text\n" + ".global _start\n" + ".type _start,@function\n" + "_start:\n\t" + "mov %rsp,%rdi\n\t" + "jmp c_main" + ); diff --git a/Documentation/virtual/kvm/api.txt b/Documentation/virtual/kvm/api.txt index 42542eb..b0e4b9c 100644 --- a/Documentation/virtual/kvm/api.txt +++ b/Documentation/virtual/kvm/api.txt @@ -180,6 +180,19 @@ KVM_CHECK_EXTENSION ioctl() to determine the value for max_vcpus at run-time. If the KVM_CAP_NR_VCPUS does not exist, you should assume that max_vcpus is 4 cpus max. +On powerpc using book3s_hv mode, the vcpus are mapped onto virtual +threads in one or more virtual CPU cores. (This is because the +hardware requires all the hardware threads in a CPU core to be in the +same partition.) The KVM_CAP_PPC_SMT capability indicates the number +of vcpus per virtual core (vcore). The vcore id is obtained by +dividing the vcpu id by the number of vcpus per vcore. The vcpus in a +given vcore will always be in the same physical core as each other +(though that might be a different physical core from time to time). +Userspace can control the threading (SMT) mode of the guest by its +allocation of vcpu ids. For example, if userspace wants +single-threaded guest vcpus, it should make all vcpu ids be a multiple +of the number of vcpus per vcore. + 4.8 KVM_GET_DIRTY_LOG (vm ioctl) Capability: basic @@ -1143,15 +1156,10 @@ Assigns an IRQ to a passed-through device. struct kvm_assigned_irq { __u32 assigned_dev_id; - __u32 host_irq; + __u32 host_irq; /* ignored (legacy field) */ __u32 guest_irq; __u32 flags; union { - struct { - __u32 addr_lo; - __u32 addr_hi; - __u32 data; - } guest_msi; __u32 reserved[12]; }; }; @@ -1239,8 +1247,10 @@ Type: vm ioctl Parameters: struct kvm_assigned_msix_nr (in) Returns: 0 on success, -1 on error -Set the number of MSI-X interrupts for an assigned device. This service can -only be called once in the lifetime of an assigned device. +Set the number of MSI-X interrupts for an assigned device. The number is +reset again by terminating the MSI-X assignment of the device via +KVM_DEASSIGN_DEV_IRQ. Calling this service more than once at any earlier +point will fail. struct kvm_assigned_msix_nr { __u32 assigned_dev_id; @@ -1291,6 +1301,135 @@ Returns the tsc frequency of the guest. The unit of the return value is KHz. If the host has unstable tsc this ioctl returns -EIO instead as an error. +4.56 KVM_GET_LAPIC + +Capability: KVM_CAP_IRQCHIP +Architectures: x86 +Type: vcpu ioctl +Parameters: struct kvm_lapic_state (out) +Returns: 0 on success, -1 on error + +#define KVM_APIC_REG_SIZE 0x400 +struct kvm_lapic_state { + char regs[KVM_APIC_REG_SIZE]; +}; + +Reads the Local APIC registers and copies them into the input argument. The +data format and layout are the same as documented in the architecture manual. + +4.57 KVM_SET_LAPIC + +Capability: KVM_CAP_IRQCHIP +Architectures: x86 +Type: vcpu ioctl +Parameters: struct kvm_lapic_state (in) +Returns: 0 on success, -1 on error + +#define KVM_APIC_REG_SIZE 0x400 +struct kvm_lapic_state { + char regs[KVM_APIC_REG_SIZE]; +}; + +Copies the input argument into the the Local APIC registers. The data format +and layout are the same as documented in the architecture manual. + +4.58 KVM_IOEVENTFD + +Capability: KVM_CAP_IOEVENTFD +Architectures: all +Type: vm ioctl +Parameters: struct kvm_ioeventfd (in) +Returns: 0 on success, !0 on error + +This ioctl attaches or detaches an ioeventfd to a legal pio/mmio address +within the guest. A guest write in the registered address will signal the +provided event instead of triggering an exit. + +struct kvm_ioeventfd { + __u64 datamatch; + __u64 addr; /* legal pio/mmio address */ + __u32 len; /* 1, 2, 4, or 8 bytes */ + __s32 fd; + __u32 flags; + __u8 pad[36]; +}; + +The following flags are defined: + +#define KVM_IOEVENTFD_FLAG_DATAMATCH (1 << kvm_ioeventfd_flag_nr_datamatch) +#define KVM_IOEVENTFD_FLAG_PIO (1 << kvm_ioeventfd_flag_nr_pio) +#define KVM_IOEVENTFD_FLAG_DEASSIGN (1 << kvm_ioeventfd_flag_nr_deassign) + +If datamatch flag is set, the event will be signaled only if the written value +to the registered address is equal to datamatch in struct kvm_ioeventfd. + +4.62 KVM_CREATE_SPAPR_TCE + +Capability: KVM_CAP_SPAPR_TCE +Architectures: powerpc +Type: vm ioctl +Parameters: struct kvm_create_spapr_tce (in) +Returns: file descriptor for manipulating the created TCE table + +This creates a virtual TCE (translation control entry) table, which +is an IOMMU for PAPR-style virtual I/O. It is used to translate +logical addresses used in virtual I/O into guest physical addresses, +and provides a scatter/gather capability for PAPR virtual I/O. + +/* for KVM_CAP_SPAPR_TCE */ +struct kvm_create_spapr_tce { + __u64 liobn; + __u32 window_size; +}; + +The liobn field gives the logical IO bus number for which to create a +TCE table. The window_size field specifies the size of the DMA window +which this TCE table will translate - the table will contain one 64 +bit TCE entry for every 4kiB of the DMA window. + +When the guest issues an H_PUT_TCE hcall on a liobn for which a TCE +table has been created using this ioctl(), the kernel will handle it +in real mode, updating the TCE table. H_PUT_TCE calls for other +liobns will cause a vm exit and must be handled by userspace. + +The return value is a file descriptor which can be passed to mmap(2) +to map the created TCE table into userspace. This lets userspace read +the entries written by kernel-handled H_PUT_TCE calls, and also lets +userspace update the TCE table directly which is useful in some +circumstances. + +4.63 KVM_ALLOCATE_RMA + +Capability: KVM_CAP_PPC_RMA +Architectures: powerpc +Type: vm ioctl +Parameters: struct kvm_allocate_rma (out) +Returns: file descriptor for mapping the allocated RMA + +This allocates a Real Mode Area (RMA) from the pool allocated at boot +time by the kernel. An RMA is a physically-contiguous, aligned region +of memory used on older POWER processors to provide the memory which +will be accessed by real-mode (MMU off) accesses in a KVM guest. +POWER processors support a set of sizes for the RMA that usually +includes 64MB, 128MB, 256MB and some larger powers of two. + +/* for KVM_ALLOCATE_RMA */ +struct kvm_allocate_rma { + __u64 rma_size; +}; + +The return value is a file descriptor which can be passed to mmap(2) +to map the allocated RMA into userspace. The mapped area can then be +passed to the KVM_SET_USER_MEMORY_REGION ioctl to establish it as the +RMA for a virtual machine. The size of the RMA in bytes (which is +fixed at host kernel boot time) is returned in the rma_size field of +the argument structure. + +The KVM_CAP_PPC_RMA capability is 1 or 2 if the KVM_ALLOCATE_RMA ioctl +is supported; 2 if the processor requires all virtual machines to have +an RMA, or 1 if the processor can use an RMA but doesn't require it, +because it supports the Virtual RMA (VRMA) facility. + 5. The kvm_run structure Application code obtains a pointer to the kvm_run structure by @@ -1473,6 +1612,23 @@ Userspace can now handle the hypercall and when it's done modify the gprs as necessary. Upon guest entry all guest GPRs will then be replaced by the values in this struct. + /* KVM_EXIT_PAPR_HCALL */ + struct { + __u64 nr; + __u64 ret; + __u64 args[9]; + } papr_hcall; + +This is used on 64-bit PowerPC when emulating a pSeries partition, +e.g. with the 'pseries' machine type in qemu. It occurs when the +guest does a hypercall using the 'sc 1' instruction. The 'nr' field +contains the hypercall number (from the guest R3), and 'args' contains +the arguments (from the guest R4 - R12). Userspace should put the +return code in 'ret' and any extra returned values in args[]. +The possible hypercalls are defined in the Power Architecture Platform +Requirements (PAPR) document available from www.power.org (free +developer registration required to access it). + /* Fix the size of the union. */ char padding[256]; }; diff --git a/Documentation/virtual/kvm/mmu.txt b/Documentation/virtual/kvm/mmu.txt index f46aa58..5dc972c 100644 --- a/Documentation/virtual/kvm/mmu.txt +++ b/Documentation/virtual/kvm/mmu.txt @@ -165,6 +165,10 @@ Shadow pages contain the following information: Contains the value of efer.nxe for which the page is valid. role.cr0_wp: Contains the value of cr0.wp for which the page is valid. + role.smep_andnot_wp: + Contains the value of cr4.smep && !cr0.wp for which the page is valid + (pages for which this is true are different from other pages; see the + treatment of cr0.wp=0 below). gfn: Either the guest page table containing the translations shadowed by this page, or the base page frame for linear translations. See role.direct. @@ -317,6 +321,20 @@ on fault type: (user write faults generate a #PF) +In the first case there is an additional complication if CR4.SMEP is +enabled: since we've turned the page into a kernel page, the kernel may now +execute it. We handle this by also setting spte.nx. If we get a user +fetch or read fault, we'll change spte.u=1 and spte.nx=gpte.nx back. + +To prevent an spte that was converted into a kernel page with cr0.wp=0 +from being written by the kernel after cr0.wp has changed to 1, we make +the value of cr0.wp part of the page role. This means that an spte created +with one value of cr0.wp cannot be used when cr0.wp has a different value - +it will simply be missed by the shadow page lookup code. A similar issue +exists when an spte created with cr0.wp=0 and cr4.smep=0 is used after +changing cr4.smep to 1. To avoid this, the value of !cr0.wp && cr4.smep +is also made a part of the page role. + Large pages =========== diff --git a/Documentation/virtual/kvm/msr.txt b/Documentation/virtual/kvm/msr.txt index d079aed..5031780 100644 --- a/Documentation/virtual/kvm/msr.txt +++ b/Documentation/virtual/kvm/msr.txt @@ -185,3 +185,37 @@ MSR_KVM_ASYNC_PF_EN: 0x4b564d02 Currently type 2 APF will be always delivered on the same vcpu as type 1 was, but guest should not rely on that. + +MSR_KVM_STEAL_TIME: 0x4b564d03 + + data: 64-byte alignment physical address of a memory area which must be + in guest RAM, plus an enable bit in bit 0. This memory is expected to + hold a copy of the following structure: + + struct kvm_steal_time { + __u64 steal; + __u32 version; + __u32 flags; + __u32 pad[12]; + } + + whose data will be filled in by the hypervisor periodically. Only one + write, or registration, is needed for each VCPU. The interval between + updates of this structure is arbitrary and implementation-dependent. + The hypervisor may update this structure at any time it sees fit until + anything with bit0 == 0 is written to it. Guest is required to make sure + this structure is initialized to zero. + + Fields have the following meanings: + + version: a sequence counter. In other words, guest has to check + this field before and after grabbing time information and make + sure they are both equal and even. An odd version indicates an + in-progress update. + + flags: At this point, always zero. May be used to indicate + changes in this structure in the future. + + steal: the amount of time in which this vCPU did not run, in + nanoseconds. Time during which the vcpu is idle, will not be + reported as steal time. diff --git a/Documentation/virtual/kvm/nested-vmx.txt b/Documentation/virtual/kvm/nested-vmx.txt new file mode 100644 index 0000000..8ed937d --- /dev/null +++ b/Documentation/virtual/kvm/nested-vmx.txt @@ -0,0 +1,251 @@ +Nested VMX +========== + +Overview +--------- + +On Intel processors, KVM uses Intel's VMX (Virtual-Machine eXtensions) +to easily and efficiently run guest operating systems. Normally, these guests +*cannot* themselves be hypervisors running their own guests, because in VMX, +guests cannot use VMX instructions. + +The "Nested VMX" feature adds this missing capability - of running guest +hypervisors (which use VMX) with their own nested guests. It does so by +allowing a guest to use VMX instructions, and correctly and efficiently +emulating them using the single level of VMX available in the hardware. + +We describe in much greater detail the theory behind the nested VMX feature, +its implementation and its performance characteristics, in the OSDI 2010 paper +"The Turtles Project: Design and Implementation of Nested Virtualization", +available at: + + http://www.usenix.org/events/osdi10/tech/full_papers/Ben-Yehuda.pdf + + +Terminology +----------- + +Single-level virtualization has two levels - the host (KVM) and the guests. +In nested virtualization, we have three levels: The host (KVM), which we call +L0, the guest hypervisor, which we call L1, and its nested guest, which we +call L2. + + +Known limitations +----------------- + +The current code supports running Linux guests under KVM guests. +Only 64-bit guest hypervisors are supported. + +Additional patches for running Windows under guest KVM, and Linux under +guest VMware server, and support for nested EPT, are currently running in +the lab, and will be sent as follow-on patchsets. + + +Running nested VMX +------------------ + +The nested VMX feature is disabled by default. It can be enabled by giving +the "nested=1" option to the kvm-intel module. + +No modifications are required to user space (qemu). However, qemu's default +emulated CPU type (qemu64) does not list the "VMX" CPU feature, so it must be +explicitly enabled, by giving qemu one of the following options: + + -cpu host (emulated CPU has all features of the real CPU) + + -cpu qemu64,+vmx (add just the vmx feature to a named CPU type) + + +ABIs +---- + +Nested VMX aims to present a standard and (eventually) fully-functional VMX +implementation for the a guest hypervisor to use. As such, the official +specification of the ABI that it provides is Intel's VMX specification, +namely volume 3B of their "Intel 64 and IA-32 Architectures Software +Developer's Manual". Not all of VMX's features are currently fully supported, +but the goal is to eventually support them all, starting with the VMX features +which are used in practice by popular hypervisors (KVM and others). + +As a VMX implementation, nested VMX presents a VMCS structure to L1. +As mandated by the spec, other than the two fields revision_id and abort, +this structure is *opaque* to its user, who is not supposed to know or care +about its internal structure. Rather, the structure is accessed through the +VMREAD and VMWRITE instructions. +Still, for debugging purposes, KVM developers might be interested to know the +internals of this structure; This is struct vmcs12 from arch/x86/kvm/vmx.c. + +The name "vmcs12" refers to the VMCS that L1 builds for L2. In the code we +also have "vmcs01", the VMCS that L0 built for L1, and "vmcs02" is the VMCS +which L0 builds to actually run L2 - how this is done is explained in the +aforementioned paper. + +For convenience, we repeat the content of struct vmcs12 here. If the internals +of this structure changes, this can break live migration across KVM versions. +VMCS12_REVISION (from vmx.c) should be changed if struct vmcs12 or its inner +struct shadow_vmcs is ever changed. + + typedef u64 natural_width; + struct __packed vmcs12 { + /* According to the Intel spec, a VMCS region must start with + * these two user-visible fields */ + u32 revision_id; + u32 abort; + + u32 launch_state; /* set to 0 by VMCLEAR, to 1 by VMLAUNCH */ + u32 padding[7]; /* room for future expansion */ + + u64 io_bitmap_a; + u64 io_bitmap_b; + u64 msr_bitmap; + u64 vm_exit_msr_store_addr; + u64 vm_exit_msr_load_addr; + u64 vm_entry_msr_load_addr; + u64 tsc_offset; + u64 virtual_apic_page_addr; + u64 apic_access_addr; + u64 ept_pointer; + u64 guest_physical_address; + u64 vmcs_link_pointer; + u64 guest_ia32_debugctl; + u64 guest_ia32_pat; + u64 guest_ia32_efer; + u64 guest_pdptr0; + u64 guest_pdptr1; + u64 guest_pdptr2; + u64 guest_pdptr3; + u64 host_ia32_pat; + u64 host_ia32_efer; + u64 padding64[8]; /* room for future expansion */ + natural_width cr0_guest_host_mask; + natural_width cr4_guest_host_mask; + natural_width cr0_read_shadow; + natural_width cr4_read_shadow; + natural_width cr3_target_value0; + natural_width cr3_target_value1; + natural_width cr3_target_value2; + natural_width cr3_target_value3; + natural_width exit_qualification; + natural_width guest_linear_address; + natural_width guest_cr0; + natural_width guest_cr3; + natural_width guest_cr4; + natural_width guest_es_base; + natural_width guest_cs_base; + natural_width guest_ss_base; + natural_width guest_ds_base; + natural_width guest_fs_base; + natural_width guest_gs_base; + natural_width guest_ldtr_base; + natural_width guest_tr_base; + natural_width guest_gdtr_base; + natural_width guest_idtr_base; + natural_width guest_dr7; + natural_width guest_rsp; + natural_width guest_rip; + natural_width guest_rflags; + natural_width guest_pending_dbg_exceptions; + natural_width guest_sysenter_esp; + natural_width guest_sysenter_eip; + natural_width host_cr0; + natural_width host_cr3; + natural_width host_cr4; + natural_width host_fs_base; + natural_width host_gs_base; + natural_width host_tr_base; + natural_width host_gdtr_base; + natural_width host_idtr_base; + natural_width host_ia32_sysenter_esp; + natural_width host_ia32_sysenter_eip; + natural_width host_rsp; + natural_width host_rip; + natural_width paddingl[8]; /* room for future expansion */ + u32 pin_based_vm_exec_control; + u32 cpu_based_vm_exec_control; + u32 exception_bitmap; + u32 page_fault_error_code_mask; + u32 page_fault_error_code_match; + u32 cr3_target_count; + u32 vm_exit_controls; + u32 vm_exit_msr_store_count; + u32 vm_exit_msr_load_count; + u32 vm_entry_controls; + u32 vm_entry_msr_load_count; + u32 vm_entry_intr_info_field; + u32 vm_entry_exception_error_code; + u32 vm_entry_instruction_len; + u32 tpr_threshold; + u32 secondary_vm_exec_control; + u32 vm_instruction_error; + u32 vm_exit_reason; + u32 vm_exit_intr_info; + u32 vm_exit_intr_error_code; + u32 idt_vectoring_info_field; + u32 idt_vectoring_error_code; + u32 vm_exit_instruction_len; + u32 vmx_instruction_info; + u32 guest_es_limit; + u32 guest_cs_limit; + u32 guest_ss_limit; + u32 guest_ds_limit; + u32 guest_fs_limit; + u32 guest_gs_limit; + u32 guest_ldtr_limit; + u32 guest_tr_limit; + u32 guest_gdtr_limit; + u32 guest_idtr_limit; + u32 guest_es_ar_bytes; + u32 guest_cs_ar_bytes; + u32 guest_ss_ar_bytes; + u32 guest_ds_ar_bytes; + u32 guest_fs_ar_bytes; + u32 guest_gs_ar_bytes; + u32 guest_ldtr_ar_bytes; + u32 guest_tr_ar_bytes; + u32 guest_interruptibility_info; + u32 guest_activity_state; + u32 guest_sysenter_cs; + u32 host_ia32_sysenter_cs; + u32 padding32[8]; /* room for future expansion */ + u16 virtual_processor_id; + u16 guest_es_selector; + u16 guest_cs_selector; + u16 guest_ss_selector; + u16 guest_ds_selector; + u16 guest_fs_selector; + u16 guest_gs_selector; + u16 guest_ldtr_selector; + u16 guest_tr_selector; + u16 host_es_selector; + u16 host_cs_selector; + u16 host_ss_selector; + u16 host_ds_selector; + u16 host_fs_selector; + u16 host_gs_selector; + u16 host_tr_selector; + }; + + +Authors +------- + +These patches were written by: + Abel Gordon, abelg il.ibm.com + Nadav Har'El, nyh il.ibm.com + Orit Wasserman, oritw il.ibm.com + Ben-Ami Yassor, benami il.ibm.com + Muli Ben-Yehuda, muli il.ibm.com + +With contributions by: + Anthony Liguori, aliguori us.ibm.com + Mike Day, mdday us.ibm.com + Michael Factor, factor il.ibm.com + Zvi Dubitzky, dubi il.ibm.com + +And valuable reviews by: + Avi Kivity, avi redhat.com + Gleb Natapov, gleb redhat.com + Marcelo Tosatti, mtosatti redhat.com + Kevin Tian, kevin.tian intel.com + and others. diff --git a/Documentation/virtual/kvm/ppc-pv.txt b/Documentation/virtual/kvm/ppc-pv.txt index 3ab969c..2b7ce19 100644 --- a/Documentation/virtual/kvm/ppc-pv.txt +++ b/Documentation/virtual/kvm/ppc-pv.txt @@ -68,9 +68,11 @@ page that contains parts of supervisor visible register state. The guest can map this shared page using the KVM hypercall KVM_HC_PPC_MAP_MAGIC_PAGE. With this hypercall issued the guest always gets the magic page mapped at the -desired location in effective and physical address space. For now, we always -map the page to -4096. This way we can access it using absolute load and store -functions. The following instruction reads the first field of the magic page: +desired location. The first parameter indicates the effective address when the +MMU is enabled. The second parameter indicates the address in real mode, if +applicable to the target. For now, we always map the page to -4096. This way we +can access it using absolute load and store functions. The following +instruction reads the first field of the magic page: ld rX, -4096(0) diff --git a/Documentation/virtual/lguest/lguest.c b/Documentation/virtual/lguest/lguest.c index cd9d6af..043bd7d 100644 --- a/Documentation/virtual/lguest/lguest.c +++ b/Documentation/virtual/lguest/lguest.c @@ -51,7 +51,7 @@ #include #include "../../../include/linux/lguest_launcher.h" /*L:110 - * We can ignore the 42 include files we need for this program, but I do want + * We can ignore the 43 include files we need for this program, but I do want * to draw attention to the use of kernel-style types. * * As Linus said, "C is a Spartan language, and so should your naming be." I @@ -65,7 +65,6 @@ typedef uint16_t u16; typedef uint8_t u8; /*:*/ -#define PAGE_PRESENT 0x7 /* Present, RW, Execute */ #define BRIDGE_PFX "bridge:" #ifndef SIOCBRADDIF #define SIOCBRADDIF 0x89a2 /* add interface to bridge */ @@ -861,8 +860,10 @@ static void console_output(struct virtqueue *vq) /* writev can return a partial write, so we loop here. */ while (!iov_empty(iov, out)) { int len = writev(STDOUT_FILENO, iov, out); - if (len <= 0) - err(1, "Write to stdout gave %i", len); + if (len <= 0) { + warn("Write to stdout gave %i (%d)", len, errno); + break; + } iov_consume(iov, out, len); } @@ -898,7 +899,7 @@ static void net_output(struct virtqueue *vq) * same format: what a coincidence! */ if (writev(net_info->tunfd, iov, out) < 0) - errx(1, "Write to tun failed?"); + warnx("Write to tun failed (%d)?", errno); /* * Done with that one; wait_for_vq_desc() will send the interrupt if @@ -955,7 +956,7 @@ static void net_input(struct virtqueue *vq) */ len = readv(net_info->tunfd, iov, in); if (len <= 0) - err(1, "Failed to read from tun."); + warn("Failed to read from tun (%d).", errno); /* * Mark that packet buffer as used, but don't interrupt here. We want @@ -1093,9 +1094,10 @@ static void update_device_status(struct device *dev) warnx("Device %s configuration FAILED", dev->name); if (dev->running) reset_device(dev); - } else if (dev->desc->status & VIRTIO_CONFIG_S_DRIVER_OK) { - if (!dev->running) - start_device(dev); + } else { + if (dev->running) + err(1, "Device %s features finalized twice", dev->name); + start_device(dev); } } @@ -1120,25 +1122,11 @@ static void handle_output(unsigned long addr) return; } - /* - * Devices *can* be used before status is set to DRIVER_OK. - * The original plan was that they would never do this: they - * would always finish setting up their status bits before - * actually touching the virtqueues. In practice, we allowed - * them to, and they do (eg. the disk probes for partition - * tables as part of initialization). - * - * If we see this, we start the device: once it's running, we - * expect the device to catch all the notifications. - */ + /* Devices should not be used before features are finalized. */ for (vq = i->vq; vq; vq = vq->next) { if (addr != vq->config.pfn*getpagesize()) continue; - if (i->running) - errx(1, "Notification on running %s", i->name); - /* This just calls create_thread() for each virtqueue */ - start_device(i); - return; + errx(1, "Notification on %s before setup!", i->name); } } @@ -1370,7 +1358,7 @@ static void setup_console(void) * --sharenet= option which opens or creates a named pipe. This can be * used to send packets to another guest in a 1:1 manner. * - * More sopisticated is to use one of the tools developed for project like UML + * More sophisticated is to use one of the tools developed for project like UML * to do networking. * * Faster is to do virtio bonding in kernel. Doing this 1:1 would be @@ -1380,7 +1368,7 @@ static void setup_console(void) * multiple inter-guest channels behind one interface, although it would * require some manner of hotplugging new virtio channels. * - * Finally, we could implement a virtio network switch in the kernel. + * Finally, we could use a virtio network switch in the kernel, ie. vhost. :*/ static u32 str2ip(const char *ipaddr) @@ -2017,10 +2005,7 @@ int main(int argc, char *argv[]) /* Tell the entry path not to try to reload segment registers. */ boot->hdr.loadflags |= KEEP_SEGMENTS; - /* - * We tell the kernel to initialize the Guest: this returns the open - * /dev/lguest file descriptor. - */ + /* We tell the kernel to initialize the Guest. */ tell_kernel(start); /* Ensure that we terminate if a device-servicing child dies. */ diff --git a/Documentation/x86/entry_64.txt b/Documentation/x86/entry_64.txt new file mode 100644 index 0000000..7869f14 --- /dev/null +++ b/Documentation/x86/entry_64.txt @@ -0,0 +1,98 @@ +This file documents some of the kernel entries in +arch/x86/kernel/entry_64.S. A lot of this explanation is adapted from +an email from Ingo Molnar: + +http://lkml.kernel.org/r/<20110529191055.GC9835%40elte.hu> + +The x86 architecture has quite a few different ways to jump into +kernel code. Most of these entry points are registered in +arch/x86/kernel/traps.c and implemented in arch/x86/kernel/entry_64.S +and arch/x86/ia32/ia32entry.S. + +The IDT vector assignments are listed in arch/x86/include/irq_vectors.h. + +Some of these entries are: + + - system_call: syscall instruction from 64-bit code. + + - ia32_syscall: int 0x80 from 32-bit or 64-bit code; compat syscall + either way. + + - ia32_syscall, ia32_sysenter: syscall and sysenter from 32-bit + code + + - interrupt: An array of entries. Every IDT vector that doesn't + explicitly point somewhere else gets set to the corresponding + value in interrupts. These point to a whole array of + magically-generated functions that make their way to do_IRQ with + the interrupt number as a parameter. + + - emulate_vsyscall: int 0xcc, a special non-ABI entry used by + vsyscall emulation. + + - APIC interrupts: Various special-purpose interrupts for things + like TLB shootdown. + + - Architecturally-defined exceptions like divide_error. + +There are a few complexities here. The different x86-64 entries +have different calling conventions. The syscall and sysenter +instructions have their own peculiar calling conventions. Some of +the IDT entries push an error code onto the stack; others don't. +IDT entries using the IST alternative stack mechanism need their own +magic to get the stack frames right. (You can find some +documentation in the AMD APM, Volume 2, Chapter 8 and the Intel SDM, +Volume 3, Chapter 6.) + +Dealing with the swapgs instruction is especially tricky. Swapgs +toggles whether gs is the kernel gs or the user gs. The swapgs +instruction is rather fragile: it must nest perfectly and only in +single depth, it should only be used if entering from user mode to +kernel mode and then when returning to user-space, and precisely +so. If we mess that up even slightly, we crash. + +So when we have a secondary entry, already in kernel mode, we *must +not* use SWAPGS blindly - nor must we forget doing a SWAPGS when it's +not switched/swapped yet. + +Now, there's a secondary complication: there's a cheap way to test +which mode the CPU is in and an expensive way. + +The cheap way is to pick this info off the entry frame on the kernel +stack, from the CS of the ptregs area of the kernel stack: + + xorl %ebx,%ebx + testl $3,CS+8(%rsp) + je error_kernelspace + SWAPGS + +The expensive (paranoid) way is to read back the MSR_GS_BASE value +(which is what SWAPGS modifies): + + movl $1,%ebx + movl $MSR_GS_BASE,%ecx + rdmsr + testl %edx,%edx + js 1f /* negative -> in kernel */ + SWAPGS + xorl %ebx,%ebx +1: ret + +and the whole paranoid non-paranoid macro complexity is about whether +to suffer that RDMSR cost. + +If we are at an interrupt or user-trap/gate-alike boundary then we can +use the faster check: the stack will be a reliable indicator of +whether SWAPGS was already done: if we see that we are a secondary +entry interrupting kernel mode execution, then we know that the GS +base has already been switched. If it says that we interrupted +user-space execution then we must do the SWAPGS. + +But if we are in an NMI/MCE/DEBUG/whatever super-atomic entry context, +which might have triggered right after a normal entry wrote CS to the +stack but before we executed SWAPGS, then the only safe way to check +for GS is the slower method: the RDMSR. + +So we try only to mark those entry methods 'paranoid' that absolutely +need the more expensive check for the GS base - and we generate all +'normal' entry points with the regular (faster) entry macros. diff --git a/Documentation/zh_CN/SubmitChecklist b/Documentation/zh_CN/SubmitChecklist index 951415b..4c741d6 100644 --- a/Documentation/zh_CN/SubmitChecklist +++ b/Documentation/zh_CN/SubmitChecklist @@ -67,7 +67,7 @@ Linux 12ѾͨCONFIG_PREEMPT, CONFIG_DEBUG_PREEMPT, CONFIG_DEBUG_SLAB, CONFIG_DEBUG_PAGEALLOC, CONFIG_DEBUG_MUTEXES, - CONFIG_DEBUG_SPINLOCK, CONFIG_DEBUG_SPINLOCK_SLEEPԣͬʱ + CONFIG_DEBUG_SPINLOCK, CONFIG_DEBUG_ATOMIC_SLEEPԣͬʱ ʹܡ 13Ѿʹû߲ʹ CONFIG_SMP CONFIG_PREEMPTִʱ䡣 diff --git a/Documentation/zh_CN/email-clients.txt b/Documentation/zh_CN/email-clients.txt index 5d65e32..b9a1a3e 100644 --- a/Documentation/zh_CN/email-clients.txt +++ b/Documentation/zh_CN/email-clients.txt @@ -1,4 +1,4 @@ -锘?Chinese translated version of Documentation/email-clients.txt +Chinese translated version of Documentation/email-clients.txt If you have any comment or update to the content, please contact the original document maintainer directly. However, if you have a problem @@ -8,203 +8,203 @@ or if there is a problem with the translation. Chinese maintainer: Harry Wei --------------------------------------------------------------------- -Documentation/email-clients.txt ???涓????缈昏?? +Documentation/email-clients.txt 的中文翻译 -濡??????宠??璁烘????存?版???????????瀹癸??璇风?存?ヨ??绯诲?????妗g??缁存?よ?????濡????浣?浣跨?ㄨ?辨?? -浜ゆ???????伴?剧??璇?锛?涔????浠ュ??涓???????缁存?よ??姹???┿??濡???????缈昏????存?颁???????舵?????缈? -璇?瀛???ㄩ??棰?锛?璇疯??绯讳腑??????缁存?よ????? +如果想评论或更新本文的内容,请直接联系原文档的维护者。如果你使用英文 +交流有困难的话,也可以向中文版维护者求助。如果本翻译更新不及时或者翻 +译存在问题,请联系中文版维护者。 -涓???????缁存?よ??锛? 璐惧??濞? Harry Wei -涓???????缈昏?????锛? 璐惧??濞? Harry Wei -涓?????????¤?????锛? Yinglin Luan +中文版维护者: 贾威威 Harry Wei +中文版翻译者: 贾威威 Harry Wei +中文版校译者: Yinglin Luan Xiaochen Wang yaxinsn -浠ヤ??涓烘?f?? +以下为正文 --------------------------------------------------------------------- -Linux???浠跺?㈡?风?????缃?淇℃?? +Linux邮件客户端配置信息 ====================================================================== -?????????缃? +普通配置 ---------------------------------------------------------------------- -Linux?????歌ˉ涓???????杩????浠惰?????浜ょ??锛????濂芥??琛ヤ??浣?涓洪??浠朵????????宓?????????????浜?缁存?よ?? -??ユ?堕??浠讹??浣???????浠剁?????瀹规?煎??搴?璇ユ??"text/plain"?????惰??锛????浠朵????????涓?璧???????锛? -???涓鸿??浼?浣胯ˉ涓????寮???ㄩ?ㄥ????ㄨ??璁鸿??绋?涓???????寰???伴?俱?? +Linux内核补丁是通过邮件被提交的,最好把补丁作为邮件体的内嵌文本。有些维护者 +接收附件,但是附件的内容格式应该是"text/plain"。然而,附件一般是不赞成的, +因为这会使补丁的引用部分在评论过程中变的很困难。 -??ㄦ?ュ?????Linux?????歌ˉ涓???????浠跺?㈡?风????ㄥ?????琛ヤ????跺??璇ュ??浜?????????????濮???舵?????渚?濡?锛? -浠?浠?涓???芥?瑰?????????????ゅ?惰〃绗???????绌烘?硷???????虫????ㄦ??涓?琛????寮?澶存?????缁?灏俱?? +用来发送Linux内核补丁的邮件客户端在发送补丁时应该处于文本的原始状态。例如, +他们不能改变或者删除制表符或者空格,甚至是在每一行的开头或者结尾。 -涓?瑕????杩?"format=flowed"妯″????????琛ヤ?????杩???蜂??寮?璧蜂?????棰????浠ュ?????瀹崇?????琛???? +不要通过"format=flowed"模式发送补丁。这样会引起不可预期以及有害的断行。 -涓?瑕?璁╀????????浠跺?㈡?风??杩?琛??????ㄦ?㈣?????杩???蜂??浼???村??浣????琛ヤ????? +不要让你的邮件客户端进行自动换行。这样也会破坏你的补丁。 -???浠跺?㈡?风??涓???芥?瑰???????????瀛?绗????缂??????瑰?????瑕??????????琛ヤ???????芥??ASCII??????UTF-8缂??????瑰??锛? -濡????浣?浣跨??UTF-8缂??????瑰???????????浠讹????d??浣?灏?浼???垮??涓?浜??????藉????????瀛?绗???????棰???? +邮件客户端不能改变文本的字符集编码方式。要发送的补丁只能是ASCII或者UTF-8编码方式, +如果你使用UTF-8编码方式发送邮件,那么你将会避免一些可能发生的字符集问题。 -???浠跺?㈡?风??搴?璇ュ舰???骞朵??淇???? References: ?????? In-Reply-To: ???棰?锛???d?? -???浠惰??棰?灏变??浼?涓??????? +邮件客户端应该形成并且保持 References: 或者 In-Reply-To: 标题,那么 +邮件话题就不会中断。 -澶???剁??甯?(?????????璐寸??甯?)???甯镐????界?ㄤ??琛ヤ??锛????涓哄?惰〃绗?浼?杞????涓虹┖??笺??浣跨??xclipboard, xclip -??????xcutsel涔?璁稿??浠ワ??浣???????濂芥??璇?涓?涓?????????垮??浣跨?ㄥ????剁??甯???? +复制粘帖(或者剪贴粘帖)通常不能用于补丁,因为制表符会转换为空格。使用xclipboard, xclip +或者xcutsel也许可以,但是最好测试一下或者避免使用复制粘帖。 -涓?瑕???ㄤ娇???PGP/GPG缃插????????浠朵腑??????琛ヤ?????杩???蜂??浣垮??寰?澶???????涓???借?诲??????????ㄤ??浣????琛ヤ????? -锛?杩?涓????棰?搴?璇ユ?????浠ヤ慨澶????锛? +不要在使用PGP/GPG署名的邮件中包含补丁。这样会使得很多脚本不能读取和适用于你的补丁。 +(这个问题应该是可以修复的) -??ㄧ???????搁??浠跺??琛ㄥ?????琛ヤ??涔????锛?缁????宸卞?????涓?涓?琛ヤ?????涓?涓???????涓绘??锛?淇?瀛???ユ?跺?扮?? -???浠讹??灏?琛ヤ?????'patch'??戒护???涓?锛?濡??????????浜?锛????缁??????搁??浠跺??琛ㄥ???????? +在给内核邮件列表发送补丁之前,给自己发送一个补丁是个不错的主意,保存接收到的 +邮件,将补丁用'patch'命令打上,如果成功了,再给内核邮件列表发送。 -涓?浜????浠跺?㈡?风?????绀? +一些邮件客户端提示 ---------------------------------------------------------------------- -杩????缁???轰??浜?璇?缁????MUA???缃????绀猴?????浠ョ?ㄤ??缁?Linux?????稿?????琛ヤ?????杩?浜?骞朵???????虫?? -?????????杞?浠跺?????缃???荤????? +这里给出一些详细的MUA配置提示,可以用于给Linux内核发送补丁。这些并不意味是 +所有的软件包配置总结。 -璇存??锛? -TUI = 浠ユ?????涓哄?虹???????ㄦ?锋?ュ?? -GUI = ??惧舰?????㈢?ㄦ?锋?ュ?? +说明: +TUI = 以文本为基础的用户接口 +GUI = 图形界面用户接口 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Alpine (TUI) -???缃????椤癸?? -???"Sending Preferences"??ㄥ??锛? +配置选项: +在"Sending Preferences"部分: -- "Do Not Send Flowed Text"蹇?椤诲????? -- "Strip Whitespace Before Sending"蹇?椤诲?抽?? +- "Do Not Send Flowed Text"必须开启 +- "Strip Whitespace Before Sending"必须关闭 -褰???????浠舵?讹????????搴?璇ユ?惧?ㄨˉ涓?浼???虹?扮????版?癸????跺?????涓?CTRL-R缁???????锛?浣挎??瀹???? -琛ヤ?????浠跺????ュ?伴??浠朵腑??? +当写邮件时,光标应该放在补丁会出现的地方,然后按下CTRL-R组合键,使指定的 +补丁文件嵌入到邮件中。 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Evolution (GUI) -涓?浜?寮????????????????浣跨?ㄥ????????琛ヤ?? +一些开发者成功的使用它发送补丁 -褰??????╅??浠堕??椤癸??Preformat - 浠?Format->Heading->Preformatted (Ctrl-7)??????宸ュ?锋?? +当选择邮件选项:Preformat + 从Format->Heading->Preformatted (Ctrl-7)或者工具栏 -??跺??浣跨??锛? - Insert->Text File... (Alt-n x)?????ヨˉ涓????浠躲?? +然后使用: + Insert->Text File... (Alt-n x)插入补丁文件。 -浣?杩????浠?"diff -Nru old.c new.c | xclip"锛???????Preformat锛???跺??浣跨?ㄤ腑??撮??杩?琛?绮?甯???? +你还可以"diff -Nru old.c new.c | xclip",选择Preformat,然后使用中间键进行粘帖。 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Kmail (GUI) -涓?浜?寮????????????????浣跨?ㄥ????????琛ヤ????? +一些开发者成功的使用它发送补丁。 -榛?璁よ?剧疆涓?涓?HTML??煎??????????????锛?涓?瑕??????ㄥ????? +默认设置不为HTML格式是合适的;不要启用它。 -褰?涔????涓?灏????浠剁????跺??锛???ㄩ??椤逛?????涓?瑕??????╄????ㄦ?㈣????????涓????缂虹?瑰氨???浣???ㄩ??浠朵腑杈???ョ??浠讳???????? -??戒??浼?琚??????ㄦ?㈣??锛????姝や??蹇?椤诲?ㄥ?????琛ヤ??涔?????????ㄦ?㈣????????绠?????????规??灏辨???????ㄨ????ㄦ?㈣????ヤ功??????浠讹?? -??跺?????瀹?淇?瀛?涓鸿??绋裤??涓????浣???ㄨ??绋夸腑???娆℃??寮?瀹?锛?瀹?宸茬????ㄩ?ㄨ????ㄦ?㈣??浜?锛???d??浣???????浠惰?界?舵病??? -?????╄????ㄦ?㈣??锛?浣????杩?涓?浼?澶卞?诲凡???????????ㄦ?㈣????? +当书写一封邮件的时候,在选项下面不要选择自动换行。唯一的缺点就是你在邮件中输入的任何文本 +都不会被自动换行,因此你必须在发送补丁之前手动换行。最简单的方法就是启用自动换行来书写邮件, +然后把它保存为草稿。一旦你在草稿中再次打开它,它已经全部自动换行了,那么你的邮件虽然没有 +选择自动换行,但是还不会失去已有的自动换行。 -??ㄩ??浠剁??搴????锛??????ヨˉ涓?涔????锛???句??甯哥?ㄧ??琛ヤ??瀹????绗?锛?涓?涓?杩?瀛????(---)??? +在邮件的底部,插入补丁之前,放上常用的补丁定界符:三个连字号(---)。 -??跺?????"Message"????????$??锛??????╂????ユ??浠讹????ョ????????浣????琛ヤ?????浠躲??杩????涓?涓?棰?澶???????椤癸??浣????浠? -???杩?瀹????缃?浣???????浠跺缓绔?宸ュ?锋????????锛?杩????浠ュ甫涓?"insert file"??炬????? +然后在"Message"菜单条目,选择插入文件,接着选取你的补丁文件。还有一个额外的选项,你可以 +通过它配置你的邮件建立工具栏菜单,还可以带上"insert file"图标。 -浣????浠ュ????ㄥ?伴??杩?GPG???璁伴??浠讹??浣???????宓?琛ヤ?????濂戒??瑕?浣跨??GPG???璁板??浠????浣?涓哄??宓??????????绛惧??琛ヤ??锛? -褰?浠?GPG涓???????7浣?缂??????朵??浣夸??浠?????????村??澶??????? +你可以安全地通过GPG标记附件,但是内嵌补丁最好不要使用GPG标记它们。作为内嵌文本的签发补丁, +当从GPG中提取7位编码时会使他们变的更加复杂。 -濡????浣????瑕?浠ラ??浠剁??褰㈠????????琛ヤ??锛???d??灏卞?抽????瑰?婚??浠讹????跺?????涓?灞???э??绐????"Suggest automatic -display"锛?杩???峰??宓????浠舵?村?规??璁╄?昏???????般?? +如果你非要以附件的形式发送补丁,那么就右键点击附件,然后选中属性,突出"Suggest automatic +display",这样内嵌附件更容易让读者看到。 -褰?浣?瑕?淇?瀛?灏?瑕?????????????宓???????琛ヤ??锛?浣????浠ヤ??娑???????琛ㄧ????奸????╁?????琛ヤ????????浠讹????跺????冲?婚????? -"save as"???浣????浠ヤ娇??ㄤ??涓?娌℃????存?圭????????琛ヤ????????浠讹??濡????瀹????浠ユ?g‘???褰㈠??缁???????褰?浣?姝g????ㄥ?? -???宸辩??绐???d??涓?瀵????锛???f?舵病??????椤瑰??浠ヤ??瀛????浠?--宸茬?????涓?涓?杩???风??bug琚?姹???ュ?颁??kmail???bugzilla -骞朵??甯????杩?灏?浼?琚?澶??????????浠舵??浠ュ?????瀵规??涓???ㄦ?峰??璇诲???????????琚?淇?瀛????锛????浠ュ?????浣???虫?????浠跺????跺?板?朵????版?癸?? -浣?涓?寰?涓????浠?浠????????????逛负缁?????????翠?????璇汇?? +当你要保存将要发送的内嵌文本补丁,你可以从消息列表窗格选择包含补丁的邮件,然后右击选择 +"save as"。你可以使用一个没有更改的包含补丁的邮件,如果它是以正确的形式组成。当你正真在它 +自己的窗口之下察看,那时没有选项可以保存邮件--已经有一个这样的bug被汇报到了kmail的bugzilla +并且希望这将会被处理。邮件是以只针对某个用户可读写的权限被保存的,所以如果你想把邮件复制到其他地方, +你不得不把他们的权限改为组或者整体可读。 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Lotus Notes (GUI) -涓?瑕?浣跨?ㄥ????? +不要使用它。 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Mutt (TUI) -寰?澶?Linux寮????浜哄??浣跨??mutt瀹㈡?风??锛????浠ヨ?????瀹????瀹?宸ヤ????????甯告??浜???? +很多Linux开发人员使用mutt客户端,所以证明它肯定工作的非常漂亮。 -Mutt涓????甯?缂?杈????锛????浠ヤ??绠′??浣跨?ㄤ??涔?缂?杈???ㄩ?戒??搴?璇ュ甫????????ㄦ??琛????澶у????扮??杈???ㄩ?藉甫??? -涓?涓?"insert file"???椤癸??瀹????浠ラ??杩?涓???瑰?????浠跺??瀹圭????瑰???????ユ??浠躲?? +Mutt不自带编辑器,所以不管你使用什么编辑器都不应该带有自动断行。大多数编辑器都带有 +一个"insert file"选项,它可以通过不改变文件内容的方式插入文件。 -'vim'浣?涓?mutt???缂?杈????锛? +'vim'作为mutt的编辑器: set editor="vi" - 濡????浣跨??xclip锛???插?ヤ互涓???戒护 + 如果使用xclip,敲入以下命令 :set paste - ???涓????涔??????????shift-insert??????浣跨?? + 按中键之前或者shift-insert或者使用 :r filename -濡??????宠?????琛ヤ??浣?涓哄??宓?????????? -(a)ttach宸ヤ?????寰?濂斤??涓?甯????"set paste"??? +如果想要把补丁作为内嵌文本。 +(a)ttach工作的很好,不带有"set paste"。 -???缃????椤癸?? -瀹?搴?璇ヤ互榛?璁よ?剧疆???褰㈠??宸ヤ????? -??惰??锛????"send_charset"璁剧疆涓?"us-ascii::utf-8"涔????涓?涓?涓???????涓绘????? +配置选项: +它应该以默认设置的形式工作。 +然而,把"send_charset"设置为"us-ascii::utf-8"也是一个不错的主意。 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Pine (TUI) -Pine杩???绘??涓?浜?绌烘?煎????????棰?锛?浣????杩?浜???板?ㄥ??璇ラ?借??淇?澶?浜???? +Pine过去有一些空格删减问题,但是这些现在应该都被修复了。 -濡???????浠ワ??璇蜂娇???alpine(pine???缁ф?胯??) +如果可以,请使用alpine(pine的继承者) -???缃????椤癸?? -- ???杩?????????????瑕?娑???ゆ??绋??????? -- "no-strip-whitespace-before-send"???椤逛????????瑕??????? +配置选项: +- 最近的版本需要消除流程文本 +- "no-strip-whitespace-before-send"选项也是需要的。 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Sylpheed (GUI) -- ???宓??????????浠ュ??濂界??宸ヤ??锛???????浣跨?ㄩ??浠讹????? -- ???璁镐娇??ㄥ????ㄧ??缂?杈???ㄣ?? -- 瀵逛?????褰?杈?澶???堕??甯告????? -- 濡???????杩?non-SSL杩???ワ?????娉?浣跨??TLS SMTP????????? -- ??ㄧ?????绐???d腑???涓?涓?寰??????ㄧ??ruler bar??? -- 缁???板?????涓?娣诲????板??灏变??浼?姝g‘???浜?瑙f?剧ず?????? +- 内嵌文本可以很好的工作(或者使用附件)。 +- 允许使用外部的编辑器。 +- 对于目录较多时非常慢。 +- 如果通过non-SSL连接,无法使用TLS SMTP授权。 +- 在组成窗口中有一个很有用的ruler bar。 +- 给地址本中添加地址就不会正确的了解显示名。 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Thunderbird (GUI) -榛?璁ゆ????典??锛?thunderbird寰?瀹规??????????????锛?浣????杩????涓?浜???规?????浠ュ己??跺?????寰???村ソ??? +默认情况下,thunderbird很容易损坏文本,但是还有一些方法可以强制它变得更好。 -- ??ㄧ?ㄦ?峰????疯?剧疆???锛?缁???????瀵诲??锛?涓?瑕???????"Compose messages in HTML format"??? +- 在用户帐号设置里,组成和寻址,不要选择"Compose messages in HTML format"。 -- 缂?杈?浣????Thunderbird???缃?璁剧疆??ヤ娇瀹?涓?瑕????琛?浣跨??锛?user_pref("mailnews.wraplength", 0); +- 编辑你的Thunderbird配置设置来使它不要拆行使用:user_pref("mailnews.wraplength", 0); -- 缂?杈?浣????Thunderbird???缃?璁剧疆锛?浣垮??涓?瑕?浣跨??"format=flowed"??煎??锛?user_pref("mailnews. +- 编辑你的Thunderbird配置设置,使它不要使用"format=flowed"格式:user_pref("mailnews. send_plaintext_flowed", false); -- 浣????瑕?浣?Thunderbird???涓洪???????煎????瑰??锛? - 濡????榛?璁ゆ????典??浣?涔??????????HTML??煎??锛???d?????寰???俱??浠?浠?浠????棰???????涓????妗?涓???????"Preformat"??煎????? - 濡????榛?璁ゆ????典??浣?涔??????????????????煎??锛?浣?涓?寰????瀹???逛负HTML??煎??锛?浠?浠?浣?涓轰??娆℃?х??锛???ヤ功?????扮??娑????锛? - ??跺??寮哄?朵娇瀹??????版???????煎??锛???????瀹?灏变?????琛????瑕?瀹???板??锛???ㄥ??淇$????炬??涓?浣跨??shift?????ヤ娇瀹????涓?HTML - ??煎??锛???跺?????棰???????涓????妗?涓???????"Preformat"??煎????? +- 你需要使Thunderbird变为预先格式方式: + 如果默认情况下你书写的是HTML格式,那不是很难。仅仅从标题栏的下拉框中选择"Preformat"格式。 + 如果默认情况下你书写的是文本格式,你不得把它改为HTML格式(仅仅作为一次性的)来书写新的消息, + 然后强制使它回到文本格式,否则它就会拆行。要实现它,在写信的图标上使用shift键来使它变为HTML + 格式,然后标题栏的下拉框中选择"Preformat"格式。 -- ???璁镐娇??ㄥ????ㄧ??缂?杈????锛? - ???瀵?Thunderbird???琛ヤ?????绠?????????规??灏辨??浣跨?ㄤ??涓?"external editor"??╁??锛???跺??浣跨?ㄤ????????娆㈢?? - $EDITOR??ヨ?诲???????????骞惰ˉ涓???版?????涓????瑕?瀹???板??锛????浠ヤ??杞藉苟涓?瀹?瑁?杩?涓???╁??锛???跺??娣诲??涓?涓?浣跨?ㄥ????? - ??????View->Toolbars->Customize...??????褰?浣?涔????淇℃???????跺??浠?浠???瑰?诲??灏卞??浠ヤ????? +- 允许使用外部的编辑器: + 针对Thunderbird打补丁最简单的方法就是使用一个"external editor"扩展,然后使用你最喜欢的 + $EDITOR来读取或者合并补丁到文本中。要实现它,可以下载并且安装这个扩展,然后添加一个使用它的 + 按键View->Toolbars->Customize...最后当你书写信息的时候仅仅点击它就可以了。 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ TkRat (GUI) -???浠ヤ娇??ㄥ?????浣跨??"Insert file..."??????澶???ㄧ??缂?杈???ㄣ?? +可以使用它。使用"Insert file..."或者外部的编辑器。 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Gmail (Web GUI) -涓?瑕?浣跨?ㄥ????????琛ヤ????? +不要使用它发送补丁。 -Gmail缃?椤靛?㈡?风???????ㄥ?版????惰〃绗?杞????涓虹┖??笺?? +Gmail网页客户端自动地把制表符转换为空格。 -??界?跺?惰〃绗?杞????涓虹┖??奸??棰????浠ヨ??澶???ㄧ??杈???ㄨВ??筹???????跺??杩?浼?浣跨?ㄥ??杞???㈣?????姣?琛???????涓?78涓?瀛?绗???? +虽然制表符转换为空格问题可以被外部编辑器解决,同时它还会使用回车换行把每行拆分为78个字符。 -???涓?涓????棰????Gmail杩?浼????浠讳??涓????ASCII???瀛?绗????淇℃????逛负base64缂???????瀹????涓?瑗垮????????娆ф床浜虹?????瀛???? +另一个问题是Gmail还会把任何不是ASCII的字符的信息改为base64编码。它把东西变的像欧洲人的名字。 ### diff --git a/Documentation/zh_CN/magic-number.txt b/Documentation/zh_CN/magic-number.txt index 4c4ce85..c278f41 100644 --- a/Documentation/zh_CN/magic-number.txt +++ b/Documentation/zh_CN/magic-number.txt @@ -66,7 +66,7 @@ MKISS_DRIVER_MAGIC 0x04bf mkiss_channel drivers/net/mkiss.h RISCOM8_MAGIC 0x0907 riscom_port drivers/char/riscom8.h SPECIALIX_MAGIC 0x0907 specialix_port drivers/char/specialix_io8.h HDLC_MAGIC 0x239e n_hdlc drivers/char/n_hdlc.c -APM_BIOS_MAGIC 0x4101 apm_user arch/i386/kernel/apm.c +APM_BIOS_MAGIC 0x4101 apm_user arch/x86/kernel/apm_32.c CYCLADES_MAGIC 0x4359 cyclades_port include/linux/cyclades.h DB_MAGIC 0x4442 fc_info drivers/net/iph5526_novram.c DL_MAGIC 0x444d fc_info drivers/net/iph5526_novram.c diff --git a/MAINTAINERS b/MAINTAINERS index 187282d..1d2e79d 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1,4 +1,5 @@ + List of maintainers and how to submit kernel changes Please try to follow the guidelines below. This will make things @@ -533,6 +534,8 @@ L: device-drivers-devel@blackfin.uclinux.org L: alsa-devel@alsa-project.org (moderated for non-subscribers) W: http://wiki.analog.com/ S: Supported +F: sound/soc/codecs/adau* +F: sound/soc/codecs/adav* F: sound/soc/codecs/ad1* F: sound/soc/codecs/ssm* @@ -693,7 +696,7 @@ T: git git://git.infradead.org/users/cbou/linux-cns3xxx.git ARM/CIRRUS LOGIC EP93XX ARM ARCHITECTURE M: Hartley Sweeten -M: Ryan Mallon +M: Ryan Mallon L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers) S: Maintained F: arch/arm/mach-ep93xx/ @@ -731,6 +734,12 @@ T: git git://git.berlios.de/gemini-board S: Maintained F: arch/arm/mach-gemini/ +ARM/CSR SIRFPRIMA2 MACHINE SUPPORT +M: Barry Song +L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers) +S: Maintained +F: arch/arm/mach-prima2/ + ARM/EBSA110 MACHINE SUPPORT M: Russell King L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers) @@ -1543,13 +1552,20 @@ F: drivers/net/tg3.* BROADCOM BRCM80211 IEEE802.11n WIRELESS DRIVER M: Brett Rudley M: Henry Ptasinski -M: Dowan Kim M: Roland Vossen M: Arend van Spriel +M: Franky (Zhenhui) Lin +M: Kan Yan L: linux-wireless@vger.kernel.org S: Supported F: drivers/staging/brcm80211/ +BROADCOM BNX2FC 10 GIGABIT FCOE DRIVER +M: Bhanu Prakash Gollapudi +L: linux-scsi@vger.kernel.org +S: Supported +F: drivers/scsi/bnx2fc/ + BROCADE BFA FC SCSI DRIVER M: Jing Huang L: linux-scsi@vger.kernel.org @@ -1579,7 +1595,7 @@ F: Documentation/sound/alsa/Bt87x.txt F: sound/pci/bt87x.c BT8XXGPIO DRIVER -M: Michael Buesch +M: Michael Buesch W: http://bu3sch.de/btgpio.php S: Maintained F: drivers/gpio/bt8xxgpio.c @@ -1772,7 +1788,8 @@ F: include/linux/clk.h CISCO FCOE HBA DRIVER M: Abhijeet Joglekar -M: Joe Eykholt +M: Venkata Siva Vijayendra Bhamidipati +M: Brian Uchino L: linux-scsi@vger.kernel.org S: Supported F: drivers/scsi/fnic/ @@ -3002,7 +3019,7 @@ F: kernel/hrtimer.c F: kernel/time/clockevents.c F: kernel/time/tick*.* F: kernel/time/timer_*.c -F: include/linux/clockevents.h +F: include/linux/clockchips.h F: include/linux/hrtimer.h HIGH-SPEED SCC DRIVER FOR AX.25 @@ -3425,10 +3442,9 @@ S: Maintained F: drivers/net/ipg.* IPATH DRIVER -M: Ralph Campbell +M: Mike Marciniszyn L: linux-rdma@vger.kernel.org -T: git git://git.qlogic.com/ipath-linux-2.6 -S: Supported +S: Maintained F: drivers/infiniband/hw/ipath/ IPMI SUBSYSTEM @@ -3886,7 +3902,7 @@ F: arch/powerpc/platforms/512x/ F: arch/powerpc/platforms/52xx/ LINUX FOR POWERPC EMBEDDED PPC4XX -M: Josh Boyer +M: Josh Boyer M: Matt Porter W: http://www.penguinppc.org/ L: linuxppc-dev@lists.ozlabs.org @@ -3918,6 +3934,7 @@ W: http://www.penguinppc.org/ L: linuxppc-dev@lists.ozlabs.org S: Maintained F: arch/powerpc/platforms/83xx/ +F: arch/powerpc/platforms/85xx/ LINUX FOR POWERPC PA SEMI PWRFICIENT M: Olof Johansson @@ -3951,6 +3968,13 @@ L: lm-sensors@lm-sensors.org S: Maintained F: drivers/hwmon/lm73.c +LM78 HARDWARE MONITOR DRIVER +M: Jean Delvare +L: lm-sensors@lm-sensors.org +S: Maintained +F: Documentation/hwmon/lm78 +F: drivers/hwmon/lm78.c + LM83 HARDWARE MONITOR DRIVER M: Jean Delvare L: lm-sensors@lm-sensors.org @@ -4097,6 +4121,12 @@ S: Maintained F: drivers/net/mv643xx_eth.* F: include/linux/mv643xx.h +MARVELL MWIFIEX WIRELESS DRIVER +M: Bing Zhao +L: linux-wireless@vger.kernel.org +S: Maintained +F: drivers/net/wireless/mwifiex/ + MARVELL MWL8K WIRELESS DRIVER M: Lennert Buytenhek L: linux-wireless@vger.kernel.org @@ -4193,9 +4223,10 @@ F: drivers/usb/image/microtek.* MIPS M: Ralf Baechle -W: http://www.linux-mips.org/ L: linux-mips@linux-mips.org +W: http://www.linux-mips.org/ T: git git://git.linux-mips.org/pub/scm/linux.git +Q: http://patchwork.linux-mips.org/project/linux-mips/list/ S: Supported F: Documentation/mips/ F: arch/mips/ @@ -4289,8 +4320,8 @@ S: Maintained F: drivers/usb/musb/ MYRICOM MYRI-10G 10GbE DRIVER (MYRI10GE) +M: Jon Mason M: Andrew Gallatin -M: Brice Goglin L: netdev@vger.kernel.org W: http://www.myri.com/scs/download-Myri10GE.html S: Supported @@ -4584,9 +4615,8 @@ S: Maintained F: drivers/mmc/host/omap.c OMAP HS MMC SUPPORT -M: Madhusudhan Chikkature L: linux-omap@vger.kernel.org -S: Maintained +S: Orphan F: drivers/mmc/host/omap_hsmmc.c OMAP RANDOM NUMBER GENERATOR SUPPORT @@ -4680,6 +4710,14 @@ F: drivers/of F: include/linux/of*.h K: of_get_property +OPENRISC ARCHITECTURE +M: Jonas Bonn +W: http://openrisc.net +L: linux@lists.openrisc.net +S: Maintained +T: git git://openrisc.net/~jonas/linux +F: arch/openrisc + OPL4 DRIVER M: Clemens Ladisch L: alsa-devel@alsa-project.org (moderated for non-subscribers) @@ -5152,6 +5190,12 @@ M: Robert Jarzmik L: rtc-linux@googlegroups.com S: Maintained +QIB DRIVER +M: Mike Marciniszyn +L: linux-rdma@vger.kernel.org +S: Supported +F: drivers/infiniband/hw/qib/ + QLOGIC QLA1280 SCSI DRIVER M: Michael Reed L: linux-scsi@vger.kernel.org @@ -5313,6 +5357,13 @@ L: reiserfs-devel@vger.kernel.org S: Supported F: fs/reiserfs/ +REGISTER MAP ABSTRACTION +M: Mark Brown +T: git git://git.kernel.org/pub/scm/linux/kernel/git/broonie/regmap.git +S: Supported +F: drivers/base/regmap/ +F: include/linux/regmap.h + RFKILL M: Johannes Berg L: linux-wireless@vger.kernel.org @@ -5875,7 +5926,7 @@ S: Maintained F: drivers/net/sonic.* SONICS SILICON BACKPLANE DRIVER (SSB) -M: Michael Buesch +M: Michael Buesch L: netdev@vger.kernel.org S: Maintained F: drivers/ssb/ @@ -6049,6 +6100,145 @@ L: devel@driverdev.osuosl.org S: Maintained F: drivers/staging/ +STAGING - AGERE HERMES II and II.5 WIRELESS DRIVERS +M: Henk de Groot +S: Odd Fixes +F: drivers/staging/wlags49_h2/ +F: drivers/staging/wlags49_h25/ + +STAGING - ASUS OLED +M: Jakub Schmidtke +S: Odd Fixes +F: drivers/staging/asus_oled/ + +STAGING - ATHEROS ATH6KL WIRELESS DRIVER +M: Luis R. Rodriguez +M: Naveen Singh +S: Odd Fixes +F: drivers/staging/ath6kl/ + +STAGING - COMEDI +M: Ian Abbott +M: Mori Hess +S: Odd Fixes +F: drivers/staging/comedi/ + +STAGING - CRYSTAL HD VIDEO DECODER +M: Naren Sankar +M: Jarod Wilson +M: Scott Davilla +M: Manu Abraham +S: Odd Fixes +F: drivers/staging/crystalhd/ + +STAGING - CYPRESS WESTBRIDGE SUPPORT +M: David Cross +S: Odd Fixes +F: drivers/staging/westbridge/ + +STAGING - ECHO CANCELLER +M: Steve Underwood +M: David Rowe +S: Odd Fixes +F: drivers/staging/echo/ + +STAGING - FLARION FT1000 DRIVERS +M: Marek Belisko +S: Odd Fixes +F: drivers/staging/ft1000/ + +STAGING - FRONTIER TRANZPORT AND ALPHATRACK +M: David Täht +S: Odd Fixes +F: drivers/staging/frontier/ + +STAGING - HYPER-V (MICROSOFT) +M: Hank Janssen +M: Haiyang Zhang +S: Odd Fixes +F: drivers/staging/hv/ + +STAGING - INDUSTRIAL IO +M: Jonathan Cameron +L: linux-iio@vger.kernel.org +S: Odd Fixes +F: drivers/staging/iio/ + +STAGING - LIRC (LINUX INFRARED REMOTE CONTROL) DRIVERS +M: Jarod Wilson +W: http://www.lirc.org/ +S: Odd Fixes +F: drivers/staging/lirc/ + +STAGING - OLPC SECONDARY DISPLAY CONTROLLER (DCON) +M: Andres Salomon +M: Chris Ball +M: Jon Nettleton +W: http://wiki.laptop.org/go/DCON +S: Odd Fixes +F: drivers/staging/olpc_dcon/ + +STAGING - PARALLEL LCD/KEYPAD PANEL DRIVER +M: Willy Tarreau +S: Odd Fixes +F: drivers/staging/panel/ + +STAGING - REALTEK RTL8712U DRIVERS +M: Larry Finger +M: Florian Schilhabel . +S: Odd Fixes +F: drivers/staging/rtl8712/ + +STAGING - SILICON MOTION SM7XX FRAME BUFFER DRIVER +M: Teddy Wang +S: Odd Fixes +F: drivers/staging/sm7xx/ + +STAGING - SOFTLOGIC 6x10 MPEG CODEC +M: Ben Collins +S: Odd Fixes +F: drivers/staging/solo6x10/ + +STAGING - SPEAKUP CONSOLE SPEECH DRIVER +M: William Hubbs +M: Chris Brannon +M: Kirk Reiser +M: Samuel Thibault +L: speakup@braille.uwo.ca +W: http://www.linux-speakup.org/ +S: Odd Fixes +F: drivers/staging/speakup/ + +STAGING - TI DSP BRIDGE DRIVERS +M: Omar Ramirez Luna +S: Odd Fixes +F: drivers/staging/tidspbridge/ + +STAGING - TRIDENT TVMASTER TMxxxx USB VIDEO CAPTURE DRIVERS +L: linux-media@vger.kernel.org +S: Odd Fixes +F: drivers/staging/tm6000/ + +STAGING - USB ENE SM/MS CARD READER DRIVER +M: Al Cho +S: Odd Fixes +F: drivers/staging/keucr/ + +STAGING - VIA VT665X DRIVERS +M: Forest Bond +S: Odd Fixes +F: drivers/staging/vt665?/ + +STAGING - WINBOND IS89C35 WLAN USB DRIVER +M: Pavel Machek +S: Odd Fixes +F: drivers/staging/winbond/ + +STAGING - XGI Z7,Z9,Z11 PCI DISPLAY DRIVER +M: Arnaud Patard +S: Odd Fixes +F: drivers/staging/xgifb/ + STARFIRE/DURALAN NETWORK DRIVER M: Ion Badulescu S: Odd Fixes @@ -6218,7 +6408,7 @@ L: tomoyo-users-en@lists.sourceforge.jp (subscribers-only, for users in English) L: tomoyo-dev@lists.sourceforge.jp (subscribers-only, for developers in Japanese) L: tomoyo-users@lists.sourceforge.jp (subscribers-only, for users in Japanese) W: http://tomoyo.sourceforge.jp/ -T: quilt http://svn.sourceforge.jp/svnroot/tomoyo/trunk/2.3.x/tomoyo-lsm/patches/ +T: quilt http://svn.sourceforge.jp/svnroot/tomoyo/trunk/2.4.x/tomoyo-lsm/patches/ S: Maintained F: security/tomoyo/ @@ -6242,9 +6432,14 @@ F: drivers/char/toshiba.c F: include/linux/toshiba.h TMIO MMC DRIVER +M: Guennadi Liakhovetski M: Ian Molton +L: linux-mmc@vger.kernel.org S: Maintained -F: drivers/mmc/host/tmio_mmc.* +F: drivers/mmc/host/tmio_mmc* +F: drivers/mmc/host/sh_mobile_sdhi.c +F: include/linux/mmc/tmio.h +F: include/linux/mmc/sh_mobile_sdhi.h TMPFS (SHMEM FILESYSTEM) M: Hugh Dickins @@ -6321,7 +6516,7 @@ F: drivers/scsi/u14-34f.c UBI FILE SYSTEM (UBIFS) M: Artem Bityutskiy -M: Adrian Hunter +M: Adrian Hunter L: linux-mtd@lists.infradead.org T: git git://git.infradead.org/ubifs-2.6.git W: http://www.linux-mtd.infradead.org/doc/ubifs.html @@ -6546,13 +6741,6 @@ W: http://pegasus2.sourceforge.net/ S: Maintained F: drivers/net/usb/rtl8150.c -USB SE401 DRIVER -L: linux-usb@vger.kernel.org -W: http://www.chello.nl/~j.vreeken/se401/ -S: Orphan -F: Documentation/video4linux/se401.txt -F: drivers/staging/se401/ - USB SERIAL BELKIN F5U103 DRIVER M: William Greathouse L: linux-usb@vger.kernel.org @@ -6938,9 +7126,9 @@ S: Maintained F: drivers/input/misc/wistron_btns.c WL1251 WIRELESS DRIVER -M: Kalle Valo +M: Luciano Coelho L: linux-wireless@vger.kernel.org -W: http://wireless.kernel.org +W: http://wireless.kernel.org/en/users/Drivers/wl1251 T: git git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-testing.git S: Maintained F: drivers/net/wireless/wl1251/* diff --git a/Makefile b/Makefile index 6a5bdad..d018956 100644 --- a/Makefile +++ b/Makefile @@ -1290,6 +1290,7 @@ help: @echo ' make O=dir [targets] Locate all output files in "dir", including .config' @echo ' make C=1 [targets] Check all c source with $$CHECK (sparse by default)' @echo ' make C=2 [targets] Force check of all c source with $$CHECK' + @echo ' make RECORDMCOUNT_WARN=1 [targets] Warn about ignored mcount sections' @echo ' make W=n [targets] Enable extra gcc checks, n=1,2,3 where' @echo ' 1: warnings which may be relevant and do not occur too often' @echo ' 2: warnings which occur quite often but may still be relevant' diff --git a/arch/alpha/Kconfig b/arch/alpha/Kconfig index 60219bf..ca2da8d 100644 --- a/arch/alpha/Kconfig +++ b/arch/alpha/Kconfig @@ -6,6 +6,7 @@ config ALPHA select HAVE_OPROFILE select HAVE_SYSCALL_WRAPPERS select HAVE_IRQ_WORK + select HAVE_PCSPKR_PLATFORM select HAVE_PERF_EVENTS select HAVE_DMA_ATTRS select HAVE_GENERIC_HARDIRQS diff --git a/arch/alpha/include/asm/8253pit.h b/arch/alpha/include/asm/8253pit.h deleted file mode 100644 index a71c9c1..0000000 --- a/arch/alpha/include/asm/8253pit.h +++ /dev/null @@ -1,3 +0,0 @@ -/* - * 8253/8254 Programmable Interval Timer - */ diff --git a/arch/alpha/include/asm/atomic.h b/arch/alpha/include/asm/atomic.h index e756d04..640f909 100644 --- a/arch/alpha/include/asm/atomic.h +++ b/arch/alpha/include/asm/atomic.h @@ -176,15 +176,15 @@ static __inline__ long atomic64_sub_return(long i, atomic64_t * v) #define atomic_xchg(v, new) (xchg(&((v)->counter), new)) /** - * atomic_add_unless - add unless the number is a given value + * __atomic_add_unless - add unless the number is a given value * @v: pointer of type atomic_t * @a: the amount to add to v... * @u: ...unless v is equal to u. * * Atomically adds @a to @v, so long as it was not @u. - * Returns non-zero if @v was not @u, and zero otherwise. + * Returns the old value of @v. */ -static __inline__ int atomic_add_unless(atomic_t *v, int a, int u) +static __inline__ int __atomic_add_unless(atomic_t *v, int a, int u) { int c, old; c = atomic_read(v); @@ -196,10 +196,9 @@ static __inline__ int atomic_add_unless(atomic_t *v, int a, int u) break; c = old; } - return c != (u); + return c; } -#define atomic_inc_not_zero(v) atomic_add_unless((v), 1, 0) /** * atomic64_add_unless - add unless the number is a given value @@ -208,7 +207,7 @@ static __inline__ int atomic_add_unless(atomic_t *v, int a, int u) * @u: ...unless v is equal to u. * * Atomically adds @a to @v, so long as it was not @u. - * Returns non-zero if @v was not @u, and zero otherwise. + * Returns the old value of @v. */ static __inline__ int atomic64_add_unless(atomic64_t *v, long a, long u) { @@ -256,5 +255,4 @@ static __inline__ int atomic64_add_unless(atomic64_t *v, long a, long u) #define smp_mb__before_atomic_inc() smp_mb() #define smp_mb__after_atomic_inc() smp_mb() -#include #endif /* _ALPHA_ATOMIC_H */ diff --git a/arch/alpha/include/asm/bitops.h b/arch/alpha/include/asm/bitops.h index 85b8152..a19ba5e 100644 --- a/arch/alpha/include/asm/bitops.h +++ b/arch/alpha/include/asm/bitops.h @@ -456,8 +456,7 @@ sched_find_first_bit(const unsigned long b[2]) #include -#define ext2_set_bit_atomic(l,n,a) test_and_set_bit(n,a) -#define ext2_clear_bit_atomic(l,n,a) test_and_clear_bit(n,a) +#include #endif /* __KERNEL__ */ diff --git a/arch/alpha/include/asm/floppy.h b/arch/alpha/include/asm/floppy.h index 0be5041..46cefbd 100644 --- a/arch/alpha/include/asm/floppy.h +++ b/arch/alpha/include/asm/floppy.h @@ -27,7 +27,7 @@ #define fd_cacheflush(addr,size) /* nothing */ #define fd_request_irq() request_irq(FLOPPY_IRQ, floppy_interrupt,\ IRQF_DISABLED, "floppy", NULL) -#define fd_free_irq() free_irq(FLOPPY_IRQ, NULL); +#define fd_free_irq() free_irq(FLOPPY_IRQ, NULL) #ifdef CONFIG_PCI diff --git a/arch/alpha/include/asm/local.h b/arch/alpha/include/asm/local.h index b9e3e33..9c94b84 100644 --- a/arch/alpha/include/asm/local.h +++ b/arch/alpha/include/asm/local.h @@ -2,7 +2,7 @@ #define _ALPHA_LOCAL_H #include -#include +#include typedef struct { diff --git a/arch/alpha/include/asm/ptrace.h b/arch/alpha/include/asm/ptrace.h index 65cf3e2..fd698a1 100644 --- a/arch/alpha/include/asm/ptrace.h +++ b/arch/alpha/include/asm/ptrace.h @@ -72,7 +72,6 @@ struct switch_stack { #define user_mode(regs) (((regs)->ps & 8) != 0) #define instruction_pointer(regs) ((regs)->pc) #define profile_pc(regs) instruction_pointer(regs) -extern void show_regs(struct pt_regs *); #define task_pt_regs(task) \ ((struct pt_regs *) (task_stack_page(task) + 2*PAGE_SIZE) - 1) diff --git a/arch/alpha/kernel/module.c b/arch/alpha/kernel/module.c index ebc3c89..2fd00b7 100644 --- a/arch/alpha/kernel/module.c +++ b/arch/alpha/kernel/module.c @@ -29,20 +29,6 @@ #define DEBUGP(fmt...) #endif -void * -module_alloc(unsigned long size) -{ - if (size == 0) - return NULL; - return vmalloc(size); -} - -void -module_free(struct module *mod, void *module_region) -{ - vfree(module_region); -} - /* Allocate the GOT at the end of the core sections. */ struct got_entry { @@ -156,14 +142,6 @@ module_frob_arch_sections(Elf64_Ehdr *hdr, Elf64_Shdr *sechdrs, } int -apply_relocate(Elf64_Shdr *sechdrs, const char *strtab, unsigned int symindex, - unsigned int relsec, struct module *me) -{ - printk(KERN_ERR "module %s: REL relocation unsupported\n", me->name); - return -ENOEXEC; -} - -int apply_relocate_add(Elf64_Shdr *sechdrs, const char *strtab, unsigned int symindex, unsigned int relsec, struct module *me) @@ -302,15 +280,3 @@ apply_relocate_add(Elf64_Shdr *sechdrs, const char *strtab, return 0; } - -int -module_finalize(const Elf_Ehdr *hdr, const Elf_Shdr *sechdrs, - struct module *me) -{ - return 0; -} - -void -module_arch_cleanup(struct module *mod) -{ -} diff --git a/arch/alpha/kernel/perf_event.c b/arch/alpha/kernel/perf_event.c index 90561c4..8143cd7 100644 --- a/arch/alpha/kernel/perf_event.c +++ b/arch/alpha/kernel/perf_event.c @@ -17,7 +17,7 @@ #include #include -#include +#include #include #include #include @@ -847,7 +847,7 @@ static void alpha_perf_event_irq_handler(unsigned long la_ptr, data.period = event->hw.last_period; if (alpha_perf_event_set_period(event, hwc, idx)) { - if (perf_event_overflow(event, 1, &data, regs)) { + if (perf_event_overflow(event, &data, regs)) { /* Interrupts coming too quickly; "throttle" the * counter, i.e., disable it for a little while. */ diff --git a/arch/alpha/kernel/process.c b/arch/alpha/kernel/process.c index 838eac1..89bbe5b 100644 --- a/arch/alpha/kernel/process.c +++ b/arch/alpha/kernel/process.c @@ -200,7 +200,6 @@ show_regs(struct pt_regs *regs) void start_thread(struct pt_regs * regs, unsigned long pc, unsigned long sp) { - set_fs(USER_DS); regs->pc = pc; regs->ps = 8; wrusp(sp); diff --git a/arch/alpha/kernel/smp.c b/arch/alpha/kernel/smp.c index d739703..4087a56 100644 --- a/arch/alpha/kernel/smp.c +++ b/arch/alpha/kernel/smp.c @@ -31,7 +31,7 @@ #include #include -#include +#include #include #include diff --git a/arch/alpha/kernel/sys_ruffian.c b/arch/alpha/kernel/sys_ruffian.c index 8de1046..f33648e 100644 --- a/arch/alpha/kernel/sys_ruffian.c +++ b/arch/alpha/kernel/sys_ruffian.c @@ -26,7 +26,6 @@ #include #include #include -#include #include "proto.h" #include "irq_impl.h" diff --git a/arch/alpha/kernel/time.c b/arch/alpha/kernel/time.c index 818e74e..e336694 100644 --- a/arch/alpha/kernel/time.c +++ b/arch/alpha/kernel/time.c @@ -46,7 +46,6 @@ #include #include #include -#include #include #include @@ -91,7 +90,7 @@ DEFINE_PER_CPU(u8, irq_work_pending); #define test_irq_work_pending() __get_cpu_var(irq_work_pending) #define clear_irq_work_pending() __get_cpu_var(irq_work_pending) = 0 -void set_irq_work_pending(void) +void arch_irq_work_raise(void) { set_irq_work_pending_flag(); } diff --git a/arch/alpha/lib/dec_and_lock.c b/arch/alpha/lib/dec_and_lock.c index 0f5520d..f9f5fe8 100644 --- a/arch/alpha/lib/dec_and_lock.c +++ b/arch/alpha/lib/dec_and_lock.c @@ -6,7 +6,7 @@ */ #include -#include +#include asm (".text \n\ .global _atomic_dec_and_lock \n\ diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index 9adc278..09ebf0b 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig @@ -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) @@ -37,6 +37,9 @@ config ARM Europe. There is an ARM Linux project with a web page at . +config ARM_HAS_SG_CHAIN + bool + config HAVE_PWM bool @@ -239,6 +242,7 @@ config ARCH_INTEGRATOR select ARM_AMBA select ARCH_HAS_CPUFREQ select CLKDEV_LOOKUP + select HAVE_MACH_CLKDEV select ICST select GENERIC_CLOCKEVENTS select PLAT_VERSATILE @@ -250,6 +254,7 @@ config ARCH_REALVIEW bool "ARM Ltd. RealView family" select ARM_AMBA select CLKDEV_LOOKUP + select HAVE_MACH_CLKDEV select ICST select GENERIC_CLOCKEVENTS select ARCH_WANT_OPTIONAL_GPIOLIB @@ -265,6 +270,7 @@ config ARCH_VERSATILE select ARM_AMBA select ARM_VIC select CLKDEV_LOOKUP + select HAVE_MACH_CLKDEV select ICST select GENERIC_CLOCKEVENTS select ARCH_WANT_OPTIONAL_GPIOLIB @@ -281,6 +287,7 @@ config ARCH_VEXPRESS select ARM_AMBA select ARM_TIMER_SP804 select CLKDEV_LOOKUP + select HAVE_MACH_CLKDEV select GENERIC_CLOCKEVENTS select HAVE_CLK select HAVE_PATA_PLATFORM @@ -321,7 +328,7 @@ config ARCH_CLPS711X config ARCH_CNS3XXX bool "Cavium Networks CNS3XXX family" - select CPU_V6 + select CPU_V6K select GENERIC_CLOCKEVENTS select ARM_GIC select MIGHT_HAVE_PCI @@ -337,6 +344,19 @@ config ARCH_GEMINI help Support for the Cortina Systems Gemini family SoCs +config ARCH_PRIMA2 + bool "CSR SiRFSoC PRIMA2 ARM Cortex A9 Platform" + select CPU_V7 + select GENERIC_TIME + select NO_IOPORT + select GENERIC_CLOCKEVENTS + select CLKDEV_LOOKUP + select GENERIC_IRQ_CHIP + select USE_OF + select ZONE_DMA + help + Support for CSR SiRFSoC ARM Cortex A9 Platform + config ARCH_EBSA110 bool "EBSA-110" select CPU_SA110 @@ -376,6 +396,7 @@ config ARCH_MXC select ARCH_REQUIRE_GPIOLIB select CLKDEV_LOOKUP select CLKSRC_MMIO + select GENERIC_IRQ_CHIP select HAVE_SCHED_CLOCK help Support for Freescale MXC/iMX-based family of processors @@ -490,14 +511,6 @@ config ARCH_KIRKWOOD Support for the following Marvell Kirkwood series SoCs: 88F6180, 88F6192 and 88F6281. -config ARCH_LOKI - bool "Marvell Loki (88RC8480)" - select CPU_FEROCEON - select GENERIC_CLOCKEVENTS - select PLAT_ORION - help - Support for the Marvell Loki (88RC8480) SoC. - config ARCH_LPC32XX bool "NXP LPC32XX" select CLKSRC_MMIO @@ -591,7 +604,6 @@ config ARCH_TEGRA select GENERIC_GPIO select HAVE_CLK select HAVE_SCHED_CLOCK - select ARCH_HAS_BARRIERS if CACHE_L2X0 select ARCH_HAS_CPUFREQ help This enables support for NVIDIA Tegra based systems (Tegra APX, @@ -618,6 +630,8 @@ config ARCH_PXA select TICK_ONESHOT select PLAT_PXA select SPARSE_IRQ + select AUTO_ZRELADDR + select MULTI_IRQ_HANDLER help Support for Intel/Marvell's PXA2xx/PXA3xx processor line. @@ -638,10 +652,12 @@ config ARCH_SHMOBILE bool "Renesas SH-Mobile / R-Mobile" select HAVE_CLK select CLKDEV_LOOKUP + select HAVE_MACH_CLKDEV select GENERIC_CLOCKEVENTS select NO_IOPORT select SPARSE_IRQ select MULTI_IRQ_HANDLER + select PM_GENERIC_DOMAINS if PM help Support for Renesas's SH-Mobile and R-Mobile ARM platforms. @@ -682,6 +698,7 @@ config ARCH_S3C2410 select GENERIC_GPIO select ARCH_HAS_CPUFREQ select HAVE_CLK + select CLKDEV_LOOKUP select ARCH_USES_GETTIMEOFFSET select HAVE_S3C2410_I2C if I2C help @@ -699,6 +716,7 @@ config ARCH_S3C64XX select CPU_V6 select ARM_VIC select HAVE_CLK + select CLKDEV_LOOKUP select NO_IOPORT select ARCH_USES_GETTIMEOFFSET select ARCH_HAS_CPUFREQ @@ -723,6 +741,8 @@ config ARCH_S5P64X0 select CPU_V6 select GENERIC_GPIO select HAVE_CLK + select CLKDEV_LOOKUP + select CLKSRC_MMIO select HAVE_S3C2410_WATCHDOG if WATCHDOG select GENERIC_CLOCKEVENTS select HAVE_SCHED_CLOCK @@ -736,6 +756,7 @@ config ARCH_S5PC100 bool "Samsung S5PC100" select GENERIC_GPIO select HAVE_CLK + select CLKDEV_LOOKUP select CPU_V7 select ARM_L1_CACHE_SHIFT_6 select ARCH_USES_GETTIMEOFFSET @@ -749,8 +770,11 @@ config ARCH_S5PV210 bool "Samsung S5PV210/S5PC110" select CPU_V7 select ARCH_SPARSEMEM_ENABLE + select ARCH_HAS_HOLES_MEMORYMODEL select GENERIC_GPIO select HAVE_CLK + select CLKDEV_LOOKUP + select CLKSRC_MMIO select ARM_L1_CACHE_SHIFT_6 select ARCH_HAS_CPUFREQ select GENERIC_CLOCKEVENTS @@ -765,8 +789,10 @@ config ARCH_EXYNOS4 bool "Samsung EXYNOS4" select CPU_V7 select ARCH_SPARSEMEM_ENABLE + select ARCH_HAS_HOLES_MEMORYMODEL select GENERIC_GPIO select HAVE_CLK + select CLKDEV_LOOKUP select ARCH_HAS_CPUFREQ select GENERIC_CLOCKEVENTS select HAVE_S3C_RTC if RTC_CLASS @@ -808,6 +834,7 @@ config ARCH_U300 select ARM_VIC select GENERIC_CLOCKEVENTS select CLKDEV_LOOKUP + select HAVE_MACH_CLKDEV select GENERIC_GPIO help Support for ST-Ericsson U300 series mobile platforms. @@ -852,6 +879,7 @@ config ARCH_OMAP select HAVE_CLK select ARCH_REQUIRE_GPIOLIB select ARCH_HAS_CPUFREQ + select CLKSRC_MMIO select GENERIC_CLOCKEVENTS select HAVE_SCHED_CLOCK select ARCH_HAS_HOLES_MEMORYMODEL @@ -879,6 +907,19 @@ config ARCH_VT8500 select HAVE_PWM help Support for VIA/WonderMedia VT8500/WM85xx System-on-Chip. + +config ARCH_ZYNQ + bool "Xilinx Zynq ARM Cortex A9 Platform" + select CPU_V7 + select GENERIC_TIME + select GENERIC_CLOCKEVENTS + select CLKDEV_LOOKUP + select ARM_GIC + select ARM_AMBA + select ICST + select USE_OF + help + Support for Xilinx Zynq ARM Cortex A9 Platform endchoice # @@ -924,8 +965,6 @@ source "arch/arm/mach-kirkwood/Kconfig" source "arch/arm/mach-ks8695/Kconfig" -source "arch/arm/mach-loki/Kconfig" - source "arch/arm/mach-lpc32xx/Kconfig" source "arch/arm/mach-msm/Kconfig" @@ -969,7 +1008,6 @@ source "arch/arm/plat-spear/Kconfig" source "arch/arm/plat-tcc/Kconfig" if ARCH_S3C2410 -source "arch/arm/mach-s3c2400/Kconfig" source "arch/arm/mach-s3c2410/Kconfig" source "arch/arm/mach-s3c2412/Kconfig" source "arch/arm/mach-s3c2416/Kconfig" @@ -1346,7 +1384,6 @@ config SMP_ON_UP config HAVE_ARM_SCU bool - depends on SMP help This option enables support for the ARM system coherency unit @@ -1715,17 +1752,34 @@ config ZBOOT_ROM Say Y here if you intend to execute your compressed kernel image (zImage) directly from ROM or flash. If unsure, say N. +choice + prompt "Include SD/MMC loader in zImage (EXPERIMENTAL)" + depends on ZBOOT_ROM && ARCH_SH7372 && EXPERIMENTAL + default ZBOOT_ROM_NONE + help + Include experimental SD/MMC loading code in the ROM-able zImage. + With this enabled it is possible to write the the ROM-able zImage + kernel image to an MMC or SD card and boot the kernel straight + from the reset vector. At reset the processor Mask ROM will load + the first part of the the ROM-able zImage which in turn loads the + rest the kernel image to RAM. + +config ZBOOT_ROM_NONE + bool "No SD/MMC loader in zImage (EXPERIMENTAL)" + help + Do not load image from SD or MMC + config ZBOOT_ROM_MMCIF bool "Include MMCIF loader in zImage (EXPERIMENTAL)" - depends on ZBOOT_ROM && ARCH_SH7372 && EXPERIMENTAL help - Say Y here to include experimental MMCIF loading code in the - ROM-able zImage. With this enabled it is possible to write the - the ROM-able zImage kernel image to an MMC card and boot the - kernel straight from the reset vector. At reset the processor - Mask ROM will load the first part of the the ROM-able zImage - which in turn loads the rest the kernel image to RAM using the - MMCIF hardware block. + Load image from MMCIF hardware block. + +config ZBOOT_ROM_SH_MOBILE_SDHI + bool "Include SuperH Mobile SDHI loader in zImage (EXPERIMENTAL)" + help + Load image from SDHI hardware block + +endchoice config CMDLINE string "Default kernel command string" @@ -1875,10 +1929,6 @@ config CPU_FREQ_PXA default y select CPU_FREQ_DEFAULT_GOV_USERSPACE -config CPU_FREQ_S3C64XX - bool "CPUfreq support for Samsung S3C64XX CPUs" - depends on CPU_FREQ && CPU_S3C6410 - config CPU_FREQ_S3C bool help diff --git a/arch/arm/Makefile b/arch/arm/Makefile index f5b2b39..3a4a04b 100644 --- a/arch/arm/Makefile +++ b/arch/arm/Makefile @@ -150,7 +150,6 @@ machine-$(CONFIG_ARCH_IXP23XX) := ixp23xx machine-$(CONFIG_ARCH_IXP4XX) := ixp4xx machine-$(CONFIG_ARCH_KIRKWOOD) := kirkwood machine-$(CONFIG_ARCH_KS8695) := ks8695 -machine-$(CONFIG_ARCH_LOKI) := loki machine-$(CONFIG_ARCH_LPC32XX) := lpc32xx machine-$(CONFIG_ARCH_MMP) := mmp machine-$(CONFIG_ARCH_MSM) := msm @@ -169,11 +168,11 @@ machine-$(CONFIG_ARCH_OMAP3) := omap2 machine-$(CONFIG_ARCH_OMAP4) := omap2 machine-$(CONFIG_ARCH_ORION5X) := orion5x machine-$(CONFIG_ARCH_PNX4008) := pnx4008 +machine-$(CONFIG_ARCH_PRIMA2) := prima2 machine-$(CONFIG_ARCH_PXA) := pxa machine-$(CONFIG_ARCH_REALVIEW) := realview machine-$(CONFIG_ARCH_RPC) := rpc -machine-$(CONFIG_ARCH_S3C2410) := s3c2410 s3c2400 s3c2412 s3c2416 s3c2440 s3c2443 -machine-$(CONFIG_ARCH_S3C24A0) := s3c24a0 +machine-$(CONFIG_ARCH_S3C2410) := s3c2410 s3c2412 s3c2416 s3c2440 s3c2443 machine-$(CONFIG_ARCH_S3C64XX) := s3c64xx machine-$(CONFIG_ARCH_S5P64X0) := s5p64x0 machine-$(CONFIG_ARCH_S5PC100) := s5pc100 @@ -196,6 +195,7 @@ machine-$(CONFIG_MACH_SPEAR300) := spear3xx machine-$(CONFIG_MACH_SPEAR310) := spear3xx machine-$(CONFIG_MACH_SPEAR320) := spear3xx machine-$(CONFIG_MACH_SPEAR600) := spear6xx +machine-$(CONFIG_ARCH_ZYNQ) := zynq # Platform directory name. This list is sorted alphanumerically # by CONFIG_* macro name. @@ -203,6 +203,7 @@ plat-$(CONFIG_ARCH_MXC) := mxc plat-$(CONFIG_ARCH_OMAP) := omap plat-$(CONFIG_ARCH_S3C64XX) := samsung plat-$(CONFIG_ARCH_TCC_926) := tcc +plat-$(CONFIG_ARCH_ZYNQ) := versatile plat-$(CONFIG_PLAT_IOP) := iop plat-$(CONFIG_PLAT_NOMADIK) := nomadik plat-$(CONFIG_PLAT_ORION) := orion diff --git a/arch/arm/boot/compressed/Makefile b/arch/arm/boot/compressed/Makefile index 23aad07..0c74a6f 100644 --- a/arch/arm/boot/compressed/Makefile +++ b/arch/arm/boot/compressed/Makefile @@ -6,13 +6,19 @@ OBJS = -# Ensure that mmcif loader code appears early in the image +# Ensure that MMCIF loader code appears early in the image # to minimise that number of bocks that have to be read in # order to load it. ifeq ($(CONFIG_ZBOOT_ROM_MMCIF),y) -ifeq ($(CONFIG_ARCH_SH7372),y) OBJS += mmcif-sh7372.o endif + +# Ensure that SDHI loader code appears early in the image +# to minimise that number of bocks that have to be read in +# order to load it. +ifeq ($(CONFIG_ZBOOT_ROM_SH_MOBILE_SDHI),y) +OBJS += sdhi-shmobile.o +OBJS += sdhi-sh7372.o endif AFLAGS_head.o += -DTEXT_OFFSET=$(TEXT_OFFSET) diff --git a/arch/arm/boot/compressed/head-shmobile.S b/arch/arm/boot/compressed/head-shmobile.S index c943d2e..fe3719b 100644 --- a/arch/arm/boot/compressed/head-shmobile.S +++ b/arch/arm/boot/compressed/head-shmobile.S @@ -25,14 +25,14 @@ /* load board-specific initialization code */ #include -#ifdef CONFIG_ZBOOT_ROM_MMCIF - /* Load image from MMC */ - adr sp, __tmp_stack + 128 +#if defined(CONFIG_ZBOOT_ROM_MMCIF) || defined(CONFIG_ZBOOT_ROM_SH_MOBILE_SDHI) + /* Load image from MMC/SD */ + adr sp, __tmp_stack + 256 ldr r0, __image_start ldr r1, __image_end subs r1, r1, r0 ldr r0, __load_base - bl mmcif_loader + bl mmc_loader /* Jump to loaded code */ ldr r0, __loaded @@ -51,9 +51,9 @@ __loaded: .long __continue .align __tmp_stack: - .space 128 + .space 256 __continue: -#endif /* CONFIG_ZBOOT_ROM_MMCIF */ +#endif /* CONFIG_ZBOOT_ROM_MMC || CONFIG_ZBOOT_ROM_SH_MOBILE_SDHI */ b 1f __atags:@ tag #1 diff --git a/arch/arm/boot/compressed/head.S b/arch/arm/boot/compressed/head.S index 940b201..e95a598 100644 --- a/arch/arm/boot/compressed/head.S +++ b/arch/arm/boot/compressed/head.S @@ -353,7 +353,8 @@ not_relocated: mov r0, #0 mov r0, #0 @ must be zero mov r1, r7 @ restore architecture number mov r2, r8 @ restore atags pointer - mov pc, r4 @ call kernel + ARM( mov pc, r4 ) @ call kernel + THUMB( bx r4 ) @ entry point is always ARM .align 2 .type LC0, #object diff --git a/arch/arm/boot/compressed/mmcif-sh7372.c b/arch/arm/boot/compressed/mmcif-sh7372.c index 7453c83..b6f61d9 100644 --- a/arch/arm/boot/compressed/mmcif-sh7372.c +++ b/arch/arm/boot/compressed/mmcif-sh7372.c @@ -40,7 +40,7 @@ * to an MMC card * # dd if=vrl4.out of=/dev/sdx bs=512 seek=1 */ -asmlinkage void mmcif_loader(unsigned char *buf, unsigned long len) +asmlinkage void mmc_loader(unsigned char *buf, unsigned long len) { mmc_init_progress(); mmc_update_progress(MMC_PROGRESS_ENTER); diff --git a/arch/arm/boot/compressed/sdhi-sh7372.c b/arch/arm/boot/compressed/sdhi-sh7372.c new file mode 100644 index 0000000..d403a8b --- /dev/null +++ b/arch/arm/boot/compressed/sdhi-sh7372.c @@ -0,0 +1,95 @@ +/* + * SuperH Mobile SDHI + * + * Copyright (C) 2010 Magnus Damm + * Copyright (C) 2010 Kuninori Morimoto + * Copyright (C) 2010 Simon Horman + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Parts inspired by u-boot + */ + +#include +#include +#include +#include + +#include "sdhi-shmobile.h" + +#define PORT179CR 0xe60520b3 +#define PORT180CR 0xe60520b4 +#define PORT181CR 0xe60520b5 +#define PORT182CR 0xe60520b6 +#define PORT183CR 0xe60520b7 +#define PORT184CR 0xe60520b8 + +#define SMSTPCR3 0xe615013c + +#define CR_INPUT_ENABLE 0x10 +#define CR_FUNCTION1 0x01 + +#define SDHI1_BASE (void __iomem *)0xe6860000 +#define SDHI_BASE SDHI1_BASE + +/* SuperH Mobile SDHI loader + * + * loads the zImage from an SD card starting from block 0 + * on physical partition 1 + * + * The image must be start with a vrl4 header and + * the zImage must start at offset 512 of the image. That is, + * at block 1 (=byte 512) of physical partition 1 + * + * Use the following line to write the vrl4 formated zImage + * to an SD card + * # dd if=vrl4.out of=/dev/sdx bs=512 + */ +asmlinkage void mmc_loader(unsigned short *buf, unsigned long len) +{ + int high_capacity; + + mmc_init_progress(); + + mmc_update_progress(MMC_PROGRESS_ENTER); + /* Initialise SDHI1 */ + /* PORT184CR: GPIO_FN_SDHICMD1 Control */ + __raw_writeb(CR_FUNCTION1, PORT184CR); + /* PORT179CR: GPIO_FN_SDHICLK1 Control */ + __raw_writeb(CR_INPUT_ENABLE|CR_FUNCTION1, PORT179CR); + /* PORT181CR: GPIO_FN_SDHID1_3 Control */ + __raw_writeb(CR_FUNCTION1, PORT183CR); + /* PORT182CR: GPIO_FN_SDHID1_2 Control */ + __raw_writeb(CR_FUNCTION1, PORT182CR); + /* PORT183CR: GPIO_FN_SDHID1_1 Control */ + __raw_writeb(CR_FUNCTION1, PORT181CR); + /* PORT180CR: GPIO_FN_SDHID1_0 Control */ + __raw_writeb(CR_FUNCTION1, PORT180CR); + + /* Enable clock to SDHI1 hardware block */ + __raw_writel(__raw_readl(SMSTPCR3) & ~(1 << 13), SMSTPCR3); + + /* setup SDHI hardware */ + mmc_update_progress(MMC_PROGRESS_INIT); + high_capacity = sdhi_boot_init(SDHI_BASE); + if (high_capacity < 0) + goto err; + + mmc_update_progress(MMC_PROGRESS_LOAD); + /* load kernel */ + if (sdhi_boot_do_read(SDHI_BASE, high_capacity, + 0, /* Kernel is at block 1 */ + (len + TMIO_BBS - 1) / TMIO_BBS, buf)) + goto err; + + /* Disable clock to SDHI1 hardware block */ + __raw_writel(__raw_readl(SMSTPCR3) & (1 << 13), SMSTPCR3); + + mmc_update_progress(MMC_PROGRESS_DONE); + + return; +err: + for(;;); +} diff --git a/arch/arm/boot/compressed/sdhi-shmobile.c b/arch/arm/boot/compressed/sdhi-shmobile.c new file mode 100644 index 0000000..bd3d469 --- /dev/null +++ b/arch/arm/boot/compressed/sdhi-shmobile.c @@ -0,0 +1,449 @@ +/* + * SuperH Mobile SDHI + * + * Copyright (C) 2010 Magnus Damm + * Copyright (C) 2010 Kuninori Morimoto + * Copyright (C) 2010 Simon Horman + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Parts inspired by u-boot + */ + +#include +#include +#include +#include +#include +#include +#include + +#define OCR_FASTBOOT (1<<29) +#define OCR_HCS (1<<30) +#define OCR_BUSY (1<<31) + +#define RESP_CMD12 0x00000030 + +static inline u16 sd_ctrl_read16(void __iomem *base, int addr) +{ + return __raw_readw(base + addr); +} + +static inline u32 sd_ctrl_read32(void __iomem *base, int addr) +{ + return __raw_readw(base + addr) | + __raw_readw(base + addr + 2) << 16; +} + +static inline void sd_ctrl_write16(void __iomem *base, int addr, u16 val) +{ + __raw_writew(val, base + addr); +} + +static inline void sd_ctrl_write32(void __iomem *base, int addr, u32 val) +{ + __raw_writew(val, base + addr); + __raw_writew(val >> 16, base + addr + 2); +} + +#define ALL_ERROR (TMIO_STAT_CMD_IDX_ERR | TMIO_STAT_CRCFAIL | \ + TMIO_STAT_STOPBIT_ERR | TMIO_STAT_DATATIMEOUT | \ + TMIO_STAT_RXOVERFLOW | TMIO_STAT_TXUNDERRUN | \ + TMIO_STAT_CMDTIMEOUT | TMIO_STAT_ILL_ACCESS | \ + TMIO_STAT_ILL_FUNC) + +static int sdhi_intr(void __iomem *base) +{ + unsigned long state = sd_ctrl_read32(base, CTL_STATUS); + + if (state & ALL_ERROR) { + sd_ctrl_write32(base, CTL_STATUS, ~ALL_ERROR); + sd_ctrl_write32(base, CTL_IRQ_MASK, + ALL_ERROR | + sd_ctrl_read32(base, CTL_IRQ_MASK)); + return -EINVAL; + } + if (state & TMIO_STAT_CMDRESPEND) { + sd_ctrl_write32(base, CTL_STATUS, ~TMIO_STAT_CMDRESPEND); + sd_ctrl_write32(base, CTL_IRQ_MASK, + TMIO_STAT_CMDRESPEND | + sd_ctrl_read32(base, CTL_IRQ_MASK)); + return 0; + } + if (state & TMIO_STAT_RXRDY) { + sd_ctrl_write32(base, CTL_STATUS, ~TMIO_STAT_RXRDY); + sd_ctrl_write32(base, CTL_IRQ_MASK, + TMIO_STAT_RXRDY | TMIO_STAT_TXUNDERRUN | + sd_ctrl_read32(base, CTL_IRQ_MASK)); + return 0; + } + if (state & TMIO_STAT_DATAEND) { + sd_ctrl_write32(base, CTL_STATUS, ~TMIO_STAT_DATAEND); + sd_ctrl_write32(base, CTL_IRQ_MASK, + TMIO_STAT_DATAEND | + sd_ctrl_read32(base, CTL_IRQ_MASK)); + return 0; + } + + return -EAGAIN; +} + +static int sdhi_boot_wait_resp_end(void __iomem *base) +{ + int err = -EAGAIN, timeout = 10000000; + + while (timeout--) { + err = sdhi_intr(base); + if (err != -EAGAIN) + break; + udelay(1); + } + + return err; +} + +/* SDHI_CLK_CTRL */ +#define CLK_MMC_ENABLE (1 << 8) +#define CLK_MMC_INIT (1 << 6) /* clk / 256 */ + +static void sdhi_boot_mmc_clk_stop(void __iomem *base) +{ + sd_ctrl_write16(base, CTL_CLK_AND_WAIT_CTL, 0x0000); + msleep(10); + sd_ctrl_write16(base, CTL_SD_CARD_CLK_CTL, ~CLK_MMC_ENABLE & + sd_ctrl_read16(base, CTL_SD_CARD_CLK_CTL)); + msleep(10); +} + +static void sdhi_boot_mmc_clk_start(void __iomem *base) +{ + sd_ctrl_write16(base, CTL_SD_CARD_CLK_CTL, CLK_MMC_ENABLE | + sd_ctrl_read16(base, CTL_SD_CARD_CLK_CTL)); + msleep(10); + sd_ctrl_write16(base, CTL_CLK_AND_WAIT_CTL, CLK_MMC_ENABLE); + msleep(10); +} + +static void sdhi_boot_reset(void __iomem *base) +{ + sd_ctrl_write16(base, CTL_RESET_SD, 0x0000); + msleep(10); + sd_ctrl_write16(base, CTL_RESET_SD, 0x0001); + msleep(10); +} + +/* Set MMC clock / power. + * Note: This controller uses a simple divider scheme therefore it cannot + * run a MMC card at full speed (20MHz). The max clock is 24MHz on SD, but as + * MMC wont run that fast, it has to be clocked at 12MHz which is the next + * slowest setting. + */ +static int sdhi_boot_mmc_set_ios(void __iomem *base, struct mmc_ios *ios) +{ + if (sd_ctrl_read32(base, CTL_STATUS) & TMIO_STAT_CMD_BUSY) + return -EBUSY; + + if (ios->clock) + sd_ctrl_write16(base, CTL_SD_CARD_CLK_CTL, + ios->clock | CLK_MMC_ENABLE); + + /* Power sequence - OFF -> ON -> UP */ + switch (ios->power_mode) { + case MMC_POWER_OFF: /* power down SD bus */ + sdhi_boot_mmc_clk_stop(base); + break; + case MMC_POWER_ON: /* power up SD bus */ + break; + case MMC_POWER_UP: /* start bus clock */ + sdhi_boot_mmc_clk_start(base); + break; + } + + switch (ios->bus_width) { + case MMC_BUS_WIDTH_1: + sd_ctrl_write16(base, CTL_SD_MEM_CARD_OPT, 0x80e0); + break; + case MMC_BUS_WIDTH_4: + sd_ctrl_write16(base, CTL_SD_MEM_CARD_OPT, 0x00e0); + break; + } + + /* Let things settle. delay taken from winCE driver */ + udelay(140); + + return 0; +} + +/* These are the bitmasks the tmio chip requires to implement the MMC response + * types. Note that R1 and R6 are the same in this scheme. */ +#define RESP_NONE 0x0300 +#define RESP_R1 0x0400 +#define RESP_R1B 0x0500 +#define RESP_R2 0x0600 +#define RESP_R3 0x0700 +#define DATA_PRESENT 0x0800 +#define TRANSFER_READ 0x1000 + +static int sdhi_boot_request(void __iomem *base, struct mmc_command *cmd) +{ + int err, c = cmd->opcode; + + switch (mmc_resp_type(cmd)) { + case MMC_RSP_NONE: c |= RESP_NONE; break; + case MMC_RSP_R1: c |= RESP_R1; break; + case MMC_RSP_R1B: c |= RESP_R1B; break; + case MMC_RSP_R2: c |= RESP_R2; break; + case MMC_RSP_R3: c |= RESP_R3; break; + default: + return -EINVAL; + } + + /* No interrupts so this may not be cleared */ + sd_ctrl_write32(base, CTL_STATUS, ~TMIO_STAT_CMDRESPEND); + + sd_ctrl_write32(base, CTL_IRQ_MASK, TMIO_STAT_CMDRESPEND | + sd_ctrl_read32(base, CTL_IRQ_MASK)); + sd_ctrl_write32(base, CTL_ARG_REG, cmd->arg); + sd_ctrl_write16(base, CTL_SD_CMD, c); + + + sd_ctrl_write32(base, CTL_IRQ_MASK, + ~(TMIO_STAT_CMDRESPEND | ALL_ERROR) & + sd_ctrl_read32(base, CTL_IRQ_MASK)); + + err = sdhi_boot_wait_resp_end(base); + if (err) + return err; + + cmd->resp[0] = sd_ctrl_read32(base, CTL_RESPONSE); + + return 0; +} + +static int sdhi_boot_do_read_single(void __iomem *base, int high_capacity, + unsigned long block, unsigned short *buf) +{ + int err, i; + + /* CMD17 - Read */ + { + struct mmc_command cmd; + + cmd.opcode = MMC_READ_SINGLE_BLOCK | \ + TRANSFER_READ | DATA_PRESENT; + if (high_capacity) + cmd.arg = block; + else + cmd.arg = block * TMIO_BBS; + cmd.flags = MMC_RSP_R1; + err = sdhi_boot_request(base, &cmd); + if (err) + return err; + } + + sd_ctrl_write32(base, CTL_IRQ_MASK, + ~(TMIO_STAT_DATAEND | TMIO_STAT_RXRDY | + TMIO_STAT_TXUNDERRUN) & + sd_ctrl_read32(base, CTL_IRQ_MASK)); + err = sdhi_boot_wait_resp_end(base); + if (err) + return err; + + sd_ctrl_write16(base, CTL_SD_XFER_LEN, TMIO_BBS); + for (i = 0; i < TMIO_BBS / sizeof(*buf); i++) + *buf++ = sd_ctrl_read16(base, RESP_CMD12); + + err = sdhi_boot_wait_resp_end(base); + if (err) + return err; + + return 0; +} + +int sdhi_boot_do_read(void __iomem *base, int high_capacity, + unsigned long offset, unsigned short count, + unsigned short *buf) +{ + unsigned long i; + int err = 0; + + for (i = 0; i < count; i++) { + err = sdhi_boot_do_read_single(base, high_capacity, offset + i, + buf + (i * TMIO_BBS / + sizeof(*buf))); + if (err) + return err; + } + + return 0; +} + +#define VOLTAGES (MMC_VDD_32_33 | MMC_VDD_33_34) + +int sdhi_boot_init(void __iomem *base) +{ + bool sd_v2 = false, sd_v1_0 = false; + unsigned short cid; + int err, high_capacity = 0; + + sdhi_boot_mmc_clk_stop(base); + sdhi_boot_reset(base); + + /* mmc0: clock 400000Hz busmode 1 powermode 2 cs 0 Vdd 21 width 0 timing 0 */ + { + struct mmc_ios ios; + ios.power_mode = MMC_POWER_ON; + ios.bus_width = MMC_BUS_WIDTH_1; + ios.clock = CLK_MMC_INIT; + err = sdhi_boot_mmc_set_ios(base, &ios); + if (err) + return err; + } + + /* CMD0 */ + { + struct mmc_command cmd; + msleep(1); + cmd.opcode = MMC_GO_IDLE_STATE; + cmd.arg = 0; + cmd.flags = MMC_RSP_NONE; + err = sdhi_boot_request(base, &cmd); + if (err) + return err; + msleep(2); + } + + /* CMD8 - Test for SD version 2 */ + { + struct mmc_command cmd; + cmd.opcode = SD_SEND_IF_COND; + cmd.arg = (VOLTAGES != 0) << 8 | 0xaa; + cmd.flags = MMC_RSP_R1; + err = sdhi_boot_request(base, &cmd); /* Ignore error */ + if ((cmd.resp[0] & 0xff) == 0xaa) + sd_v2 = true; + } + + /* CMD55 - Get OCR (SD) */ + { + int timeout = 1000; + struct mmc_command cmd; + + cmd.arg = 0; + + do { + cmd.opcode = MMC_APP_CMD; + cmd.flags = MMC_RSP_R1; + cmd.arg = 0; + err = sdhi_boot_request(base, &cmd); + if (err) + break; + + cmd.opcode = SD_APP_OP_COND; + cmd.flags = MMC_RSP_R3; + cmd.arg = (VOLTAGES & 0xff8000); + if (sd_v2) + cmd.arg |= OCR_HCS; + cmd.arg |= OCR_FASTBOOT; + err = sdhi_boot_request(base, &cmd); + if (err) + break; + + msleep(1); + } while((!(cmd.resp[0] & OCR_BUSY)) && --timeout); + + if (!err && timeout) { + if (!sd_v2) + sd_v1_0 = true; + high_capacity = (cmd.resp[0] & OCR_HCS) == OCR_HCS; + } + } + + /* CMD1 - Get OCR (MMC) */ + if (!sd_v2 && !sd_v1_0) { + int timeout = 1000; + struct mmc_command cmd; + + do { + cmd.opcode = MMC_SEND_OP_COND; + cmd.arg = VOLTAGES | OCR_HCS; + cmd.flags = MMC_RSP_R3; + err = sdhi_boot_request(base, &cmd); + if (err) + return err; + + msleep(1); + } while((!(cmd.resp[0] & OCR_BUSY)) && --timeout); + + if (!timeout) + return -EAGAIN; + + high_capacity = (cmd.resp[0] & OCR_HCS) == OCR_HCS; + } + + /* CMD2 - Get CID */ + { + struct mmc_command cmd; + cmd.opcode = MMC_ALL_SEND_CID; + cmd.arg = 0; + cmd.flags = MMC_RSP_R2; + err = sdhi_boot_request(base, &cmd); + if (err) + return err; + } + + /* CMD3 + * MMC: Set the relative address + * SD: Get the relative address + * Also puts the card into the standby state + */ + { + struct mmc_command cmd; + cmd.opcode = MMC_SET_RELATIVE_ADDR; + cmd.arg = 0; + cmd.flags = MMC_RSP_R1; + err = sdhi_boot_request(base, &cmd); + if (err) + return err; + cid = cmd.resp[0] >> 16; + } + + /* CMD9 - Get CSD */ + { + struct mmc_command cmd; + cmd.opcode = MMC_SEND_CSD; + cmd.arg = cid << 16; + cmd.flags = MMC_RSP_R2; + err = sdhi_boot_request(base, &cmd); + if (err) + return err; + } + + /* CMD7 - Select the card */ + { + struct mmc_command cmd; + cmd.opcode = MMC_SELECT_CARD; + //cmd.arg = rca << 16; + cmd.arg = cid << 16; + //cmd.flags = MMC_RSP_R1B; + cmd.flags = MMC_RSP_R1; + err = sdhi_boot_request(base, &cmd); + if (err) + return err; + } + + /* CMD16 - Set the block size */ + { + struct mmc_command cmd; + cmd.opcode = MMC_SET_BLOCKLEN; + cmd.arg = TMIO_BBS; + cmd.flags = MMC_RSP_R1; + err = sdhi_boot_request(base, &cmd); + if (err) + return err; + } + + return high_capacity; +} diff --git a/arch/arm/boot/compressed/sdhi-shmobile.h b/arch/arm/boot/compressed/sdhi-shmobile.h new file mode 100644 index 0000000..92eaa09 --- /dev/null +++ b/arch/arm/boot/compressed/sdhi-shmobile.h @@ -0,0 +1,11 @@ +#ifndef SDHI_MOBILE_H +#define SDHI_MOBILE_H + +#include + +int sdhi_boot_do_read(void __iomem *base, int high_capacity, + unsigned long offset, unsigned short count, + unsigned short *buf); +int sdhi_boot_init(void __iomem *base); + +#endif diff --git a/arch/arm/boot/compressed/vmlinux.lds.in b/arch/arm/boot/compressed/vmlinux.lds.in index ea80abe..4e72883 100644 --- a/arch/arm/boot/compressed/vmlinux.lds.in +++ b/arch/arm/boot/compressed/vmlinux.lds.in @@ -33,20 +33,24 @@ SECTIONS *(.text.*) *(.fixup) *(.gnu.warning) + *(.glue_7t) + *(.glue_7) + } + .rodata : { *(.rodata) *(.rodata.*) - *(.glue_7) - *(.glue_7t) + } + .piggydata : { *(.piggydata) - . = ALIGN(4); } + . = ALIGN(4); _etext = .; + .got.plt : { *(.got.plt) } _got_start = .; .got : { *(.got) } _got_end = .; - .got.plt : { *(.got.plt) } _edata = .; . = BSS_START; diff --git a/arch/arm/boot/dts/prima2-cb.dts b/arch/arm/boot/dts/prima2-cb.dts new file mode 100644 index 0000000..6fecc88 --- /dev/null +++ b/arch/arm/boot/dts/prima2-cb.dts @@ -0,0 +1,416 @@ +/dts-v1/; +/ { + model = "SiRF Prima2 eVB"; + compatible = "sirf,prima2-cb", "sirf,prima2"; + #address-cells = <1>; + #size-cells = <1>; + interrupt-parent = <&intc>; + + memory { + reg = <0x00000000 0x20000000>; + }; + + chosen { + bootargs = "mem=512M real_root=/dev/mmcblk0p2 console=ttyS0 panel=1 bootsplash=true bpp=16 androidboot.console=ttyS1"; + linux,stdout-path = &uart1; + }; + + cpus { + #address-cells = <1>; + #size-cells = <0>; + + cpu@0 { + reg = <0x0>; + d-cache-line-size = <32>; + i-cache-line-size = <32>; + d-cache-size = <32768>; + i-cache-size = <32768>; + /* from bootloader */ + timebase-frequency = <0>; + bus-frequency = <0>; + clock-frequency = <0>; + }; + }; + + axi { + compatible = "simple-bus"; + #address-cells = <1>; + #size-cells = <1>; + ranges = <0x40000000 0x40000000 0x80000000>; + + l2-cache-controller@80040000 { + compatible = "arm,pl310-cache"; + reg = <0x80040000 0x1000>; + interrupts = <59>; + }; + + intc: interrupt-controller@80020000 { + #interrupt-cells = <1>; + interrupt-controller; + compatible = "sirf,prima2-intc"; + reg = <0x80020000 0x1000>; + }; + + sys-iobg { + compatible = "simple-bus"; + #address-cells = <1>; + #size-cells = <1>; + ranges = <0x88000000 0x88000000 0x40000>; + + clock-controller@88000000 { + compatible = "sirf,prima2-clkc"; + reg = <0x88000000 0x1000>; + interrupts = <3>; + }; + + reset-controller@88010000 { + compatible = "sirf,prima2-rstc"; + reg = <0x88010000 0x1000>; + }; + }; + + mem-iobg { + compatible = "simple-bus"; + #address-cells = <1>; + #size-cells = <1>; + ranges = <0x90000000 0x90000000 0x10000>; + + memory-controller@90000000 { + compatible = "sirf,prima2-memc"; + reg = <0x90000000 0x10000>; + interrupts = <27>; + }; + }; + + disp-iobg { + compatible = "simple-bus"; + #address-cells = <1>; + #size-cells = <1>; + ranges = <0x90010000 0x90010000 0x30000>; + + display@90010000 { + compatible = "sirf,prima2-lcd"; + reg = <0x90010000 0x20000>; + interrupts = <30>; + }; + + vpp@90020000 { + compatible = "sirf,prima2-vpp"; + reg = <0x90020000 0x10000>; + interrupts = <31>; + }; + }; + + graphics-iobg { + compatible = "simple-bus"; + #address-cells = <1>; + #size-cells = <1>; + ranges = <0x98000000 0x98000000 0x8000000>; + + graphics@98000000 { + compatible = "powervr,sgx531"; + reg = <0x98000000 0x8000000>; + interrupts = <6>; + }; + }; + + multimedia-iobg { + compatible = "simple-bus"; + #address-cells = <1>; + #size-cells = <1>; + ranges = <0xa0000000 0xa0000000 0x8000000>; + + multimedia@a0000000 { + compatible = "sirf,prima2-video-codec"; + reg = <0xa0000000 0x8000000>; + interrupts = <5>; + }; + }; + + dsp-iobg { + compatible = "simple-bus"; + #address-cells = <1>; + #size-cells = <1>; + ranges = <0xa8000000 0xa8000000 0x2000000>; + + dspif@a8000000 { + compatible = "sirf,prima2-dspif"; + reg = <0xa8000000 0x10000>; + interrupts = <9>; + }; + + gps@a8010000 { + compatible = "sirf,prima2-gps"; + reg = <0xa8010000 0x10000>; + interrupts = <7>; + }; + + dsp@a9000000 { + compatible = "sirf,prima2-dsp"; + reg = <0xa9000000 0x1000000>; + interrupts = <8>; + }; + }; + + peri-iobg { + compatible = "simple-bus"; + #address-cells = <1>; + #size-cells = <1>; + ranges = <0xb0000000 0xb0000000 0x180000>; + + timer@b0020000 { + compatible = "sirf,prima2-tick"; + reg = <0xb0020000 0x1000>; + interrupts = <0>; + }; + + nand@b0030000 { + compatible = "sirf,prima2-nand"; + reg = <0xb0030000 0x10000>; + interrupts = <41>; + }; + + audio@b0040000 { + compatible = "sirf,prima2-audio"; + reg = <0xb0040000 0x10000>; + interrupts = <35>; + }; + + uart0: uart@b0050000 { + cell-index = <0>; + compatible = "sirf,prima2-uart"; + reg = <0xb0050000 0x10000>; + interrupts = <17>; + }; + + uart1: uart@b0060000 { + cell-index = <1>; + compatible = "sirf,prima2-uart"; + reg = <0xb0060000 0x10000>; + interrupts = <18>; + }; + + uart2: uart@b0070000 { + cell-index = <2>; + compatible = "sirf,prima2-uart"; + reg = <0xb0070000 0x10000>; + interrupts = <19>; + }; + + usp0: usp@b0080000 { + cell-index = <0>; + compatible = "sirf,prima2-usp"; + reg = <0xb0080000 0x10000>; + interrupts = <20>; + }; + + usp1: usp@b0090000 { + cell-index = <1>; + compatible = "sirf,prima2-usp"; + reg = <0xb0090000 0x10000>; + interrupts = <21>; + }; + + usp2: usp@b00a0000 { + cell-index = <2>; + compatible = "sirf,prima2-usp"; + reg = <0xb00a0000 0x10000>; + interrupts = <22>; + }; + + dmac0: dma-controller@b00b0000 { + cell-index = <0>; + compatible = "sirf,prima2-dmac"; + reg = <0xb00b0000 0x10000>; + interrupts = <12>; + }; + + dmac1: dma-controller@b0160000 { + cell-index = <1>; + compatible = "sirf,prima2-dmac"; + reg = <0xb0160000 0x10000>; + interrupts = <13>; + }; + + vip@b00C0000 { + compatible = "sirf,prima2-vip"; + reg = <0xb00C0000 0x10000>; + }; + + spi0: spi@b00d0000 { + cell-index = <0>; + compatible = "sirf,prima2-spi"; + reg = <0xb00d0000 0x10000>; + interrupts = <15>; + }; + + spi1: spi@b0170000 { + cell-index = <1>; + compatible = "sirf,prima2-spi"; + reg = <0xb0170000 0x10000>; + interrupts = <16>; + }; + + i2c0: i2c@b00e0000 { + cell-index = <0>; + compatible = "sirf,prima2-i2c"; + reg = <0xb00e0000 0x10000>; + interrupts = <24>; + }; + + i2c1: i2c@b00f0000 { + cell-index = <1>; + compatible = "sirf,prima2-i2c"; + reg = <0xb00f0000 0x10000>; + interrupts = <25>; + }; + + tsc@b0110000 { + compatible = "sirf,prima2-tsc"; + reg = <0xb0110000 0x10000>; + interrupts = <33>; + }; + + gpio: gpio-controller@b0120000 { + #gpio-cells = <2>; + #interrupt-cells = <2>; + compatible = "sirf,prima2-gpio"; + reg = <0xb0120000 0x10000>; + gpio-controller; + interrupt-controller; + }; + + pwm@b0130000 { + compatible = "sirf,prima2-pwm"; + reg = <0xb0130000 0x10000>; + }; + + efusesys@b0140000 { + compatible = "sirf,prima2-efuse"; + reg = <0xb0140000 0x10000>; + }; + + pulsec@b0150000 { + compatible = "sirf,prima2-pulsec"; + reg = <0xb0150000 0x10000>; + interrupts = <48>; + }; + + pci-iobg { + compatible = "sirf,prima2-pciiobg", "simple-bus"; + #address-cells = <1>; + #size-cells = <1>; + ranges = <0x56000000 0x56000000 0x1b00000>; + + sd0: sdhci@56000000 { + cell-index = <0>; + compatible = "sirf,prima2-sdhc"; + reg = <0x56000000 0x100000>; + interrupts = <38>; + }; + + sd1: sdhci@56100000 { + cell-index = <1>; + compatible = "sirf,prima2-sdhc"; + reg = <0x56100000 0x100000>; + interrupts = <38>; + }; + + sd2: sdhci@56200000 { + cell-index = <2>; + compatible = "sirf,prima2-sdhc"; + reg = <0x56200000 0x100000>; + interrupts = <23>; + }; + + sd3: sdhci@56300000 { + cell-index = <3>; + compatible = "sirf,prima2-sdhc"; + reg = <0x56300000 0x100000>; + interrupts = <23>; + }; + + sd4: sdhci@56400000 { + cell-index = <4>; + compatible = "sirf,prima2-sdhc"; + reg = <0x56400000 0x100000>; + interrupts = <39>; + }; + + sd5: sdhci@56500000 { + cell-index = <5>; + compatible = "sirf,prima2-sdhc"; + reg = <0x56500000 0x100000>; + interrupts = <39>; + }; + + pci-copy@57900000 { + compatible = "sirf,prima2-pcicp"; + reg = <0x57900000 0x100000>; + interrupts = <40>; + }; + + rom-interface@57a00000 { + compatible = "sirf,prima2-romif"; + reg = <0x57a00000 0x100000>; + }; + }; + }; + + rtc-iobg { + compatible = "sirf,prima2-rtciobg", "simple-bus"; + #address-cells = <1>; + #size-cells = <1>; + reg = <0x80030000 0x10000>; + + gpsrtc@1000 { + compatible = "sirf,prima2-gpsrtc"; + reg = <0x1000 0x1000>; + interrupts = <55 56 57>; + }; + + sysrtc@2000 { + compatible = "sirf,prima2-sysrtc"; + reg = <0x2000 0x1000>; + interrupts = <52 53 54>; + }; + + pwrc@3000 { + compatible = "sirf,prima2-pwrc"; + reg = <0x3000 0x1000>; + interrupts = <32>; + }; + }; + + uus-iobg { + compatible = "simple-bus"; + #address-cells = <1>; + #size-cells = <1>; + ranges = <0xb8000000 0xb8000000 0x40000>; + + usb0: usb@b00e0000 { + compatible = "chipidea,ci13611a-prima2"; + reg = <0xb8000000 0x10000>; + interrupts = <10>; + }; + + usb1: usb@b00f0000 { + compatible = "chipidea,ci13611a-prima2"; + reg = <0xb8010000 0x10000>; + interrupts = <11>; + }; + + sata@b00f0000 { + compatible = "synopsys,dwc-ahsata"; + reg = <0xb8020000 0x10000>; + interrupts = <37>; + }; + + security@b00f0000 { + compatible = "sirf,prima2-security"; + reg = <0xb8030000 0x10000>; + interrupts = <42>; + }; + }; + }; +}; diff --git a/arch/arm/boot/dts/zynq-ep107.dts b/arch/arm/boot/dts/zynq-ep107.dts new file mode 100644 index 0000000..37ca192 --- /dev/null +++ b/arch/arm/boot/dts/zynq-ep107.dts @@ -0,0 +1,52 @@ +/* + * Copyright (C) 2011 Xilinx + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * 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. + */ + +/dts-v1/; +/ { + model = "Xilinx Zynq EP107"; + compatible = "xlnx,zynq-ep107"; + #address-cells = <1>; + #size-cells = <1>; + interrupt-parent = <&intc>; + + memory { + device_type = "memory"; + reg = <0x0 0x10000000>; + }; + + chosen { + bootargs = "console=ttyPS0,9600 root=/dev/ram rw initrd=0x800000,8M earlyprintk"; + linux,stdout-path = &uart0; + }; + + amba { + compatible = "simple-bus"; + #address-cells = <1>; + #size-cells = <1>; + ranges; + + intc: interrupt-controller@f8f01000 { + interrupt-controller; + compatible = "arm,gic"; + reg = <0xF8F01000 0x1000>; + #interrupt-cells = <2>; + }; + + uart0: uart@e0000000 { + compatible = "xlnx,xuartps"; + reg = <0xE0000000 0x1000>; + interrupts = <59 0>; + clock = <50000000>; + }; + }; +}; diff --git a/arch/arm/common/dmabounce.c b/arch/arm/common/dmabounce.c index 841df7d..595ecd2 100644 --- a/arch/arm/common/dmabounce.c +++ b/arch/arm/common/dmabounce.c @@ -79,6 +79,8 @@ struct dmabounce_device_info { struct dmabounce_pool large; rwlock_t lock; + + int (*needs_bounce)(struct device *, dma_addr_t, size_t); }; #ifdef STATS @@ -210,114 +212,91 @@ static struct safe_buffer *find_safe_buffer_dev(struct device *dev, if (!dev || !dev->archdata.dmabounce) return NULL; if (dma_mapping_error(dev, dma_addr)) { - if (dev) - dev_err(dev, "Trying to %s invalid mapping\n", where); - else - pr_err("unknown device: Trying to %s invalid mapping\n", where); + dev_err(dev, "Trying to %s invalid mapping\n", where); return NULL; } return find_safe_buffer(dev->archdata.dmabounce, dma_addr); } -static inline dma_addr_t map_single(struct device *dev, void *ptr, size_t size, - enum dma_data_direction dir) +static int needs_bounce(struct device *dev, dma_addr_t dma_addr, size_t size) { - struct dmabounce_device_info *device_info = dev->archdata.dmabounce; - dma_addr_t dma_addr; - int needs_bounce = 0; - - if (device_info) - DO_STATS ( device_info->map_op_count++ ); - - dma_addr = virt_to_dma(dev, ptr); + if (!dev || !dev->archdata.dmabounce) + return 0; if (dev->dma_mask) { - unsigned long mask = *dev->dma_mask; - unsigned long limit; + unsigned long limit, mask = *dev->dma_mask; limit = (mask + 1) & ~mask; if (limit && size > limit) { dev_err(dev, "DMA mapping too big (requested %#x " "mask %#Lx)\n", size, *dev->dma_mask); - return ~0; + return -E2BIG; } - /* - * Figure out if we need to bounce from the DMA mask. - */ - needs_bounce = (dma_addr | (dma_addr + size - 1)) & ~mask; + /* Figure out if we need to bounce from the DMA mask. */ + if ((dma_addr | (dma_addr + size - 1)) & ~mask) + return 1; } - if (device_info && (needs_bounce || dma_needs_bounce(dev, dma_addr, size))) { - struct safe_buffer *buf; + return !!dev->archdata.dmabounce->needs_bounce(dev, dma_addr, size); +} - buf = alloc_safe_buffer(device_info, ptr, size, dir); - if (buf == 0) { - dev_err(dev, "%s: unable to map unsafe buffer %p!\n", - __func__, ptr); - return ~0; - } +static inline dma_addr_t map_single(struct device *dev, void *ptr, size_t size, + enum dma_data_direction dir) +{ + struct dmabounce_device_info *device_info = dev->archdata.dmabounce; + struct safe_buffer *buf; - dev_dbg(dev, - "%s: unsafe buffer %p (dma=%#x) mapped to %p (dma=%#x)\n", - __func__, buf->ptr, virt_to_dma(dev, buf->ptr), - buf->safe, buf->safe_dma_addr); + if (device_info) + DO_STATS ( device_info->map_op_count++ ); - if ((dir == DMA_TO_DEVICE) || - (dir == DMA_BIDIRECTIONAL)) { - dev_dbg(dev, "%s: copy unsafe %p to safe %p, size %d\n", - __func__, ptr, buf->safe, size); - memcpy(buf->safe, ptr, size); - } - ptr = buf->safe; + buf = alloc_safe_buffer(device_info, ptr, size, dir); + if (buf == NULL) { + dev_err(dev, "%s: unable to map unsafe buffer %p!\n", + __func__, ptr); + return ~0; + } - dma_addr = buf->safe_dma_addr; - } else { - /* - * We don't need to sync the DMA buffer since - * it was allocated via the coherent allocators. - */ - __dma_single_cpu_to_dev(ptr, size, dir); + dev_dbg(dev, "%s: unsafe buffer %p (dma=%#x) mapped to %p (dma=%#x)\n", + __func__, buf->ptr, virt_to_dma(dev, buf->ptr), + buf->safe, buf->safe_dma_addr); + + if (dir == DMA_TO_DEVICE || dir == DMA_BIDIRECTIONAL) { + dev_dbg(dev, "%s: copy unsafe %p to safe %p, size %d\n", + __func__, ptr, buf->safe, size); + memcpy(buf->safe, ptr, size); } - return dma_addr; + return buf->safe_dma_addr; } -static inline void unmap_single(struct device *dev, dma_addr_t dma_addr, +static inline void unmap_single(struct device *dev, struct safe_buffer *buf, size_t size, enum dma_data_direction dir) { - struct safe_buffer *buf = find_safe_buffer_dev(dev, dma_addr, "unmap"); - - if (buf) { - BUG_ON(buf->size != size); - BUG_ON(buf->direction != dir); + BUG_ON(buf->size != size); + BUG_ON(buf->direction != dir); - dev_dbg(dev, - "%s: unsafe buffer %p (dma=%#x) mapped to %p (dma=%#x)\n", - __func__, buf->ptr, virt_to_dma(dev, buf->ptr), - buf->safe, buf->safe_dma_addr); + dev_dbg(dev, "%s: unsafe buffer %p (dma=%#x) mapped to %p (dma=%#x)\n", + __func__, buf->ptr, virt_to_dma(dev, buf->ptr), + buf->safe, buf->safe_dma_addr); - DO_STATS(dev->archdata.dmabounce->bounce_count++); + DO_STATS(dev->archdata.dmabounce->bounce_count++); - if (dir == DMA_FROM_DEVICE || dir == DMA_BIDIRECTIONAL) { - void *ptr = buf->ptr; + if (dir == DMA_FROM_DEVICE || dir == DMA_BIDIRECTIONAL) { + void *ptr = buf->ptr; - dev_dbg(dev, - "%s: copy back safe %p to unsafe %p size %d\n", - __func__, buf->safe, ptr, size); - memcpy(ptr, buf->safe, size); + dev_dbg(dev, "%s: copy back safe %p to unsafe %p size %d\n", + __func__, buf->safe, ptr, size); + memcpy(ptr, buf->safe, size); - /* - * Since we may have written to a page cache page, - * we need to ensure that the data will be coherent - * with user mappings. - */ - __cpuc_flush_dcache_area(ptr, size); - } - free_safe_buffer(dev->archdata.dmabounce, buf); - } else { - __dma_single_dev_to_cpu(dma_to_virt(dev, dma_addr), size, dir); + /* + * Since we may have written to a page cache page, + * we need to ensure that the data will be coherent + * with user mappings. + */ + __cpuc_flush_dcache_area(ptr, size); } + free_safe_buffer(dev->archdata.dmabounce, buf); } /* ************************************************** */ @@ -328,45 +307,28 @@ static inline void unmap_single(struct device *dev, dma_addr_t dma_addr, * substitute the safe buffer for the unsafe one. * (basically move the buffer from an unsafe area to a safe one) */ -dma_addr_t __dma_map_single(struct device *dev, void *ptr, size_t size, - enum dma_data_direction dir) -{ - dev_dbg(dev, "%s(ptr=%p,size=%d,dir=%x)\n", - __func__, ptr, size, dir); - - BUG_ON(!valid_dma_direction(dir)); - - return map_single(dev, ptr, size, dir); -} -EXPORT_SYMBOL(__dma_map_single); - -/* - * see if a mapped address was really a "safe" buffer and if so, copy - * the data from the safe buffer back to the unsafe buffer and free up - * the safe buffer. (basically return things back to the way they - * should be) - */ -void __dma_unmap_single(struct device *dev, dma_addr_t dma_addr, size_t size, - enum dma_data_direction dir) -{ - dev_dbg(dev, "%s(ptr=%p,size=%d,dir=%x)\n", - __func__, (void *) dma_addr, size, dir); - - unmap_single(dev, dma_addr, size, dir); -} -EXPORT_SYMBOL(__dma_unmap_single); - dma_addr_t __dma_map_page(struct device *dev, struct page *page, unsigned long offset, size_t size, enum dma_data_direction dir) { + dma_addr_t dma_addr; + int ret; + dev_dbg(dev, "%s(page=%p,off=%#lx,size=%zx,dir=%x)\n", __func__, page, offset, size, dir); - BUG_ON(!valid_dma_direction(dir)); + dma_addr = pfn_to_dma(dev, page_to_pfn(page)) + offset; + + ret = needs_bounce(dev, dma_addr, size); + if (ret < 0) + return ~0; + + if (ret == 0) { + __dma_page_cpu_to_dev(page, offset, size, dir); + return dma_addr; + } if (PageHighMem(page)) { - dev_err(dev, "DMA buffer bouncing of HIGHMEM pages " - "is not supported\n"); + dev_err(dev, "DMA buffer bouncing of HIGHMEM pages is not supported\n"); return ~0; } @@ -383,10 +345,19 @@ EXPORT_SYMBOL(__dma_map_page); void __dma_unmap_page(struct device *dev, dma_addr_t dma_addr, size_t size, enum dma_data_direction dir) { - dev_dbg(dev, "%s(ptr=%p,size=%d,dir=%x)\n", - __func__, (void *) dma_addr, size, dir); + struct safe_buffer *buf; + + dev_dbg(dev, "%s(dma=%#x,size=%d,dir=%x)\n", + __func__, dma_addr, size, dir); + + buf = find_safe_buffer_dev(dev, dma_addr, __func__); + if (!buf) { + __dma_page_dev_to_cpu(pfn_to_page(dma_to_pfn(dev, dma_addr)), + dma_addr & ~PAGE_MASK, size, dir); + return; + } - unmap_single(dev, dma_addr, size, dir); + unmap_single(dev, buf, size, dir); } EXPORT_SYMBOL(__dma_unmap_page); @@ -461,7 +432,8 @@ static int dmabounce_init_pool(struct dmabounce_pool *pool, struct device *dev, } int dmabounce_register_dev(struct device *dev, unsigned long small_buffer_size, - unsigned long large_buffer_size) + unsigned long large_buffer_size, + int (*needs_bounce_fn)(struct device *, dma_addr_t, size_t)) { struct dmabounce_device_info *device_info; int ret; @@ -497,6 +469,7 @@ int dmabounce_register_dev(struct device *dev, unsigned long small_buffer_size, device_info->dev = dev; INIT_LIST_HEAD(&device_info->safe_buffers); rwlock_init(&device_info->lock); + device_info->needs_bounce = needs_bounce_fn; #ifdef STATS device_info->total_allocs = 0; diff --git a/arch/arm/common/gic.c b/arch/arm/common/gic.c index 4ddd0a6..3227ca9 100644 --- a/arch/arm/common/gic.c +++ b/arch/arm/common/gic.c @@ -38,12 +38,6 @@ static DEFINE_SPINLOCK(irq_controller_lock); /* Address of GIC 0 CPU interface */ void __iomem *gic_cpu_base_addr __read_mostly; -struct gic_chip_data { - unsigned int irq_offset; - void __iomem *dist_base; - void __iomem *cpu_base; -}; - /* * Supported arch specific GIC irq extension. * Default make them NULL. @@ -179,22 +173,21 @@ static int gic_set_affinity(struct irq_data *d, const struct cpumask *mask_val, { void __iomem *reg = gic_dist_base(d) + GIC_DIST_TARGET + (gic_irq(d) & ~3); unsigned int shift = (d->irq % 4) * 8; - unsigned int cpu = cpumask_first(mask_val); + unsigned int cpu = cpumask_any_and(mask_val, cpu_online_mask); u32 val, mask, bit; - if (cpu >= 8) + if (cpu >= 8 || cpu >= nr_cpu_ids) return -EINVAL; mask = 0xff << shift; bit = 1 << (cpu + shift); spin_lock(&irq_controller_lock); - d->node = cpu; val = readl_relaxed(reg) & ~mask; writel_relaxed(val | bit, reg); spin_unlock(&irq_controller_lock); - return 0; + return IRQ_SET_MASK_OK; } #endif diff --git a/arch/arm/common/it8152.c b/arch/arm/common/it8152.c index 7a21927..14ad62e 100644 --- a/arch/arm/common/it8152.c +++ b/arch/arm/common/it8152.c @@ -243,6 +243,12 @@ static struct resource it8152_mem = { * ITE8152 chip can address up to 64MByte, so all the devices * connected to ITE8152 (PCI and USB) should have limited DMA window */ +static int it8152_needs_bounce(struct device *dev, dma_addr_t dma_addr, size_t size) +{ + dev_dbg(dev, "%s: dma_addr %08x, size %08x\n", + __func__, dma_addr, size); + return (dma_addr + size - PHYS_OFFSET) >= SZ_64M; +} /* * Setup DMA mask to 64MB on devices connected to ITE8152. Ignore all @@ -254,7 +260,7 @@ static int it8152_pci_platform_notify(struct device *dev) if (dev->dma_mask) *dev->dma_mask = (SZ_64M - 1) | PHYS_OFFSET; dev->coherent_dma_mask = (SZ_64M - 1) | PHYS_OFFSET; - dmabounce_register_dev(dev, 2048, 4096); + dmabounce_register_dev(dev, 2048, 4096, it8152_needs_bounce); } return 0; } @@ -267,14 +273,6 @@ static int it8152_pci_platform_notify_remove(struct device *dev) return 0; } -int dma_needs_bounce(struct device *dev, dma_addr_t dma_addr, size_t size) -{ - dev_dbg(dev, "%s: dma_addr %08x, size %08x\n", - __func__, dma_addr, size); - return (dev->bus == &pci_bus_type) && - ((dma_addr + size - PHYS_OFFSET) >= SZ_64M); -} - int dma_set_coherent_mask(struct device *dev, u64 mask) { if (mask >= PHYS_OFFSET + SZ_64M - 1) diff --git a/arch/arm/common/sa1111.c b/arch/arm/common/sa1111.c index 9c49a46..0569de6 100644 --- a/arch/arm/common/sa1111.c +++ b/arch/arm/common/sa1111.c @@ -579,7 +579,36 @@ sa1111_configure_smc(struct sa1111 *sachip, int sdram, unsigned int drac, sachip->dev->coherent_dma_mask &= sa1111_dma_mask[drac >> 2]; } +#endif +#ifdef CONFIG_DMABOUNCE +/* + * According to the "Intel StrongARM SA-1111 Microprocessor Companion + * Chip Specification Update" (June 2000), erratum #7, there is a + * significant bug in the SA1111 SDRAM shared memory controller. If + * an access to a region of memory above 1MB relative to the bank base, + * it is important that address bit 10 _NOT_ be asserted. Depending + * on the configuration of the RAM, bit 10 may correspond to one + * of several different (processor-relative) address bits. + * + * This routine only identifies whether or not a given DMA address + * is susceptible to the bug. + * + * This should only get called for sa1111_device types due to the + * way we configure our device dma_masks. + */ +static int sa1111_needs_bounce(struct device *dev, dma_addr_t addr, size_t size) +{ + /* + * Section 4.6 of the "Intel StrongARM SA-1111 Development Module + * User's Guide" mentions that jumpers R51 and R52 control the + * target of SA-1111 DMA (either SDRAM bank 0 on Assabet, or + * SDRAM bank 1 on Neponset). The default configuration selects + * Assabet, so any address in bank 1 is necessarily invalid. + */ + return (machine_is_assabet() || machine_is_pfs168()) && + (addr >= 0xc8000000 || (addr + size) >= 0xc8000000); +} #endif static void sa1111_dev_release(struct device *_dev) @@ -644,7 +673,8 @@ sa1111_init_one_child(struct sa1111 *sachip, struct resource *parent, dev->dev.dma_mask = &dev->dma_mask; if (dev->dma_mask != 0xffffffffUL) { - ret = dmabounce_register_dev(&dev->dev, 1024, 4096); + ret = dmabounce_register_dev(&dev->dev, 1024, 4096, + sa1111_needs_bounce); if (ret) { dev_err(&dev->dev, "SA1111: Failed to register" " with dmabounce\n"); @@ -818,34 +848,6 @@ static void __sa1111_remove(struct sa1111 *sachip) kfree(sachip); } -/* - * According to the "Intel StrongARM SA-1111 Microprocessor Companion - * Chip Specification Update" (June 2000), erratum #7, there is a - * significant bug in the SA1111 SDRAM shared memory controller. If - * an access to a region of memory above 1MB relative to the bank base, - * it is important that address bit 10 _NOT_ be asserted. Depending - * on the configuration of the RAM, bit 10 may correspond to one - * of several different (processor-relative) address bits. - * - * This routine only identifies whether or not a given DMA address - * is susceptible to the bug. - * - * This should only get called for sa1111_device types due to the - * way we configure our device dma_masks. - */ -int dma_needs_bounce(struct device *dev, dma_addr_t addr, size_t size) -{ - /* - * Section 4.6 of the "Intel StrongARM SA-1111 Development Module - * User's Guide" mentions that jumpers R51 and R52 control the - * target of SA-1111 DMA (either SDRAM bank 0 on Assabet, or - * SDRAM bank 1 on Neponset). The default configuration selects - * Assabet, so any address in bank 1 is necessarily invalid. - */ - return ((machine_is_assabet() || machine_is_pfs168()) && - (addr >= 0xc8000000 || (addr + size) >= 0xc8000000)); -} - struct sa1111_save_data { unsigned int skcr; unsigned int skpcr; diff --git a/arch/arm/common/scoop.c b/arch/arm/common/scoop.c index c11af1e..a07b0e7 100644 --- a/arch/arm/common/scoop.c +++ b/arch/arm/common/scoop.c @@ -193,7 +193,7 @@ static int __devinit scoop_probe(struct platform_device *pdev) spin_lock_init(&devptr->scoop_lock); inf = pdev->dev.platform_data; - devptr->base = ioremap(mem->start, mem->end - mem->start + 1); + devptr->base = ioremap(mem->start, resource_size(mem)); if (!devptr->base) { ret = -ENOMEM; diff --git a/arch/arm/configs/cm_x300_defconfig b/arch/arm/configs/cm_x300_defconfig index 921e56a..f4b7672 100644 --- a/arch/arm/configs/cm_x300_defconfig +++ b/arch/arm/configs/cm_x300_defconfig @@ -5,7 +5,6 @@ CONFIG_SYSVIPC=y CONFIG_IKCONFIG=y CONFIG_IKCONFIG_PROC=y CONFIG_LOG_BUF_SHIFT=18 -CONFIG_SYSFS_DEPRECATED_V2=y CONFIG_BLK_DEV_INITRD=y # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set CONFIG_MODULES=y @@ -13,6 +12,7 @@ CONFIG_MODULE_UNLOAD=y CONFIG_MODULE_FORCE_UNLOAD=y # CONFIG_BLK_DEV_BSG is not set CONFIG_ARCH_PXA=y +CONFIG_GPIO_PCA953X=y CONFIG_MACH_CM_X300=y CONFIG_NO_HZ=y CONFIG_AEABI=y @@ -23,7 +23,6 @@ CONFIG_CMDLINE="root=/dev/mtdblock5 rootfstype=ubifs console=ttyS2,38400" CONFIG_CPU_FREQ=y CONFIG_CPU_FREQ_GOV_USERSPACE=y CONFIG_FPE_NWFPE=y -CONFIG_PM=y CONFIG_APM_EMULATION=y CONFIG_NET=y CONFIG_PACKET=y @@ -40,8 +39,8 @@ CONFIG_IP_PNP_RARP=y # CONFIG_INET_DIAG is not set # CONFIG_IPV6 is not set CONFIG_BT=m -CONFIG_BT_L2CAP=m -CONFIG_BT_SCO=m +CONFIG_BT_L2CAP=y +CONFIG_BT_SCO=y CONFIG_BT_RFCOMM=m CONFIG_BT_RFCOMM_TTY=y CONFIG_BT_BNEP=m @@ -60,7 +59,6 @@ CONFIG_MTD_NAND_PXA3xx=y CONFIG_MTD_UBI=y CONFIG_BLK_DEV_LOOP=y CONFIG_BLK_DEV_RAM=y -# CONFIG_MISC_DEVICES is not set CONFIG_SCSI=y CONFIG_BLK_DEV_SD=y CONFIG_NETDEVICES=y @@ -81,16 +79,15 @@ CONFIG_TOUCHSCREEN_WM97XX=m # CONFIG_TOUCHSCREEN_WM9705 is not set # CONFIG_TOUCHSCREEN_WM9713 is not set # CONFIG_SERIO is not set +# CONFIG_LEGACY_PTYS is not set CONFIG_SERIAL_PXA=y CONFIG_SERIAL_PXA_CONSOLE=y -# CONFIG_LEGACY_PTYS is not set # CONFIG_HW_RANDOM is not set CONFIG_I2C=y CONFIG_I2C_PXA=y CONFIG_SPI=y CONFIG_SPI_GPIO=y CONFIG_GPIO_SYSFS=y -CONFIG_GPIO_PCA953X=y # CONFIG_HWMON is not set CONFIG_PMIC_DA903X=y CONFIG_REGULATOR=y @@ -102,7 +99,6 @@ CONFIG_LCD_CLASS_DEVICE=y CONFIG_LCD_TDO24M=y # CONFIG_BACKLIGHT_GENERIC is not set CONFIG_BACKLIGHT_DA903X=m -# CONFIG_VGA_CONSOLE is not set CONFIG_FRAMEBUFFER_CONSOLE=y CONFIG_FRAMEBUFFER_CONSOLE_DETECT_PRIMARY=y CONFIG_FONTS=y @@ -131,7 +127,6 @@ CONFIG_HID_GREENASIA=y CONFIG_HID_SMARTJOYPLUS=y CONFIG_HID_TOPSEED=y CONFIG_HID_THRUSTMASTER=y -CONFIG_HID_WACOM=m CONFIG_HID_ZEROPLUS=y CONFIG_USB=y CONFIG_USB_DEVICEFS=y @@ -152,7 +147,6 @@ CONFIG_RTC_DRV_PXA=y CONFIG_EXT2_FS=y CONFIG_EXT3_FS=y # CONFIG_EXT3_FS_XATTR is not set -CONFIG_INOTIFY=y CONFIG_MSDOS_FS=m CONFIG_VFAT_FS=m CONFIG_TMPFS=y @@ -164,7 +158,6 @@ CONFIG_NFS_V3=y CONFIG_NFS_V3_ACL=y CONFIG_NFS_V4=y CONFIG_ROOT_NFS=y -CONFIG_SMB_FS=m CONFIG_CIFS=m CONFIG_CIFS_WEAK_PW_HASH=y CONFIG_PARTITION_ADVANCED=y @@ -172,9 +165,7 @@ CONFIG_NLS_CODEPAGE_437=m CONFIG_NLS_ISO8859_1=m CONFIG_DEBUG_FS=y CONFIG_DEBUG_KERNEL=y -# CONFIG_DETECT_SOFTLOCKUP is not set # CONFIG_SCHED_DEBUG is not set -# CONFIG_RCU_CPU_STALL_DETECTOR is not set CONFIG_SYSCTL_SYSCALL_CHECK=y # CONFIG_FTRACE is not set CONFIG_DEBUG_USER=y @@ -182,7 +173,6 @@ CONFIG_DEBUG_LL=y CONFIG_CRYPTO_ECB=m CONFIG_CRYPTO_MICHAEL_MIC=m CONFIG_CRYPTO_AES=m -CONFIG_CRYPTO_ARC4=m # CONFIG_CRYPTO_ANSI_CPRNG is not set # CONFIG_CRYPTO_HW is not set CONFIG_CRC_T10DIF=y diff --git a/arch/arm/configs/loki_defconfig b/arch/arm/configs/loki_defconfig deleted file mode 100644 index 1ba752b..0000000 --- a/arch/arm/configs/loki_defconfig +++ /dev/null @@ -1,120 +0,0 @@ -CONFIG_EXPERIMENTAL=y -CONFIG_SYSVIPC=y -CONFIG_LOG_BUF_SHIFT=14 -CONFIG_EXPERT=y -CONFIG_SLAB=y -CONFIG_MODULES=y -CONFIG_MODULE_UNLOAD=y -# CONFIG_BLK_DEV_BSG is not set -CONFIG_ARCH_LOKI=y -CONFIG_MACH_LB88RC8480=y -# CONFIG_CPU_FEROCEON_OLD_ID is not set -CONFIG_NO_HZ=y -CONFIG_HIGH_RES_TIMERS=y -CONFIG_PREEMPT=y -CONFIG_AEABI=y -CONFIG_ZBOOT_ROM_TEXT=0x0 -CONFIG_ZBOOT_ROM_BSS=0x0 -CONFIG_NET=y -CONFIG_PACKET=y -CONFIG_UNIX=y -CONFIG_INET=y -CONFIG_IP_MULTICAST=y -CONFIG_IP_PNP=y -CONFIG_IP_PNP_DHCP=y -CONFIG_IP_PNP_BOOTP=y -# CONFIG_IPV6 is not set -CONFIG_NET_PKTGEN=m -CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug" -CONFIG_MTD=y -CONFIG_MTD_PARTITIONS=y -CONFIG_MTD_CMDLINE_PARTS=y -CONFIG_MTD_CHAR=y -CONFIG_MTD_BLOCK=y -CONFIG_FTL=y -CONFIG_NFTL=y -CONFIG_MTD_CFI=y -CONFIG_MTD_JEDECPROBE=y -CONFIG_MTD_CFI_ADV_OPTIONS=y -CONFIG_MTD_CFI_GEOMETRY=y -CONFIG_MTD_CFI_I4=y -CONFIG_MTD_CFI_INTELEXT=y -CONFIG_MTD_CFI_AMDSTD=y -CONFIG_MTD_CFI_STAA=y -CONFIG_MTD_PHYSMAP=y -CONFIG_MTD_M25P80=y -CONFIG_MTD_NAND=y -CONFIG_MTD_NAND_VERIFY_WRITE=y -CONFIG_MTD_NAND_ORION=y -CONFIG_BLK_DEV_LOOP=y -# CONFIG_MISC_DEVICES is not set -# CONFIG_SCSI_PROC_FS is not set -CONFIG_BLK_DEV_SD=y -CONFIG_BLK_DEV_SR=m -CONFIG_CHR_DEV_SG=m -CONFIG_ATA=y -CONFIG_SATA_MV=y -CONFIG_NETDEVICES=y -CONFIG_NET_ETHERNET=y -CONFIG_MII=y -CONFIG_MV643XX_ETH=y -# CONFIG_NETDEV_10000 is not set -# CONFIG_INPUT_KEYBOARD is not set -# CONFIG_INPUT_MOUSE is not set -# CONFIG_SERIO is not set -CONFIG_SERIAL_8250=y -CONFIG_SERIAL_8250_CONSOLE=y -CONFIG_SERIAL_8250_RUNTIME_UARTS=2 -CONFIG_LEGACY_PTY_COUNT=16 -CONFIG_I2C=y -CONFIG_I2C_CHARDEV=y -CONFIG_I2C_MV64XXX=y -CONFIG_SPI=y -# CONFIG_HWMON is not set -# CONFIG_VGA_CONSOLE is not set -CONFIG_USB=y -CONFIG_USB_DEVICEFS=y -CONFIG_USB_PRINTER=y -CONFIG_USB_STORAGE=y -CONFIG_USB_STORAGE_DATAFAB=y -CONFIG_USB_STORAGE_FREECOM=y -CONFIG_USB_STORAGE_SDDR09=y -CONFIG_USB_STORAGE_SDDR55=y -CONFIG_USB_STORAGE_JUMPSHOT=y -CONFIG_NEW_LEDS=y -CONFIG_EXT2_FS=y -CONFIG_EXT3_FS=y -# CONFIG_EXT3_FS_XATTR is not set -CONFIG_XFS_FS=y -CONFIG_INOTIFY=y -CONFIG_ISO9660_FS=y -CONFIG_UDF_FS=m -CONFIG_MSDOS_FS=y -CONFIG_VFAT_FS=y -CONFIG_TMPFS=y -CONFIG_JFFS2_FS=y -CONFIG_CRAMFS=y -CONFIG_NFS_FS=y -CONFIG_NFS_V3=y -CONFIG_ROOT_NFS=y -CONFIG_PARTITION_ADVANCED=y -CONFIG_BSD_DISKLABEL=y -CONFIG_MINIX_SUBPARTITION=y -CONFIG_SOLARIS_X86_PARTITION=y -CONFIG_UNIXWARE_DISKLABEL=y -CONFIG_LDM_PARTITION=y -CONFIG_LDM_DEBUG=y -CONFIG_SUN_PARTITION=y -CONFIG_NLS_CODEPAGE_437=y -CONFIG_NLS_CODEPAGE_850=y -CONFIG_NLS_ISO8859_1=y -CONFIG_NLS_ISO8859_2=y -CONFIG_MAGIC_SYSRQ=y -CONFIG_SYSCTL_SYSCALL_CHECK=y -CONFIG_DEBUG_USER=y -CONFIG_CRYPTO_CBC=m -CONFIG_CRYPTO_ECB=m -CONFIG_CRYPTO_PCBC=m -CONFIG_CRC_CCITT=y -CONFIG_CRC16=y -CONFIG_LIBCRC32C=y diff --git a/arch/arm/configs/mmp2_defconfig b/arch/arm/configs/mmp2_defconfig index 47ad3b1..5a58452 100644 --- a/arch/arm/configs/mmp2_defconfig +++ b/arch/arm/configs/mmp2_defconfig @@ -8,6 +8,7 @@ CONFIG_MODULE_UNLOAD=y CONFIG_MODULE_FORCE_UNLOAD=y # CONFIG_BLK_DEV_BSG is not set CONFIG_ARCH_MMP=y +CONFIG_MACH_BROWNSTONE=y CONFIG_MACH_FLINT=y CONFIG_MACH_MARVELL_JASPER=y CONFIG_HIGH_RES_TIMERS=y @@ -63,10 +64,16 @@ CONFIG_BACKLIGHT_MAX8925=y # CONFIG_USB_SUPPORT is not set CONFIG_RTC_CLASS=y CONFIG_RTC_DRV_MAX8925=y +CONFIG_MMC=y # CONFIG_DNOTIFY is not set CONFIG_INOTIFY=y CONFIG_TMPFS=y CONFIG_TMPFS_POSIX_ACL=y +CONFIG_EXT2_FS=y +CONFIG_EXT3_FS=y +CONFIG_EXT4_FS=y +CONFIG_MSDOS_FS=y +CONFIG_FAT_DEFAULT_CODEPAGE=437 CONFIG_JFFS2_FS=y CONFIG_CRAMFS=y CONFIG_NFS_FS=y @@ -81,7 +88,7 @@ CONFIG_DEBUG_KERNEL=y # CONFIG_DEBUG_PREEMPT is not set CONFIG_DEBUG_INFO=y # CONFIG_RCU_CPU_STALL_DETECTOR is not set -CONFIG_DYNAMIC_DEBUG=y +# CONFIG_DYNAMIC_DEBUG is not set CONFIG_DEBUG_USER=y CONFIG_DEBUG_ERRORS=y # CONFIG_CRYPTO_ANSI_CPRNG is not set diff --git a/arch/arm/configs/mx51_defconfig b/arch/arm/configs/mx51_defconfig index 0ace16c..88c5802 100644 --- a/arch/arm/configs/mx51_defconfig +++ b/arch/arm/configs/mx51_defconfig @@ -106,6 +106,7 @@ CONFIG_GPIO_SYSFS=y CONFIG_USB=y CONFIG_USB_EHCI_HCD=y CONFIG_USB_EHCI_MXC=y +CONFIG_USB_STORAGE=y CONFIG_MMC=y CONFIG_MMC_BLOCK=m CONFIG_MMC_SDHCI=m @@ -145,7 +146,7 @@ CONFIG_ROOT_NFS=y CONFIG_NLS_DEFAULT="cp437" CONFIG_NLS_CODEPAGE_437=y CONFIG_NLS_ASCII=y -CONFIG_NLS_ISO8859_1=m +CONFIG_NLS_ISO8859_1=y CONFIG_NLS_ISO8859_15=m CONFIG_NLS_UTF8=y CONFIG_MAGIC_SYSRQ=y diff --git a/arch/arm/configs/mxs_defconfig b/arch/arm/configs/mxs_defconfig index 2bf2243..db2cb7d 100644 --- a/arch/arm/configs/mxs_defconfig +++ b/arch/arm/configs/mxs_defconfig @@ -22,6 +22,8 @@ CONFIG_BLK_DEV_INTEGRITY=y # CONFIG_IOSCHED_DEADLINE is not set # CONFIG_IOSCHED_CFQ is not set CONFIG_ARCH_MXS=y +CONFIG_MACH_MX23EVK=y +CONFIG_MACH_MX28EVK=y CONFIG_MACH_STMP378X_DEVB=y CONFIG_MACH_TX28=y # CONFIG_ARM_THUMB is not set @@ -89,7 +91,7 @@ CONFIG_DISPLAY_SUPPORT=m # CONFIG_USB_SUPPORT is not set CONFIG_MMC=y CONFIG_MMC_MXS=y -CONFIG_RTC_CLASS=m +CONFIG_RTC_CLASS=y CONFIG_RTC_DRV_DS1307=m CONFIG_DMADEVICES=y CONFIG_MXS_DMA=y diff --git a/arch/arm/configs/u8500_defconfig b/arch/arm/configs/u8500_defconfig index a5cce24..97d31a4 100644 --- a/arch/arm/configs/u8500_defconfig +++ b/arch/arm/configs/u8500_defconfig @@ -11,12 +11,12 @@ CONFIG_ARCH_U8500=y CONFIG_UX500_SOC_DB5500=y CONFIG_UX500_SOC_DB8500=y CONFIG_MACH_U8500=y +CONFIG_MACH_SNOWBALL=y CONFIG_MACH_U5500=y CONFIG_NO_HZ=y CONFIG_HIGH_RES_TIMERS=y CONFIG_SMP=y CONFIG_NR_CPUS=2 -CONFIG_HOTPLUG_CPU=y CONFIG_PREEMPT=y CONFIG_AEABI=y CONFIG_CMDLINE="root=/dev/ram0 console=ttyAMA2,115200n8" @@ -25,8 +25,13 @@ CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND=y CONFIG_VFP=y CONFIG_NEON=y CONFIG_NET=y +CONFIG_PACKET=y +CONFIG_UNIX=y +CONFIG_INET=y +CONFIG_IP_PNP=y +CONFIG_IP_PNP_DHCP=y +CONFIG_NETFILTER=y CONFIG_PHONET=y -CONFIG_PHONET_PIPECTRLR=y # CONFIG_WIRELESS is not set CONFIG_CAIF=y CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug" @@ -35,6 +40,13 @@ CONFIG_BLK_DEV_RAM_SIZE=65536 CONFIG_MISC_DEVICES=y CONFIG_AB8500_PWM=y CONFIG_SENSORS_BH1780=y +CONFIG_NETDEVICES=y +CONFIG_SMSC_PHY=y +CONFIG_NET_ETHERNET=y +CONFIG_SMSC911X=y +# CONFIG_NETDEV_1000 is not set +# CONFIG_NETDEV_10000 is not set +# CONFIG_WLAN is not set # CONFIG_INPUT_MOUSEDEV_PSAUX is not set CONFIG_INPUT_EVDEV=y # CONFIG_KEYBOARD_ATKBD is not set @@ -49,9 +61,9 @@ CONFIG_INPUT_MISC=y CONFIG_INPUT_AB8500_PONKEY=y # CONFIG_SERIO is not set CONFIG_VT_HW_CONSOLE_BINDING=y +# CONFIG_LEGACY_PTYS is not set CONFIG_SERIAL_AMBA_PL011=y CONFIG_SERIAL_AMBA_PL011_CONSOLE=y -# CONFIG_LEGACY_PTYS is not set CONFIG_HW_RANDOM=y CONFIG_HW_RANDOM_NOMADIK=y CONFIG_I2C=y @@ -64,14 +76,19 @@ CONFIG_GPIO_TC3589X=y CONFIG_MFD_STMPE=y CONFIG_MFD_TC3589X=y CONFIG_AB8500_CORE=y -CONFIG_REGULATOR=y CONFIG_REGULATOR_AB8500=y # CONFIG_HID_SUPPORT is not set -# CONFIG_USB_SUPPORT is not set +CONFIG_USB_MUSB_HDRC=y +CONFIG_USB_GADGET_MUSB_HDRC=y +CONFIG_MUSB_PIO_ONLY=y +CONFIG_USB_GADGET=y +CONFIG_AB8500_USB=y CONFIG_MMC=y +CONFIG_MMC_CLKGATE=y CONFIG_MMC_ARMMMCI=y CONFIG_NEW_LEDS=y CONFIG_LEDS_CLASS=y +CONFIG_LEDS_LM3530=y CONFIG_LEDS_LP5521=y CONFIG_RTC_CLASS=y CONFIG_RTC_DRV_AB8500=y @@ -79,7 +96,6 @@ CONFIG_RTC_DRV_PL031=y CONFIG_DMADEVICES=y CONFIG_STE_DMA40=y CONFIG_STAGING=y -# CONFIG_STAGING_EXCLUDE_BUILD is not set CONFIG_TOUCHSCREEN_SYNAPTICS_I2C_RMI4=y CONFIG_EXT2_FS=y CONFIG_EXT2_FS_XATTR=y @@ -91,6 +107,8 @@ CONFIG_TMPFS=y CONFIG_TMPFS_POSIX_ACL=y CONFIG_CONFIGFS_FS=m # CONFIG_MISC_FILESYSTEMS is not set +CONFIG_NFS_FS=y +CONFIG_ROOT_NFS=y CONFIG_NLS_CODEPAGE_437=y CONFIG_NLS_ISO8859_1=y CONFIG_MAGIC_SYSRQ=y @@ -99,7 +117,5 @@ CONFIG_DEBUG_KERNEL=y # CONFIG_SCHED_DEBUG is not set # CONFIG_DEBUG_PREEMPT is not set CONFIG_DEBUG_INFO=y -# CONFIG_RCU_CPU_STALL_DETECTOR is not set # CONFIG_FTRACE is not set CONFIG_DEBUG_USER=y -CONFIG_DEBUG_ERRORS=y diff --git a/arch/arm/include/asm/assembler.h b/arch/arm/include/asm/assembler.h index 65c3f24..29035e8 100644 --- a/arch/arm/include/asm/assembler.h +++ b/arch/arm/include/asm/assembler.h @@ -293,4 +293,13 @@ .macro ldrusr, reg, ptr, inc, cond=al, rept=1, abort=9001f usracc ldr, \reg, \ptr, \inc, \cond, \rept, \abort .endm + +/* Utility macro for declaring string literals */ + .macro string name:req, string + .type \name , #object +\name: + .asciz "\string" + .size \name , . - \name + .endm + #endif /* __ASM_ASSEMBLER_H__ */ diff --git a/arch/arm/include/asm/atomic.h b/arch/arm/include/asm/atomic.h index 7e79503..86976d0 100644 --- a/arch/arm/include/asm/atomic.h +++ b/arch/arm/include/asm/atomic.h @@ -208,16 +208,15 @@ static inline void atomic_clear_mask(unsigned long mask, unsigned long *addr) #define atomic_xchg(v, new) (xchg(&((v)->counter), new)) -static inline int atomic_add_unless(atomic_t *v, int a, int u) +static inline int __atomic_add_unless(atomic_t *v, int a, int u) { int c, old; c = atomic_read(v); while (c != u && (old = atomic_cmpxchg((v), c, c + a)) != c) c = old; - return c != u; + return c; } -#define atomic_inc_not_zero(v) atomic_add_unless((v), 1, 0) #define atomic_inc(v) atomic_add(1, v) #define atomic_dec(v) atomic_sub(1, v) @@ -460,9 +459,6 @@ static inline int atomic64_add_unless(atomic64_t *v, u64 a, u64 u) #define atomic64_dec_and_test(v) (atomic64_dec_return((v)) == 0) #define atomic64_inc_not_zero(v) atomic64_add_unless((v), 1LL, 0LL) -#else /* !CONFIG_GENERIC_ATOMIC64 */ -#include -#endif -#include +#endif /* !CONFIG_GENERIC_ATOMIC64 */ #endif #endif diff --git a/arch/arm/include/asm/bitops.h b/arch/arm/include/asm/bitops.h index b4892a0..f7419ef 100644 --- a/arch/arm/include/asm/bitops.h +++ b/arch/arm/include/asm/bitops.h @@ -26,8 +26,8 @@ #include #include -#define smp_mb__before_clear_bit() mb() -#define smp_mb__after_clear_bit() mb() +#define smp_mb__before_clear_bit() smp_mb() +#define smp_mb__after_clear_bit() smp_mb() /* * These functions are the basis of our bit ops. @@ -310,10 +310,7 @@ static inline int find_next_bit_le(const void *p, int size, int offset) /* * Ext2 is defined to use little-endian byte ordering. */ -#define ext2_set_bit_atomic(lock, nr, p) \ - test_and_set_bit_le(nr, p) -#define ext2_clear_bit_atomic(lock, nr, p) \ - test_and_clear_bit_le(nr, p) +#include #endif /* __KERNEL__ */ diff --git a/arch/arm/include/asm/clkdev.h b/arch/arm/include/asm/clkdev.h index 765d332..80751c1 100644 --- a/arch/arm/include/asm/clkdev.h +++ b/arch/arm/include/asm/clkdev.h @@ -14,7 +14,12 @@ #include +#ifdef CONFIG_HAVE_MACH_CLKDEV #include +#else +#define __clk_get(clk) ({ 1; }) +#define __clk_put(clk) do { } while (0) +#endif static inline struct clk_lookup_alloc *__clkdev_alloc(size_t size) { diff --git a/arch/arm/include/asm/dma-mapping.h b/arch/arm/include/asm/dma-mapping.h index 4fff837..7a21d0b 100644 --- a/arch/arm/include/asm/dma-mapping.h +++ b/arch/arm/include/asm/dma-mapping.h @@ -115,39 +115,8 @@ static inline void __dma_page_dev_to_cpu(struct page *page, unsigned long off, ___dma_page_dev_to_cpu(page, off, size, dir); } -/* - * Return whether the given device DMA address mask can be supported - * properly. For example, if your device can only drive the low 24-bits - * during bus mastering, then you would pass 0x00ffffff as the mask - * to this function. - * - * FIXME: This should really be a platform specific issue - we should - * return false if GFP_DMA allocations may not satisfy the supplied 'mask'. - */ -static inline int dma_supported(struct device *dev, u64 mask) -{ - if (mask < ISA_DMA_THRESHOLD) - return 0; - return 1; -} - -static inline int dma_set_mask(struct device *dev, u64 dma_mask) -{ -#ifdef CONFIG_DMABOUNCE - if (dev->archdata.dmabounce) { - if (dma_mask >= ISA_DMA_THRESHOLD) - return 0; - else - return -EIO; - } -#endif - if (!dev->dma_mask || !dma_supported(dev, dma_mask)) - return -EIO; - - *dev->dma_mask = dma_mask; - - return 0; -} +extern int dma_supported(struct device *, u64); +extern int dma_set_mask(struct device *, u64); /* * DMA errors are defined by all-bits-set in the DMA address. @@ -256,14 +225,14 @@ int dma_mmap_writecombine(struct device *, struct vm_area_struct *, * @dev: valid struct device pointer * @small_buf_size: size of buffers to use with small buffer pool * @large_buf_size: size of buffers to use with large buffer pool (can be 0) + * @needs_bounce_fn: called to determine whether buffer needs bouncing * * This function should be called by low-level platform code to register * a device as requireing DMA buffer bouncing. The function will allocate * appropriate DMA pools for the device. - * */ extern int dmabounce_register_dev(struct device *, unsigned long, - unsigned long); + unsigned long, int (*)(struct device *, dma_addr_t, size_t)); /** * dmabounce_unregister_dev @@ -277,31 +246,9 @@ extern int dmabounce_register_dev(struct device *, unsigned long, */ extern void dmabounce_unregister_dev(struct device *); -/** - * dma_needs_bounce - * - * @dev: valid struct device pointer - * @dma_handle: dma_handle of unbounced buffer - * @size: size of region being mapped - * - * Platforms that utilize the dmabounce mechanism must implement - * this function. - * - * The dmabounce routines call this function whenever a dma-mapping - * is requested to determine whether a given buffer needs to be bounced - * or not. The function must return 0 if the buffer is OK for - * DMA access and 1 if the buffer needs to be bounced. - * - */ -extern int dma_needs_bounce(struct device*, dma_addr_t, size_t); - /* * The DMA API, implemented by dmabounce.c. See below for descriptions. */ -extern dma_addr_t __dma_map_single(struct device *, void *, size_t, - enum dma_data_direction); -extern void __dma_unmap_single(struct device *, dma_addr_t, size_t, - enum dma_data_direction); extern dma_addr_t __dma_map_page(struct device *, struct page *, unsigned long, size_t, enum dma_data_direction); extern void __dma_unmap_page(struct device *, dma_addr_t, size_t, @@ -328,13 +275,6 @@ static inline int dmabounce_sync_for_device(struct device *d, dma_addr_t addr, } -static inline dma_addr_t __dma_map_single(struct device *dev, void *cpu_addr, - size_t size, enum dma_data_direction dir) -{ - __dma_single_cpu_to_dev(cpu_addr, size, dir); - return virt_to_dma(dev, cpu_addr); -} - static inline dma_addr_t __dma_map_page(struct device *dev, struct page *page, unsigned long offset, size_t size, enum dma_data_direction dir) { @@ -342,12 +282,6 @@ static inline dma_addr_t __dma_map_page(struct device *dev, struct page *page, return pfn_to_dma(dev, page_to_pfn(page)) + offset; } -static inline void __dma_unmap_single(struct device *dev, dma_addr_t handle, - size_t size, enum dma_data_direction dir) -{ - __dma_single_dev_to_cpu(dma_to_virt(dev, handle), size, dir); -} - static inline void __dma_unmap_page(struct device *dev, dma_addr_t handle, size_t size, enum dma_data_direction dir) { @@ -373,14 +307,18 @@ static inline void __dma_unmap_page(struct device *dev, dma_addr_t handle, static inline dma_addr_t dma_map_single(struct device *dev, void *cpu_addr, size_t size, enum dma_data_direction dir) { + unsigned long offset; + struct page *page; dma_addr_t addr; + BUG_ON(!virt_addr_valid(cpu_addr)); + BUG_ON(!virt_addr_valid(cpu_addr + size - 1)); BUG_ON(!valid_dma_direction(dir)); - addr = __dma_map_single(dev, cpu_addr, size, dir); - debug_dma_map_page(dev, virt_to_page(cpu_addr), - (unsigned long)cpu_addr & ~PAGE_MASK, size, - dir, addr, true); + page = virt_to_page(cpu_addr); + offset = (unsigned long)cpu_addr & ~PAGE_MASK; + addr = __dma_map_page(dev, page, offset, size, dir); + debug_dma_map_page(dev, page, offset, size, dir, addr, true); return addr; } @@ -430,7 +368,7 @@ static inline void dma_unmap_single(struct device *dev, dma_addr_t handle, size_t size, enum dma_data_direction dir) { debug_dma_unmap_page(dev, handle, size, dir, true); - __dma_unmap_single(dev, handle, size, dir); + __dma_unmap_page(dev, handle, size, dir); } /** diff --git a/arch/arm/include/asm/dma.h b/arch/arm/include/asm/dma.h index 4200554..628670e 100644 --- a/arch/arm/include/asm/dma.h +++ b/arch/arm/include/asm/dma.h @@ -1,15 +1,16 @@ #ifndef __ASM_ARM_DMA_H #define __ASM_ARM_DMA_H -#include - /* * This is the maximum virtual address which can be DMA'd from. */ -#ifndef ARM_DMA_ZONE_SIZE -#define MAX_DMA_ADDRESS 0xffffffff +#ifndef CONFIG_ZONE_DMA +#define MAX_DMA_ADDRESS 0xffffffffUL #else -#define MAX_DMA_ADDRESS (PAGE_OFFSET + ARM_DMA_ZONE_SIZE) +#define MAX_DMA_ADDRESS ({ \ + extern unsigned long arm_dma_zone_size; \ + arm_dma_zone_size ? \ + (PAGE_OFFSET + arm_dma_zone_size) : 0xffffffffUL; }) #endif #ifdef CONFIG_ISA_DMA_API diff --git a/arch/arm/include/asm/entry-macro-multi.S b/arch/arm/include/asm/entry-macro-multi.S index 2da8547..2f1e209 100644 --- a/arch/arm/include/asm/entry-macro-multi.S +++ b/arch/arm/include/asm/entry-macro-multi.S @@ -4,8 +4,8 @@ * Interrupt handling. Preserves r7, r8, r9 */ .macro arch_irq_handler_default - get_irqnr_preamble r5, lr -1: get_irqnr_and_base r0, r6, r5, lr + get_irqnr_preamble r6, lr +1: get_irqnr_and_base r0, r2, r6, lr movne r1, sp @ @ routine called with r0 = irq number, r1 = struct pt_regs * @@ -17,17 +17,17 @@ /* * XXX * - * this macro assumes that irqstat (r6) and base (r5) are + * this macro assumes that irqstat (r2) and base (r6) are * preserved from get_irqnr_and_base above */ - ALT_SMP(test_for_ipi r0, r6, r5, lr) + ALT_SMP(test_for_ipi r0, r2, r6, lr) ALT_UP_B(9997f) movne r1, sp adrne lr, BSYM(1b) bne do_IPI #ifdef CONFIG_LOCAL_TIMERS - test_for_ltirq r0, r6, r5, lr + test_for_ltirq r0, r2, r6, lr movne r0, sp adrne lr, BSYM(1b) bne do_local_timer @@ -40,7 +40,7 @@ .align 5 .global \symbol_name \symbol_name: - mov r4, lr + mov r8, lr arch_irq_handler_default - mov pc, r4 + mov pc, r8 .endm diff --git a/arch/arm/include/asm/hardware/gic.h b/arch/arm/include/asm/hardware/gic.h index 0691f9d..435d3f8 100644 --- a/arch/arm/include/asm/hardware/gic.h +++ b/arch/arm/include/asm/hardware/gic.h @@ -41,6 +41,12 @@ void gic_secondary_init(unsigned int); void gic_cascade_irq(unsigned int gic_nr, unsigned int irq); void gic_raise_softirq(const struct cpumask *mask, unsigned int irq); void gic_enable_ppi(unsigned int); + +struct gic_chip_data { + unsigned int irq_offset; + void __iomem *dist_base; + void __iomem *cpu_base; +}; #endif #endif diff --git a/arch/arm/include/asm/hardware/scoop.h b/arch/arm/include/asm/hardware/scoop.h index ebb3cea..58cdf5d 100644 --- a/arch/arm/include/asm/hardware/scoop.h +++ b/arch/arm/include/asm/hardware/scoop.h @@ -61,7 +61,6 @@ struct scoop_pcmcia_dev { struct scoop_pcmcia_config { struct scoop_pcmcia_dev *devs; int num_devs; - void (*pcmcia_init)(void); void (*power_ctrl)(struct device *scoop, unsigned short cpr, int nr); }; diff --git a/arch/arm/include/asm/hwcap.h b/arch/arm/include/asm/hwcap.h index c1062c3..c93a22a 100644 --- a/arch/arm/include/asm/hwcap.h +++ b/arch/arm/include/asm/hwcap.h @@ -4,22 +4,26 @@ /* * HWCAP flags - for elf_hwcap (in kernel) and AT_HWCAP */ -#define HWCAP_SWP 1 -#define HWCAP_HALF 2 -#define HWCAP_THUMB 4 -#define HWCAP_26BIT 8 /* Play it safe */ -#define HWCAP_FAST_MULT 16 -#define HWCAP_FPA 32 -#define HWCAP_VFP 64 -#define HWCAP_EDSP 128 -#define HWCAP_JAVA 256 -#define HWCAP_IWMMXT 512 -#define HWCAP_CRUNCH 1024 -#define HWCAP_THUMBEE 2048 -#define HWCAP_NEON 4096 -#define HWCAP_VFPv3 8192 -#define HWCAP_VFPv3D16 16384 -#define HWCAP_TLS 32768 +#define HWCAP_SWP (1 << 0) +#define HWCAP_HALF (1 << 1) +#define HWCAP_THUMB (1 << 2) +#define HWCAP_26BIT (1 << 3) /* Play it safe */ +#define HWCAP_FAST_MULT (1 << 4) +#define HWCAP_FPA (1 << 5) +#define HWCAP_VFP (1 << 6) +#define HWCAP_EDSP (1 << 7) +#define HWCAP_JAVA (1 << 8) +#define HWCAP_IWMMXT (1 << 9) +#define HWCAP_CRUNCH (1 << 10) +#define HWCAP_THUMBEE (1 << 11) +#define HWCAP_NEON (1 << 12) +#define HWCAP_VFPv3 (1 << 13) +#define HWCAP_VFPv3D16 (1 << 14) +#define HWCAP_TLS (1 << 15) +#define HWCAP_VFPv4 (1 << 16) +#define HWCAP_IDIVA (1 << 17) +#define HWCAP_IDIVT (1 << 18) +#define HWCAP_IDIV (HWCAP_IDIVA | HWCAP_IDIVT) #if defined(__KERNEL__) && !defined(__ASSEMBLY__) /* diff --git a/arch/arm/include/asm/i8253.h b/arch/arm/include/asm/i8253.h deleted file mode 100644 index 70656b6..0000000 --- a/arch/arm/include/asm/i8253.h +++ /dev/null @@ -1,15 +0,0 @@ -#ifndef __ASMARM_I8253_H -#define __ASMARM_I8253_H - -/* i8253A PIT registers */ -#define PIT_MODE 0x43 -#define PIT_CH0 0x40 - -#define PIT_LATCH ((PIT_TICK_RATE + HZ / 2) / HZ) - -extern raw_spinlock_t i8253_lock; - -#define outb_pit outb_p -#define inb_pit inb_p - -#endif diff --git a/arch/arm/include/asm/irq.h b/arch/arm/include/asm/irq.h index 2721a58..5a526af 100644 --- a/arch/arm/include/asm/irq.h +++ b/arch/arm/include/asm/irq.h @@ -23,6 +23,7 @@ struct pt_regs; extern void migrate_irqs(void); extern void asm_do_IRQ(unsigned int, struct pt_regs *); +void handle_IRQ(unsigned int, struct pt_regs *); void init_IRQ(void); #endif diff --git a/arch/arm/include/asm/kprobes.h b/arch/arm/include/asm/kprobes.h index e46bdd0..feec867 100644 --- a/arch/arm/include/asm/kprobes.h +++ b/arch/arm/include/asm/kprobes.h @@ -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 */ diff --git a/arch/arm/include/asm/mach/arch.h b/arch/arm/include/asm/mach/arch.h index 946f4d7..3281fb4 100644 --- a/arch/arm/include/asm/mach/arch.h +++ b/arch/arm/include/asm/mach/arch.h @@ -23,6 +23,10 @@ struct machine_desc { unsigned int nr_irqs; /* number of IRQs */ +#ifdef CONFIG_ZONE_DMA + unsigned long dma_zone_size; /* size of DMA-able area */ +#endif + unsigned int video_start; /* start of video RAM */ unsigned int video_end; /* end of video RAM */ diff --git a/arch/arm/include/asm/memory.h b/arch/arm/include/asm/memory.h index af44a8f..b8de516 100644 --- a/arch/arm/include/asm/memory.h +++ b/arch/arm/include/asm/memory.h @@ -204,18 +204,6 @@ static inline unsigned long __phys_to_virt(unsigned long x) #endif /* - * The DMA mask corresponding to the maximum bus address allocatable - * using GFP_DMA. The default here places no restriction on DMA - * allocations. This must be the smallest DMA mask in the system, - * so a successful GFP_DMA allocation will always satisfy this. - */ -#ifndef ARM_DMA_ZONE_SIZE -#define ISA_DMA_THRESHOLD (0xffffffffULL) -#else -#define ISA_DMA_THRESHOLD (PHYS_OFFSET + ARM_DMA_ZONE_SIZE - 1) -#endif - -/* * PFNs are used to describe any physical page; this means * PFN 0 == physical address 0. * diff --git a/arch/arm/include/asm/pci.h b/arch/arm/include/asm/pci.h index 92e2a83..2b1f245 100644 --- a/arch/arm/include/asm/pci.h +++ b/arch/arm/include/asm/pci.h @@ -3,9 +3,19 @@ #ifdef __KERNEL__ #include +#include #include /* for pci_sys_data */ -#include /* for PCIBIOS_MIN_* */ + +extern unsigned long pcibios_min_io; +#define PCIBIOS_MIN_IO pcibios_min_io +extern unsigned long pcibios_min_mem; +#define PCIBIOS_MIN_MEM pcibios_min_mem + +static inline int pcibios_assign_all_busses(void) +{ + return pci_has_flag(PCI_REASSIGN_ALL_RSRC); +} #ifdef CONFIG_PCI_DOMAINS static inline int pci_domain_nr(struct pci_bus *bus) diff --git a/arch/arm/include/asm/perf_event.h b/arch/arm/include/asm/perf_event.h index c4aa4e8..0f8e382 100644 --- a/arch/arm/include/asm/perf_event.h +++ b/arch/arm/include/asm/perf_event.h @@ -24,6 +24,8 @@ enum arm_perf_pmu_ids { ARM_PERF_PMU_ID_V6MP, ARM_PERF_PMU_ID_CA8, ARM_PERF_PMU_ID_CA9, + ARM_PERF_PMU_ID_CA5, + ARM_PERF_PMU_ID_CA15, ARM_NUM_PMU_IDS, }; diff --git a/arch/arm/include/asm/pmu.h b/arch/arm/include/asm/pmu.h index 7544ce6..67c70a3 100644 --- a/arch/arm/include/asm/pmu.h +++ b/arch/arm/include/asm/pmu.h @@ -52,7 +52,7 @@ reserve_pmu(enum arm_pmu_type device); * a cookie. */ extern int -release_pmu(struct platform_device *pdev); +release_pmu(enum arm_pmu_type type); /** * init_pmu() - Initialise the PMU. diff --git a/arch/arm/include/asm/proc-fns.h b/arch/arm/include/asm/proc-fns.h index 8ec535e..633d1cb 100644 --- a/arch/arm/include/asm/proc-fns.h +++ b/arch/arm/include/asm/proc-fns.h @@ -82,13 +82,13 @@ extern void cpu_do_switch_mm(unsigned long pgd_phys, struct mm_struct *mm); extern void cpu_set_pte_ext(pte_t *ptep, pte_t pte, unsigned int ext); extern void cpu_reset(unsigned long addr) __attribute__((noreturn)); #else -#define cpu_proc_init() processor._proc_init() -#define cpu_proc_fin() processor._proc_fin() -#define cpu_reset(addr) processor.reset(addr) -#define cpu_do_idle() processor._do_idle() -#define cpu_dcache_clean_area(addr,sz) processor.dcache_clean_area(addr,sz) -#define cpu_set_pte_ext(ptep,pte,ext) processor.set_pte_ext(ptep,pte,ext) -#define cpu_do_switch_mm(pgd,mm) processor.switch_mm(pgd,mm) +#define cpu_proc_init processor._proc_init +#define cpu_proc_fin processor._proc_fin +#define cpu_reset processor.reset +#define cpu_do_idle processor._do_idle +#define cpu_dcache_clean_area processor.dcache_clean_area +#define cpu_set_pte_ext processor.set_pte_ext +#define cpu_do_switch_mm processor.switch_mm #endif extern void cpu_resume(void); diff --git a/arch/arm/include/asm/ptrace.h b/arch/arm/include/asm/ptrace.h index 312d108..96187ff 100644 --- a/arch/arm/include/asm/ptrace.h +++ b/arch/arm/include/asm/ptrace.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 */ @@ -200,6 +201,14 @@ extern unsigned long profile_pc(struct pt_regs *regs); #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 */ #include diff --git a/arch/arm/include/asm/scatterlist.h b/arch/arm/include/asm/scatterlist.h index 2f87870..cefdb8f 100644 --- a/arch/arm/include/asm/scatterlist.h +++ b/arch/arm/include/asm/scatterlist.h @@ -1,6 +1,10 @@ #ifndef _ASMARM_SCATTERLIST_H #define _ASMARM_SCATTERLIST_H +#ifdef CONFIG_ARM_HAS_SG_CHAIN +#define ARCH_HAS_SG_CHAIN +#endif + #include #include #include diff --git a/arch/arm/include/asm/setup.h b/arch/arm/include/asm/setup.h index ee2ad8a..915696d 100644 --- a/arch/arm/include/asm/setup.h +++ b/arch/arm/include/asm/setup.h @@ -187,12 +187,16 @@ struct tagtable { #define __tag __used __attribute__((__section__(".taglist.init"))) #define __tagtable(tag, fn) \ -static struct tagtable __tagtable_##fn __tag = { tag, fn } +static const struct tagtable __tagtable_##fn __tag = { tag, fn } /* * Memory map description */ -#define NR_BANKS 8 +#ifdef CONFIG_ARCH_EP93XX +# define NR_BANKS 16 +#else +# define NR_BANKS 8 +#endif struct membank { phys_addr_t start; diff --git a/arch/arm/include/asm/suspend.h b/arch/arm/include/asm/suspend.h new file mode 100644 index 0000000..b0e4e1a --- /dev/null +++ b/arch/arm/include/asm/suspend.h @@ -0,0 +1,22 @@ +#ifndef __ASM_ARM_SUSPEND_H +#define __ASM_ARM_SUSPEND_H + +#include +#include + +extern void cpu_resume(void); + +/* + * Hide the first two arguments to __cpu_suspend - these are an implementation + * detail which platform code shouldn't have to know about. + */ +static inline int cpu_suspend(unsigned long arg, int (*fn)(unsigned long)) +{ + extern int __cpu_suspend(int, long, unsigned long, + int (*)(unsigned long)); + int ret = __cpu_suspend(0, PHYS_OFFSET - PAGE_OFFSET, arg, fn); + flush_tlb_all(); + return ret; +} + +#endif diff --git a/arch/arm/include/asm/tcm.h b/arch/arm/include/asm/tcm.h index 5929ef5..8578d72 100644 --- a/arch/arm/include/asm/tcm.h +++ b/arch/arm/include/asm/tcm.h @@ -27,5 +27,7 @@ void *tcm_alloc(size_t len); void tcm_free(void *addr, size_t len); +bool tcm_dtcm_present(void); +bool tcm_itcm_present(void); #endif diff --git a/arch/arm/include/asm/tlbflush.h b/arch/arm/include/asm/tlbflush.h index d2005de..8077145 100644 --- a/arch/arm/include/asm/tlbflush.h +++ b/arch/arm/include/asm/tlbflush.h @@ -34,16 +34,12 @@ #define TLB_V6_D_ASID (1 << 17) #define TLB_V6_I_ASID (1 << 18) -#define TLB_BTB (1 << 28) - /* Unified Inner Shareable TLB operations (ARMv7 MP extensions) */ #define TLB_V7_UIS_PAGE (1 << 19) #define TLB_V7_UIS_FULL (1 << 20) #define TLB_V7_UIS_ASID (1 << 21) -/* Inner Shareable BTB operation (ARMv7 MP extensions) */ -#define TLB_V7_IS_BTB (1 << 22) - +#define TLB_BARRIER (1 << 28) #define TLB_L2CLEAN_FR (1 << 29) /* Feroceon */ #define TLB_DCLEAN (1 << 30) #define TLB_WB (1 << 31) @@ -58,7 +54,7 @@ * v4wb - ARMv4 with write buffer without I TLB flush entry instruction * v4wbi - ARMv4 with write buffer with I TLB flush entry instruction * fr - Feroceon (v4wbi with non-outer-cacheable page table walks) - * fa - Faraday (v4 with write buffer with UTLB and branch target buffer (BTB)) + * fa - Faraday (v4 with write buffer with UTLB) * v6wbi - ARMv6 with write buffer with I TLB flush entry instruction * v7wbi - identical to v6wbi */ @@ -99,7 +95,7 @@ # define v4_always_flags (-1UL) #endif -#define fa_tlb_flags (TLB_WB | TLB_BTB | TLB_DCLEAN | \ +#define fa_tlb_flags (TLB_WB | TLB_DCLEAN | TLB_BARRIER | \ TLB_V4_U_FULL | TLB_V4_U_PAGE) #ifdef CONFIG_CPU_TLB_FA @@ -166,7 +162,7 @@ # define v4wb_always_flags (-1UL) #endif -#define v6wbi_tlb_flags (TLB_WB | TLB_DCLEAN | TLB_BTB | \ +#define v6wbi_tlb_flags (TLB_WB | TLB_DCLEAN | TLB_BARRIER | \ TLB_V6_I_FULL | TLB_V6_D_FULL | \ TLB_V6_I_PAGE | TLB_V6_D_PAGE | \ TLB_V6_I_ASID | TLB_V6_D_ASID) @@ -184,9 +180,9 @@ # define v6wbi_always_flags (-1UL) #endif -#define v7wbi_tlb_flags_smp (TLB_WB | TLB_DCLEAN | TLB_V7_IS_BTB | \ +#define v7wbi_tlb_flags_smp (TLB_WB | TLB_DCLEAN | TLB_BARRIER | \ TLB_V7_UIS_FULL | TLB_V7_UIS_PAGE | TLB_V7_UIS_ASID) -#define v7wbi_tlb_flags_up (TLB_WB | TLB_DCLEAN | TLB_BTB | \ +#define v7wbi_tlb_flags_up (TLB_WB | TLB_DCLEAN | TLB_BARRIER | \ TLB_V6_U_FULL | TLB_V6_U_PAGE | TLB_V6_U_ASID) #ifdef CONFIG_CPU_TLB_V7 @@ -341,15 +337,7 @@ static inline void local_flush_tlb_all(void) if (tlb_flag(TLB_V7_UIS_FULL)) asm("mcr p15, 0, %0, c8, c3, 0" : : "r" (zero) : "cc"); - if (tlb_flag(TLB_BTB)) { - /* flush the branch target cache */ - asm("mcr p15, 0, %0, c7, c5, 6" : : "r" (zero) : "cc"); - dsb(); - isb(); - } - if (tlb_flag(TLB_V7_IS_BTB)) { - /* flush the branch target cache */ - asm("mcr p15, 0, %0, c7, c1, 6" : : "r" (zero) : "cc"); + if (tlb_flag(TLB_BARRIER)) { dsb(); isb(); } @@ -389,17 +377,8 @@ static inline void local_flush_tlb_mm(struct mm_struct *mm) asm("mcr p15, 0, %0, c8, c3, 2" : : "r" (asid) : "cc"); #endif - if (tlb_flag(TLB_BTB)) { - /* flush the branch target cache */ - asm("mcr p15, 0, %0, c7, c5, 6" : : "r" (zero) : "cc"); - dsb(); - } - if (tlb_flag(TLB_V7_IS_BTB)) { - /* flush the branch target cache */ - asm("mcr p15, 0, %0, c7, c1, 6" : : "r" (zero) : "cc"); + if (tlb_flag(TLB_BARRIER)) dsb(); - isb(); - } } static inline void @@ -439,17 +418,8 @@ local_flush_tlb_page(struct vm_area_struct *vma, unsigned long uaddr) asm("mcr p15, 0, %0, c8, c3, 1" : : "r" (uaddr) : "cc"); #endif - if (tlb_flag(TLB_BTB)) { - /* flush the branch target cache */ - asm("mcr p15, 0, %0, c7, c5, 6" : : "r" (zero) : "cc"); - dsb(); - } - if (tlb_flag(TLB_V7_IS_BTB)) { - /* flush the branch target cache */ - asm("mcr p15, 0, %0, c7, c1, 6" : : "r" (zero) : "cc"); + if (tlb_flag(TLB_BARRIER)) dsb(); - isb(); - } } static inline void local_flush_tlb_kernel_page(unsigned long kaddr) @@ -482,15 +452,7 @@ static inline void local_flush_tlb_kernel_page(unsigned long kaddr) if (tlb_flag(TLB_V7_UIS_PAGE)) asm("mcr p15, 0, %0, c8, c3, 1" : : "r" (kaddr) : "cc"); - if (tlb_flag(TLB_BTB)) { - /* flush the branch target cache */ - asm("mcr p15, 0, %0, c7, c5, 6" : : "r" (zero) : "cc"); - dsb(); - isb(); - } - if (tlb_flag(TLB_V7_IS_BTB)) { - /* flush the branch target cache */ - asm("mcr p15, 0, %0, c7, c1, 6" : : "r" (zero) : "cc"); + if (tlb_flag(TLB_BARRIER)) { dsb(); isb(); } diff --git a/arch/arm/include/asm/traps.h b/arch/arm/include/asm/traps.h index f90756d..5b29a66 100644 --- a/arch/arm/include/asm/traps.h +++ b/arch/arm/include/asm/traps.h @@ -3,6 +3,9 @@ #include +struct pt_regs; +struct task_struct; + struct undef_hook { struct list_head node; u32 instr_mask; diff --git a/arch/arm/include/asm/vga.h b/arch/arm/include/asm/vga.h index 250a4dd..91f4021 100644 --- a/arch/arm/include/asm/vga.h +++ b/arch/arm/include/asm/vga.h @@ -2,9 +2,10 @@ #define ASMARM_VGA_H #include -#include -#define VGA_MAP_MEM(x,s) (PCIMEM_BASE + (x)) +extern unsigned long vga_base; + +#define VGA_MAP_MEM(x,s) (vga_base + (x)) #define vga_readb(x) (*((volatile unsigned char *)x)) #define vga_writeb(x,y) (*((volatile unsigned char *)y) = (x)) diff --git a/arch/arm/kernel/Makefile b/arch/arm/kernel/Makefile index a5b31af..f7887dc 100644 --- a/arch/arm/kernel/Makefile +++ b/arch/arm/kernel/Makefile @@ -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 diff --git a/arch/arm/kernel/asm-offsets.c b/arch/arm/kernel/asm-offsets.c index 927522c..16baba2 100644 --- a/arch/arm/kernel/asm-offsets.c +++ b/arch/arm/kernel/asm-offsets.c @@ -59,6 +59,9 @@ int main(void) DEFINE(TI_TP_VALUE, offsetof(struct thread_info, tp_value)); DEFINE(TI_FPSTATE, offsetof(struct thread_info, fpstate)); DEFINE(TI_VFPSTATE, offsetof(struct thread_info, vfpstate)); +#ifdef CONFIG_SMP + DEFINE(VFP_CPU, offsetof(union vfp_state, hard.cpu)); +#endif #ifdef CONFIG_ARM_THUMBEE DEFINE(TI_THUMBEE_STATE, offsetof(struct thread_info, thumbee_state)); #endif diff --git a/arch/arm/kernel/entry-armv.S b/arch/arm/kernel/entry-armv.S index 90c62cd..a87cbf8 100644 --- a/arch/arm/kernel/entry-armv.S +++ b/arch/arm/kernel/entry-armv.S @@ -29,21 +29,53 @@ #include /* - * Interrupt handling. Preserves r7, r8, r9 + * Interrupt handling. */ .macro irq_handler #ifdef CONFIG_MULTI_IRQ_HANDLER - ldr r5, =handle_arch_irq + ldr r1, =handle_arch_irq mov r0, sp - ldr r5, [r5] + ldr r1, [r1] adr lr, BSYM(9997f) - teq r5, #0 - movne pc, r5 + teq r1, #0 + movne pc, r1 #endif arch_irq_handler_default 9997: .endm + .macro pabt_helper + @ PABORT handler takes pt_regs in r2, fault address in r4 and psr in r5 +#ifdef MULTI_PABORT + ldr ip, .LCprocfns + mov lr, pc + ldr pc, [ip, #PROCESSOR_PABT_FUNC] +#else + bl CPU_PABORT_HANDLER +#endif + .endm + + .macro dabt_helper + + @ + @ Call the processor-specific abort handler: + @ + @ r2 - pt_regs + @ r4 - aborted context pc + @ r5 - aborted context psr + @ + @ The abort handler must return the aborted address in r0, and + @ the fault status register in r1. r9 must be preserved. + @ +#ifdef MULTI_DABORT + ldr ip, .LCprocfns + mov lr, pc + ldr pc, [ip, #PROCESSOR_DABT_FUNC] +#else + bl CPU_DABORT_HANDLER +#endif + .endm + #ifdef CONFIG_KPROBES .section .kprobes.text,"ax",%progbits #else @@ -126,106 +158,74 @@ ENDPROC(__und_invalid) SPFIX( subeq sp, sp, #4 ) stmia sp, {r1 - r12} - ldmia r0, {r1 - r3} - add r5, sp, #S_SP - 4 @ here for interlock avoidance - mov r4, #-1 @ "" "" "" "" - add r0, sp, #(S_FRAME_SIZE + \stack_hole - 4) - SPFIX( addeq r0, r0, #4 ) - str r1, [sp, #-4]! @ save the "real" r0 copied + ldmia r0, {r3 - r5} + add r7, sp, #S_SP - 4 @ here for interlock avoidance + mov r6, #-1 @ "" "" "" "" + add r2, sp, #(S_FRAME_SIZE + \stack_hole - 4) + SPFIX( addeq r2, r2, #4 ) + str r3, [sp, #-4]! @ save the "real" r0 copied @ from the exception stack - mov r1, lr + mov r3, lr @ @ We are now ready to fill in the remaining blanks on the stack: @ - @ r0 - sp_svc - @ r1 - lr_svc - @ r2 - lr_, already fixed up for correct return/restart - @ r3 - spsr_ - @ r4 - orig_r0 (see pt_regs definition in ptrace.h) + @ r2 - sp_svc + @ r3 - lr_svc + @ r4 - lr_, already fixed up for correct return/restart + @ r5 - spsr_ + @ r6 - orig_r0 (see pt_regs definition in ptrace.h) @ - stmia r5, {r0 - r4} + stmia r7, {r2 - r6} + +#ifdef CONFIG_TRACE_IRQFLAGS + bl trace_hardirqs_off +#endif .endm .align 5 __dabt_svc: svc_entry - - @ - @ get ready to re-enable interrupts if appropriate - @ - mrs r9, cpsr - tst r3, #PSR_I_BIT - biceq r9, r9, #PSR_I_BIT - - @ - @ Call the processor-specific abort handler: - @ - @ r2 - aborted context pc - @ r3 - aborted context cpsr - @ - @ The abort handler must return the aborted address in r0, and - @ the fault status register in r1. r9 must be preserved. - @ -#ifdef MULTI_DABORT - ldr r4, .LCprocfns - mov lr, pc - ldr pc, [r4, #PROCESSOR_DABT_FUNC] -#else - bl CPU_DABORT_HANDLER -#endif - - @ - @ set desired IRQ state, then call main handler - @ - debug_entry r1 - msr cpsr_c, r9 mov r2, sp - bl do_DataAbort + dabt_helper @ @ IRQs off again before pulling preserved data off the stack @ disable_irq_notrace - @ - @ restore SPSR and restart the instruction - @ - ldr r2, [sp, #S_PSR] - svc_exit r2 @ return from exception +#ifdef CONFIG_TRACE_IRQFLAGS + tst r5, #PSR_I_BIT + bleq trace_hardirqs_on + tst r5, #PSR_I_BIT + blne trace_hardirqs_off +#endif + svc_exit r5 @ return from exception UNWIND(.fnend ) ENDPROC(__dabt_svc) .align 5 __irq_svc: svc_entry + irq_handler -#ifdef CONFIG_TRACE_IRQFLAGS - bl trace_hardirqs_off -#endif #ifdef CONFIG_PREEMPT get_thread_info tsk ldr r8, [tsk, #TI_PREEMPT] @ get preempt count - add r7, r8, #1 @ increment it - str r7, [tsk, #TI_PREEMPT] -#endif - - irq_handler -#ifdef CONFIG_PREEMPT - str r8, [tsk, #TI_PREEMPT] @ restore preempt count ldr r0, [tsk, #TI_FLAGS] @ get flags teq r8, #0 @ if preempt count != 0 movne r0, #0 @ force flags to 0 tst r0, #_TIF_NEED_RESCHED blne svc_preempt #endif - ldr r4, [sp, #S_PSR] @ irqs are already disabled + #ifdef CONFIG_TRACE_IRQFLAGS - tst r4, #PSR_I_BIT - bleq trace_hardirqs_on + @ The parent context IRQs must have been enabled to get here in + @ the first place, so there's no point checking the PSR I bit. + bl trace_hardirqs_on #endif - svc_exit r4 @ return from exception + svc_exit r5 @ return from exception UNWIND(.fnend ) ENDPROC(__irq_svc) @@ -251,7 +251,6 @@ __und_svc: #else svc_entry #endif - @ @ call emulation code, which returns using r9 if it has emulated @ the instruction, or the more conventional lr if we are to treat @@ -260,15 +259,16 @@ __und_svc: @ r0 - instruction @ #ifndef CONFIG_THUMB2_KERNEL - ldr r0, [r2, #-4] + ldr r0, [r4, #-4] #else - ldrh r0, [r2, #-2] @ Thumb instruction at LR - 2 + ldrh r0, [r4, #-2] @ Thumb instruction at LR - 2 and r9, r0, #0xf800 cmp r9, #0xe800 @ 32-bit instruction if xx >= 0 - ldrhhs r9, [r2] @ bottom 16 bits + ldrhhs r9, [r4] @ bottom 16 bits orrhs r0, r9, r0, lsl #16 #endif adr r9, BSYM(1f) + mov r2, r4 bl call_fpe mov r0, sp @ struct pt_regs *regs @@ -282,45 +282,35 @@ __und_svc: @ @ restore SPSR and restart the instruction @ - ldr r2, [sp, #S_PSR] @ Get SVC cpsr - svc_exit r2 @ return from exception + ldr r5, [sp, #S_PSR] @ Get SVC cpsr +#ifdef CONFIG_TRACE_IRQFLAGS + tst r5, #PSR_I_BIT + bleq trace_hardirqs_on + tst r5, #PSR_I_BIT + blne trace_hardirqs_off +#endif + svc_exit r5 @ return from exception UNWIND(.fnend ) ENDPROC(__und_svc) .align 5 __pabt_svc: svc_entry - - @ - @ re-enable interrupts if appropriate - @ - mrs r9, cpsr - tst r3, #PSR_I_BIT - biceq r9, r9, #PSR_I_BIT - - mov r0, r2 @ pass address of aborted instruction. -#ifdef MULTI_PABORT - ldr r4, .LCprocfns - mov lr, pc - ldr pc, [r4, #PROCESSOR_PABT_FUNC] -#else - bl CPU_PABORT_HANDLER -#endif - debug_entry r1 - msr cpsr_c, r9 @ Maybe enable interrupts mov r2, sp @ regs - bl do_PrefetchAbort @ call abort handler + pabt_helper @ @ IRQs off again before pulling preserved data off the stack @ disable_irq_notrace - @ - @ restore SPSR and restart the instruction - @ - ldr r2, [sp, #S_PSR] - svc_exit r2 @ return from exception +#ifdef CONFIG_TRACE_IRQFLAGS + tst r5, #PSR_I_BIT + bleq trace_hardirqs_on + tst r5, #PSR_I_BIT + blne trace_hardirqs_off +#endif + svc_exit r5 @ return from exception UNWIND(.fnend ) ENDPROC(__pabt_svc) @@ -351,23 +341,23 @@ ENDPROC(__pabt_svc) ARM( stmib sp, {r1 - r12} ) THUMB( stmia sp, {r0 - r12} ) - ldmia r0, {r1 - r3} + ldmia r0, {r3 - r5} add r0, sp, #S_PC @ here for interlock avoidance - mov r4, #-1 @ "" "" "" "" + mov r6, #-1 @ "" "" "" "" - str r1, [sp] @ save the "real" r0 copied + str r3, [sp] @ save the "real" r0 copied @ from the exception stack @ @ We are now ready to fill in the remaining blanks on the stack: @ - @ r2 - lr_, already fixed up for correct return/restart - @ r3 - spsr_ - @ r4 - orig_r0 (see pt_regs definition in ptrace.h) + @ r4 - lr_, already fixed up for correct return/restart + @ r5 - spsr_ + @ r6 - orig_r0 (see pt_regs definition in ptrace.h) @ @ Also, separately save sp_usr and lr_usr @ - stmia r0, {r2 - r4} + stmia r0, {r4 - r6} ARM( stmdb r0, {sp, lr}^ ) THUMB( store_user_sp_lr r0, r1, S_SP - S_PC ) @@ -380,10 +370,14 @@ ENDPROC(__pabt_svc) @ Clear FP to mark the first stack frame @ zero_fp + +#ifdef CONFIG_IRQSOFF_TRACER + bl trace_hardirqs_off +#endif .endm .macro kuser_cmpxchg_check -#if __LINUX_ARM_ARCH__ < 6 && !defined(CONFIG_NEEDS_SYSCALL_FOR_CMPXCHG) +#if !defined(CONFIG_CPU_32v6K) && !defined(CONFIG_NEEDS_SYSCALL_FOR_CMPXCHG) #ifndef CONFIG_MMU #warning "NPTL on non MMU needs fixing" #else @@ -391,8 +385,8 @@ ENDPROC(__pabt_svc) @ if it was interrupted in a critical region. Here we @ perform a quick test inline since it should be false @ 99.9999% of the time. The rest is done out of line. - cmp r2, #TASK_SIZE - blhs kuser_cmpxchg_fixup + cmp r4, #TASK_SIZE + blhs kuser_cmpxchg64_fixup #endif #endif .endm @@ -401,32 +395,9 @@ ENDPROC(__pabt_svc) __dabt_usr: usr_entry kuser_cmpxchg_check - - @ - @ Call the processor-specific abort handler: - @ - @ r2 - aborted context pc - @ r3 - aborted context cpsr - @ - @ The abort handler must return the aborted address in r0, and - @ the fault status register in r1. - @ -#ifdef MULTI_DABORT - ldr r4, .LCprocfns - mov lr, pc - ldr pc, [r4, #PROCESSOR_DABT_FUNC] -#else - bl CPU_DABORT_HANDLER -#endif - - @ - @ IRQs on, then call the main handler - @ - debug_entry r1 - enable_irq mov r2, sp - adr lr, BSYM(ret_from_exception) - b do_DataAbort + dabt_helper + b ret_from_exception UNWIND(.fnend ) ENDPROC(__dabt_usr) @@ -434,28 +405,8 @@ ENDPROC(__dabt_usr) __irq_usr: usr_entry kuser_cmpxchg_check - -#ifdef CONFIG_IRQSOFF_TRACER - bl trace_hardirqs_off -#endif - - get_thread_info tsk -#ifdef CONFIG_PREEMPT - ldr r8, [tsk, #TI_PREEMPT] @ get preempt count - add r7, r8, #1 @ increment it - str r7, [tsk, #TI_PREEMPT] -#endif - irq_handler -#ifdef CONFIG_PREEMPT - ldr r0, [tsk, #TI_PREEMPT] - str r8, [tsk, #TI_PREEMPT] - teq r0, r7 - ARM( strne r0, [r0, -r0] ) - THUMB( movne r0, #0 ) - THUMB( strne r0, [r0] ) -#endif - + get_thread_info tsk mov why, #0 b ret_to_user_from_irq UNWIND(.fnend ) @@ -467,6 +418,9 @@ ENDPROC(__irq_usr) __und_usr: usr_entry + mov r2, r4 + mov r3, r5 + @ @ fall through to the emulation code, which returns using r9 if @ it has emulated the instruction, or the more conventional lr @@ -682,19 +636,8 @@ ENDPROC(__und_usr_unknown) .align 5 __pabt_usr: usr_entry - - mov r0, r2 @ pass address of aborted instruction. -#ifdef MULTI_PABORT - ldr r4, .LCprocfns - mov lr, pc - ldr pc, [r4, #PROCESSOR_PABT_FUNC] -#else - bl CPU_PABORT_HANDLER -#endif - debug_entry r1 - enable_irq @ Enable interrupts mov r2, sp @ regs - bl do_PrefetchAbort @ call abort handler + pabt_helper UNWIND(.fnend ) /* fall through */ /* @@ -758,31 +701,12 @@ ENDPROC(__switch_to) /* * User helpers. * - * These are segment of kernel provided user code reachable from user space - * at a fixed address in kernel memory. This is used to provide user space - * with some operations which require kernel help because of unimplemented - * native feature and/or instructions in many ARM CPUs. The idea is for - * this code to be executed directly in user mode for best efficiency but - * which is too intimate with the kernel counter part to be left to user - * libraries. In fact this code might even differ from one CPU to another - * depending on the available instruction set and restrictions like on - * SMP systems. In other words, the kernel reserves the right to change - * this code as needed without warning. Only the entry points and their - * results are guaranteed to be stable. - * * Each segment is 32-byte aligned and will be moved to the top of the high * vector page. New segments (if ever needed) must be added in front of * existing ones. This mechanism should be used only for things that are * really small and justified, and not be abused freely. * - * User space is expected to implement those things inline when optimizing - * for a processor that has the necessary native support, but only if such - * resulting binaries are already to be incompatible with earlier ARM - * processors due to the use of unsupported instructions other than what - * is provided here. In other words don't make binaries unable to run on - * earlier processors just for the sake of not using these kernel helpers - * if your compiled code is not going to use the new instructions for other - * purpose. + * See Documentation/arm/kernel_user_helpers.txt for formal definitions. */ THUMB( .arm ) @@ -799,96 +723,103 @@ ENDPROC(__switch_to) __kuser_helper_start: /* - * Reference prototype: - * - * void __kernel_memory_barrier(void) - * - * Input: - * - * lr = return address - * - * Output: - * - * none - * - * Clobbered: - * - * none - * - * Definition and user space usage example: - * - * typedef void (__kernel_dmb_t)(void); - * #define __kernel_dmb (*(__kernel_dmb_t *)0xffff0fa0) - * - * Apply any needed memory barrier to preserve consistency with data modified - * manually and __kuser_cmpxchg usage. - * - * This could be used as follows: - * - * #define __kernel_dmb() \ - * asm volatile ( "mov r0, #0xffff0fff; mov lr, pc; sub pc, r0, #95" \ - * : : : "r0", "lr","cc" ) + * Due to the length of some sequences, __kuser_cmpxchg64 spans 2 regular + * kuser "slots", therefore 0xffff0f80 is not used as a valid entry point. */ -__kuser_memory_barrier: @ 0xffff0fa0 +__kuser_cmpxchg64: @ 0xffff0f60 + +#if defined(CONFIG_NEEDS_SYSCALL_FOR_CMPXCHG) + + /* + * Poor you. No fast solution possible... + * The kernel itself must perform the operation. + * A special ghost syscall is used for that (see traps.c). + */ + stmfd sp!, {r7, lr} + ldr r7, 1f @ it's 20 bits + swi __ARM_NR_cmpxchg64 + ldmfd sp!, {r7, pc} +1: .word __ARM_NR_cmpxchg64 + +#elif defined(CONFIG_CPU_32v6K) + + stmfd sp!, {r4, r5, r6, r7} + ldrd r4, r5, [r0] @ load old val + ldrd r6, r7, [r1] @ load new val + smp_dmb arm +1: ldrexd r0, r1, [r2] @ load current val + eors r3, r0, r4 @ compare with oldval (1) + eoreqs r3, r1, r5 @ compare with oldval (2) + strexdeq r3, r6, r7, [r2] @ store newval if eq + teqeq r3, #1 @ success? + beq 1b @ if no then retry smp_dmb arm + rsbs r0, r3, #0 @ set returned val and C flag + ldmfd sp!, {r4, r5, r6, r7} + bx lr + +#elif !defined(CONFIG_SMP) + +#ifdef CONFIG_MMU + + /* + * The only thing that can break atomicity in this cmpxchg64 + * implementation is either an IRQ or a data abort exception + * causing another process/thread to be scheduled in the middle of + * the critical sequence. The same strategy as for cmpxchg is used. + */ + stmfd sp!, {r4, r5, r6, lr} + ldmia r0, {r4, r5} @ load old val + ldmia r1, {r6, lr} @ load new val +1: ldmia r2, {r0, r1} @ load current val + eors r3, r0, r4 @ compare with oldval (1) + eoreqs r3, r1, r5 @ compare with oldval (2) +2: stmeqia r2, {r6, lr} @ store newval if eq + rsbs r0, r3, #0 @ set return val and C flag + ldmfd sp!, {r4, r5, r6, pc} + + .text +kuser_cmpxchg64_fixup: + @ Called from kuser_cmpxchg_fixup. + @ r4 = address of interrupted insn (must be preserved). + @ sp = saved regs. r7 and r8 are clobbered. + @ 1b = first critical insn, 2b = last critical insn. + @ If r4 >= 1b and r4 <= 2b then saved pc_usr is set to 1b. + mov r7, #0xffff0fff + sub r7, r7, #(0xffff0fff - (0xffff0f60 + (1b - __kuser_cmpxchg64))) + subs r8, r4, r7 + rsbcss r8, r8, #(2b - 1b) + strcs r7, [sp, #S_PC] +#if __LINUX_ARM_ARCH__ < 6 + bcc kuser_cmpxchg32_fixup +#endif + mov pc, lr + .previous + +#else +#warning "NPTL on non MMU needs fixing" + mov r0, #-1 + adds r0, r0, #0 usr_ret lr +#endif + +#else +#error "incoherent kernel configuration" +#endif + + /* pad to next slot */ + .rept (16 - (. - __kuser_cmpxchg64)/4) + .word 0 + .endr .align 5 -/* - * Reference prototype: - * - * int __kernel_cmpxchg(int oldval, int newval, int *ptr) - * - * Input: - * - * r0 = oldval - * r1 = newval - * r2 = ptr - * lr = return address - * - * Output: - * - * r0 = returned value (zero or non-zero) - * C flag = set if r0 == 0, clear if r0 != 0 - * - * Clobbered: - * - * r3, ip, flags - * - * Definition and user space usage example: - * - * typedef int (__kernel_cmpxchg_t)(int oldval, int newval, int *ptr); - * #define __kernel_cmpxchg (*(__kernel_cmpxchg_t *)0xffff0fc0) - * - * Atomically store newval in *ptr if *ptr is equal to oldval for user space. - * Return zero if *ptr was changed or non-zero if no exchange happened. - * The C flag is also set if *ptr was changed to allow for assembly - * optimization in the calling code. - * - * Notes: - * - * - This routine already includes memory barriers as needed. - * - * For example, a user space atomic_add implementation could look like this: - * - * #define atomic_add(ptr, val) \ - * ({ register unsigned int *__ptr asm("r2") = (ptr); \ - * register unsigned int __result asm("r1"); \ - * asm volatile ( \ - * "1: @ atomic_add\n\t" \ - * "ldr r0, [r2]\n\t" \ - * "mov r3, #0xffff0fff\n\t" \ - * "add lr, pc, #4\n\t" \ - * "add r1, r0, %2\n\t" \ - * "add pc, r3, #(0xffff0fc0 - 0xffff0fff)\n\t" \ - * "bcc 1b" \ - * : "=&r" (__result) \ - * : "r" (__ptr), "rIL" (val) \ - * : "r0","r3","ip","lr","cc","memory" ); \ - * __result; }) - */ +__kuser_memory_barrier: @ 0xffff0fa0 + smp_dmb arm + usr_ret lr + + .align 5 __kuser_cmpxchg: @ 0xffff0fc0 @@ -925,15 +856,15 @@ __kuser_cmpxchg: @ 0xffff0fc0 usr_ret lr .text -kuser_cmpxchg_fixup: +kuser_cmpxchg32_fixup: @ Called from kuser_cmpxchg_check macro. - @ r2 = address of interrupted insn (must be preserved). + @ r4 = address of interrupted insn (must be preserved). @ sp = saved regs. r7 and r8 are clobbered. @ 1b = first critical insn, 2b = last critical insn. - @ If r2 >= 1b and r2 <= 2b then saved pc_usr is set to 1b. + @ If r4 >= 1b and r4 <= 2b then saved pc_usr is set to 1b. mov r7, #0xffff0fff sub r7, r7, #(0xffff0fff - (0xffff0fc0 + (1b - __kuser_cmpxchg))) - subs r8, r2, r7 + subs r8, r4, r7 rsbcss r8, r8, #(2b - 1b) strcs r7, [sp, #S_PC] mov pc, lr @@ -963,39 +894,6 @@ kuser_cmpxchg_fixup: .align 5 -/* - * Reference prototype: - * - * int __kernel_get_tls(void) - * - * Input: - * - * lr = return address - * - * Output: - * - * r0 = TLS value - * - * Clobbered: - * - * none - * - * Definition and user space usage example: - * - * typedef int (__kernel_get_tls_t)(void); - * #define __kernel_get_tls (*(__kernel_get_tls_t *)0xffff0fe0) - * - * Get the TLS value as previously set via the __ARM_NR_set_tls syscall. - * - * This could be used as follows: - * - * #define __kernel_get_tls() \ - * ({ register unsigned int __val asm("r0"); \ - * asm( "mov r0, #0xffff0fff; mov lr, pc; sub pc, r0, #31" \ - * : "=r" (__val) : : "lr","cc" ); \ - * __val; }) - */ - __kuser_get_tls: @ 0xffff0fe0 ldr r0, [pc, #(16 - 8)] @ read TLS, set in kuser_get_tls_init usr_ret lr @@ -1004,19 +902,6 @@ __kuser_get_tls: @ 0xffff0fe0 .word 0 @ 0xffff0ff0 software TLS value, then .endr @ pad up to __kuser_helper_version -/* - * Reference declaration: - * - * extern unsigned int __kernel_helper_version; - * - * Definition and user space usage example: - * - * #define __kernel_helper_version (*(unsigned int *)0xffff0ffc) - * - * User space may read this to determine the curent number of helpers - * available. - */ - __kuser_helper_version: @ 0xffff0ffc .word ((__kuser_helper_end - __kuser_helper_start) >> 5) diff --git a/arch/arm/kernel/entry-header.S b/arch/arm/kernel/entry-header.S index 051166c..9a8531e 100644 --- a/arch/arm/kernel/entry-header.S +++ b/arch/arm/kernel/entry-header.S @@ -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 @@ -165,25 +163,6 @@ .endm #endif /* !CONFIG_THUMB2_KERNEL */ - @ - @ Debug exceptions are taken as prefetch or data aborts. - @ We must disable preemption during the handler so that - @ we can access the debug registers safely. - @ - .macro debug_entry, fsr -#if defined(CONFIG_HAVE_HW_BREAKPOINT) && defined(CONFIG_PREEMPT) - ldr r4, =0x40f @ mask out fsr.fs - and r5, r4, \fsr - cmp r5, #2 @ debug exception - bne 1f - get_thread_info r10 - ldr r6, [r10, #TI_PREEMPT] @ get preempt count - add r11, r6, #1 @ increment it - str r11, [r10, #TI_PREEMPT] -1: -#endif - .endm - /* * These are the registers used in the syscall handler, and allow us to * have in theory up to 7 arguments to a function - r0 to r6. diff --git a/arch/arm/kernel/head-nommu.S b/arch/arm/kernel/head-nommu.S index 6b1e0ad..d46f259 100644 --- a/arch/arm/kernel/head-nommu.S +++ b/arch/arm/kernel/head-nommu.S @@ -32,8 +32,16 @@ * numbers for r1. * */ + .arm + __HEAD ENTRY(stext) + + THUMB( adr r9, BSYM(1f) ) @ Kernel is always entered in ARM. + THUMB( bx r9 ) @ If this is a Thumb-2 kernel, + THUMB( .thumb ) @ switch to Thumb now. + THUMB(1: ) + setmode PSR_F_BIT | PSR_I_BIT | SVC_MODE, r9 @ ensure svc mode @ and irqs disabled #ifndef CONFIG_CPU_CP15 diff --git a/arch/arm/kernel/head.S b/arch/arm/kernel/head.S index 278c1b0..742b610 100644 --- a/arch/arm/kernel/head.S +++ b/arch/arm/kernel/head.S @@ -71,8 +71,16 @@ * crap here - that's what the boot loader (or in extreme, well justified * circumstances, zImage) is for. */ + .arm + __HEAD ENTRY(stext) + + THUMB( adr r9, BSYM(1f) ) @ Kernel is always entered in ARM. + THUMB( bx r9 ) @ If this is a Thumb-2 kernel, + THUMB( .thumb ) @ switch to Thumb now. + THUMB(1: ) + setmode PSR_F_BIT | PSR_I_BIT | SVC_MODE, r9 @ ensure svc mode @ and irqs disabled mrc p15, 0, r9, c0, c0 @ get processor id diff --git a/arch/arm/kernel/hw_breakpoint.c b/arch/arm/kernel/hw_breakpoint.c index 87acc25..a927ca1 100644 --- a/arch/arm/kernel/hw_breakpoint.c +++ b/arch/arm/kernel/hw_breakpoint.c @@ -796,7 +796,7 @@ unlock: /* * Called from either the Data Abort Handler [watchpoint] or the - * Prefetch Abort Handler [breakpoint] with preemption disabled. + * Prefetch Abort Handler [breakpoint] with interrupts disabled. */ static int hw_breakpoint_pending(unsigned long addr, unsigned int fsr, struct pt_regs *regs) @@ -804,8 +804,10 @@ static int hw_breakpoint_pending(unsigned long addr, unsigned int fsr, int ret = 0; u32 dscr; - /* We must be called with preemption disabled. */ - WARN_ON(preemptible()); + preempt_disable(); + + if (interrupts_enabled(regs)) + local_irq_enable(); /* We only handle watchpoints and hardware breakpoints. */ ARM_DBG_READ(c1, 0, dscr); @@ -824,10 +826,6 @@ static int hw_breakpoint_pending(unsigned long addr, unsigned int fsr, ret = 1; /* Unhandled fault. */ } - /* - * Re-enable preemption after it was disabled in the - * low-level exception handling code. - */ preempt_enable(); return ret; diff --git a/arch/arm/kernel/irq.c b/arch/arm/kernel/irq.c index 83bbad0..de3dcab 100644 --- a/arch/arm/kernel/irq.c +++ b/arch/arm/kernel/irq.c @@ -67,12 +67,12 @@ int arch_show_interrupts(struct seq_file *p, int prec) } /* - * do_IRQ handles all hardware IRQ's. Decoded IRQs should not - * come via this function. Instead, they should provide their - * own 'handler' + * handle_IRQ handles all hardware IRQ's. Decoded IRQs should + * not come via this function. Instead, they should provide their + * own 'handler'. Used by platform code implementing C-based 1st + * level decoding. */ -asmlinkage void __exception_irq_entry -asm_do_IRQ(unsigned int irq, struct pt_regs *regs) +void handle_IRQ(unsigned int irq, struct pt_regs *regs) { struct pt_regs *old_regs = set_irq_regs(regs); @@ -97,6 +97,15 @@ asm_do_IRQ(unsigned int irq, struct pt_regs *regs) set_irq_regs(old_regs); } +/* + * asm_do_IRQ is the interface to be used from assembly code. + */ +asmlinkage void __exception_irq_entry +asm_do_IRQ(unsigned int irq, struct pt_regs *regs) +{ + handle_IRQ(irq, regs); +} + void set_irq_flags(unsigned int irq, unsigned int iflags) { unsigned long clr = 0, set = IRQ_NOREQUEST | IRQ_NOPROBE | IRQ_NOAUTOEN; @@ -131,54 +140,63 @@ int __init arch_probe_nr_irqs(void) #ifdef CONFIG_HOTPLUG_CPU -static bool migrate_one_irq(struct irq_data *d) +static bool migrate_one_irq(struct irq_desc *desc) { - unsigned int cpu = cpumask_any_and(d->affinity, cpu_online_mask); + struct irq_data *d = irq_desc_get_irq_data(desc); + const struct cpumask *affinity = d->affinity; + struct irq_chip *c; bool ret = false; - if (cpu >= nr_cpu_ids) { - cpu = cpumask_any(cpu_online_mask); + /* + * If this is a per-CPU interrupt, or the affinity does not + * include this CPU, then we have nothing to do. + */ + if (irqd_is_per_cpu(d) || !cpumask_test_cpu(smp_processor_id(), affinity)) + return false; + + if (cpumask_any_and(affinity, cpu_online_mask) >= nr_cpu_ids) { + affinity = cpu_online_mask; ret = true; } - pr_debug("IRQ%u: moving from cpu%u to cpu%u\n", d->irq, d->node, cpu); - - d->chip->irq_set_affinity(d, cpumask_of(cpu), true); + c = irq_data_get_irq_chip(d); + if (c->irq_set_affinity) + c->irq_set_affinity(d, affinity, true); + else + pr_debug("IRQ%u: unable to set affinity\n", d->irq); return ret; } /* - * The CPU has been marked offline. Migrate IRQs off this CPU. If - * the affinity settings do not allow other CPUs, force them onto any + * The current CPU has been marked offline. Migrate IRQs off this CPU. + * If the affinity settings do not allow other CPUs, force them onto any * available CPU. + * + * Note: we must iterate over all IRQs, whether they have an attached + * action structure or not, as we need to get chained interrupts too. */ void migrate_irqs(void) { - unsigned int i, cpu = smp_processor_id(); + unsigned int i; struct irq_desc *desc; unsigned long flags; local_irq_save(flags); for_each_irq_desc(i, desc) { - struct irq_data *d = &desc->irq_data; bool affinity_broken = false; - raw_spin_lock(&desc->lock); - do { - if (desc->action == NULL) - break; - - if (d->node != cpu) - break; + if (!desc) + continue; - affinity_broken = migrate_one_irq(d); - } while (0); + raw_spin_lock(&desc->lock); + affinity_broken = migrate_one_irq(desc); raw_spin_unlock(&desc->lock); if (affinity_broken && printk_ratelimit()) - pr_warning("IRQ%u no longer affine to CPU%u\n", i, cpu); + pr_warning("IRQ%u no longer affine to CPU%u\n", i, + smp_processor_id()); } local_irq_restore(flags); diff --git a/arch/arm/kernel/kprobes-arm.c b/arch/arm/kernel/kprobes-arm.c new file mode 100644 index 0000000..79203ee --- /dev/null +++ b/arch/arm/kernel/kprobes-arm.c @@ -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 +#include + +#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) */ + + /* 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), + + /* 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); +} diff --git a/arch/arm/kernel/kprobes-common.c b/arch/arm/kernel/kprobes-common.c new file mode 100644 index 0000000..a5394fb4 --- /dev/null +++ b/arch/arm/kernel/kprobes-common.c @@ -0,0 +1,577 @@ +/* + * arch/arm/kernel/kprobes-common.c + * + * Copyright (C) 2011 Jon Medhurst . + * + * 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 +#include + +#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; + } + } + } diff --git a/arch/arm/kernel/kprobes-decode.c b/arch/arm/kernel/kprobes-decode.c deleted file mode 100644 index 15eeff6..0000000 --- a/arch/arm/kernel/kprobes-decode.c +++ /dev/null @@ -1,1670 +0,0 @@ -/* - * 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 -#include - -#define sign_extend(x, signbit) ((x) | (0 - ((x) & (1 << (signbit))))) - -#define branch_displacement(insn) sign_extend(((insn) & 0xffffff) << 2, 25) - -#define is_r15(insn, bitpos) (((insn) & (0xf << bitpos)) == (0xf << bitpos)) - -/* - * 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) - -#define PSR_fs (PSR_f|PSR_s) - -#define KPROBE_RETURN_INSTRUCTION 0xe1a0f00e /* mov pc, lr */ - -typedef long (insn_0arg_fn_t)(void); -typedef long (insn_1arg_fn_t)(long); -typedef long (insn_2arg_fn_t)(long, long); -typedef long (insn_3arg_fn_t)(long, long, long); -typedef long (insn_4arg_fn_t)(long, long, long, long); -typedef long long (insn_llret_0arg_fn_t)(void); -typedef long long (insn_llret_3arg_fn_t)(long, long, long); -typedef long long (insn_llret_4arg_fn_t)(long, long, long, long); - -union reg_pair { - long long dr; -#ifdef __LITTLE_ENDIAN - struct { long r0, r1; }; -#else - struct { long r1, r0; }; -#endif -}; - -/* - * 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. - */ - -static int str_pc_offset; - -static 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; -} - -/* - * The insnslot_?arg_r[w]flags() functions below are to keep the - * msr -> *fn -> mrs instruction sequences indivisible so that - * the state of the CPSR flags aren't inadvertently modified - * just before or just after the call. - */ - -static inline long __kprobes -insnslot_0arg_rflags(long cpsr, insn_0arg_fn_t *fn) -{ - register long ret asm("r0"); - - __asm__ __volatile__ ( - "msr cpsr_fs, %[cpsr] \n\t" - "mov lr, pc \n\t" - "mov pc, %[fn] \n\t" - : "=r" (ret) - : [cpsr] "r" (cpsr), [fn] "r" (fn) - : "lr", "cc" - ); - return ret; -} - -static inline long long __kprobes -insnslot_llret_0arg_rflags(long cpsr, insn_llret_0arg_fn_t *fn) -{ - register long ret0 asm("r0"); - register long ret1 asm("r1"); - union reg_pair fnr; - - __asm__ __volatile__ ( - "msr cpsr_fs, %[cpsr] \n\t" - "mov lr, pc \n\t" - "mov pc, %[fn] \n\t" - : "=r" (ret0), "=r" (ret1) - : [cpsr] "r" (cpsr), [fn] "r" (fn) - : "lr", "cc" - ); - fnr.r0 = ret0; - fnr.r1 = ret1; - return fnr.dr; -} - -static inline long __kprobes -insnslot_1arg_rflags(long r0, long cpsr, insn_1arg_fn_t *fn) -{ - register long rr0 asm("r0") = r0; - register long ret asm("r0"); - - __asm__ __volatile__ ( - "msr cpsr_fs, %[cpsr] \n\t" - "mov lr, pc \n\t" - "mov pc, %[fn] \n\t" - : "=r" (ret) - : "0" (rr0), [cpsr] "r" (cpsr), [fn] "r" (fn) - : "lr", "cc" - ); - return ret; -} - -static inline long __kprobes -insnslot_2arg_rflags(long r0, long r1, long cpsr, insn_2arg_fn_t *fn) -{ - register long rr0 asm("r0") = r0; - register long rr1 asm("r1") = r1; - register long ret asm("r0"); - - __asm__ __volatile__ ( - "msr cpsr_fs, %[cpsr] \n\t" - "mov lr, pc \n\t" - "mov pc, %[fn] \n\t" - : "=r" (ret) - : "0" (rr0), "r" (rr1), - [cpsr] "r" (cpsr), [fn] "r" (fn) - : "lr", "cc" - ); - return ret; -} - -static inline long __kprobes -insnslot_3arg_rflags(long r0, long r1, long r2, long cpsr, insn_3arg_fn_t *fn) -{ - register long rr0 asm("r0") = r0; - register long rr1 asm("r1") = r1; - register long rr2 asm("r2") = r2; - register long ret asm("r0"); - - __asm__ __volatile__ ( - "msr cpsr_fs, %[cpsr] \n\t" - "mov lr, pc \n\t" - "mov pc, %[fn] \n\t" - : "=r" (ret) - : "0" (rr0), "r" (rr1), "r" (rr2), - [cpsr] "r" (cpsr), [fn] "r" (fn) - : "lr", "cc" - ); - return ret; -} - -static inline long long __kprobes -insnslot_llret_3arg_rflags(long r0, long r1, long r2, long cpsr, - insn_llret_3arg_fn_t *fn) -{ - register long rr0 asm("r0") = r0; - register long rr1 asm("r1") = r1; - register long rr2 asm("r2") = r2; - register long ret0 asm("r0"); - register long ret1 asm("r1"); - union reg_pair fnr; - - __asm__ __volatile__ ( - "msr cpsr_fs, %[cpsr] \n\t" - "mov lr, pc \n\t" - "mov pc, %[fn] \n\t" - : "=r" (ret0), "=r" (ret1) - : "0" (rr0), "r" (rr1), "r" (rr2), - [cpsr] "r" (cpsr), [fn] "r" (fn) - : "lr", "cc" - ); - fnr.r0 = ret0; - fnr.r1 = ret1; - return fnr.dr; -} - -static inline long __kprobes -insnslot_4arg_rflags(long r0, long r1, long r2, long r3, long cpsr, - insn_4arg_fn_t *fn) -{ - register long rr0 asm("r0") = r0; - register long rr1 asm("r1") = r1; - register long rr2 asm("r2") = r2; - register long rr3 asm("r3") = r3; - register long ret asm("r0"); - - __asm__ __volatile__ ( - "msr cpsr_fs, %[cpsr] \n\t" - "mov lr, pc \n\t" - "mov pc, %[fn] \n\t" - : "=r" (ret) - : "0" (rr0), "r" (rr1), "r" (rr2), "r" (rr3), - [cpsr] "r" (cpsr), [fn] "r" (fn) - : "lr", "cc" - ); - return ret; -} - -static inline long __kprobes -insnslot_1arg_rwflags(long r0, long *cpsr, insn_1arg_fn_t *fn) -{ - register long rr0 asm("r0") = r0; - register long ret asm("r0"); - long oldcpsr = *cpsr; - long newcpsr; - - __asm__ __volatile__ ( - "msr cpsr_fs, %[oldcpsr] \n\t" - "mov lr, pc \n\t" - "mov pc, %[fn] \n\t" - "mrs %[newcpsr], cpsr \n\t" - : "=r" (ret), [newcpsr] "=r" (newcpsr) - : "0" (rr0), [oldcpsr] "r" (oldcpsr), [fn] "r" (fn) - : "lr", "cc" - ); - *cpsr = (oldcpsr & ~PSR_fs) | (newcpsr & PSR_fs); - return ret; -} - -static inline long __kprobes -insnslot_2arg_rwflags(long r0, long r1, long *cpsr, insn_2arg_fn_t *fn) -{ - register long rr0 asm("r0") = r0; - register long rr1 asm("r1") = r1; - register long ret asm("r0"); - long oldcpsr = *cpsr; - long newcpsr; - - __asm__ __volatile__ ( - "msr cpsr_fs, %[oldcpsr] \n\t" - "mov lr, pc \n\t" - "mov pc, %[fn] \n\t" - "mrs %[newcpsr], cpsr \n\t" - : "=r" (ret), [newcpsr] "=r" (newcpsr) - : "0" (rr0), "r" (rr1), [oldcpsr] "r" (oldcpsr), [fn] "r" (fn) - : "lr", "cc" - ); - *cpsr = (oldcpsr & ~PSR_fs) | (newcpsr & PSR_fs); - return ret; -} - -static inline long __kprobes -insnslot_3arg_rwflags(long r0, long r1, long r2, long *cpsr, - insn_3arg_fn_t *fn) -{ - register long rr0 asm("r0") = r0; - register long rr1 asm("r1") = r1; - register long rr2 asm("r2") = r2; - register long ret asm("r0"); - long oldcpsr = *cpsr; - long newcpsr; - - __asm__ __volatile__ ( - "msr cpsr_fs, %[oldcpsr] \n\t" - "mov lr, pc \n\t" - "mov pc, %[fn] \n\t" - "mrs %[newcpsr], cpsr \n\t" - : "=r" (ret), [newcpsr] "=r" (newcpsr) - : "0" (rr0), "r" (rr1), "r" (rr2), - [oldcpsr] "r" (oldcpsr), [fn] "r" (fn) - : "lr", "cc" - ); - *cpsr = (oldcpsr & ~PSR_fs) | (newcpsr & PSR_fs); - return ret; -} - -static inline long __kprobes -insnslot_4arg_rwflags(long r0, long r1, long r2, long r3, long *cpsr, - insn_4arg_fn_t *fn) -{ - register long rr0 asm("r0") = r0; - register long rr1 asm("r1") = r1; - register long rr2 asm("r2") = r2; - register long rr3 asm("r3") = r3; - register long ret asm("r0"); - long oldcpsr = *cpsr; - long newcpsr; - - __asm__ __volatile__ ( - "msr cpsr_fs, %[oldcpsr] \n\t" - "mov lr, pc \n\t" - "mov pc, %[fn] \n\t" - "mrs %[newcpsr], cpsr \n\t" - : "=r" (ret), [newcpsr] "=r" (newcpsr) - : "0" (rr0), "r" (rr1), "r" (rr2), "r" (rr3), - [oldcpsr] "r" (oldcpsr), [fn] "r" (fn) - : "lr", "cc" - ); - *cpsr = (oldcpsr & ~PSR_fs) | (newcpsr & PSR_fs); - return ret; -} - -static inline long long __kprobes -insnslot_llret_4arg_rwflags(long r0, long r1, long r2, long r3, long *cpsr, - insn_llret_4arg_fn_t *fn) -{ - register long rr0 asm("r0") = r0; - register long rr1 asm("r1") = r1; - register long rr2 asm("r2") = r2; - register long rr3 asm("r3") = r3; - register long ret0 asm("r0"); - register long ret1 asm("r1"); - long oldcpsr = *cpsr; - long newcpsr; - union reg_pair fnr; - - __asm__ __volatile__ ( - "msr cpsr_fs, %[oldcpsr] \n\t" - "mov lr, pc \n\t" - "mov pc, %[fn] \n\t" - "mrs %[newcpsr], cpsr \n\t" - : "=r" (ret0), "=r" (ret1), [newcpsr] "=r" (newcpsr) - : "0" (rr0), "r" (rr1), "r" (rr2), "r" (rr3), - [oldcpsr] "r" (oldcpsr), [fn] "r" (fn) - : "lr", "cc" - ); - *cpsr = (oldcpsr & ~PSR_fs) | (newcpsr & PSR_fs); - fnr.r0 = ret0; - fnr.r1 = ret1; - return fnr.dr; -} - -/* - * 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_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_mov_ipsp(struct kprobe *p, struct pt_regs *regs) -{ - regs->uregs[12] = regs->uregs[13]; -} - -static void __kprobes emulate_ldrd(struct kprobe *p, struct pt_regs *regs) -{ - insn_2arg_fn_t *i_fn = (insn_2arg_fn_t *)&p->ainsn.insn[0]; - kprobe_opcode_t insn = p->opcode; - long ppc = (long)p->addr + 8; - int rd = (insn >> 12) & 0xf; - int rn = (insn >> 16) & 0xf; - int rm = insn & 0xf; /* rm may be invalid, don't care. */ - long rmv = (rm == 15) ? ppc : regs->uregs[rm]; - long rnv = (rn == 15) ? ppc : regs->uregs[rn]; - - /* Not following the C calling convention here, so need asm(). */ - __asm__ __volatile__ ( - "ldr r0, %[rn] \n\t" - "ldr r1, %[rm] \n\t" - "msr cpsr_fs, %[cpsr]\n\t" - "mov lr, pc \n\t" - "mov pc, %[i_fn] \n\t" - "str r0, %[rn] \n\t" /* in case of writeback */ - "str r2, %[rd0] \n\t" - "str r3, %[rd1] \n\t" - : [rn] "+m" (rnv), - [rd0] "=m" (regs->uregs[rd]), - [rd1] "=m" (regs->uregs[rd+1]) - : [rm] "m" (rmv), - [cpsr] "r" (regs->ARM_cpsr), - [i_fn] "r" (i_fn) - : "r0", "r1", "r2", "r3", "lr", "cc" - ); - if (is_writeback(insn)) - regs->uregs[rn] = rnv; -} - -static void __kprobes emulate_strd(struct kprobe *p, struct pt_regs *regs) -{ - insn_4arg_fn_t *i_fn = (insn_4arg_fn_t *)&p->ainsn.insn[0]; - kprobe_opcode_t insn = p->opcode; - long ppc = (long)p->addr + 8; - int rd = (insn >> 12) & 0xf; - int rn = (insn >> 16) & 0xf; - int rm = insn & 0xf; - long rnv = (rn == 15) ? ppc : regs->uregs[rn]; - /* rm/rmv may be invalid, don't care. */ - long rmv = (rm == 15) ? ppc : regs->uregs[rm]; - long rnv_wb; - - rnv_wb = insnslot_4arg_rflags(rnv, rmv, regs->uregs[rd], - regs->uregs[rd+1], - regs->ARM_cpsr, i_fn); - if (is_writeback(insn)) - regs->uregs[rn] = rnv_wb; -} - -static void __kprobes emulate_ldr(struct kprobe *p, struct pt_regs *regs) -{ - insn_llret_3arg_fn_t *i_fn = (insn_llret_3arg_fn_t *)&p->ainsn.insn[0]; - kprobe_opcode_t insn = p->opcode; - long ppc = (long)p->addr + 8; - union reg_pair fnr; - int rd = (insn >> 12) & 0xf; - int rn = (insn >> 16) & 0xf; - int rm = insn & 0xf; - long rdv; - long rnv = (rn == 15) ? ppc : regs->uregs[rn]; - long rmv = (rm == 15) ? ppc : regs->uregs[rm]; - long cpsr = regs->ARM_cpsr; - - fnr.dr = insnslot_llret_3arg_rflags(rnv, 0, rmv, cpsr, i_fn); - if (rn != 15) - regs->uregs[rn] = fnr.r0; /* Save Rn in case of writeback. */ - rdv = fnr.r1; - - if (rd == 15) { -#if __LINUX_ARM_ARCH__ >= 5 - cpsr &= ~PSR_T_BIT; - if (rdv & 0x1) - cpsr |= PSR_T_BIT; - regs->ARM_cpsr = cpsr; - rdv &= ~0x1; -#else - rdv &= ~0x2; -#endif - } - regs->uregs[rd] = rdv; -} - -static void __kprobes emulate_str(struct kprobe *p, struct pt_regs *regs) -{ - insn_3arg_fn_t *i_fn = (insn_3arg_fn_t *)&p->ainsn.insn[0]; - kprobe_opcode_t insn = p->opcode; - long iaddr = (long)p->addr; - int rd = (insn >> 12) & 0xf; - int rn = (insn >> 16) & 0xf; - int rm = insn & 0xf; - long rdv = (rd == 15) ? iaddr + str_pc_offset : regs->uregs[rd]; - long rnv = (rn == 15) ? iaddr + 8 : regs->uregs[rn]; - long rmv = regs->uregs[rm]; /* rm/rmv may be invalid, don't care. */ - long rnv_wb; - - rnv_wb = insnslot_3arg_rflags(rnv, rdv, rmv, regs->ARM_cpsr, i_fn); - if (rn != 15) - regs->uregs[rn] = rnv_wb; /* Save Rn in case of writeback. */ -} - -static void __kprobes emulate_sat(struct kprobe *p, struct pt_regs *regs) -{ - insn_1arg_fn_t *i_fn = (insn_1arg_fn_t *)&p->ainsn.insn[0]; - kprobe_opcode_t insn = p->opcode; - int rd = (insn >> 12) & 0xf; - int rm = insn & 0xf; - long rmv = regs->uregs[rm]; - - /* Writes Q flag */ - regs->uregs[rd] = insnslot_1arg_rwflags(rmv, ®s->ARM_cpsr, i_fn); -} - -static void __kprobes emulate_sel(struct kprobe *p, struct pt_regs *regs) -{ - insn_2arg_fn_t *i_fn = (insn_2arg_fn_t *)&p->ainsn.insn[0]; - kprobe_opcode_t insn = p->opcode; - int rd = (insn >> 12) & 0xf; - int rn = (insn >> 16) & 0xf; - int rm = insn & 0xf; - long rnv = regs->uregs[rn]; - long rmv = regs->uregs[rm]; - - /* Reads GE bits */ - regs->uregs[rd] = insnslot_2arg_rflags(rnv, rmv, regs->ARM_cpsr, i_fn); -} - -static void __kprobes emulate_none(struct kprobe *p, struct pt_regs *regs) -{ - insn_0arg_fn_t *i_fn = (insn_0arg_fn_t *)&p->ainsn.insn[0]; - - insnslot_0arg_rflags(regs->ARM_cpsr, i_fn); -} - -static void __kprobes emulate_nop(struct kprobe *p, struct pt_regs *regs) -{ -} - -static void __kprobes -emulate_rd12_modify(struct kprobe *p, struct pt_regs *regs) -{ - insn_1arg_fn_t *i_fn = (insn_1arg_fn_t *)&p->ainsn.insn[0]; - kprobe_opcode_t insn = p->opcode; - int rd = (insn >> 12) & 0xf; - long rdv = regs->uregs[rd]; - - regs->uregs[rd] = insnslot_1arg_rflags(rdv, regs->ARM_cpsr, i_fn); -} - -static void __kprobes -emulate_rd12rn0_modify(struct kprobe *p, struct pt_regs *regs) -{ - insn_2arg_fn_t *i_fn = (insn_2arg_fn_t *)&p->ainsn.insn[0]; - kprobe_opcode_t insn = p->opcode; - int rd = (insn >> 12) & 0xf; - int rn = insn & 0xf; - long rdv = regs->uregs[rd]; - long rnv = regs->uregs[rn]; - - regs->uregs[rd] = insnslot_2arg_rflags(rdv, rnv, regs->ARM_cpsr, i_fn); -} - -static void __kprobes emulate_rd12rm0(struct kprobe *p, struct pt_regs *regs) -{ - insn_1arg_fn_t *i_fn = (insn_1arg_fn_t *)&p->ainsn.insn[0]; - kprobe_opcode_t insn = p->opcode; - int rd = (insn >> 12) & 0xf; - int rm = insn & 0xf; - long rmv = regs->uregs[rm]; - - regs->uregs[rd] = insnslot_1arg_rflags(rmv, regs->ARM_cpsr, i_fn); -} - -static void __kprobes -emulate_rd12rn16rm0_rwflags(struct kprobe *p, struct pt_regs *regs) -{ - insn_2arg_fn_t *i_fn = (insn_2arg_fn_t *)&p->ainsn.insn[0]; - kprobe_opcode_t insn = p->opcode; - int rd = (insn >> 12) & 0xf; - int rn = (insn >> 16) & 0xf; - int rm = insn & 0xf; - long rnv = regs->uregs[rn]; - long rmv = regs->uregs[rm]; - - regs->uregs[rd] = - insnslot_2arg_rwflags(rnv, rmv, ®s->ARM_cpsr, i_fn); -} - -static void __kprobes -emulate_rd16rn12rs8rm0_rwflags(struct kprobe *p, struct pt_regs *regs) -{ - insn_3arg_fn_t *i_fn = (insn_3arg_fn_t *)&p->ainsn.insn[0]; - kprobe_opcode_t insn = p->opcode; - int rd = (insn >> 16) & 0xf; - int rn = (insn >> 12) & 0xf; - int rs = (insn >> 8) & 0xf; - int rm = insn & 0xf; - long rnv = regs->uregs[rn]; - long rsv = regs->uregs[rs]; - long rmv = regs->uregs[rm]; - - regs->uregs[rd] = - insnslot_3arg_rwflags(rnv, rsv, rmv, ®s->ARM_cpsr, i_fn); -} - -static void __kprobes -emulate_rd16rs8rm0_rwflags(struct kprobe *p, struct pt_regs *regs) -{ - insn_2arg_fn_t *i_fn = (insn_2arg_fn_t *)&p->ainsn.insn[0]; - kprobe_opcode_t insn = p->opcode; - int rd = (insn >> 16) & 0xf; - int rs = (insn >> 8) & 0xf; - int rm = insn & 0xf; - long rsv = regs->uregs[rs]; - long rmv = regs->uregs[rm]; - - regs->uregs[rd] = - insnslot_2arg_rwflags(rsv, rmv, ®s->ARM_cpsr, i_fn); -} - -static void __kprobes -emulate_rdhi16rdlo12rs8rm0_rwflags(struct kprobe *p, struct pt_regs *regs) -{ - insn_llret_4arg_fn_t *i_fn = (insn_llret_4arg_fn_t *)&p->ainsn.insn[0]; - kprobe_opcode_t insn = p->opcode; - union reg_pair fnr; - int rdhi = (insn >> 16) & 0xf; - int rdlo = (insn >> 12) & 0xf; - int rs = (insn >> 8) & 0xf; - int rm = insn & 0xf; - long rsv = regs->uregs[rs]; - long rmv = regs->uregs[rm]; - - fnr.dr = insnslot_llret_4arg_rwflags(regs->uregs[rdhi], - regs->uregs[rdlo], rsv, rmv, - ®s->ARM_cpsr, i_fn); - regs->uregs[rdhi] = fnr.r0; - regs->uregs[rdlo] = fnr.r1; -} - -static void __kprobes -emulate_alu_imm_rflags(struct kprobe *p, struct pt_regs *regs) -{ - insn_1arg_fn_t *i_fn = (insn_1arg_fn_t *)&p->ainsn.insn[0]; - kprobe_opcode_t insn = p->opcode; - int rd = (insn >> 12) & 0xf; - int rn = (insn >> 16) & 0xf; - long rnv = (rn == 15) ? (long)p->addr + 8 : regs->uregs[rn]; - - regs->uregs[rd] = insnslot_1arg_rflags(rnv, regs->ARM_cpsr, i_fn); -} - -static void __kprobes -emulate_alu_imm_rwflags(struct kprobe *p, struct pt_regs *regs) -{ - insn_1arg_fn_t *i_fn = (insn_1arg_fn_t *)&p->ainsn.insn[0]; - kprobe_opcode_t insn = p->opcode; - int rd = (insn >> 12) & 0xf; - int rn = (insn >> 16) & 0xf; - long rnv = (rn == 15) ? (long)p->addr + 8 : regs->uregs[rn]; - - regs->uregs[rd] = insnslot_1arg_rwflags(rnv, ®s->ARM_cpsr, i_fn); -} - -static void __kprobes -emulate_alu_tests_imm(struct kprobe *p, struct pt_regs *regs) -{ - insn_1arg_fn_t *i_fn = (insn_1arg_fn_t *)&p->ainsn.insn[0]; - kprobe_opcode_t insn = p->opcode; - int rn = (insn >> 16) & 0xf; - long rnv = (rn == 15) ? (long)p->addr + 8 : regs->uregs[rn]; - - insnslot_1arg_rwflags(rnv, ®s->ARM_cpsr, i_fn); -} - -static void __kprobes -emulate_alu_rflags(struct kprobe *p, struct pt_regs *regs) -{ - insn_3arg_fn_t *i_fn = (insn_3arg_fn_t *)&p->ainsn.insn[0]; - kprobe_opcode_t insn = p->opcode; - long ppc = (long)p->addr + 8; - int rd = (insn >> 12) & 0xf; - int rn = (insn >> 16) & 0xf; /* rn/rnv/rs/rsv may be */ - int rs = (insn >> 8) & 0xf; /* invalid, don't care. */ - int rm = insn & 0xf; - long rnv = (rn == 15) ? ppc : regs->uregs[rn]; - long rmv = (rm == 15) ? ppc : regs->uregs[rm]; - long rsv = regs->uregs[rs]; - - regs->uregs[rd] = - insnslot_3arg_rflags(rnv, rmv, rsv, regs->ARM_cpsr, i_fn); -} - -static void __kprobes -emulate_alu_rwflags(struct kprobe *p, struct pt_regs *regs) -{ - insn_3arg_fn_t *i_fn = (insn_3arg_fn_t *)&p->ainsn.insn[0]; - kprobe_opcode_t insn = p->opcode; - long ppc = (long)p->addr + 8; - int rd = (insn >> 12) & 0xf; - int rn = (insn >> 16) & 0xf; /* rn/rnv/rs/rsv may be */ - int rs = (insn >> 8) & 0xf; /* invalid, don't care. */ - int rm = insn & 0xf; - long rnv = (rn == 15) ? ppc : regs->uregs[rn]; - long rmv = (rm == 15) ? ppc : regs->uregs[rm]; - long rsv = regs->uregs[rs]; - - regs->uregs[rd] = - insnslot_3arg_rwflags(rnv, rmv, rsv, ®s->ARM_cpsr, i_fn); -} - -static void __kprobes -emulate_alu_tests(struct kprobe *p, struct pt_regs *regs) -{ - insn_3arg_fn_t *i_fn = (insn_3arg_fn_t *)&p->ainsn.insn[0]; - kprobe_opcode_t insn = p->opcode; - long ppc = (long)p->addr + 8; - int rn = (insn >> 16) & 0xf; - int rs = (insn >> 8) & 0xf; /* rs/rsv may be invalid, don't care. */ - int rm = insn & 0xf; - long rnv = (rn == 15) ? ppc : regs->uregs[rn]; - long rmv = (rm == 15) ? ppc : regs->uregs[rm]; - long rsv = regs->uregs[rs]; - - insnslot_3arg_rwflags(rnv, rmv, rsv, ®s->ARM_cpsr, i_fn); -} - -static enum kprobe_insn __kprobes -prep_emulate_ldr_str(kprobe_opcode_t insn, struct arch_specific_insn *asi) -{ - int not_imm = (insn & (1 << 26)) ? (insn & (1 << 25)) - : (~insn & (1 << 22)); - - if (is_writeback(insn) && is_r15(insn, 16)) - return INSN_REJECTED; /* Writeback to PC */ - - insn &= 0xfff00fff; - insn |= 0x00001000; /* Rn = r0, Rd = r1 */ - if (not_imm) { - insn &= ~0xf; - insn |= 2; /* Rm = r2 */ - } - asi->insn[0] = insn; - asi->insn_handler = (insn & (1 << 20)) ? emulate_ldr : emulate_str; - return INSN_GOOD; -} - -static enum kprobe_insn __kprobes -prep_emulate_rd12_modify(kprobe_opcode_t insn, struct arch_specific_insn *asi) -{ - if (is_r15(insn, 12)) - return INSN_REJECTED; /* Rd is PC */ - - insn &= 0xffff0fff; /* Rd = r0 */ - asi->insn[0] = insn; - asi->insn_handler = emulate_rd12_modify; - return INSN_GOOD; -} - -static enum kprobe_insn __kprobes -prep_emulate_rd12rn0_modify(kprobe_opcode_t insn, - struct arch_specific_insn *asi) -{ - if (is_r15(insn, 12)) - return INSN_REJECTED; /* Rd is PC */ - - insn &= 0xffff0ff0; /* Rd = r0 */ - insn |= 0x00000001; /* Rn = r1 */ - asi->insn[0] = insn; - asi->insn_handler = emulate_rd12rn0_modify; - return INSN_GOOD; -} - -static enum kprobe_insn __kprobes -prep_emulate_rd12rm0(kprobe_opcode_t insn, struct arch_specific_insn *asi) -{ - if (is_r15(insn, 12)) - return INSN_REJECTED; /* Rd is PC */ - - insn &= 0xffff0ff0; /* Rd = r0, Rm = r0 */ - asi->insn[0] = insn; - asi->insn_handler = emulate_rd12rm0; - return INSN_GOOD; -} - -static enum kprobe_insn __kprobes -prep_emulate_rd12rn16rm0_wflags(kprobe_opcode_t insn, - struct arch_specific_insn *asi) -{ - if (is_r15(insn, 12)) - return INSN_REJECTED; /* Rd is PC */ - - insn &= 0xfff00ff0; /* Rd = r0, Rn = r0 */ - insn |= 0x00000001; /* Rm = r1 */ - asi->insn[0] = insn; - asi->insn_handler = emulate_rd12rn16rm0_rwflags; - return INSN_GOOD; -} - -static enum kprobe_insn __kprobes -prep_emulate_rd16rs8rm0_wflags(kprobe_opcode_t insn, - struct arch_specific_insn *asi) -{ - if (is_r15(insn, 16)) - return INSN_REJECTED; /* Rd is PC */ - - insn &= 0xfff0f0f0; /* Rd = r0, Rs = r0 */ - insn |= 0x00000001; /* Rm = r1 */ - asi->insn[0] = insn; - asi->insn_handler = emulate_rd16rs8rm0_rwflags; - return INSN_GOOD; -} - -static enum kprobe_insn __kprobes -prep_emulate_rd16rn12rs8rm0_wflags(kprobe_opcode_t insn, - struct arch_specific_insn *asi) -{ - if (is_r15(insn, 16)) - return INSN_REJECTED; /* Rd is PC */ - - insn &= 0xfff000f0; /* Rd = r0, Rn = r0 */ - insn |= 0x00000102; /* Rs = r1, Rm = r2 */ - asi->insn[0] = insn; - asi->insn_handler = emulate_rd16rn12rs8rm0_rwflags; - return INSN_GOOD; -} - -static enum kprobe_insn __kprobes -prep_emulate_rdhi16rdlo12rs8rm0_wflags(kprobe_opcode_t insn, - struct arch_specific_insn *asi) -{ - if (is_r15(insn, 16) || is_r15(insn, 12)) - return INSN_REJECTED; /* RdHi or RdLo is PC */ - - insn &= 0xfff000f0; /* RdHi = r0, RdLo = r1 */ - insn |= 0x00001203; /* Rs = r2, Rm = r3 */ - asi->insn[0] = insn; - asi->insn_handler = emulate_rdhi16rdlo12rs8rm0_rwflags; - return INSN_GOOD; -} - -/* - * 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 enum kprobe_insn __kprobes -space_1111(kprobe_opcode_t insn, struct arch_specific_insn *asi) -{ - /* memory hint : 1111 0100 x001 xxxx xxxx xxxx xxxx xxxx : */ - /* PLDI : 1111 0100 x101 xxxx xxxx xxxx xxxx xxxx : */ - /* PLDW : 1111 0101 x001 xxxx xxxx xxxx xxxx xxxx : */ - /* PLD : 1111 0101 x101 xxxx xxxx xxxx xxxx xxxx : */ - if ((insn & 0xfe300000) == 0xf4100000) { - asi->insn_handler = emulate_nop; - return INSN_GOOD_NO_SLOT; - } - - /* BLX(1) : 1111 101x xxxx xxxx xxxx xxxx xxxx xxxx : */ - if ((insn & 0xfe000000) == 0xfa000000) { - asi->insn_handler = simulate_blx1; - return INSN_GOOD_NO_SLOT; - } - - /* 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 : (Rd != Rn) */ - /* MRRC2 : 1111 1100 0101 xxxx xxxx xxxx xxxx xxxx : (Rd != Rn) */ - /* 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 */ - - return INSN_REJECTED; -} - -static enum kprobe_insn __kprobes -space_cccc_000x(kprobe_opcode_t insn, struct arch_specific_insn *asi) -{ - /* cccc 0001 0xx0 xxxx xxxx xxxx xxxx xxx0 xxxx */ - if ((insn & 0x0f900010) == 0x01000000) { - - /* MRS cpsr : cccc 0001 0000 xxxx xxxx xxxx 0000 xxxx */ - if ((insn & 0x0ff000f0) == 0x01000000) { - if (is_r15(insn, 12)) - return INSN_REJECTED; /* Rd is PC */ - asi->insn_handler = simulate_mrs; - return INSN_GOOD_NO_SLOT; - } - - /* SMLALxy : cccc 0001 0100 xxxx xxxx xxxx 1xx0 xxxx */ - if ((insn & 0x0ff00090) == 0x01400080) - return prep_emulate_rdhi16rdlo12rs8rm0_wflags(insn, - asi); - - /* SMULWy : cccc 0001 0010 xxxx xxxx xxxx 1x10 xxxx */ - /* SMULxy : cccc 0001 0110 xxxx xxxx xxxx 1xx0 xxxx */ - if ((insn & 0x0ff000b0) == 0x012000a0 || - (insn & 0x0ff00090) == 0x01600080) - return prep_emulate_rd16rs8rm0_wflags(insn, asi); - - /* SMLAxy : cccc 0001 0000 xxxx xxxx xxxx 1xx0 xxxx : Q */ - /* SMLAWy : cccc 0001 0010 xxxx xxxx xxxx 1x00 xxxx : Q */ - if ((insn & 0x0ff00090) == 0x01000080 || - (insn & 0x0ff000b0) == 0x01200080) - return prep_emulate_rd16rn12rs8rm0_wflags(insn, asi); - - /* 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 */ - - /* Other instruction encodings aren't yet defined */ - return INSN_REJECTED; - } - - /* cccc 0001 0xx0 xxxx xxxx xxxx xxxx 0xx1 xxxx */ - else if ((insn & 0x0f900090) == 0x01000010) { - - /* BLX(2) : cccc 0001 0010 xxxx xxxx xxxx 0011 xxxx */ - /* BX : cccc 0001 0010 xxxx xxxx xxxx 0001 xxxx */ - if ((insn & 0x0ff000d0) == 0x01200010) { - if ((insn & 0x0ff000ff) == 0x0120003f) - return INSN_REJECTED; /* BLX pc */ - asi->insn_handler = simulate_blx2bx; - return INSN_GOOD_NO_SLOT; - } - - /* CLZ : cccc 0001 0110 xxxx xxxx xxxx 0001 xxxx */ - if ((insn & 0x0ff000f0) == 0x01600010) - return prep_emulate_rd12rm0(insn, asi); - - /* QADD : cccc 0001 0000 xxxx xxxx xxxx 0101 xxxx :Q */ - /* QSUB : cccc 0001 0010 xxxx xxxx xxxx 0101 xxxx :Q */ - /* QDADD : cccc 0001 0100 xxxx xxxx xxxx 0101 xxxx :Q */ - /* QDSUB : cccc 0001 0110 xxxx xxxx xxxx 0101 xxxx :Q */ - if ((insn & 0x0f9000f0) == 0x01000050) - return prep_emulate_rd12rn16rm0_wflags(insn, asi); - - /* BKPT : 1110 0001 0010 xxxx xxxx xxxx 0111 xxxx */ - /* SMC : cccc 0001 0110 xxxx xxxx xxxx 0111 xxxx */ - - /* Other instruction encodings aren't yet defined */ - return INSN_REJECTED; - } - - /* cccc 0000 xxxx xxxx xxxx xxxx xxxx 1001 xxxx */ - else if ((insn & 0x0f0000f0) == 0x00000090) { - - /* MUL : cccc 0000 0000 xxxx xxxx xxxx 1001 xxxx : */ - /* MULS : cccc 0000 0001 xxxx xxxx xxxx 1001 xxxx :cc */ - /* MLA : cccc 0000 0010 xxxx xxxx xxxx 1001 xxxx : */ - /* MLAS : cccc 0000 0011 xxxx xxxx xxxx 1001 xxxx :cc */ - /* UMAAL : cccc 0000 0100 xxxx xxxx xxxx 1001 xxxx : */ - /* undef : cccc 0000 0101 xxxx xxxx xxxx 1001 xxxx : */ - /* MLS : cccc 0000 0110 xxxx xxxx xxxx 1001 xxxx : */ - /* undef : cccc 0000 0111 xxxx xxxx xxxx 1001 xxxx : */ - /* UMULL : cccc 0000 1000 xxxx xxxx xxxx 1001 xxxx : */ - /* UMULLS : cccc 0000 1001 xxxx xxxx xxxx 1001 xxxx :cc */ - /* UMLAL : cccc 0000 1010 xxxx xxxx xxxx 1001 xxxx : */ - /* UMLALS : cccc 0000 1011 xxxx xxxx xxxx 1001 xxxx :cc */ - /* SMULL : cccc 0000 1100 xxxx xxxx xxxx 1001 xxxx : */ - /* SMULLS : cccc 0000 1101 xxxx xxxx xxxx 1001 xxxx :cc */ - /* SMLAL : cccc 0000 1110 xxxx xxxx xxxx 1001 xxxx : */ - /* SMLALS : cccc 0000 1111 xxxx xxxx xxxx 1001 xxxx :cc */ - if ((insn & 0x00d00000) == 0x00500000) - return INSN_REJECTED; - else if ((insn & 0x00e00000) == 0x00000000) - return prep_emulate_rd16rs8rm0_wflags(insn, asi); - else if ((insn & 0x00a00000) == 0x00200000) - return prep_emulate_rd16rn12rs8rm0_wflags(insn, asi); - else - return prep_emulate_rdhi16rdlo12rs8rm0_wflags(insn, - asi); - } - - /* cccc 000x xxxx xxxx xxxx xxxx xxxx 1xx1 xxxx */ - else if ((insn & 0x0e000090) == 0x00000090) { - - /* SWP : cccc 0001 0000 xxxx xxxx xxxx 1001 xxxx */ - /* SWPB : cccc 0001 0100 xxxx xxxx xxxx 1001 xxxx */ - /* ??? : cccc 0001 0x01 xxxx xxxx xxxx 1001 xxxx */ - /* ??? : cccc 0001 0x10 xxxx xxxx xxxx 1001 xxxx */ - /* ??? : cccc 0001 0x11 xxxx xxxx xxxx 1001 xxxx */ - /* STREX : cccc 0001 1000 xxxx xxxx xxxx 1001 xxxx */ - /* LDREX : cccc 0001 1001 xxxx xxxx xxxx 1001 xxxx */ - /* STREXD: cccc 0001 1010 xxxx xxxx xxxx 1001 xxxx */ - /* LDREXD: cccc 0001 1011 xxxx xxxx xxxx 1001 xxxx */ - /* STREXB: cccc 0001 1100 xxxx xxxx xxxx 1001 xxxx */ - /* LDREXB: cccc 0001 1101 xxxx xxxx xxxx 1001 xxxx */ - /* STREXH: cccc 0001 1110 xxxx xxxx xxxx 1001 xxxx */ - /* LDREXH: cccc 0001 1111 xxxx xxxx xxxx 1001 xxxx */ - - /* LDRD : cccc 000x xxx0 xxxx xxxx xxxx 1101 xxxx */ - /* STRD : cccc 000x xxx0 xxxx xxxx xxxx 1111 xxxx */ - /* LDRH : cccc 000x xxx1 xxxx xxxx xxxx 1011 xxxx */ - /* STRH : cccc 000x xxx0 xxxx xxxx xxxx 1011 xxxx */ - /* LDRSB : cccc 000x xxx1 xxxx xxxx xxxx 1101 xxxx */ - /* LDRSH : cccc 000x xxx1 xxxx xxxx xxxx 1111 xxxx */ - if ((insn & 0x0f0000f0) == 0x01000090) { - if ((insn & 0x0fb000f0) == 0x01000090) { - /* SWP/SWPB */ - return prep_emulate_rd12rn16rm0_wflags(insn, - asi); - } else { - /* STREX/LDREX variants and unallocaed space */ - return INSN_REJECTED; - } - - } else if ((insn & 0x0e1000d0) == 0x00000d0) { - /* STRD/LDRD */ - if ((insn & 0x0000e000) == 0x0000e000) - return INSN_REJECTED; /* Rd is LR or PC */ - if (is_writeback(insn) && is_r15(insn, 16)) - return INSN_REJECTED; /* Writeback to PC */ - - insn &= 0xfff00fff; - insn |= 0x00002000; /* Rn = r0, Rd = r2 */ - if (!(insn & (1 << 22))) { - /* Register index */ - insn &= ~0xf; - insn |= 1; /* Rm = r1 */ - } - asi->insn[0] = insn; - asi->insn_handler = - (insn & (1 << 5)) ? emulate_strd : emulate_ldrd; - return INSN_GOOD; - } - - /* LDRH/STRH/LDRSB/LDRSH */ - if (is_r15(insn, 12)) - return INSN_REJECTED; /* Rd is PC */ - return prep_emulate_ldr_str(insn, asi); - } - - /* cccc 000x xxxx xxxx xxxx xxxx xxxx xxxx xxxx */ - - /* - * ALU op with S bit and Rd == 15 : - * cccc 000x xxx1 xxxx 1111 xxxx xxxx xxxx - */ - if ((insn & 0x0e10f000) == 0x0010f000) - return INSN_REJECTED; - - /* - * "mov ip, sp" is the most common kprobe'd instruction by far. - * Check and optimize for it explicitly. - */ - if (insn == 0xe1a0c00d) { - asi->insn_handler = simulate_mov_ipsp; - return INSN_GOOD_NO_SLOT; - } - - /* - * Data processing: Immediate-shift / Register-shift - * ALU op : cccc 000x xxxx xxxx xxxx xxxx xxxx xxxx - * CPY : cccc 0001 1010 xxxx xxxx 0000 0000 xxxx - * MOV : cccc 0001 101x xxxx xxxx xxxx xxxx xxxx - * *S (bit 20) updates condition codes - * ADC/SBC/RSC reads the C flag - */ - insn &= 0xfff00ff0; /* Rn = r0, Rd = r0 */ - insn |= 0x00000001; /* Rm = r1 */ - if (insn & 0x010) { - insn &= 0xfffff0ff; /* register shift */ - insn |= 0x00000200; /* Rs = r2 */ - } - asi->insn[0] = insn; - - if ((insn & 0x0f900000) == 0x01100000) { - /* - * TST : cccc 0001 0001 xxxx xxxx xxxx xxxx xxxx - * TEQ : cccc 0001 0011 xxxx xxxx xxxx xxxx xxxx - * CMP : cccc 0001 0101 xxxx xxxx xxxx xxxx xxxx - * CMN : cccc 0001 0111 xxxx xxxx xxxx xxxx xxxx - */ - asi->insn_handler = emulate_alu_tests; - } else { - /* ALU ops which write to Rd */ - asi->insn_handler = (insn & (1 << 20)) ? /* S-bit */ - emulate_alu_rwflags : emulate_alu_rflags; - } - return INSN_GOOD; -} - -static enum kprobe_insn __kprobes -space_cccc_001x(kprobe_opcode_t insn, struct arch_specific_insn *asi) -{ - /* MOVW : cccc 0011 0000 xxxx xxxx xxxx xxxx xxxx */ - /* MOVT : cccc 0011 0100 xxxx xxxx xxxx xxxx xxxx */ - if ((insn & 0x0fb00000) == 0x03000000) - return prep_emulate_rd12_modify(insn, asi); - - /* hints : cccc 0011 0010 0000 xxxx xxxx xxxx xxxx */ - if ((insn & 0x0fff0000) == 0x03200000) { - unsigned op2 = insn & 0x000000ff; - if (op2 == 0x01 || op2 == 0x04) { - /* YIELD : cccc 0011 0010 0000 xxxx xxxx 0000 0001 */ - /* SEV : cccc 0011 0010 0000 xxxx xxxx 0000 0100 */ - asi->insn[0] = insn; - asi->insn_handler = emulate_none; - return INSN_GOOD; - } else if (op2 <= 0x03) { - /* 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 */ - /* - * We make WFE and WFI true NOPs to avoid stalls due - * to missing events whilst processing the probe. - */ - asi->insn_handler = emulate_nop; - return INSN_GOOD_NO_SLOT; - } - /* For DBG and unallocated hints it's safest to reject them */ - return INSN_REJECTED; - } - - /* - * MSR : cccc 0011 0x10 xxxx xxxx xxxx xxxx xxxx - * ALU op with S bit and Rd == 15 : - * cccc 001x xxx1 xxxx 1111 xxxx xxxx xxxx - */ - if ((insn & 0x0fb00000) == 0x03200000 || /* MSR */ - (insn & 0x0e10f000) == 0x0210f000) /* ALU s-bit, R15 */ - return INSN_REJECTED; - - /* - * Data processing: 32-bit Immediate - * ALU op : cccc 001x xxxx xxxx xxxx xxxx xxxx xxxx - * MOV : cccc 0011 101x xxxx xxxx xxxx xxxx xxxx - * *S (bit 20) updates condition codes - * ADC/SBC/RSC reads the C flag - */ - insn &= 0xfff00fff; /* Rn = r0 and Rd = r0 */ - asi->insn[0] = insn; - - if ((insn & 0x0f900000) == 0x03100000) { - /* - * TST : cccc 0011 0001 xxxx xxxx xxxx xxxx xxxx - * TEQ : cccc 0011 0011 xxxx xxxx xxxx xxxx xxxx - * CMP : cccc 0011 0101 xxxx xxxx xxxx xxxx xxxx - * CMN : cccc 0011 0111 xxxx xxxx xxxx xxxx xxxx - */ - asi->insn_handler = emulate_alu_tests_imm; - } else { - /* ALU ops which write to Rd */ - asi->insn_handler = (insn & (1 << 20)) ? /* S-bit */ - emulate_alu_imm_rwflags : emulate_alu_imm_rflags; - } - return INSN_GOOD; -} - -static enum kprobe_insn __kprobes -space_cccc_0110__1(kprobe_opcode_t insn, struct arch_specific_insn *asi) -{ - /* SEL : cccc 0110 1000 xxxx xxxx xxxx 1011 xxxx GE: !!! */ - if ((insn & 0x0ff000f0) == 0x068000b0) { - if (is_r15(insn, 12)) - return INSN_REJECTED; /* Rd is PC */ - insn &= 0xfff00ff0; /* Rd = r0, Rn = r0 */ - insn |= 0x00000001; /* Rm = r1 */ - asi->insn[0] = insn; - asi->insn_handler = emulate_sel; - return INSN_GOOD; - } - - /* SSAT : cccc 0110 101x xxxx xxxx xxxx xx01 xxxx :Q */ - /* USAT : cccc 0110 111x xxxx xxxx xxxx xx01 xxxx :Q */ - /* SSAT16 : cccc 0110 1010 xxxx xxxx xxxx 0011 xxxx :Q */ - /* USAT16 : cccc 0110 1110 xxxx xxxx xxxx 0011 xxxx :Q */ - if ((insn & 0x0fa00030) == 0x06a00010 || - (insn & 0x0fb000f0) == 0x06a00030) { - if (is_r15(insn, 12)) - return INSN_REJECTED; /* Rd is PC */ - insn &= 0xffff0ff0; /* Rd = r0, Rm = r0 */ - asi->insn[0] = insn; - asi->insn_handler = emulate_sat; - return INSN_GOOD; - } - - /* 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 */ - if ((insn & 0x0ff00070) == 0x06b00030 || - (insn & 0x0ff00070) == 0x06f00030) - return prep_emulate_rd12rm0(insn, asi); - - /* ??? : cccc 0110 0000 xxxx xxxx xxxx xxx1 xxxx : */ - /* SADD16 : cccc 0110 0001 xxxx xxxx xxxx 0001 xxxx :GE */ - /* SADDSUBX : cccc 0110 0001 xxxx xxxx xxxx 0011 xxxx :GE */ - /* SSUBADDX : cccc 0110 0001 xxxx xxxx xxxx 0101 xxxx :GE */ - /* SSUB16 : cccc 0110 0001 xxxx xxxx xxxx 0111 xxxx :GE */ - /* SADD8 : cccc 0110 0001 xxxx xxxx xxxx 1001 xxxx :GE */ - /* ??? : cccc 0110 0001 xxxx xxxx xxxx 1011 xxxx : */ - /* ??? : cccc 0110 0001 xxxx xxxx xxxx 1101 xxxx : */ - /* SSUB8 : cccc 0110 0001 xxxx xxxx xxxx 1111 xxxx :GE */ - /* 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 : */ - /* ??? : cccc 0110 0010 xxxx xxxx xxxx 1011 xxxx : */ - /* ??? : cccc 0110 0010 xxxx xxxx xxxx 1101 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 : */ - /* ??? : cccc 0110 0011 xxxx xxxx xxxx 1011 xxxx : */ - /* ??? : cccc 0110 0011 xxxx xxxx xxxx 1101 xxxx : */ - /* SHSUB8 : cccc 0110 0011 xxxx xxxx xxxx 1111 xxxx : */ - /* ??? : cccc 0110 0100 xxxx xxxx xxxx xxx1 xxxx : */ - /* UADD16 : cccc 0110 0101 xxxx xxxx xxxx 0001 xxxx :GE */ - /* UADDSUBX : cccc 0110 0101 xxxx xxxx xxxx 0011 xxxx :GE */ - /* USUBADDX : cccc 0110 0101 xxxx xxxx xxxx 0101 xxxx :GE */ - /* USUB16 : cccc 0110 0101 xxxx xxxx xxxx 0111 xxxx :GE */ - /* UADD8 : cccc 0110 0101 xxxx xxxx xxxx 1001 xxxx :GE */ - /* ??? : cccc 0110 0101 xxxx xxxx xxxx 1011 xxxx : */ - /* ??? : cccc 0110 0101 xxxx xxxx xxxx 1101 xxxx : */ - /* USUB8 : cccc 0110 0101 xxxx xxxx xxxx 1111 xxxx :GE */ - /* 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 : */ - /* ??? : cccc 0110 0110 xxxx xxxx xxxx 1011 xxxx : */ - /* ??? : cccc 0110 0110 xxxx xxxx xxxx 1101 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 : */ - /* ??? : cccc 0110 0111 xxxx xxxx xxxx 1011 xxxx : */ - /* ??? : cccc 0110 0111 xxxx xxxx xxxx 1101 xxxx : */ - /* UHSUB8 : cccc 0110 0111 xxxx xxxx xxxx 1111 xxxx : */ - if ((insn & 0x0f800010) == 0x06000010) { - if ((insn & 0x00300000) == 0x00000000 || - (insn & 0x000000e0) == 0x000000a0 || - (insn & 0x000000e0) == 0x000000c0) - return INSN_REJECTED; /* Unallocated space */ - return prep_emulate_rd12rn16rm0_wflags(insn, asi); - } - - /* PKHBT : cccc 0110 1000 xxxx xxxx xxxx x001 xxxx : */ - /* PKHTB : cccc 0110 1000 xxxx xxxx xxxx x101 xxxx : */ - if ((insn & 0x0ff00030) == 0x06800010) - return prep_emulate_rd12rn16rm0_wflags(insn, asi); - - /* SXTAB16 : cccc 0110 1000 xxxx xxxx xxxx 0111 xxxx : */ - /* SXTB16 : cccc 0110 1000 1111 xxxx xxxx 0111 xxxx : */ - /* ??? : cccc 0110 1001 xxxx xxxx xxxx 0111 xxxx : */ - /* SXTAB : cccc 0110 1010 xxxx xxxx xxxx 0111 xxxx : */ - /* SXTB : cccc 0110 1010 1111 xxxx xxxx 0111 xxxx : */ - /* SXTAH : cccc 0110 1011 xxxx xxxx xxxx 0111 xxxx : */ - /* SXTH : cccc 0110 1011 1111 xxxx xxxx 0111 xxxx : */ - /* UXTAB16 : cccc 0110 1100 xxxx xxxx xxxx 0111 xxxx : */ - /* UXTB16 : cccc 0110 1100 1111 xxxx xxxx 0111 xxxx : */ - /* ??? : cccc 0110 1101 xxxx xxxx xxxx 0111 xxxx : */ - /* UXTAB : cccc 0110 1110 xxxx xxxx xxxx 0111 xxxx : */ - /* UXTB : cccc 0110 1110 1111 xxxx xxxx 0111 xxxx : */ - /* UXTAH : cccc 0110 1111 xxxx xxxx xxxx 0111 xxxx : */ - /* UXTH : cccc 0110 1111 1111 xxxx xxxx 0111 xxxx : */ - if ((insn & 0x0f8000f0) == 0x06800070) { - if ((insn & 0x00300000) == 0x00100000) - return INSN_REJECTED; /* Unallocated space */ - - if ((insn & 0x000f0000) == 0x000f0000) - return prep_emulate_rd12rm0(insn, asi); - else - return prep_emulate_rd12rn16rm0_wflags(insn, asi); - } - - /* Other instruction encodings aren't yet defined */ - return INSN_REJECTED; -} - -static enum kprobe_insn __kprobes -space_cccc_0111__1(kprobe_opcode_t insn, struct arch_specific_insn *asi) -{ - /* Undef : cccc 0111 1111 xxxx xxxx xxxx 1111 xxxx */ - if ((insn & 0x0ff000f0) == 0x03f000f0) - return INSN_REJECTED; - - /* SMLALD : cccc 0111 0100 xxxx xxxx xxxx 00x1 xxxx */ - /* SMLSLD : cccc 0111 0100 xxxx xxxx xxxx 01x1 xxxx */ - if ((insn & 0x0ff00090) == 0x07400010) - return prep_emulate_rdhi16rdlo12rs8rm0_wflags(insn, asi); - - /* SMLAD : cccc 0111 0000 xxxx xxxx xxxx 00x1 xxxx :Q */ - /* SMUAD : cccc 0111 0000 xxxx 1111 xxxx 00x1 xxxx :Q */ - /* SMLSD : cccc 0111 0000 xxxx xxxx xxxx 01x1 xxxx :Q */ - /* SMUSD : cccc 0111 0000 xxxx 1111 xxxx 01x1 xxxx : */ - /* SMMLA : cccc 0111 0101 xxxx xxxx xxxx 00x1 xxxx : */ - /* SMMUL : cccc 0111 0101 xxxx 1111 xxxx 00x1 xxxx : */ - /* USADA8 : cccc 0111 1000 xxxx xxxx xxxx 0001 xxxx : */ - /* USAD8 : cccc 0111 1000 xxxx 1111 xxxx 0001 xxxx : */ - if ((insn & 0x0ff00090) == 0x07000010 || - (insn & 0x0ff000d0) == 0x07500010 || - (insn & 0x0ff000f0) == 0x07800010) { - - if ((insn & 0x0000f000) == 0x0000f000) - return prep_emulate_rd16rs8rm0_wflags(insn, asi); - else - return prep_emulate_rd16rn12rs8rm0_wflags(insn, asi); - } - - /* SMMLS : cccc 0111 0101 xxxx xxxx xxxx 11x1 xxxx : */ - if ((insn & 0x0ff000d0) == 0x075000d0) - return prep_emulate_rd16rn12rs8rm0_wflags(insn, asi); - - /* SBFX : cccc 0111 101x xxxx xxxx xxxx x101 xxxx : */ - /* UBFX : cccc 0111 111x xxxx xxxx xxxx x101 xxxx : */ - if ((insn & 0x0fa00070) == 0x07a00050) - return prep_emulate_rd12rm0(insn, asi); - - /* BFI : cccc 0111 110x xxxx xxxx xxxx x001 xxxx : */ - /* BFC : cccc 0111 110x xxxx xxxx xxxx x001 1111 : */ - if ((insn & 0x0fe00070) == 0x07c00010) { - - if ((insn & 0x0000000f) == 0x0000000f) - return prep_emulate_rd12_modify(insn, asi); - else - return prep_emulate_rd12rn0_modify(insn, asi); - } - - return INSN_REJECTED; -} - -static enum kprobe_insn __kprobes -space_cccc_01xx(kprobe_opcode_t insn, struct arch_specific_insn *asi) -{ - /* LDR : cccc 01xx x0x1 xxxx xxxx xxxx xxxx xxxx */ - /* LDRB : cccc 01xx x1x1 xxxx xxxx xxxx xxxx xxxx */ - /* LDRBT : cccc 01x0 x111 xxxx xxxx xxxx xxxx xxxx */ - /* LDRT : cccc 01x0 x011 xxxx xxxx xxxx xxxx xxxx */ - /* STR : cccc 01xx x0x0 xxxx xxxx xxxx xxxx xxxx */ - /* STRB : cccc 01xx x1x0 xxxx xxxx xxxx xxxx xxxx */ - /* STRBT : cccc 01x0 x110 xxxx xxxx xxxx xxxx xxxx */ - /* STRT : cccc 01x0 x010 xxxx xxxx xxxx xxxx xxxx */ - - if ((insn & 0x00500000) == 0x00500000 && is_r15(insn, 12)) - return INSN_REJECTED; /* LDRB into PC */ - - return prep_emulate_ldr_str(insn, asi); -} - -static enum kprobe_insn __kprobes -space_cccc_100x(kprobe_opcode_t insn, struct arch_specific_insn *asi) -{ - /* LDM(2) : cccc 100x x101 xxxx 0xxx xxxx xxxx xxxx */ - /* LDM(3) : cccc 100x x1x1 xxxx 1xxx xxxx xxxx xxxx */ - if ((insn & 0x0e708000) == 0x85000000 || - (insn & 0x0e508000) == 0x85010000) - return INSN_REJECTED; - - /* LDM(1) : cccc 100x x0x1 xxxx xxxx xxxx xxxx xxxx */ - /* STM(1) : cccc 100x x0x0 xxxx xxxx xxxx xxxx xxxx */ - asi->insn_handler = ((insn & 0x108000) == 0x008000) ? /* STM & R15 */ - simulate_stm1_pc : simulate_ldm1stm1; - return INSN_GOOD_NO_SLOT; -} - -static enum kprobe_insn __kprobes -space_cccc_101x(kprobe_opcode_t insn, struct arch_specific_insn *asi) -{ - /* B : cccc 1010 xxxx xxxx xxxx xxxx xxxx xxxx */ - /* BL : cccc 1011 xxxx xxxx xxxx xxxx xxxx xxxx */ - asi->insn_handler = simulate_bbl; - return INSN_GOOD_NO_SLOT; -} - -static enum kprobe_insn __kprobes -space_cccc_11xx(kprobe_opcode_t insn, struct arch_specific_insn *asi) -{ - /* Coprocessor instructions... */ - /* MCRR : cccc 1100 0100 xxxx xxxx xxxx xxxx xxxx : (Rd!=Rn) */ - /* MRRC : cccc 1100 0101 xxxx xxxx xxxx xxxx xxxx : (Rd!=Rn) */ - /* 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 */ - - return INSN_REJECTED; -} - -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; -} - -static kprobe_check_cc * const 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 -}; - -/* 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_check_cc = condition_checks[insn>>28]; - asi->insn[1] = KPROBE_RETURN_INSTRUCTION; - - if ((insn & 0xf0000000) == 0xf0000000) - - return space_1111(insn, asi); - - else if ((insn & 0x0e000000) == 0x00000000) - - return space_cccc_000x(insn, asi); - - else if ((insn & 0x0e000000) == 0x02000000) - - return space_cccc_001x(insn, asi); - - else if ((insn & 0x0f000010) == 0x06000010) - - return space_cccc_0110__1(insn, asi); - - else if ((insn & 0x0f000010) == 0x07000010) - - return space_cccc_0111__1(insn, asi); - - else if ((insn & 0x0c000000) == 0x04000000) - - return space_cccc_01xx(insn, asi); - - else if ((insn & 0x0e000000) == 0x08000000) - - return space_cccc_100x(insn, asi); - - else if ((insn & 0x0e000000) == 0x0a000000) - - return space_cccc_101x(insn, asi); - - return space_cccc_11xx(insn, asi); -} - -void __init arm_kprobe_decode_init(void) -{ - find_str_pc_offset(); -} diff --git a/arch/arm/kernel/kprobes-thumb.c b/arch/arm/kernel/kprobes-thumb.c new file mode 100644 index 0000000..902ca59 --- /dev/null +++ b/arch/arm/kernel/kprobes-thumb.c @@ -0,0 +1,1462 @@ +/* + * arch/arm/kernel/kprobes-thumb.c + * + * Copyright (C) 2011 Jon Medhurst . + * + * 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 +#include + +#include "kprobes.h" + + +/* + * True if current instruction is in an IT block. + */ +#define in_it_block(cpsr) ((cpsr & 0x06000c00) != 0x00000000) + +/* + * Return the condition code to check for the currently executing instruction. + * This is in ITSTATE<7:4> which is in CPSR<15:12> but is only valid if + * in_it_block returns true. + */ +#define current_cond(cpsr) ((cpsr >> 12) & 0xf) + +/* + * Return the PC value for a probe in thumb code. + * This is the address of the probed instruction plus 4. + * We subtract one because the address will have bit zero set to indicate + * a pointer to thumb code. + */ +static inline unsigned long __kprobes thumb_probe_pc(struct kprobe *p) +{ + return (unsigned long)p->addr - 1 + 4; +} + +static void __kprobes +t32_simulate_table_branch(struct kprobe *p, struct pt_regs *regs) +{ + kprobe_opcode_t insn = p->opcode; + unsigned long pc = thumb_probe_pc(p); + int rn = (insn >> 16) & 0xf; + int rm = insn & 0xf; + + unsigned long rnv = (rn == 15) ? pc : regs->uregs[rn]; + unsigned long rmv = regs->uregs[rm]; + unsigned int halfwords; + + if (insn & 0x10) /* TBH */ + halfwords = ((u16 *)rnv)[rmv]; + else /* TBB */ + halfwords = ((u8 *)rnv)[rmv]; + + regs->ARM_pc = pc + 2 * halfwords; +} + +static void __kprobes +t32_simulate_mrs(struct kprobe *p, struct pt_regs *regs) +{ + kprobe_opcode_t insn = p->opcode; + int rd = (insn >> 8) & 0xf; + unsigned long mask = 0xf8ff03df; /* Mask out execution state */ + regs->uregs[rd] = regs->ARM_cpsr & mask; +} + +static void __kprobes +t32_simulate_cond_branch(struct kprobe *p, struct pt_regs *regs) +{ + kprobe_opcode_t insn = p->opcode; + unsigned long pc = thumb_probe_pc(p); + + long offset = insn & 0x7ff; /* imm11 */ + offset += (insn & 0x003f0000) >> 5; /* imm6 */ + offset += (insn & 0x00002000) << 4; /* J1 */ + offset += (insn & 0x00000800) << 7; /* J2 */ + offset -= (insn & 0x04000000) >> 7; /* Apply sign bit */ + + regs->ARM_pc = pc + (offset * 2); +} + +static enum kprobe_insn __kprobes +t32_decode_cond_branch(kprobe_opcode_t insn, struct arch_specific_insn *asi) +{ + int cc = (insn >> 22) & 0xf; + asi->insn_check_cc = kprobe_condition_checks[cc]; + asi->insn_handler = t32_simulate_cond_branch; + return INSN_GOOD_NO_SLOT; +} + +static void __kprobes +t32_simulate_branch(struct kprobe *p, struct pt_regs *regs) +{ + kprobe_opcode_t insn = p->opcode; + unsigned long pc = thumb_probe_pc(p); + + long offset = insn & 0x7ff; /* imm11 */ + offset += (insn & 0x03ff0000) >> 5; /* imm10 */ + offset += (insn & 0x00002000) << 9; /* J1 */ + offset += (insn & 0x00000800) << 10; /* J2 */ + if (insn & 0x04000000) + offset -= 0x00800000; /* Apply sign bit */ + else + offset ^= 0x00600000; /* Invert J1 and J2 */ + + if (insn & (1 << 14)) { + /* BL or BLX */ + regs->ARM_lr = (unsigned long)p->addr + 4; + if (!(insn & (1 << 12))) { + /* BLX so switch to ARM mode */ + regs->ARM_cpsr &= ~PSR_T_BIT; + pc &= ~3; + } + } + + regs->ARM_pc = pc + (offset * 2); +} + +static void __kprobes +t32_simulate_ldr_literal(struct kprobe *p, struct pt_regs *regs) +{ + kprobe_opcode_t insn = p->opcode; + unsigned long addr = thumb_probe_pc(p) & ~3; + int rt = (insn >> 12) & 0xf; + unsigned long rtv; + + long offset = insn & 0xfff; + if (insn & 0x00800000) + addr += offset; + else + addr -= offset; + + if (insn & 0x00400000) { + /* LDR */ + rtv = *(unsigned long *)addr; + if (rt == 15) { + bx_write_pc(rtv, regs); + return; + } + } else if (insn & 0x00200000) { + /* LDRH */ + if (insn & 0x01000000) + rtv = *(s16 *)addr; + else + rtv = *(u16 *)addr; + } else { + /* LDRB */ + if (insn & 0x01000000) + rtv = *(s8 *)addr; + else + rtv = *(u8 *)addr; + } + + regs->uregs[rt] = rtv; +} + +static enum kprobe_insn __kprobes +t32_decode_ldmstm(kprobe_opcode_t insn, struct arch_specific_insn *asi) +{ + enum kprobe_insn ret = kprobe_decode_ldmstm(insn, asi); + + /* Fixup modified instruction to have halfwords in correct order...*/ + insn = asi->insn[0]; + ((u16 *)asi->insn)[0] = insn >> 16; + ((u16 *)asi->insn)[1] = insn & 0xffff; + + return ret; +} + +static void __kprobes +t32_emulate_ldrdstrd(struct kprobe *p, struct pt_regs *regs) +{ + kprobe_opcode_t insn = p->opcode; + unsigned long pc = thumb_probe_pc(p) & ~3; + int rt1 = (insn >> 12) & 0xf; + int rt2 = (insn >> 8) & 0xf; + int rn = (insn >> 16) & 0xf; + + register unsigned long rt1v asm("r0") = regs->uregs[rt1]; + register unsigned long rt2v asm("r1") = regs->uregs[rt2]; + register unsigned long rnv asm("r2") = (rn == 15) ? pc + : regs->uregs[rn]; + + __asm__ __volatile__ ( + "blx %[fn]" + : "=r" (rt1v), "=r" (rt2v), "=r" (rnv) + : "0" (rt1v), "1" (rt2v), "2" (rnv), [fn] "r" (p->ainsn.insn_fn) + : "lr", "memory", "cc" + ); + + if (rn != 15) + regs->uregs[rn] = rnv; /* Writeback base register */ + regs->uregs[rt1] = rt1v; + regs->uregs[rt2] = rt2v; +} + +static void __kprobes +t32_emulate_ldrstr(struct kprobe *p, struct pt_regs *regs) +{ + kprobe_opcode_t insn = p->opcode; + 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 rnv asm("r2") = regs->uregs[rn]; + register unsigned long rmv asm("r3") = regs->uregs[rm]; + + __asm__ __volatile__ ( + "blx %[fn]" + : "=r" (rtv), "=r" (rnv) + : "0" (rtv), "1" (rnv), "r" (rmv), [fn] "r" (p->ainsn.insn_fn) + : "lr", "memory", "cc" + ); + + regs->uregs[rn] = rnv; /* Writeback base register */ + if (rt == 15) /* Can't be true for a STR as they aren't allowed */ + bx_write_pc(rtv, regs); + else + regs->uregs[rt] = rtv; +} + +static void __kprobes +t32_emulate_rd8rn16rm0_rwflags(struct kprobe *p, struct pt_regs *regs) +{ + kprobe_opcode_t insn = p->opcode; + int rd = (insn >> 8) & 0xf; + int rn = (insn >> 16) & 0xf; + int rm = insn & 0xf; + + register unsigned long rdv asm("r1") = 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] \n\t" + "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 +t32_emulate_rd8pc16_noflags(struct kprobe *p, struct pt_regs *regs) +{ + kprobe_opcode_t insn = p->opcode; + unsigned long pc = thumb_probe_pc(p); + int rd = (insn >> 8) & 0xf; + + register unsigned long rdv asm("r1") = regs->uregs[rd]; + register unsigned long rnv asm("r2") = pc & ~3; + + __asm__ __volatile__ ( + "blx %[fn]" + : "=r" (rdv) + : "0" (rdv), "r" (rnv), [fn] "r" (p->ainsn.insn_fn) + : "lr", "memory", "cc" + ); + + regs->uregs[rd] = rdv; +} + +static void __kprobes +t32_emulate_rd8rn16_noflags(struct kprobe *p, struct pt_regs *regs) +{ + kprobe_opcode_t insn = p->opcode; + int rd = (insn >> 8) & 0xf; + int rn = (insn >> 16) & 0xf; + + register unsigned long rdv asm("r1") = regs->uregs[rd]; + register unsigned long rnv asm("r2") = regs->uregs[rn]; + + __asm__ __volatile__ ( + "blx %[fn]" + : "=r" (rdv) + : "0" (rdv), "r" (rnv), [fn] "r" (p->ainsn.insn_fn) + : "lr", "memory", "cc" + ); + + regs->uregs[rd] = rdv; +} + +static void __kprobes +t32_emulate_rdlo12rdhi8rn16rm0_noflags(struct kprobe *p, struct pt_regs *regs) +{ + kprobe_opcode_t insn = p->opcode; + int rdlo = (insn >> 12) & 0xf; + int rdhi = (insn >> 8) & 0xf; + int rn = (insn >> 16) & 0xf; + int rm = insn & 0xf; + + register unsigned long rdlov asm("r0") = regs->uregs[rdlo]; + register unsigned long rdhiv asm("r1") = regs->uregs[rdhi]; + register unsigned long rnv asm("r2") = regs->uregs[rn]; + register unsigned long rmv asm("r3") = regs->uregs[rm]; + + __asm__ __volatile__ ( + "blx %[fn]" + : "=r" (rdlov), "=r" (rdhiv) + : "0" (rdlov), "1" (rdhiv), "r" (rnv), "r" (rmv), + [fn] "r" (p->ainsn.insn_fn) + : "lr", "memory", "cc" + ); + + regs->uregs[rdlo] = rdlov; + regs->uregs[rdhi] = rdhiv; +} + +/* These emulation encodings are functionally equivalent... */ +#define t32_emulate_rd8rn16rm0ra12_noflags \ + t32_emulate_rdlo12rdhi8rn16rm0_noflags + +static const union decode_item t32_table_1110_100x_x0xx[] = { + /* Load/store multiple instructions */ + + /* Rn is PC 1110 100x x0xx 1111 xxxx xxxx xxxx xxxx */ + DECODE_REJECT (0xfe4f0000, 0xe80f0000), + + /* SRS 1110 1000 00x0 xxxx xxxx xxxx xxxx xxxx */ + /* RFE 1110 1000 00x1 xxxx xxxx xxxx xxxx xxxx */ + DECODE_REJECT (0xffc00000, 0xe8000000), + /* SRS 1110 1001 10x0 xxxx xxxx xxxx xxxx xxxx */ + /* RFE 1110 1001 10x1 xxxx xxxx xxxx xxxx xxxx */ + DECODE_REJECT (0xffc00000, 0xe9800000), + + /* STM Rn, {...pc} 1110 100x x0x0 xxxx 1xxx xxxx xxxx xxxx */ + DECODE_REJECT (0xfe508000, 0xe8008000), + /* LDM Rn, {...lr,pc} 1110 100x x0x1 xxxx 11xx xxxx xxxx xxxx */ + DECODE_REJECT (0xfe50c000, 0xe810c000), + /* LDM/STM Rn, {...sp} 1110 100x x0xx xxxx xx1x xxxx xxxx xxxx */ + DECODE_REJECT (0xfe402000, 0xe8002000), + + /* STMIA 1110 1000 10x0 xxxx xxxx xxxx xxxx xxxx */ + /* LDMIA 1110 1000 10x1 xxxx xxxx xxxx xxxx xxxx */ + /* STMDB 1110 1001 00x0 xxxx xxxx xxxx xxxx xxxx */ + /* LDMDB 1110 1001 00x1 xxxx xxxx xxxx xxxx xxxx */ + DECODE_CUSTOM (0xfe400000, 0xe8000000, t32_decode_ldmstm), + + DECODE_END +}; + +static const union decode_item t32_table_1110_100x_x1xx[] = { + /* Load/store dual, load/store exclusive, table branch */ + + /* STRD (immediate) 1110 1000 x110 xxxx xxxx xxxx xxxx xxxx */ + /* LDRD (immediate) 1110 1000 x111 xxxx xxxx xxxx xxxx xxxx */ + DECODE_OR (0xff600000, 0xe8600000), + /* STRD (immediate) 1110 1001 x1x0 xxxx xxxx xxxx xxxx xxxx */ + /* LDRD (immediate) 1110 1001 x1x1 xxxx xxxx xxxx xxxx xxxx */ + DECODE_EMULATEX (0xff400000, 0xe9400000, t32_emulate_ldrdstrd, + REGS(NOPCWB, NOSPPC, NOSPPC, 0, 0)), + + /* TBB 1110 1000 1101 xxxx xxxx xxxx 0000 xxxx */ + /* TBH 1110 1000 1101 xxxx xxxx xxxx 0001 xxxx */ + DECODE_SIMULATEX(0xfff000e0, 0xe8d00000, t32_simulate_table_branch, + REGS(NOSP, 0, 0, 0, NOSPPC)), + + /* STREX 1110 1000 0100 xxxx xxxx xxxx xxxx xxxx */ + /* LDREX 1110 1000 0101 xxxx xxxx xxxx xxxx xxxx */ + /* STREXB 1110 1000 1100 xxxx xxxx xxxx 0100 xxxx */ + /* STREXH 1110 1000 1100 xxxx xxxx xxxx 0101 xxxx */ + /* STREXD 1110 1000 1100 xxxx xxxx xxxx 0111 xxxx */ + /* LDREXB 1110 1000 1101 xxxx xxxx xxxx 0100 xxxx */ + /* LDREXH 1110 1000 1101 xxxx xxxx xxxx 0101 xxxx */ + /* LDREXD 1110 1000 1101 xxxx xxxx xxxx 0111 xxxx */ + /* And unallocated instructions... */ + DECODE_END +}; + +static const union decode_item t32_table_1110_101x[] = { + /* Data-processing (shifted register) */ + + /* TST 1110 1010 0001 xxxx xxxx 1111 xxxx xxxx */ + /* TEQ 1110 1010 1001 xxxx xxxx 1111 xxxx xxxx */ + DECODE_EMULATEX (0xff700f00, 0xea100f00, t32_emulate_rd8rn16rm0_rwflags, + REGS(NOSPPC, 0, 0, 0, NOSPPC)), + + /* CMN 1110 1011 0001 xxxx xxxx 1111 xxxx xxxx */ + DECODE_OR (0xfff00f00, 0xeb100f00), + /* CMP 1110 1011 1011 xxxx xxxx 1111 xxxx xxxx */ + DECODE_EMULATEX (0xfff00f00, 0xebb00f00, t32_emulate_rd8rn16rm0_rwflags, + REGS(NOPC, 0, 0, 0, NOSPPC)), + + /* MOV 1110 1010 010x 1111 xxxx xxxx xxxx xxxx */ + /* MVN 1110 1010 011x 1111 xxxx xxxx xxxx xxxx */ + DECODE_EMULATEX (0xffcf0000, 0xea4f0000, t32_emulate_rd8rn16rm0_rwflags, + REGS(0, 0, NOSPPC, 0, NOSPPC)), + + /* ??? 1110 1010 101x xxxx xxxx xxxx xxxx xxxx */ + /* ??? 1110 1010 111x xxxx xxxx xxxx xxxx xxxx */ + DECODE_REJECT (0xffa00000, 0xeaa00000), + /* ??? 1110 1011 001x xxxx xxxx xxxx xxxx xxxx */ + DECODE_REJECT (0xffe00000, 0xeb200000), + /* ??? 1110 1011 100x xxxx xxxx xxxx xxxx xxxx */ + DECODE_REJECT (0xffe00000, 0xeb800000), + /* ??? 1110 1011 111x xxxx xxxx xxxx xxxx xxxx */ + DECODE_REJECT (0xffe00000, 0xebe00000), + + /* ADD/SUB SP, SP, Rm, LSL #0..3 */ + /* 1110 1011 x0xx 1101 x000 1101 xx00 xxxx */ + DECODE_EMULATEX (0xff4f7f30, 0xeb0d0d00, t32_emulate_rd8rn16rm0_rwflags, + REGS(SP, 0, SP, 0, NOSPPC)), + + /* ADD/SUB SP, SP, Rm, shift */ + /* 1110 1011 x0xx 1101 xxxx 1101 xxxx xxxx */ + DECODE_REJECT (0xff4f0f00, 0xeb0d0d00), + + /* ADD/SUB Rd, SP, Rm, shift */ + /* 1110 1011 x0xx 1101 xxxx xxxx xxxx xxxx */ + DECODE_EMULATEX (0xff4f0000, 0xeb0d0000, t32_emulate_rd8rn16rm0_rwflags, + REGS(SP, 0, NOPC, 0, NOSPPC)), + + /* AND 1110 1010 000x xxxx xxxx xxxx xxxx xxxx */ + /* BIC 1110 1010 001x xxxx xxxx xxxx xxxx xxxx */ + /* ORR 1110 1010 010x xxxx xxxx xxxx xxxx xxxx */ + /* ORN 1110 1010 011x xxxx xxxx xxxx xxxx xxxx */ + /* EOR 1110 1010 100x xxxx xxxx xxxx xxxx xxxx */ + /* PKH 1110 1010 110x xxxx xxxx xxxx xxxx xxxx */ + /* ADD 1110 1011 000x xxxx xxxx xxxx xxxx xxxx */ + /* ADC 1110 1011 010x xxxx xxxx xxxx xxxx xxxx */ + /* SBC 1110 1011 011x xxxx xxxx xxxx xxxx xxxx */ + /* SUB 1110 1011 101x xxxx xxxx xxxx xxxx xxxx */ + /* RSB 1110 1011 110x xxxx xxxx xxxx xxxx xxxx */ + DECODE_EMULATEX (0xfe000000, 0xea000000, t32_emulate_rd8rn16rm0_rwflags, + REGS(NOSPPC, 0, NOSPPC, 0, NOSPPC)), + + DECODE_END +}; + +static const union decode_item t32_table_1111_0x0x___0[] = { + /* Data-processing (modified immediate) */ + + /* TST 1111 0x00 0001 xxxx 0xxx 1111 xxxx xxxx */ + /* TEQ 1111 0x00 1001 xxxx 0xxx 1111 xxxx xxxx */ + DECODE_EMULATEX (0xfb708f00, 0xf0100f00, t32_emulate_rd8rn16rm0_rwflags, + REGS(NOSPPC, 0, 0, 0, 0)), + + /* CMN 1111 0x01 0001 xxxx 0xxx 1111 xxxx xxxx */ + DECODE_OR (0xfbf08f00, 0xf1100f00), + /* CMP 1111 0x01 1011 xxxx 0xxx 1111 xxxx xxxx */ + DECODE_EMULATEX (0xfbf08f00, 0xf1b00f00, t32_emulate_rd8rn16rm0_rwflags, + REGS(NOPC, 0, 0, 0, 0)), + + /* MOV 1111 0x00 010x 1111 0xxx xxxx xxxx xxxx */ + /* MVN 1111 0x00 011x 1111 0xxx xxxx xxxx xxxx */ + DECODE_EMULATEX (0xfbcf8000, 0xf04f0000, t32_emulate_rd8rn16rm0_rwflags, + REGS(0, 0, NOSPPC, 0, 0)), + + /* ??? 1111 0x00 101x xxxx 0xxx xxxx xxxx xxxx */ + DECODE_REJECT (0xfbe08000, 0xf0a00000), + /* ??? 1111 0x00 110x xxxx 0xxx xxxx xxxx xxxx */ + /* ??? 1111 0x00 111x xxxx 0xxx xxxx xxxx xxxx */ + DECODE_REJECT (0xfbc08000, 0xf0c00000), + /* ??? 1111 0x01 001x xxxx 0xxx xxxx xxxx xxxx */ + DECODE_REJECT (0xfbe08000, 0xf1200000), + /* ??? 1111 0x01 100x xxxx 0xxx xxxx xxxx xxxx */ + DECODE_REJECT (0xfbe08000, 0xf1800000), + /* ??? 1111 0x01 111x xxxx 0xxx xxxx xxxx xxxx */ + DECODE_REJECT (0xfbe08000, 0xf1e00000), + + /* ADD Rd, SP, #imm 1111 0x01 000x 1101 0xxx xxxx xxxx xxxx */ + /* SUB Rd, SP, #imm 1111 0x01 101x 1101 0xxx xxxx xxxx xxxx */ + DECODE_EMULATEX (0xfb4f8000, 0xf10d0000, t32_emulate_rd8rn16rm0_rwflags, + REGS(SP, 0, NOPC, 0, 0)), + + /* AND 1111 0x00 000x xxxx 0xxx xxxx xxxx xxxx */ + /* BIC 1111 0x00 001x xxxx 0xxx xxxx xxxx xxxx */ + /* ORR 1111 0x00 010x xxxx 0xxx xxxx xxxx xxxx */ + /* ORN 1111 0x00 011x xxxx 0xxx xxxx xxxx xxxx */ + /* EOR 1111 0x00 100x xxxx 0xxx xxxx xxxx xxxx */ + /* ADD 1111 0x01 000x xxxx 0xxx xxxx xxxx xxxx */ + /* ADC 1111 0x01 010x xxxx 0xxx xxxx xxxx xxxx */ + /* SBC 1111 0x01 011x xxxx 0xxx xxxx xxxx xxxx */ + /* SUB 1111 0x01 101x xxxx 0xxx xxxx xxxx xxxx */ + /* RSB 1111 0x01 110x xxxx 0xxx xxxx xxxx xxxx */ + DECODE_EMULATEX (0xfa008000, 0xf0000000, t32_emulate_rd8rn16rm0_rwflags, + REGS(NOSPPC, 0, NOSPPC, 0, 0)), + + DECODE_END +}; + +static const union decode_item t32_table_1111_0x1x___0[] = { + /* Data-processing (plain binary immediate) */ + + /* ADDW Rd, PC, #imm 1111 0x10 0000 1111 0xxx xxxx xxxx xxxx */ + DECODE_OR (0xfbff8000, 0xf20f0000), + /* SUBW Rd, PC, #imm 1111 0x10 1010 1111 0xxx xxxx xxxx xxxx */ + DECODE_EMULATEX (0xfbff8000, 0xf2af0000, t32_emulate_rd8pc16_noflags, + REGS(PC, 0, NOSPPC, 0, 0)), + + /* ADDW SP, SP, #imm 1111 0x10 0000 1101 0xxx 1101 xxxx xxxx */ + DECODE_OR (0xfbff8f00, 0xf20d0d00), + /* SUBW SP, SP, #imm 1111 0x10 1010 1101 0xxx 1101 xxxx xxxx */ + DECODE_EMULATEX (0xfbff8f00, 0xf2ad0d00, t32_emulate_rd8rn16_noflags, + REGS(SP, 0, SP, 0, 0)), + + /* ADDW 1111 0x10 0000 xxxx 0xxx xxxx xxxx xxxx */ + DECODE_OR (0xfbf08000, 0xf2000000), + /* SUBW 1111 0x10 1010 xxxx 0xxx xxxx xxxx xxxx */ + DECODE_EMULATEX (0xfbf08000, 0xf2a00000, t32_emulate_rd8rn16_noflags, + REGS(NOPCX, 0, NOSPPC, 0, 0)), + + /* MOVW 1111 0x10 0100 xxxx 0xxx xxxx xxxx xxxx */ + /* MOVT 1111 0x10 1100 xxxx 0xxx xxxx xxxx xxxx */ + DECODE_EMULATEX (0xfb708000, 0xf2400000, t32_emulate_rd8rn16_noflags, + REGS(0, 0, NOSPPC, 0, 0)), + + /* SSAT16 1111 0x11 0010 xxxx 0000 xxxx 00xx xxxx */ + /* SSAT 1111 0x11 00x0 xxxx 0xxx xxxx xxxx xxxx */ + /* USAT16 1111 0x11 1010 xxxx 0000 xxxx 00xx xxxx */ + /* USAT 1111 0x11 10x0 xxxx 0xxx xxxx xxxx xxxx */ + DECODE_EMULATEX (0xfb508000, 0xf3000000, t32_emulate_rd8rn16rm0_rwflags, + REGS(NOSPPC, 0, NOSPPC, 0, 0)), + + /* SFBX 1111 0x11 0100 xxxx 0xxx xxxx xxxx xxxx */ + /* UFBX 1111 0x11 1100 xxxx 0xxx xxxx xxxx xxxx */ + DECODE_EMULATEX (0xfb708000, 0xf3400000, t32_emulate_rd8rn16_noflags, + REGS(NOSPPC, 0, NOSPPC, 0, 0)), + + /* BFC 1111 0x11 0110 1111 0xxx xxxx xxxx xxxx */ + DECODE_EMULATEX (0xfbff8000, 0xf36f0000, t32_emulate_rd8rn16_noflags, + REGS(0, 0, NOSPPC, 0, 0)), + + /* BFI 1111 0x11 0110 xxxx 0xxx xxxx xxxx xxxx */ + DECODE_EMULATEX (0xfbf08000, 0xf3600000, t32_emulate_rd8rn16_noflags, + REGS(NOSPPCX, 0, NOSPPC, 0, 0)), + + DECODE_END +}; + +static const union decode_item t32_table_1111_0xxx___1[] = { + /* Branches and miscellaneous control */ + + /* YIELD 1111 0011 1010 xxxx 10x0 x000 0000 0001 */ + DECODE_OR (0xfff0d7ff, 0xf3a08001), + /* SEV 1111 0011 1010 xxxx 10x0 x000 0000 0100 */ + DECODE_EMULATE (0xfff0d7ff, 0xf3a08004, kprobe_emulate_none), + /* NOP 1111 0011 1010 xxxx 10x0 x000 0000 0000 */ + /* WFE 1111 0011 1010 xxxx 10x0 x000 0000 0010 */ + /* WFI 1111 0011 1010 xxxx 10x0 x000 0000 0011 */ + DECODE_SIMULATE (0xfff0d7fc, 0xf3a08000, kprobe_simulate_nop), + + /* MRS Rd, CPSR 1111 0011 1110 xxxx 10x0 xxxx xxxx xxxx */ + DECODE_SIMULATEX(0xfff0d000, 0xf3e08000, t32_simulate_mrs, + REGS(0, 0, NOSPPC, 0, 0)), + + /* + * Unsupported instructions + * 1111 0x11 1xxx xxxx 10x0 xxxx xxxx xxxx + * + * MSR 1111 0011 100x xxxx 10x0 xxxx xxxx xxxx + * DBG hint 1111 0011 1010 xxxx 10x0 x000 1111 xxxx + * Unallocated hints 1111 0011 1010 xxxx 10x0 x000 xxxx xxxx + * CPS 1111 0011 1010 xxxx 10x0 xxxx xxxx xxxx + * CLREX/DSB/DMB/ISB 1111 0011 1011 xxxx 10x0 xxxx xxxx xxxx + * BXJ 1111 0011 1100 xxxx 10x0 xxxx xxxx xxxx + * SUBS PC,LR,# 1111 0011 1101 xxxx 10x0 xxxx xxxx xxxx + * MRS Rd, SPSR 1111 0011 1111 xxxx 10x0 xxxx xxxx xxxx + * SMC 1111 0111 1111 xxxx 1000 xxxx xxxx xxxx + * UNDEFINED 1111 0111 1111 xxxx 1010 xxxx xxxx xxxx + * ??? 1111 0111 1xxx xxxx 1010 xxxx xxxx xxxx + */ + DECODE_REJECT (0xfb80d000, 0xf3808000), + + /* Bcc 1111 0xxx xxxx xxxx 10x0 xxxx xxxx xxxx */ + DECODE_CUSTOM (0xf800d000, 0xf0008000, t32_decode_cond_branch), + + /* BLX 1111 0xxx xxxx xxxx 11x0 xxxx xxxx xxx0 */ + DECODE_OR (0xf800d001, 0xf000c000), + /* B 1111 0xxx xxxx xxxx 10x1 xxxx xxxx xxxx */ + /* BL 1111 0xxx xxxx xxxx 11x1 xxxx xxxx xxxx */ + DECODE_SIMULATE (0xf8009000, 0xf0009000, t32_simulate_branch), + + DECODE_END +}; + +static const union decode_item t32_table_1111_100x_x0x1__1111[] = { + /* Memory hints */ + + /* PLD (literal) 1111 1000 x001 1111 1111 xxxx xxxx xxxx */ + /* PLI (literal) 1111 1001 x001 1111 1111 xxxx xxxx xxxx */ + DECODE_SIMULATE (0xfe7ff000, 0xf81ff000, kprobe_simulate_nop), + + /* PLD{W} (immediate) 1111 1000 10x1 xxxx 1111 xxxx xxxx xxxx */ + DECODE_OR (0xffd0f000, 0xf890f000), + /* PLD{W} (immediate) 1111 1000 00x1 xxxx 1111 1100 xxxx xxxx */ + DECODE_OR (0xffd0ff00, 0xf810fc00), + /* PLI (immediate) 1111 1001 1001 xxxx 1111 xxxx xxxx xxxx */ + DECODE_OR (0xfff0f000, 0xf990f000), + /* PLI (immediate) 1111 1001 0001 xxxx 1111 1100 xxxx xxxx */ + DECODE_SIMULATEX(0xfff0ff00, 0xf910fc00, kprobe_simulate_nop, + REGS(NOPCX, 0, 0, 0, 0)), + + /* PLD{W} (register) 1111 1000 00x1 xxxx 1111 0000 00xx xxxx */ + DECODE_OR (0xffd0ffc0, 0xf810f000), + /* PLI (register) 1111 1001 0001 xxxx 1111 0000 00xx xxxx */ + DECODE_SIMULATEX(0xfff0ffc0, 0xf910f000, kprobe_simulate_nop, + REGS(NOPCX, 0, 0, 0, NOSPPC)), + + /* Other unallocated instructions... */ + DECODE_END +}; + +static const union decode_item t32_table_1111_100x[] = { + /* Store/Load single data item */ + + /* ??? 1111 100x x11x xxxx xxxx xxxx xxxx xxxx */ + DECODE_REJECT (0xfe600000, 0xf8600000), + + /* ??? 1111 1001 0101 xxxx xxxx xxxx xxxx xxxx */ + DECODE_REJECT (0xfff00000, 0xf9500000), + + /* ??? 1111 100x 0xxx xxxx xxxx 10x0 xxxx xxxx */ + DECODE_REJECT (0xfe800d00, 0xf8000800), + + /* STRBT 1111 1000 0000 xxxx xxxx 1110 xxxx xxxx */ + /* STRHT 1111 1000 0010 xxxx xxxx 1110 xxxx xxxx */ + /* STRT 1111 1000 0100 xxxx xxxx 1110 xxxx xxxx */ + /* LDRBT 1111 1000 0001 xxxx xxxx 1110 xxxx xxxx */ + /* LDRSBT 1111 1001 0001 xxxx xxxx 1110 xxxx xxxx */ + /* LDRHT 1111 1000 0011 xxxx xxxx 1110 xxxx xxxx */ + /* LDRSHT 1111 1001 0011 xxxx xxxx 1110 xxxx xxxx */ + /* LDRT 1111 1000 0101 xxxx xxxx 1110 xxxx xxxx */ + DECODE_REJECT (0xfe800f00, 0xf8000e00), + + /* STR{,B,H} Rn,[PC...] 1111 1000 xxx0 1111 xxxx xxxx xxxx xxxx */ + DECODE_REJECT (0xff1f0000, 0xf80f0000), + + /* STR{,B,H} PC,[Rn...] 1111 1000 xxx0 xxxx 1111 xxxx xxxx xxxx */ + DECODE_REJECT (0xff10f000, 0xf800f000), + + /* LDR (literal) 1111 1000 x101 1111 xxxx xxxx xxxx xxxx */ + DECODE_SIMULATEX(0xff7f0000, 0xf85f0000, t32_simulate_ldr_literal, + REGS(PC, ANY, 0, 0, 0)), + + /* STR (immediate) 1111 1000 0100 xxxx xxxx 1xxx xxxx xxxx */ + /* LDR (immediate) 1111 1000 0101 xxxx xxxx 1xxx xxxx xxxx */ + DECODE_OR (0xffe00800, 0xf8400800), + /* STR (immediate) 1111 1000 1100 xxxx xxxx xxxx xxxx xxxx */ + /* LDR (immediate) 1111 1000 1101 xxxx xxxx xxxx xxxx xxxx */ + DECODE_EMULATEX (0xffe00000, 0xf8c00000, t32_emulate_ldrstr, + REGS(NOPCX, ANY, 0, 0, 0)), + + /* STR (register) 1111 1000 0100 xxxx xxxx 0000 00xx xxxx */ + /* LDR (register) 1111 1000 0101 xxxx xxxx 0000 00xx xxxx */ + DECODE_EMULATEX (0xffe00fc0, 0xf8400000, t32_emulate_ldrstr, + REGS(NOPCX, ANY, 0, 0, NOSPPC)), + + /* LDRB (literal) 1111 1000 x001 1111 xxxx xxxx xxxx xxxx */ + /* LDRSB (literal) 1111 1001 x001 1111 xxxx xxxx xxxx xxxx */ + /* LDRH (literal) 1111 1000 x011 1111 xxxx xxxx xxxx xxxx */ + /* LDRSH (literal) 1111 1001 x011 1111 xxxx xxxx xxxx xxxx */ + DECODE_EMULATEX (0xfe5f0000, 0xf81f0000, t32_simulate_ldr_literal, + REGS(PC, NOSPPCX, 0, 0, 0)), + + /* STRB (immediate) 1111 1000 0000 xxxx xxxx 1xxx xxxx xxxx */ + /* STRH (immediate) 1111 1000 0010 xxxx xxxx 1xxx xxxx xxxx */ + /* LDRB (immediate) 1111 1000 0001 xxxx xxxx 1xxx xxxx xxxx */ + /* LDRSB (immediate) 1111 1001 0001 xxxx xxxx 1xxx xxxx xxxx */ + /* LDRH (immediate) 1111 1000 0011 xxxx xxxx 1xxx xxxx xxxx */ + /* LDRSH (immediate) 1111 1001 0011 xxxx xxxx 1xxx xxxx xxxx */ + DECODE_OR (0xfec00800, 0xf8000800), + /* STRB (immediate) 1111 1000 1000 xxxx xxxx xxxx xxxx xxxx */ + /* STRH (immediate) 1111 1000 1010 xxxx xxxx xxxx xxxx xxxx */ + /* LDRB (immediate) 1111 1000 1001 xxxx xxxx xxxx xxxx xxxx */ + /* LDRSB (immediate) 1111 1001 1001 xxxx xxxx xxxx xxxx xxxx */ + /* LDRH (immediate) 1111 1000 1011 xxxx xxxx xxxx xxxx xxxx */ + /* LDRSH (immediate) 1111 1001 1011 xxxx xxxx xxxx xxxx xxxx */ + DECODE_EMULATEX (0xfec00000, 0xf8800000, t32_emulate_ldrstr, + REGS(NOPCX, NOSPPCX, 0, 0, 0)), + + /* STRB (register) 1111 1000 0000 xxxx xxxx 0000 00xx xxxx */ + /* STRH (register) 1111 1000 0010 xxxx xxxx 0000 00xx xxxx */ + /* LDRB (register) 1111 1000 0001 xxxx xxxx 0000 00xx xxxx */ + /* LDRSB (register) 1111 1001 0001 xxxx xxxx 0000 00xx xxxx */ + /* LDRH (register) 1111 1000 0011 xxxx xxxx 0000 00xx xxxx */ + /* LDRSH (register) 1111 1001 0011 xxxx xxxx 0000 00xx xxxx */ + DECODE_EMULATEX (0xfe800fc0, 0xf8000000, t32_emulate_ldrstr, + REGS(NOPCX, NOSPPCX, 0, 0, NOSPPC)), + + /* Other unallocated instructions... */ + DECODE_END +}; + +static const union decode_item t32_table_1111_1010___1111[] = { + /* Data-processing (register) */ + + /* ??? 1111 1010 011x xxxx 1111 xxxx 1xxx xxxx */ + DECODE_REJECT (0xffe0f080, 0xfa60f080), + + /* SXTH 1111 1010 0000 1111 1111 xxxx 1xxx xxxx */ + /* UXTH 1111 1010 0001 1111 1111 xxxx 1xxx xxxx */ + /* SXTB16 1111 1010 0010 1111 1111 xxxx 1xxx xxxx */ + /* UXTB16 1111 1010 0011 1111 1111 xxxx 1xxx xxxx */ + /* SXTB 1111 1010 0100 1111 1111 xxxx 1xxx xxxx */ + /* UXTB 1111 1010 0101 1111 1111 xxxx 1xxx xxxx */ + DECODE_EMULATEX (0xff8ff080, 0xfa0ff080, t32_emulate_rd8rn16rm0_rwflags, + REGS(0, 0, NOSPPC, 0, NOSPPC)), + + + /* ??? 1111 1010 1xxx xxxx 1111 xxxx 0x11 xxxx */ + DECODE_REJECT (0xff80f0b0, 0xfa80f030), + /* ??? 1111 1010 1x11 xxxx 1111 xxxx 0xxx xxxx */ + DECODE_REJECT (0xffb0f080, 0xfab0f000), + + /* SADD16 1111 1010 1001 xxxx 1111 xxxx 0000 xxxx */ + /* SASX 1111 1010 1010 xxxx 1111 xxxx 0000 xxxx */ + /* SSAX 1111 1010 1110 xxxx 1111 xxxx 0000 xxxx */ + /* SSUB16 1111 1010 1101 xxxx 1111 xxxx 0000 xxxx */ + /* SADD8 1111 1010 1000 xxxx 1111 xxxx 0000 xxxx */ + /* SSUB8 1111 1010 1100 xxxx 1111 xxxx 0000 xxxx */ + + /* QADD16 1111 1010 1001 xxxx 1111 xxxx 0001 xxxx */ + /* QASX 1111 1010 1010 xxxx 1111 xxxx 0001 xxxx */ + /* QSAX 1111 1010 1110 xxxx 1111 xxxx 0001 xxxx */ + /* QSUB16 1111 1010 1101 xxxx 1111 xxxx 0001 xxxx */ + /* QADD8 1111 1010 1000 xxxx 1111 xxxx 0001 xxxx */ + /* QSUB8 1111 1010 1100 xxxx 1111 xxxx 0001 xxxx */ + + /* SHADD16 1111 1010 1001 xxxx 1111 xxxx 0010 xxxx */ + /* SHASX 1111 1010 1010 xxxx 1111 xxxx 0010 xxxx */ + /* SHSAX 1111 1010 1110 xxxx 1111 xxxx 0010 xxxx */ + /* SHSUB16 1111 1010 1101 xxxx 1111 xxxx 0010 xxxx */ + /* SHADD8 1111 1010 1000 xxxx 1111 xxxx 0010 xxxx */ + /* SHSUB8 1111 1010 1100 xxxx 1111 xxxx 0010 xxxx */ + + /* UADD16 1111 1010 1001 xxxx 1111 xxxx 0100 xxxx */ + /* UASX 1111 1010 1010 xxxx 1111 xxxx 0100 xxxx */ + /* USAX 1111 1010 1110 xxxx 1111 xxxx 0100 xxxx */ + /* USUB16 1111 1010 1101 xxxx 1111 xxxx 0100 xxxx */ + /* UADD8 1111 1010 1000 xxxx 1111 xxxx 0100 xxxx */ + /* USUB8 1111 1010 1100 xxxx 1111 xxxx 0100 xxxx */ + + /* UQADD16 1111 1010 1001 xxxx 1111 xxxx 0101 xxxx */ + /* UQASX 1111 1010 1010 xxxx 1111 xxxx 0101 xxxx */ + /* UQSAX 1111 1010 1110 xxxx 1111 xxxx 0101 xxxx */ + /* UQSUB16 1111 1010 1101 xxxx 1111 xxxx 0101 xxxx */ + /* UQADD8 1111 1010 1000 xxxx 1111 xxxx 0101 xxxx */ + /* UQSUB8 1111 1010 1100 xxxx 1111 xxxx 0101 xxxx */ + + /* UHADD16 1111 1010 1001 xxxx 1111 xxxx 0110 xxxx */ + /* UHASX 1111 1010 1010 xxxx 1111 xxxx 0110 xxxx */ + /* UHSAX 1111 1010 1110 xxxx 1111 xxxx 0110 xxxx */ + /* UHSUB16 1111 1010 1101 xxxx 1111 xxxx 0110 xxxx */ + /* UHADD8 1111 1010 1000 xxxx 1111 xxxx 0110 xxxx */ + /* UHSUB8 1111 1010 1100 xxxx 1111 xxxx 0110 xxxx */ + DECODE_OR (0xff80f080, 0xfa80f000), + + /* SXTAH 1111 1010 0000 xxxx 1111 xxxx 1xxx xxxx */ + /* UXTAH 1111 1010 0001 xxxx 1111 xxxx 1xxx xxxx */ + /* SXTAB16 1111 1010 0010 xxxx 1111 xxxx 1xxx xxxx */ + /* UXTAB16 1111 1010 0011 xxxx 1111 xxxx 1xxx xxxx */ + /* SXTAB 1111 1010 0100 xxxx 1111 xxxx 1xxx xxxx */ + /* UXTAB 1111 1010 0101 xxxx 1111 xxxx 1xxx xxxx */ + DECODE_OR (0xff80f080, 0xfa00f080), + + /* QADD 1111 1010 1000 xxxx 1111 xxxx 1000 xxxx */ + /* QDADD 1111 1010 1000 xxxx 1111 xxxx 1001 xxxx */ + /* QSUB 1111 1010 1000 xxxx 1111 xxxx 1010 xxxx */ + /* QDSUB 1111 1010 1000 xxxx 1111 xxxx 1011 xxxx */ + DECODE_OR (0xfff0f0c0, 0xfa80f080), + + /* SEL 1111 1010 1010 xxxx 1111 xxxx 1000 xxxx */ + DECODE_OR (0xfff0f0f0, 0xfaa0f080), + + /* LSL 1111 1010 000x xxxx 1111 xxxx 0000 xxxx */ + /* LSR 1111 1010 001x xxxx 1111 xxxx 0000 xxxx */ + /* ASR 1111 1010 010x xxxx 1111 xxxx 0000 xxxx */ + /* ROR 1111 1010 011x xxxx 1111 xxxx 0000 xxxx */ + DECODE_EMULATEX (0xff80f0f0, 0xfa00f000, t32_emulate_rd8rn16rm0_rwflags, + REGS(NOSPPC, 0, NOSPPC, 0, NOSPPC)), + + /* CLZ 1111 1010 1010 xxxx 1111 xxxx 1000 xxxx */ + DECODE_OR (0xfff0f0f0, 0xfab0f080), + + /* REV 1111 1010 1001 xxxx 1111 xxxx 1000 xxxx */ + /* REV16 1111 1010 1001 xxxx 1111 xxxx 1001 xxxx */ + /* RBIT 1111 1010 1001 xxxx 1111 xxxx 1010 xxxx */ + /* REVSH 1111 1010 1001 xxxx 1111 xxxx 1011 xxxx */ + DECODE_EMULATEX (0xfff0f0c0, 0xfa90f080, t32_emulate_rd8rn16_noflags, + REGS(NOSPPC, 0, NOSPPC, 0, SAMEAS16)), + + /* Other unallocated instructions... */ + DECODE_END +}; + +static const union decode_item t32_table_1111_1011_0[] = { + /* Multiply, multiply accumulate, and absolute difference */ + + /* ??? 1111 1011 0000 xxxx 1111 xxxx 0001 xxxx */ + DECODE_REJECT (0xfff0f0f0, 0xfb00f010), + /* ??? 1111 1011 0111 xxxx 1111 xxxx 0001 xxxx */ + DECODE_REJECT (0xfff0f0f0, 0xfb70f010), + + /* SMULxy 1111 1011 0001 xxxx 1111 xxxx 00xx xxxx */ + DECODE_OR (0xfff0f0c0, 0xfb10f000), + /* MUL 1111 1011 0000 xxxx 1111 xxxx 0000 xxxx */ + /* SMUAD{X} 1111 1011 0010 xxxx 1111 xxxx 000x xxxx */ + /* SMULWy 1111 1011 0011 xxxx 1111 xxxx 000x xxxx */ + /* SMUSD{X} 1111 1011 0100 xxxx 1111 xxxx 000x xxxx */ + /* SMMUL{R} 1111 1011 0101 xxxx 1111 xxxx 000x xxxx */ + /* USAD8 1111 1011 0111 xxxx 1111 xxxx 0000 xxxx */ + DECODE_EMULATEX (0xff80f0e0, 0xfb00f000, t32_emulate_rd8rn16rm0_rwflags, + REGS(NOSPPC, 0, NOSPPC, 0, NOSPPC)), + + /* ??? 1111 1011 0111 xxxx xxxx xxxx 0001 xxxx */ + DECODE_REJECT (0xfff000f0, 0xfb700010), + + /* SMLAxy 1111 1011 0001 xxxx xxxx xxxx 00xx xxxx */ + DECODE_OR (0xfff000c0, 0xfb100000), + /* MLA 1111 1011 0000 xxxx xxxx xxxx 0000 xxxx */ + /* MLS 1111 1011 0000 xxxx xxxx xxxx 0001 xxxx */ + /* SMLAD{X} 1111 1011 0010 xxxx xxxx xxxx 000x xxxx */ + /* SMLAWy 1111 1011 0011 xxxx xxxx xxxx 000x xxxx */ + /* SMLSD{X} 1111 1011 0100 xxxx xxxx xxxx 000x xxxx */ + /* SMMLA{R} 1111 1011 0101 xxxx xxxx xxxx 000x xxxx */ + /* SMMLS{R} 1111 1011 0110 xxxx xxxx xxxx 000x xxxx */ + /* USADA8 1111 1011 0111 xxxx xxxx xxxx 0000 xxxx */ + DECODE_EMULATEX (0xff8000c0, 0xfb000000, t32_emulate_rd8rn16rm0ra12_noflags, + REGS(NOSPPC, NOSPPCX, NOSPPC, 0, NOSPPC)), + + /* Other unallocated instructions... */ + DECODE_END +}; + +static const union decode_item t32_table_1111_1011_1[] = { + /* Long multiply, long multiply accumulate, and divide */ + + /* UMAAL 1111 1011 1110 xxxx xxxx xxxx 0110 xxxx */ + DECODE_OR (0xfff000f0, 0xfbe00060), + /* SMLALxy 1111 1011 1100 xxxx xxxx xxxx 10xx xxxx */ + DECODE_OR (0xfff000c0, 0xfbc00080), + /* SMLALD{X} 1111 1011 1100 xxxx xxxx xxxx 110x xxxx */ + /* SMLSLD{X} 1111 1011 1101 xxxx xxxx xxxx 110x xxxx */ + DECODE_OR (0xffe000e0, 0xfbc000c0), + /* SMULL 1111 1011 1000 xxxx xxxx xxxx 0000 xxxx */ + /* UMULL 1111 1011 1010 xxxx xxxx xxxx 0000 xxxx */ + /* SMLAL 1111 1011 1100 xxxx xxxx xxxx 0000 xxxx */ + /* UMLAL 1111 1011 1110 xxxx xxxx xxxx 0000 xxxx */ + DECODE_EMULATEX (0xff9000f0, 0xfb800000, t32_emulate_rdlo12rdhi8rn16rm0_noflags, + REGS(NOSPPC, NOSPPC, NOSPPC, 0, NOSPPC)), + + /* SDIV 1111 1011 1001 xxxx xxxx xxxx 1111 xxxx */ + /* UDIV 1111 1011 1011 xxxx xxxx xxxx 1111 xxxx */ + /* Other unallocated instructions... */ + DECODE_END +}; + +const union decode_item kprobe_decode_thumb32_table[] = { + + /* + * Load/store multiple instructions + * 1110 100x x0xx xxxx xxxx xxxx xxxx xxxx + */ + DECODE_TABLE (0xfe400000, 0xe8000000, t32_table_1110_100x_x0xx), + + /* + * Load/store dual, load/store exclusive, table branch + * 1110 100x x1xx xxxx xxxx xxxx xxxx xxxx + */ + DECODE_TABLE (0xfe400000, 0xe8400000, t32_table_1110_100x_x1xx), + + /* + * Data-processing (shifted register) + * 1110 101x xxxx xxxx xxxx xxxx xxxx xxxx + */ + DECODE_TABLE (0xfe000000, 0xea000000, t32_table_1110_101x), + + /* + * Coprocessor instructions + * 1110 11xx xxxx xxxx xxxx xxxx xxxx xxxx + */ + DECODE_REJECT (0xfc000000, 0xec000000), + + /* + * Data-processing (modified immediate) + * 1111 0x0x xxxx xxxx 0xxx xxxx xxxx xxxx + */ + DECODE_TABLE (0xfa008000, 0xf0000000, t32_table_1111_0x0x___0), + + /* + * Data-processing (plain binary immediate) + * 1111 0x1x xxxx xxxx 0xxx xxxx xxxx xxxx + */ + DECODE_TABLE (0xfa008000, 0xf2000000, t32_table_1111_0x1x___0), + + /* + * Branches and miscellaneous control + * 1111 0xxx xxxx xxxx 1xxx xxxx xxxx xxxx + */ + DECODE_TABLE (0xf8008000, 0xf0008000, t32_table_1111_0xxx___1), + + /* + * Advanced SIMD element or structure load/store instructions + * 1111 1001 xxx0 xxxx xxxx xxxx xxxx xxxx + */ + DECODE_REJECT (0xff100000, 0xf9000000), + + /* + * Memory hints + * 1111 100x x0x1 xxxx 1111 xxxx xxxx xxxx + */ + DECODE_TABLE (0xfe50f000, 0xf810f000, t32_table_1111_100x_x0x1__1111), + + /* + * Store single data item + * 1111 1000 xxx0 xxxx xxxx xxxx xxxx xxxx + * Load single data items + * 1111 100x xxx1 xxxx xxxx xxxx xxxx xxxx + */ + DECODE_TABLE (0xfe000000, 0xf8000000, t32_table_1111_100x), + + /* + * Data-processing (register) + * 1111 1010 xxxx xxxx 1111 xxxx xxxx xxxx + */ + DECODE_TABLE (0xff00f000, 0xfa00f000, t32_table_1111_1010___1111), + + /* + * Multiply, multiply accumulate, and absolute difference + * 1111 1011 0xxx xxxx xxxx xxxx xxxx xxxx + */ + DECODE_TABLE (0xff800000, 0xfb000000, t32_table_1111_1011_0), + + /* + * Long multiply, long multiply accumulate, and divide + * 1111 1011 1xxx xxxx xxxx xxxx xxxx xxxx + */ + DECODE_TABLE (0xff800000, 0xfb800000, t32_table_1111_1011_1), + + /* + * Coprocessor instructions + * 1111 11xx xxxx xxxx xxxx xxxx xxxx xxxx + */ + DECODE_END +}; + +static void __kprobes +t16_simulate_bxblx(struct kprobe *p, struct pt_regs *regs) +{ + kprobe_opcode_t insn = p->opcode; + unsigned long pc = thumb_probe_pc(p); + int rm = (insn >> 3) & 0xf; + unsigned long rmv = (rm == 15) ? pc : regs->uregs[rm]; + + if (insn & (1 << 7)) /* BLX ? */ + regs->ARM_lr = (unsigned long)p->addr + 2; + + bx_write_pc(rmv, regs); +} + +static void __kprobes +t16_simulate_ldr_literal(struct kprobe *p, struct pt_regs *regs) +{ + kprobe_opcode_t insn = p->opcode; + unsigned long* base = (unsigned long *)(thumb_probe_pc(p) & ~3); + long index = insn & 0xff; + int rt = (insn >> 8) & 0x7; + regs->uregs[rt] = base[index]; +} + +static void __kprobes +t16_simulate_ldrstr_sp_relative(struct kprobe *p, struct pt_regs *regs) +{ + kprobe_opcode_t insn = p->opcode; + unsigned long* base = (unsigned long *)regs->ARM_sp; + long index = insn & 0xff; + int rt = (insn >> 8) & 0x7; + if (insn & 0x800) /* LDR */ + regs->uregs[rt] = base[index]; + else /* STR */ + base[index] = regs->uregs[rt]; +} + +static void __kprobes +t16_simulate_reladr(struct kprobe *p, struct pt_regs *regs) +{ + kprobe_opcode_t insn = p->opcode; + unsigned long base = (insn & 0x800) ? regs->ARM_sp + : (thumb_probe_pc(p) & ~3); + long offset = insn & 0xff; + int rt = (insn >> 8) & 0x7; + regs->uregs[rt] = base + offset * 4; +} + +static void __kprobes +t16_simulate_add_sp_imm(struct kprobe *p, struct pt_regs *regs) +{ + kprobe_opcode_t insn = p->opcode; + long imm = insn & 0x7f; + if (insn & 0x80) /* SUB */ + regs->ARM_sp -= imm * 4; + else /* ADD */ + regs->ARM_sp += imm * 4; +} + +static void __kprobes +t16_simulate_cbz(struct kprobe *p, struct pt_regs *regs) +{ + kprobe_opcode_t insn = p->opcode; + int rn = insn & 0x7; + kprobe_opcode_t nonzero = regs->uregs[rn] ? insn : ~insn; + if (nonzero & 0x800) { + long i = insn & 0x200; + long imm5 = insn & 0xf8; + unsigned long pc = thumb_probe_pc(p); + regs->ARM_pc = pc + (i >> 3) + (imm5 >> 2); + } +} + +static void __kprobes +t16_simulate_it(struct kprobe *p, struct pt_regs *regs) +{ + /* + * 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> + * The new IT state is in the lower byte of insn. + */ + kprobe_opcode_t insn = p->opcode; + unsigned long cpsr = regs->ARM_cpsr; + cpsr &= ~PSR_IT_MASK; + cpsr |= (insn & 0xfc) << 8; + cpsr |= (insn & 0x03) << 25; + regs->ARM_cpsr = cpsr; +} + +static void __kprobes +t16_singlestep_it(struct kprobe *p, struct pt_regs *regs) +{ + regs->ARM_pc += 2; + t16_simulate_it(p, regs); +} + +static enum kprobe_insn __kprobes +t16_decode_it(kprobe_opcode_t insn, struct arch_specific_insn *asi) +{ + asi->insn_singlestep = t16_singlestep_it; + return INSN_GOOD_NO_SLOT; +} + +static void __kprobes +t16_simulate_cond_branch(struct kprobe *p, struct pt_regs *regs) +{ + kprobe_opcode_t insn = p->opcode; + unsigned long pc = thumb_probe_pc(p); + long offset = insn & 0x7f; + offset -= insn & 0x80; /* Apply sign bit */ + regs->ARM_pc = pc + (offset * 2); +} + +static enum kprobe_insn __kprobes +t16_decode_cond_branch(kprobe_opcode_t insn, struct arch_specific_insn *asi) +{ + int cc = (insn >> 8) & 0xf; + asi->insn_check_cc = kprobe_condition_checks[cc]; + asi->insn_handler = t16_simulate_cond_branch; + return INSN_GOOD_NO_SLOT; +} + +static void __kprobes +t16_simulate_branch(struct kprobe *p, struct pt_regs *regs) +{ + kprobe_opcode_t insn = p->opcode; + unsigned long pc = thumb_probe_pc(p); + long offset = insn & 0x3ff; + offset -= insn & 0x400; /* Apply sign bit */ + regs->ARM_pc = pc + (offset * 2); +} + +static unsigned long __kprobes +t16_emulate_loregs(struct kprobe *p, struct pt_regs *regs) +{ + unsigned long oldcpsr = regs->ARM_cpsr; + unsigned long newcpsr; + + __asm__ __volatile__ ( + "msr cpsr_fs, %[oldcpsr] \n\t" + "ldmia %[regs], {r0-r7} \n\t" + "blx %[fn] \n\t" + "stmia %[regs], {r0-r7} \n\t" + "mrs %[newcpsr], cpsr \n\t" + : [newcpsr] "=r" (newcpsr) + : [oldcpsr] "r" (oldcpsr), [regs] "r" (regs), + [fn] "r" (p->ainsn.insn_fn) + : "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", + "lr", "memory", "cc" + ); + + return (oldcpsr & ~APSR_MASK) | (newcpsr & APSR_MASK); +} + +static void __kprobes +t16_emulate_loregs_rwflags(struct kprobe *p, struct pt_regs *regs) +{ + regs->ARM_cpsr = t16_emulate_loregs(p, regs); +} + +static void __kprobes +t16_emulate_loregs_noitrwflags(struct kprobe *p, struct pt_regs *regs) +{ + unsigned long cpsr = t16_emulate_loregs(p, regs); + if (!in_it_block(cpsr)) + regs->ARM_cpsr = cpsr; +} + +static void __kprobes +t16_emulate_hiregs(struct kprobe *p, struct pt_regs *regs) +{ + kprobe_opcode_t insn = p->opcode; + unsigned long pc = thumb_probe_pc(p); + int rdn = (insn & 0x7) | ((insn & 0x80) >> 4); + int rm = (insn >> 3) & 0xf; + + register unsigned long rdnv asm("r1"); + register unsigned long rmv asm("r0"); + unsigned long cpsr = regs->ARM_cpsr; + + rdnv = (rdn == 15) ? pc : regs->uregs[rdn]; + rmv = (rm == 15) ? pc : regs->uregs[rm]; + + __asm__ __volatile__ ( + "msr cpsr_fs, %[cpsr] \n\t" + "blx %[fn] \n\t" + "mrs %[cpsr], cpsr \n\t" + : "=r" (rdnv), [cpsr] "=r" (cpsr) + : "0" (rdnv), "r" (rmv), "1" (cpsr), [fn] "r" (p->ainsn.insn_fn) + : "lr", "memory", "cc" + ); + + if (rdn == 15) + rdnv &= ~1; + + regs->uregs[rdn] = rdnv; + regs->ARM_cpsr = (regs->ARM_cpsr & ~APSR_MASK) | (cpsr & APSR_MASK); +} + +static enum kprobe_insn __kprobes +t16_decode_hiregs(kprobe_opcode_t insn, struct arch_specific_insn *asi) +{ + insn &= ~0x00ff; + insn |= 0x001; /* Set Rdn = R1 and Rm = R0 */ + ((u16 *)asi->insn)[0] = insn; + asi->insn_handler = t16_emulate_hiregs; + return INSN_GOOD; +} + +static void __kprobes +t16_emulate_push(struct kprobe *p, struct pt_regs *regs) +{ + __asm__ __volatile__ ( + "ldr r9, [%[regs], #13*4] \n\t" + "ldr r8, [%[regs], #14*4] \n\t" + "ldmia %[regs], {r0-r7} \n\t" + "blx %[fn] \n\t" + "str r9, [%[regs], #13*4] \n\t" + : + : [regs] "r" (regs), [fn] "r" (p->ainsn.insn_fn) + : "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", "r8", "r9", + "lr", "memory", "cc" + ); +} + +static enum kprobe_insn __kprobes +t16_decode_push(kprobe_opcode_t insn, struct arch_specific_insn *asi) +{ + /* + * To simulate a PUSH we use a Thumb-2 "STMDB R9!, {registers}" + * and call it with R9=SP and LR in the register list represented + * by R8. + */ + ((u16 *)asi->insn)[0] = 0xe929; /* 1st half STMDB R9!,{} */ + ((u16 *)asi->insn)[1] = insn & 0x1ff; /* 2nd half (register list) */ + asi->insn_handler = t16_emulate_push; + return INSN_GOOD; +} + +static void __kprobes +t16_emulate_pop_nopc(struct kprobe *p, struct pt_regs *regs) +{ + __asm__ __volatile__ ( + "ldr r9, [%[regs], #13*4] \n\t" + "ldmia %[regs], {r0-r7} \n\t" + "blx %[fn] \n\t" + "stmia %[regs], {r0-r7} \n\t" + "str r9, [%[regs], #13*4] \n\t" + : + : [regs] "r" (regs), [fn] "r" (p->ainsn.insn_fn) + : "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", "r9", + "lr", "memory", "cc" + ); +} + +static void __kprobes +t16_emulate_pop_pc(struct kprobe *p, struct pt_regs *regs) +{ + register unsigned long pc asm("r8"); + + __asm__ __volatile__ ( + "ldr r9, [%[regs], #13*4] \n\t" + "ldmia %[regs], {r0-r7} \n\t" + "blx %[fn] \n\t" + "stmia %[regs], {r0-r7} \n\t" + "str r9, [%[regs], #13*4] \n\t" + : "=r" (pc) + : [regs] "r" (regs), [fn] "r" (p->ainsn.insn_fn) + : "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", "r9", + "lr", "memory", "cc" + ); + + bx_write_pc(pc, regs); +} + +static enum kprobe_insn __kprobes +t16_decode_pop(kprobe_opcode_t insn, struct arch_specific_insn *asi) +{ + /* + * To simulate a POP we use a Thumb-2 "LDMDB R9!, {registers}" + * and call it with R9=SP and PC in the register list represented + * by R8. + */ + ((u16 *)asi->insn)[0] = 0xe8b9; /* 1st half LDMIA R9!,{} */ + ((u16 *)asi->insn)[1] = insn & 0x1ff; /* 2nd half (register list) */ + asi->insn_handler = insn & 0x100 ? t16_emulate_pop_pc + : t16_emulate_pop_nopc; + return INSN_GOOD; +} + +static const union decode_item t16_table_1011[] = { + /* Miscellaneous 16-bit instructions */ + + /* ADD (SP plus immediate) 1011 0000 0xxx xxxx */ + /* SUB (SP minus immediate) 1011 0000 1xxx xxxx */ + DECODE_SIMULATE (0xff00, 0xb000, t16_simulate_add_sp_imm), + + /* CBZ 1011 00x1 xxxx xxxx */ + /* CBNZ 1011 10x1 xxxx xxxx */ + DECODE_SIMULATE (0xf500, 0xb100, t16_simulate_cbz), + + /* SXTH 1011 0010 00xx xxxx */ + /* SXTB 1011 0010 01xx xxxx */ + /* UXTH 1011 0010 10xx xxxx */ + /* UXTB 1011 0010 11xx xxxx */ + /* REV 1011 1010 00xx xxxx */ + /* REV16 1011 1010 01xx xxxx */ + /* ??? 1011 1010 10xx xxxx */ + /* REVSH 1011 1010 11xx xxxx */ + DECODE_REJECT (0xffc0, 0xba80), + DECODE_EMULATE (0xf500, 0xb000, t16_emulate_loregs_rwflags), + + /* PUSH 1011 010x xxxx xxxx */ + DECODE_CUSTOM (0xfe00, 0xb400, t16_decode_push), + /* POP 1011 110x xxxx xxxx */ + DECODE_CUSTOM (0xfe00, 0xbc00, t16_decode_pop), + + /* + * If-Then, and hints + * 1011 1111 xxxx xxxx + */ + + /* YIELD 1011 1111 0001 0000 */ + DECODE_OR (0xffff, 0xbf10), + /* SEV 1011 1111 0100 0000 */ + DECODE_EMULATE (0xffff, 0xbf40, kprobe_emulate_none), + /* NOP 1011 1111 0000 0000 */ + /* WFE 1011 1111 0010 0000 */ + /* WFI 1011 1111 0011 0000 */ + DECODE_SIMULATE (0xffcf, 0xbf00, kprobe_simulate_nop), + /* Unassigned hints 1011 1111 xxxx 0000 */ + DECODE_REJECT (0xff0f, 0xbf00), + /* IT 1011 1111 xxxx xxxx */ + DECODE_CUSTOM (0xff00, 0xbf00, t16_decode_it), + + /* SETEND 1011 0110 010x xxxx */ + /* CPS 1011 0110 011x xxxx */ + /* BKPT 1011 1110 xxxx xxxx */ + /* And unallocated instructions... */ + DECODE_END +}; + +const union decode_item kprobe_decode_thumb16_table[] = { + + /* + * Shift (immediate), add, subtract, move, and compare + * 00xx xxxx xxxx xxxx + */ + + /* CMP (immediate) 0010 1xxx xxxx xxxx */ + DECODE_EMULATE (0xf800, 0x2800, t16_emulate_loregs_rwflags), + + /* ADD (register) 0001 100x xxxx xxxx */ + /* SUB (register) 0001 101x xxxx xxxx */ + /* LSL (immediate) 0000 0xxx xxxx xxxx */ + /* LSR (immediate) 0000 1xxx xxxx xxxx */ + /* ASR (immediate) 0001 0xxx xxxx xxxx */ + /* ADD (immediate, Thumb) 0001 110x xxxx xxxx */ + /* SUB (immediate, Thumb) 0001 111x xxxx xxxx */ + /* MOV (immediate) 0010 0xxx xxxx xxxx */ + /* ADD (immediate, Thumb) 0011 0xxx xxxx xxxx */ + /* SUB (immediate, Thumb) 0011 1xxx xxxx xxxx */ + DECODE_EMULATE (0xc000, 0x0000, t16_emulate_loregs_noitrwflags), + + /* + * 16-bit Thumb data-processing instructions + * 0100 00xx xxxx xxxx + */ + + /* TST (register) 0100 0010 00xx xxxx */ + DECODE_EMULATE (0xffc0, 0x4200, t16_emulate_loregs_rwflags), + /* CMP (register) 0100 0010 10xx xxxx */ + /* CMN (register) 0100 0010 11xx xxxx */ + DECODE_EMULATE (0xff80, 0x4280, t16_emulate_loregs_rwflags), + /* AND (register) 0100 0000 00xx xxxx */ + /* EOR (register) 0100 0000 01xx xxxx */ + /* LSL (register) 0100 0000 10xx xxxx */ + /* LSR (register) 0100 0000 11xx xxxx */ + /* ASR (register) 0100 0001 00xx xxxx */ + /* ADC (register) 0100 0001 01xx xxxx */ + /* SBC (register) 0100 0001 10xx xxxx */ + /* ROR (register) 0100 0001 11xx xxxx */ + /* RSB (immediate) 0100 0010 01xx xxxx */ + /* ORR (register) 0100 0011 00xx xxxx */ + /* MUL 0100 0011 00xx xxxx */ + /* BIC (register) 0100 0011 10xx xxxx */ + /* MVN (register) 0100 0011 10xx xxxx */ + DECODE_EMULATE (0xfc00, 0x4000, t16_emulate_loregs_noitrwflags), + + /* + * Special data instructions and branch and exchange + * 0100 01xx xxxx xxxx + */ + + /* BLX pc 0100 0111 1111 1xxx */ + DECODE_REJECT (0xfff8, 0x47f8), + + /* BX (register) 0100 0111 0xxx xxxx */ + /* BLX (register) 0100 0111 1xxx xxxx */ + DECODE_SIMULATE (0xff00, 0x4700, t16_simulate_bxblx), + + /* ADD pc, pc 0100 0100 1111 1111 */ + DECODE_REJECT (0xffff, 0x44ff), + + /* ADD (register) 0100 0100 xxxx xxxx */ + /* CMP (register) 0100 0101 xxxx xxxx */ + /* MOV (register) 0100 0110 xxxx xxxx */ + DECODE_CUSTOM (0xfc00, 0x4400, t16_decode_hiregs), + + /* + * Load from Literal Pool + * LDR (literal) 0100 1xxx xxxx xxxx + */ + DECODE_SIMULATE (0xf800, 0x4800, t16_simulate_ldr_literal), + + /* + * 16-bit Thumb Load/store instructions + * 0101 xxxx xxxx xxxx + * 011x xxxx xxxx xxxx + * 100x xxxx xxxx xxxx + */ + + /* STR (register) 0101 000x xxxx xxxx */ + /* STRH (register) 0101 001x xxxx xxxx */ + /* STRB (register) 0101 010x xxxx xxxx */ + /* LDRSB (register) 0101 011x xxxx xxxx */ + /* LDR (register) 0101 100x xxxx xxxx */ + /* LDRH (register) 0101 101x xxxx xxxx */ + /* LDRB (register) 0101 110x xxxx xxxx */ + /* LDRSH (register) 0101 111x xxxx xxxx */ + /* STR (immediate, Thumb) 0110 0xxx xxxx xxxx */ + /* LDR (immediate, Thumb) 0110 1xxx xxxx xxxx */ + /* STRB (immediate, Thumb) 0111 0xxx xxxx xxxx */ + /* LDRB (immediate, Thumb) 0111 1xxx xxxx xxxx */ + DECODE_EMULATE (0xc000, 0x4000, t16_emulate_loregs_rwflags), + /* STRH (immediate, Thumb) 1000 0xxx xxxx xxxx */ + /* LDRH (immediate, Thumb) 1000 1xxx xxxx xxxx */ + DECODE_EMULATE (0xf000, 0x8000, t16_emulate_loregs_rwflags), + /* STR (immediate, Thumb) 1001 0xxx xxxx xxxx */ + /* LDR (immediate, Thumb) 1001 1xxx xxxx xxxx */ + DECODE_SIMULATE (0xf000, 0x9000, t16_simulate_ldrstr_sp_relative), + + /* + * Generate PC-/SP-relative address + * ADR (literal) 1010 0xxx xxxx xxxx + * ADD (SP plus immediate) 1010 1xxx xxxx xxxx + */ + DECODE_SIMULATE (0xf000, 0xa000, t16_simulate_reladr), + + /* + * Miscellaneous 16-bit instructions + * 1011 xxxx xxxx xxxx + */ + DECODE_TABLE (0xf000, 0xb000, t16_table_1011), + + /* STM 1100 0xxx xxxx xxxx */ + /* LDM 1100 1xxx xxxx xxxx */ + DECODE_EMULATE (0xf000, 0xc000, t16_emulate_loregs_rwflags), + + /* + * Conditional branch, and Supervisor Call + */ + + /* Permanently UNDEFINED 1101 1110 xxxx xxxx */ + /* SVC 1101 1111 xxxx xxxx */ + DECODE_REJECT (0xfe00, 0xde00), + + /* Conditional branch 1101 xxxx xxxx xxxx */ + DECODE_CUSTOM (0xf000, 0xd000, t16_decode_cond_branch), + + /* + * Unconditional branch + * B 1110 0xxx xxxx xxxx + */ + DECODE_SIMULATE (0xf800, 0xe000, t16_simulate_branch), + + DECODE_END +}; + +static unsigned long __kprobes thumb_check_cc(unsigned long cpsr) +{ + if (unlikely(in_it_block(cpsr))) + return kprobe_condition_checks[current_cond(cpsr)](cpsr); + return true; +} + +static void __kprobes thumb16_singlestep(struct kprobe *p, struct pt_regs *regs) +{ + regs->ARM_pc += 2; + p->ainsn.insn_handler(p, regs); + regs->ARM_cpsr = it_advance(regs->ARM_cpsr); +} + +static void __kprobes thumb32_singlestep(struct kprobe *p, struct pt_regs *regs) +{ + regs->ARM_pc += 4; + p->ainsn.insn_handler(p, regs); + regs->ARM_cpsr = it_advance(regs->ARM_cpsr); +} + +enum kprobe_insn __kprobes +thumb16_kprobe_decode_insn(kprobe_opcode_t insn, struct arch_specific_insn *asi) +{ + asi->insn_singlestep = thumb16_singlestep; + asi->insn_check_cc = thumb_check_cc; + return kprobe_decode_insn(insn, asi, kprobe_decode_thumb16_table, true); +} + +enum kprobe_insn __kprobes +thumb32_kprobe_decode_insn(kprobe_opcode_t insn, struct arch_specific_insn *asi) +{ + asi->insn_singlestep = thumb32_singlestep; + asi->insn_check_cc = thumb_check_cc; + return kprobe_decode_insn(insn, asi, kprobe_decode_thumb32_table, true); +} diff --git a/arch/arm/kernel/kprobes.c b/arch/arm/kernel/kprobes.c index 1656c87..129c116 100644 --- a/arch/arm/kernel/kprobes.c +++ b/arch/arm/kernel/kprobes.c @@ -28,14 +28,16 @@ #include #include +#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) +{ + 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) { - *p->addr = KPROBE_BREAKPOINT_INSTRUCTION; - flush_insns(p->addr, 1); + 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 = { +#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_BREAKPOINT_INSTRUCTION, + .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; } diff --git a/arch/arm/kernel/kprobes.h b/arch/arm/kernel/kprobes.h new file mode 100644 index 0000000..a6aeda0 --- /dev/null +++ b/arch/arm/kernel/kprobes.h @@ -0,0 +1,420 @@ +/* + * arch/arm/kernel/kprobes.h + * + * Copyright (C) 2011 Jon Medhurst . + * + * 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 ,,, " + * + * 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 */ diff --git a/arch/arm/kernel/module.c b/arch/arm/kernel/module.c index 016d6a0..05b3776 100644 --- a/arch/arm/kernel/module.c +++ b/arch/arm/kernel/module.c @@ -43,25 +43,7 @@ void *module_alloc(unsigned long size) GFP_KERNEL, PAGE_KERNEL_EXEC, -1, __builtin_return_address(0)); } -#else /* CONFIG_MMU */ -void *module_alloc(unsigned long size) -{ - return size == 0 ? NULL : vmalloc(size); -} -#endif /* !CONFIG_MMU */ - -void module_free(struct module *module, void *region) -{ - vfree(region); -} - -int module_frob_arch_sections(Elf_Ehdr *hdr, - Elf_Shdr *sechdrs, - char *secstrings, - struct module *mod) -{ - return 0; -} +#endif int apply_relocate(Elf32_Shdr *sechdrs, const char *strtab, unsigned int symindex, @@ -265,15 +247,6 @@ apply_relocate(Elf32_Shdr *sechdrs, const char *strtab, unsigned int symindex, return 0; } -int -apply_relocate_add(Elf32_Shdr *sechdrs, const char *strtab, - unsigned int symindex, unsigned int relsec, struct module *module) -{ - printk(KERN_ERR "module %s: ADD RELOCATION unsupported\n", - module->name); - return -ENOEXEC; -} - struct mod_unwind_map { const Elf_Shdr *unw_sec; const Elf_Shdr *txt_sec; diff --git a/arch/arm/kernel/perf_event.c b/arch/arm/kernel/perf_event.c index 2b5b142..53c9c26 100644 --- a/arch/arm/kernel/perf_event.c +++ b/arch/arm/kernel/perf_event.c @@ -435,7 +435,7 @@ armpmu_reserve_hardware(void) if (irq >= 0) free_irq(irq, NULL); } - release_pmu(pmu_device); + release_pmu(ARM_PMU_DEVICE_CPU); pmu_device = NULL; } @@ -454,7 +454,7 @@ armpmu_release_hardware(void) } armpmu->stop(); - release_pmu(pmu_device); + release_pmu(ARM_PMU_DEVICE_CPU); pmu_device = NULL; } @@ -662,6 +662,12 @@ init_hw_perf_events(void) case 0xC090: /* Cortex-A9 */ armpmu = armv7_a9_pmu_init(); break; + case 0xC050: /* Cortex-A5 */ + armpmu = armv7_a5_pmu_init(); + break; + case 0xC0F0: /* Cortex-A15 */ + armpmu = armv7_a15_pmu_init(); + break; } /* Intel CPUs [xscale]. */ } else if (0x69 == implementor) { diff --git a/arch/arm/kernel/perf_event_v6.c b/arch/arm/kernel/perf_event_v6.c index f1e8dd9..dd7f3b9 100644 --- a/arch/arm/kernel/perf_event_v6.c +++ b/arch/arm/kernel/perf_event_v6.c @@ -173,6 +173,20 @@ static const unsigned armv6_perf_cache_map[PERF_COUNT_HW_CACHE_MAX] [C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED, }, }, + [C(NODE)] = { + [C(OP_READ)] = { + [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED, + [C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED, + }, + [C(OP_WRITE)] = { + [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED, + [C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED, + }, + [C(OP_PREFETCH)] = { + [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED, + [C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED, + }, + }, }; enum armv6mpcore_perf_types { @@ -310,6 +324,20 @@ static const unsigned armv6mpcore_perf_cache_map[PERF_COUNT_HW_CACHE_MAX] [C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED, }, }, + [C(NODE)] = { + [C(OP_READ)] = { + [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED, + [C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED, + }, + [C(OP_WRITE)] = { + [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED, + [C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED, + }, + [C(OP_PREFETCH)] = { + [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED, + [C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED, + }, + }, }; static inline unsigned long @@ -479,7 +507,7 @@ armv6pmu_handle_irq(int irq_num, if (!armpmu_event_set_period(event, hwc, idx)) continue; - if (perf_event_overflow(event, 0, &data, regs)) + if (perf_event_overflow(event, &data, regs)) armpmu->disable(hwc, idx); } diff --git a/arch/arm/kernel/perf_event_v7.c b/arch/arm/kernel/perf_event_v7.c index 4960686..4c85183 100644 --- a/arch/arm/kernel/perf_event_v7.c +++ b/arch/arm/kernel/perf_event_v7.c @@ -17,17 +17,23 @@ */ #ifdef CONFIG_CPU_V7 -/* Common ARMv7 event types */ +/* + * Common ARMv7 event types + * + * Note: An implementation may not be able to count all of these events + * but the encodings are considered to be `reserved' in the case that + * they are not available. + */ enum armv7_perf_types { ARMV7_PERFCTR_PMNC_SW_INCR = 0x00, ARMV7_PERFCTR_IFETCH_MISS = 0x01, ARMV7_PERFCTR_ITLB_MISS = 0x02, - ARMV7_PERFCTR_DCACHE_REFILL = 0x03, - ARMV7_PERFCTR_DCACHE_ACCESS = 0x04, + ARMV7_PERFCTR_DCACHE_REFILL = 0x03, /* L1 */ + ARMV7_PERFCTR_DCACHE_ACCESS = 0x04, /* L1 */ ARMV7_PERFCTR_DTLB_REFILL = 0x05, ARMV7_PERFCTR_DREAD = 0x06, ARMV7_PERFCTR_DWRITE = 0x07, - + ARMV7_PERFCTR_INSTR_EXECUTED = 0x08, ARMV7_PERFCTR_EXC_TAKEN = 0x09, ARMV7_PERFCTR_EXC_EXECUTED = 0x0A, ARMV7_PERFCTR_CID_WRITE = 0x0B, @@ -39,21 +45,30 @@ enum armv7_perf_types { */ ARMV7_PERFCTR_PC_WRITE = 0x0C, ARMV7_PERFCTR_PC_IMM_BRANCH = 0x0D, + ARMV7_PERFCTR_PC_PROC_RETURN = 0x0E, ARMV7_PERFCTR_UNALIGNED_ACCESS = 0x0F, + + /* These events are defined by the PMUv2 supplement (ARM DDI 0457A). */ ARMV7_PERFCTR_PC_BRANCH_MIS_PRED = 0x10, ARMV7_PERFCTR_CLOCK_CYCLES = 0x11, - - ARMV7_PERFCTR_PC_BRANCH_MIS_USED = 0x12, + ARMV7_PERFCTR_PC_BRANCH_PRED = 0x12, + ARMV7_PERFCTR_MEM_ACCESS = 0x13, + ARMV7_PERFCTR_L1_ICACHE_ACCESS = 0x14, + ARMV7_PERFCTR_L1_DCACHE_WB = 0x15, + ARMV7_PERFCTR_L2_DCACHE_ACCESS = 0x16, + ARMV7_PERFCTR_L2_DCACHE_REFILL = 0x17, + ARMV7_PERFCTR_L2_DCACHE_WB = 0x18, + ARMV7_PERFCTR_BUS_ACCESS = 0x19, + ARMV7_PERFCTR_MEMORY_ERROR = 0x1A, + ARMV7_PERFCTR_INSTR_SPEC = 0x1B, + ARMV7_PERFCTR_TTBR_WRITE = 0x1C, + ARMV7_PERFCTR_BUS_CYCLES = 0x1D, ARMV7_PERFCTR_CPU_CYCLES = 0xFF }; /* ARMv7 Cortex-A8 specific event types */ enum armv7_a8_perf_types { - ARMV7_PERFCTR_INSTR_EXECUTED = 0x08, - - ARMV7_PERFCTR_PC_PROC_RETURN = 0x0E, - ARMV7_PERFCTR_WRITE_BUFFER_FULL = 0x40, ARMV7_PERFCTR_L2_STORE_MERGED = 0x41, ARMV7_PERFCTR_L2_STORE_BUFF = 0x42, @@ -138,6 +153,39 @@ enum armv7_a9_perf_types { ARMV7_PERFCTR_PLE_RQST_PROG = 0xA5 }; +/* ARMv7 Cortex-A5 specific event types */ +enum armv7_a5_perf_types { + ARMV7_PERFCTR_IRQ_TAKEN = 0x86, + ARMV7_PERFCTR_FIQ_TAKEN = 0x87, + + ARMV7_PERFCTR_EXT_MEM_RQST = 0xc0, + ARMV7_PERFCTR_NC_EXT_MEM_RQST = 0xc1, + ARMV7_PERFCTR_PREFETCH_LINEFILL = 0xc2, + ARMV7_PERFCTR_PREFETCH_LINEFILL_DROP = 0xc3, + ARMV7_PERFCTR_ENTER_READ_ALLOC = 0xc4, + ARMV7_PERFCTR_READ_ALLOC = 0xc5, + + ARMV7_PERFCTR_STALL_SB_FULL = 0xc9, +}; + +/* ARMv7 Cortex-A15 specific event types */ +enum armv7_a15_perf_types { + ARMV7_PERFCTR_L1_DCACHE_READ_ACCESS = 0x40, + ARMV7_PERFCTR_L1_DCACHE_WRITE_ACCESS = 0x41, + ARMV7_PERFCTR_L1_DCACHE_READ_REFILL = 0x42, + ARMV7_PERFCTR_L1_DCACHE_WRITE_REFILL = 0x43, + + ARMV7_PERFCTR_L1_DTLB_READ_REFILL = 0x4C, + ARMV7_PERFCTR_L1_DTLB_WRITE_REFILL = 0x4D, + + ARMV7_PERFCTR_L2_DCACHE_READ_ACCESS = 0x50, + ARMV7_PERFCTR_L2_DCACHE_WRITE_ACCESS = 0x51, + ARMV7_PERFCTR_L2_DCACHE_READ_REFILL = 0x52, + ARMV7_PERFCTR_L2_DCACHE_WRITE_REFILL = 0x53, + + ARMV7_PERFCTR_SPEC_PC_WRITE = 0x76, +}; + /* * Cortex-A8 HW events mapping * @@ -207,11 +255,6 @@ static const unsigned armv7_a8_perf_cache_map[PERF_COUNT_HW_CACHE_MAX] }, }, [C(DTLB)] = { - /* - * Only ITLB misses and DTLB refills are supported. - * If users want the DTLB refills misses a raw counter - * must be used. - */ [C(OP_READ)] = { [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED, [C(RESULT_MISS)] = ARMV7_PERFCTR_DTLB_REFILL, @@ -255,6 +298,20 @@ static const unsigned armv7_a8_perf_cache_map[PERF_COUNT_HW_CACHE_MAX] [C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED, }, }, + [C(NODE)] = { + [C(OP_READ)] = { + [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED, + [C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED, + }, + [C(OP_WRITE)] = { + [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED, + [C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED, + }, + [C(OP_PREFETCH)] = { + [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED, + [C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED, + }, + }, }; /* @@ -323,11 +380,6 @@ static const unsigned armv7_a9_perf_cache_map[PERF_COUNT_HW_CACHE_MAX] }, }, [C(DTLB)] = { - /* - * Only ITLB misses and DTLB refills are supported. - * If users want the DTLB refills misses a raw counter - * must be used. - */ [C(OP_READ)] = { [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED, [C(RESULT_MISS)] = ARMV7_PERFCTR_DTLB_REFILL, @@ -371,6 +423,256 @@ static const unsigned armv7_a9_perf_cache_map[PERF_COUNT_HW_CACHE_MAX] [C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED, }, }, + [C(NODE)] = { + [C(OP_READ)] = { + [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED, + [C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED, + }, + [C(OP_WRITE)] = { + [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED, + [C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED, + }, + [C(OP_PREFETCH)] = { + [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED, + [C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED, + }, + }, +}; + +/* + * Cortex-A5 HW events mapping + */ +static const unsigned armv7_a5_perf_map[PERF_COUNT_HW_MAX] = { + [PERF_COUNT_HW_CPU_CYCLES] = ARMV7_PERFCTR_CPU_CYCLES, + [PERF_COUNT_HW_INSTRUCTIONS] = ARMV7_PERFCTR_INSTR_EXECUTED, + [PERF_COUNT_HW_CACHE_REFERENCES] = HW_OP_UNSUPPORTED, + [PERF_COUNT_HW_CACHE_MISSES] = HW_OP_UNSUPPORTED, + [PERF_COUNT_HW_BRANCH_INSTRUCTIONS] = ARMV7_PERFCTR_PC_WRITE, + [PERF_COUNT_HW_BRANCH_MISSES] = ARMV7_PERFCTR_PC_BRANCH_MIS_PRED, + [PERF_COUNT_HW_BUS_CYCLES] = HW_OP_UNSUPPORTED, +}; + +static const unsigned armv7_a5_perf_cache_map[PERF_COUNT_HW_CACHE_MAX] + [PERF_COUNT_HW_CACHE_OP_MAX] + [PERF_COUNT_HW_CACHE_RESULT_MAX] = { + [C(L1D)] = { + [C(OP_READ)] = { + [C(RESULT_ACCESS)] + = ARMV7_PERFCTR_DCACHE_ACCESS, + [C(RESULT_MISS)] + = ARMV7_PERFCTR_DCACHE_REFILL, + }, + [C(OP_WRITE)] = { + [C(RESULT_ACCESS)] + = ARMV7_PERFCTR_DCACHE_ACCESS, + [C(RESULT_MISS)] + = ARMV7_PERFCTR_DCACHE_REFILL, + }, + [C(OP_PREFETCH)] = { + [C(RESULT_ACCESS)] + = ARMV7_PERFCTR_PREFETCH_LINEFILL, + [C(RESULT_MISS)] + = ARMV7_PERFCTR_PREFETCH_LINEFILL_DROP, + }, + }, + [C(L1I)] = { + [C(OP_READ)] = { + [C(RESULT_ACCESS)] = ARMV7_PERFCTR_L1_ICACHE_ACCESS, + [C(RESULT_MISS)] = ARMV7_PERFCTR_IFETCH_MISS, + }, + [C(OP_WRITE)] = { + [C(RESULT_ACCESS)] = ARMV7_PERFCTR_L1_ICACHE_ACCESS, + [C(RESULT_MISS)] = ARMV7_PERFCTR_IFETCH_MISS, + }, + /* + * The prefetch counters don't differentiate between the I + * side and the D side. + */ + [C(OP_PREFETCH)] = { + [C(RESULT_ACCESS)] + = ARMV7_PERFCTR_PREFETCH_LINEFILL, + [C(RESULT_MISS)] + = ARMV7_PERFCTR_PREFETCH_LINEFILL_DROP, + }, + }, + [C(LL)] = { + [C(OP_READ)] = { + [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED, + [C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED, + }, + [C(OP_WRITE)] = { + [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED, + [C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED, + }, + [C(OP_PREFETCH)] = { + [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED, + [C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED, + }, + }, + [C(DTLB)] = { + [C(OP_READ)] = { + [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED, + [C(RESULT_MISS)] = ARMV7_PERFCTR_DTLB_REFILL, + }, + [C(OP_WRITE)] = { + [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED, + [C(RESULT_MISS)] = ARMV7_PERFCTR_DTLB_REFILL, + }, + [C(OP_PREFETCH)] = { + [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED, + [C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED, + }, + }, + [C(ITLB)] = { + [C(OP_READ)] = { + [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED, + [C(RESULT_MISS)] = ARMV7_PERFCTR_ITLB_MISS, + }, + [C(OP_WRITE)] = { + [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED, + [C(RESULT_MISS)] = ARMV7_PERFCTR_ITLB_MISS, + }, + [C(OP_PREFETCH)] = { + [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED, + [C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED, + }, + }, + [C(BPU)] = { + [C(OP_READ)] = { + [C(RESULT_ACCESS)] = ARMV7_PERFCTR_PC_BRANCH_PRED, + [C(RESULT_MISS)] + = ARMV7_PERFCTR_PC_BRANCH_MIS_PRED, + }, + [C(OP_WRITE)] = { + [C(RESULT_ACCESS)] = ARMV7_PERFCTR_PC_BRANCH_PRED, + [C(RESULT_MISS)] + = ARMV7_PERFCTR_PC_BRANCH_MIS_PRED, + }, + [C(OP_PREFETCH)] = { + [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED, + [C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED, + }, + }, +}; + +/* + * Cortex-A15 HW events mapping + */ +static const unsigned armv7_a15_perf_map[PERF_COUNT_HW_MAX] = { + [PERF_COUNT_HW_CPU_CYCLES] = ARMV7_PERFCTR_CPU_CYCLES, + [PERF_COUNT_HW_INSTRUCTIONS] = ARMV7_PERFCTR_INSTR_EXECUTED, + [PERF_COUNT_HW_CACHE_REFERENCES] = HW_OP_UNSUPPORTED, + [PERF_COUNT_HW_CACHE_MISSES] = HW_OP_UNSUPPORTED, + [PERF_COUNT_HW_BRANCH_INSTRUCTIONS] = ARMV7_PERFCTR_SPEC_PC_WRITE, + [PERF_COUNT_HW_BRANCH_MISSES] = ARMV7_PERFCTR_PC_BRANCH_MIS_PRED, + [PERF_COUNT_HW_BUS_CYCLES] = ARMV7_PERFCTR_BUS_CYCLES, +}; + +static const unsigned armv7_a15_perf_cache_map[PERF_COUNT_HW_CACHE_MAX] + [PERF_COUNT_HW_CACHE_OP_MAX] + [PERF_COUNT_HW_CACHE_RESULT_MAX] = { + [C(L1D)] = { + [C(OP_READ)] = { + [C(RESULT_ACCESS)] + = ARMV7_PERFCTR_L1_DCACHE_READ_ACCESS, + [C(RESULT_MISS)] + = ARMV7_PERFCTR_L1_DCACHE_READ_REFILL, + }, + [C(OP_WRITE)] = { + [C(RESULT_ACCESS)] + = ARMV7_PERFCTR_L1_DCACHE_WRITE_ACCESS, + [C(RESULT_MISS)] + = ARMV7_PERFCTR_L1_DCACHE_WRITE_REFILL, + }, + [C(OP_PREFETCH)] = { + [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED, + [C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED, + }, + }, + [C(L1I)] = { + /* + * Not all performance counters differentiate between read + * and write accesses/misses so we're not always strictly + * correct, but it's the best we can do. Writes and reads get + * combined in these cases. + */ + [C(OP_READ)] = { + [C(RESULT_ACCESS)] = ARMV7_PERFCTR_L1_ICACHE_ACCESS, + [C(RESULT_MISS)] = ARMV7_PERFCTR_IFETCH_MISS, + }, + [C(OP_WRITE)] = { + [C(RESULT_ACCESS)] = ARMV7_PERFCTR_L1_ICACHE_ACCESS, + [C(RESULT_MISS)] = ARMV7_PERFCTR_IFETCH_MISS, + }, + [C(OP_PREFETCH)] = { + [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED, + [C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED, + }, + }, + [C(LL)] = { + [C(OP_READ)] = { + [C(RESULT_ACCESS)] + = ARMV7_PERFCTR_L2_DCACHE_READ_ACCESS, + [C(RESULT_MISS)] + = ARMV7_PERFCTR_L2_DCACHE_READ_REFILL, + }, + [C(OP_WRITE)] = { + [C(RESULT_ACCESS)] + = ARMV7_PERFCTR_L2_DCACHE_WRITE_ACCESS, + [C(RESULT_MISS)] + = ARMV7_PERFCTR_L2_DCACHE_WRITE_REFILL, + }, + [C(OP_PREFETCH)] = { + [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED, + [C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED, + }, + }, + [C(DTLB)] = { + [C(OP_READ)] = { + [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED, + [C(RESULT_MISS)] + = ARMV7_PERFCTR_L1_DTLB_READ_REFILL, + }, + [C(OP_WRITE)] = { + [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED, + [C(RESULT_MISS)] + = ARMV7_PERFCTR_L1_DTLB_WRITE_REFILL, + }, + [C(OP_PREFETCH)] = { + [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED, + [C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED, + }, + }, + [C(ITLB)] = { + [C(OP_READ)] = { + [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED, + [C(RESULT_MISS)] = ARMV7_PERFCTR_ITLB_MISS, + }, + [C(OP_WRITE)] = { + [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED, + [C(RESULT_MISS)] = ARMV7_PERFCTR_ITLB_MISS, + }, + [C(OP_PREFETCH)] = { + [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED, + [C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED, + }, + }, + [C(BPU)] = { + [C(OP_READ)] = { + [C(RESULT_ACCESS)] = ARMV7_PERFCTR_PC_BRANCH_PRED, + [C(RESULT_MISS)] + = ARMV7_PERFCTR_PC_BRANCH_MIS_PRED, + }, + [C(OP_WRITE)] = { + [C(RESULT_ACCESS)] = ARMV7_PERFCTR_PC_BRANCH_PRED, + [C(RESULT_MISS)] + = ARMV7_PERFCTR_PC_BRANCH_MIS_PRED, + }, + [C(OP_PREFETCH)] = { + [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED, + [C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED, + }, + }, }; /* @@ -787,7 +1089,7 @@ static irqreturn_t armv7pmu_handle_irq(int irq_num, void *dev) if (!armpmu_event_set_period(event, hwc, idx)) continue; - if (perf_event_overflow(event, 0, &data, regs)) + if (perf_event_overflow(event, &data, regs)) armpmu->disable(hwc, idx); } @@ -905,6 +1207,26 @@ static const struct arm_pmu *__init armv7_a9_pmu_init(void) armv7pmu.num_events = armv7_read_num_pmnc_events(); return &armv7pmu; } + +static const struct arm_pmu *__init armv7_a5_pmu_init(void) +{ + armv7pmu.id = ARM_PERF_PMU_ID_CA5; + armv7pmu.name = "ARMv7 Cortex-A5"; + armv7pmu.cache_map = &armv7_a5_perf_cache_map; + armv7pmu.event_map = &armv7_a5_perf_map; + armv7pmu.num_events = armv7_read_num_pmnc_events(); + return &armv7pmu; +} + +static const struct arm_pmu *__init armv7_a15_pmu_init(void) +{ + armv7pmu.id = ARM_PERF_PMU_ID_CA15; + armv7pmu.name = "ARMv7 Cortex-A15"; + armv7pmu.cache_map = &armv7_a15_perf_cache_map; + armv7pmu.event_map = &armv7_a15_perf_map; + armv7pmu.num_events = armv7_read_num_pmnc_events(); + return &armv7pmu; +} #else static const struct arm_pmu *__init armv7_a8_pmu_init(void) { @@ -915,4 +1237,14 @@ static const struct arm_pmu *__init armv7_a9_pmu_init(void) { return NULL; } + +static const struct arm_pmu *__init armv7_a5_pmu_init(void) +{ + return NULL; +} + +static const struct arm_pmu *__init armv7_a15_pmu_init(void) +{ + return NULL; +} #endif /* CONFIG_CPU_V7 */ diff --git a/arch/arm/kernel/perf_event_xscale.c b/arch/arm/kernel/perf_event_xscale.c index 39affbe..3c43974 100644 --- a/arch/arm/kernel/perf_event_xscale.c +++ b/arch/arm/kernel/perf_event_xscale.c @@ -144,6 +144,20 @@ static const unsigned xscale_perf_cache_map[PERF_COUNT_HW_CACHE_MAX] [C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED, }, }, + [C(NODE)] = { + [C(OP_READ)] = { + [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED, + [C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED, + }, + [C(OP_WRITE)] = { + [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED, + [C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED, + }, + [C(OP_PREFETCH)] = { + [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED, + [C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED, + }, + }, }; #define XSCALE_PMU_ENABLE 0x001 @@ -251,7 +265,7 @@ xscale1pmu_handle_irq(int irq_num, void *dev) if (!armpmu_event_set_period(event, hwc, idx)) continue; - if (perf_event_overflow(event, 0, &data, regs)) + if (perf_event_overflow(event, &data, regs)) armpmu->disable(hwc, idx); } @@ -583,7 +597,7 @@ xscale2pmu_handle_irq(int irq_num, void *dev) if (!armpmu_event_set_period(event, hwc, idx)) continue; - if (perf_event_overflow(event, 0, &data, regs)) + if (perf_event_overflow(event, &data, regs)) armpmu->disable(hwc, idx); } diff --git a/arch/arm/kernel/pmu.c b/arch/arm/kernel/pmu.c index 2c79eec..2b70709 100644 --- a/arch/arm/kernel/pmu.c +++ b/arch/arm/kernel/pmu.c @@ -17,6 +17,7 @@ #include #include #include +#include #include #include @@ -25,36 +26,88 @@ static volatile long pmu_lock; static struct platform_device *pmu_devices[ARM_NUM_PMU_DEVICES]; -static int __devinit pmu_device_probe(struct platform_device *pdev) +static int __devinit pmu_register(struct platform_device *pdev, + enum arm_pmu_type type) { - - if (pdev->id < 0 || pdev->id >= ARM_NUM_PMU_DEVICES) { + if (type < 0 || type >= ARM_NUM_PMU_DEVICES) { pr_warning("received registration request for unknown " - "device %d\n", pdev->id); + "device %d\n", type); return -EINVAL; } - if (pmu_devices[pdev->id]) - pr_warning("registering new PMU device type %d overwrites " - "previous registration!\n", pdev->id); - else - pr_info("registered new PMU device of type %d\n", - pdev->id); + if (pmu_devices[type]) { + pr_warning("rejecting duplicate registration of PMU device " + "type %d.", type); + return -ENOSPC; + } - pmu_devices[pdev->id] = pdev; + pr_info("registered new PMU device of type %d\n", type); + pmu_devices[type] = pdev; return 0; } -static struct platform_driver pmu_driver = { +#define OF_MATCH_PMU(_name, _type) { \ + .compatible = _name, \ + .data = (void *)_type, \ +} + +#define OF_MATCH_CPU(name) OF_MATCH_PMU(name, ARM_PMU_DEVICE_CPU) + +static struct of_device_id armpmu_of_device_ids[] = { + OF_MATCH_CPU("arm,cortex-a9-pmu"), + OF_MATCH_CPU("arm,cortex-a8-pmu"), + OF_MATCH_CPU("arm,arm1136-pmu"), + OF_MATCH_CPU("arm,arm1176-pmu"), + {}, +}; + +#define PLAT_MATCH_PMU(_name, _type) { \ + .name = _name, \ + .driver_data = _type, \ +} + +#define PLAT_MATCH_CPU(_name) PLAT_MATCH_PMU(_name, ARM_PMU_DEVICE_CPU) + +static struct platform_device_id armpmu_plat_device_ids[] = { + PLAT_MATCH_CPU("arm-pmu"), + {}, +}; + +enum arm_pmu_type armpmu_device_type(struct platform_device *pdev) +{ + const struct of_device_id *of_id; + const struct platform_device_id *pdev_id; + + /* provided by of_device_id table */ + if (pdev->dev.of_node) { + of_id = of_match_device(armpmu_of_device_ids, &pdev->dev); + BUG_ON(!of_id); + return (enum arm_pmu_type)of_id->data; + } + + /* Provided by platform_device_id table */ + pdev_id = platform_get_device_id(pdev); + BUG_ON(!pdev_id); + return pdev_id->driver_data; +} + +static int __devinit armpmu_device_probe(struct platform_device *pdev) +{ + return pmu_register(pdev, armpmu_device_type(pdev)); +} + +static struct platform_driver armpmu_driver = { .driver = { .name = "arm-pmu", + .of_match_table = armpmu_of_device_ids, }, - .probe = pmu_device_probe, + .probe = armpmu_device_probe, + .id_table = armpmu_plat_device_ids, }; static int __init register_pmu_driver(void) { - return platform_driver_register(&pmu_driver); + return platform_driver_register(&armpmu_driver); } device_initcall(register_pmu_driver); @@ -77,11 +130,11 @@ reserve_pmu(enum arm_pmu_type device) EXPORT_SYMBOL_GPL(reserve_pmu); int -release_pmu(struct platform_device *pdev) +release_pmu(enum arm_pmu_type device) { - if (WARN_ON(pdev != pmu_devices[pdev->id])) + if (WARN_ON(!pmu_devices[device])) return -EINVAL; - clear_bit_unlock(pdev->id, &pmu_lock); + clear_bit_unlock(device, &pmu_lock); return 0; } EXPORT_SYMBOL_GPL(release_pmu); diff --git a/arch/arm/kernel/ptrace.c b/arch/arm/kernel/ptrace.c index 9726006..2491f3b 100644 --- a/arch/arm/kernel/ptrace.c +++ b/arch/arm/kernel/ptrace.c @@ -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) @@ -396,7 +374,7 @@ static long ptrace_hbp_idx_to_num(int idx) /* * Handle hitting a HW-breakpoint. */ -static void ptrace_hbptriggered(struct perf_event *bp, int unused, +static void ptrace_hbptriggered(struct perf_event *bp, struct perf_sample_data *data, struct pt_regs *regs) { @@ -479,7 +457,8 @@ static struct perf_event *ptrace_hbp_create(struct task_struct *tsk, int type) attr.bp_type = type; attr.disabled = 1; - return register_user_hw_breakpoint(&attr, ptrace_hbptriggered, tsk); + return register_user_hw_breakpoint(&attr, ptrace_hbptriggered, NULL, + tsk); } static int ptrace_gethbpregs(struct task_struct *tsk, long num, diff --git a/arch/arm/kernel/setup.c b/arch/arm/kernel/setup.c index acbb447..70bca64 100644 --- a/arch/arm/kernel/setup.c +++ b/arch/arm/kernel/setup.c @@ -343,54 +343,6 @@ static void __init feat_v6_fixup(void) elf_hwcap &= ~HWCAP_TLS; } -static void __init setup_processor(void) -{ - struct proc_info_list *list; - - /* - * locate processor in the list of supported processor - * types. The linker builds this table for us from the - * entries in arch/arm/mm/proc-*.S - */ - list = lookup_processor_type(read_cpuid_id()); - if (!list) { - printk("CPU configuration botched (ID %08x), unable " - "to continue.\n", read_cpuid_id()); - while (1); - } - - cpu_name = list->cpu_name; - -#ifdef MULTI_CPU - processor = *list->proc; -#endif -#ifdef MULTI_TLB - cpu_tlb = *list->tlb; -#endif -#ifdef MULTI_USER - cpu_user = *list->user; -#endif -#ifdef MULTI_CACHE - cpu_cache = *list->cache; -#endif - - printk("CPU: %s [%08x] revision %d (ARMv%s), cr=%08lx\n", - cpu_name, read_cpuid_id(), read_cpuid_id() & 15, - proc_arch[cpu_architecture()], cr_alignment); - - sprintf(init_utsname()->machine, "%s%c", list->arch_name, ENDIANNESS); - sprintf(elf_platform, "%s%c", list->elf_name, ENDIANNESS); - elf_hwcap = list->elf_hwcap; -#ifndef CONFIG_ARM_THUMB - elf_hwcap &= ~HWCAP_THUMB; -#endif - - feat_v6_fixup(); - - cacheid_init(); - cpu_proc_init(); -} - /* * cpu_init - initialise one CPU. * @@ -406,6 +358,8 @@ void cpu_init(void) BUG(); } + cpu_proc_init(); + /* * Define the placement constraint for the inline asm directive below. * In Thumb-2, msr with an immediate value is not allowed. @@ -442,6 +396,54 @@ void cpu_init(void) : "r14"); } +static void __init setup_processor(void) +{ + struct proc_info_list *list; + + /* + * locate processor in the list of supported processor + * types. The linker builds this table for us from the + * entries in arch/arm/mm/proc-*.S + */ + list = lookup_processor_type(read_cpuid_id()); + if (!list) { + printk("CPU configuration botched (ID %08x), unable " + "to continue.\n", read_cpuid_id()); + while (1); + } + + cpu_name = list->cpu_name; + +#ifdef MULTI_CPU + processor = *list->proc; +#endif +#ifdef MULTI_TLB + cpu_tlb = *list->tlb; +#endif +#ifdef MULTI_USER + cpu_user = *list->user; +#endif +#ifdef MULTI_CACHE + cpu_cache = *list->cache; +#endif + + printk("CPU: %s [%08x] revision %d (ARMv%s), cr=%08lx\n", + cpu_name, read_cpuid_id(), read_cpuid_id() & 15, + proc_arch[cpu_architecture()], cr_alignment); + + sprintf(init_utsname()->machine, "%s%c", list->arch_name, ENDIANNESS); + sprintf(elf_platform, "%s%c", list->elf_name, ENDIANNESS); + elf_hwcap = list->elf_hwcap; +#ifndef CONFIG_ARM_THUMB + elf_hwcap &= ~HWCAP_THUMB; +#endif + + feat_v6_fixup(); + + cacheid_init(); + cpu_init(); +} + void __init dump_machine_table(void) { struct machine_desc *p; @@ -915,9 +917,14 @@ void __init setup_arch(char **cmdline_p) #endif reserve_crashkernel(); - cpu_init(); tcm_init(); +#ifdef CONFIG_ZONE_DMA + if (mdesc->dma_zone_size) { + extern unsigned long arm_dma_zone_size; + arm_dma_zone_size = mdesc->dma_zone_size; + } +#endif #ifdef CONFIG_MULTI_IRQ_HANDLER handle_arch_irq = mdesc->handle_irq; #endif @@ -979,6 +986,10 @@ static const char *hwcap_str[] = { "neon", "vfpv3", "vfpv3d16", + "tls", + "vfpv4", + "idiva", + "idivt", NULL }; diff --git a/arch/arm/kernel/sleep.S b/arch/arm/kernel/sleep.S index 6398ead..dc902f2 100644 --- a/arch/arm/kernel/sleep.S +++ b/arch/arm/kernel/sleep.S @@ -10,64 +10,61 @@ /* * Save CPU state for a suspend * r1 = v:p offset - * r3 = virtual return function - * Note: sp is decremented to allocate space for CPU state on stack - * r0-r3,r9,r10,lr corrupted + * r2 = suspend function arg0 + * r3 = suspend function */ -ENTRY(cpu_suspend) - mov r9, lr +ENTRY(__cpu_suspend) + stmfd sp!, {r4 - r11, lr} #ifdef MULTI_CPU ldr r10, =processor - mov r2, sp @ current virtual SP - ldr r0, [r10, #CPU_SLEEP_SIZE] @ size of CPU sleep state + ldr r5, [r10, #CPU_SLEEP_SIZE] @ size of CPU sleep state ldr ip, [r10, #CPU_DO_RESUME] @ virtual resume function - sub sp, sp, r0 @ allocate CPU state on stack - mov r0, sp @ save pointer +#else + ldr r5, =cpu_suspend_size + ldr ip, =cpu_do_resume +#endif + mov r6, sp @ current virtual SP + sub sp, sp, r5 @ allocate CPU state on stack + mov r0, sp @ save pointer to CPU save block add ip, ip, r1 @ convert resume fn to phys - stmfd sp!, {r1, r2, r3, ip} @ save v:p, virt SP, retfn, phys resume fn - ldr r3, =sleep_save_sp - add r2, sp, r1 @ convert SP to phys + stmfd sp!, {r1, r6, ip} @ save v:p, virt SP, phys resume fn + ldr r5, =sleep_save_sp + add r6, sp, r1 @ convert SP to phys + stmfd sp!, {r2, r3} @ save suspend func arg and pointer #ifdef CONFIG_SMP ALT_SMP(mrc p15, 0, lr, c0, c0, 5) ALT_UP(mov lr, #0) and lr, lr, #15 - str r2, [r3, lr, lsl #2] @ save phys SP + str r6, [r5, lr, lsl #2] @ save phys SP #else - str r2, [r3] @ save phys SP + str r6, [r5] @ save phys SP #endif +#ifdef MULTI_CPU mov lr, pc ldr pc, [r10, #CPU_DO_SUSPEND] @ save CPU state #else - mov r2, sp @ current virtual SP - ldr r0, =cpu_suspend_size - sub sp, sp, r0 @ allocate CPU state on stack - mov r0, sp @ save pointer - stmfd sp!, {r1, r2, r3} @ save v:p, virt SP, return fn - ldr r3, =sleep_save_sp - add r2, sp, r1 @ convert SP to phys -#ifdef CONFIG_SMP - ALT_SMP(mrc p15, 0, lr, c0, c0, 5) - ALT_UP(mov lr, #0) - and lr, lr, #15 - str r2, [r3, lr, lsl #2] @ save phys SP -#else - str r2, [r3] @ save phys SP -#endif bl cpu_do_suspend #endif @ flush data cache #ifdef MULTI_CACHE ldr r10, =cpu_cache - mov lr, r9 + mov lr, pc ldr pc, [r10, #CACHE_FLUSH_KERN_ALL] #else - mov lr, r9 - b __cpuc_flush_kern_all + bl __cpuc_flush_kern_all #endif -ENDPROC(cpu_suspend) + adr lr, BSYM(cpu_suspend_abort) + ldmfd sp!, {r0, pc} @ call suspend fn +ENDPROC(__cpu_suspend) .ltorg +cpu_suspend_abort: + ldmia sp!, {r1 - r3} @ pop v:p, virt SP, phys resume fn + mov sp, r2 + ldmfd sp!, {r4 - r11, pc} +ENDPROC(cpu_suspend_abort) + /* * r0 = control register value * r1 = v:p offset (preserved by cpu_do_resume) @@ -97,7 +94,9 @@ ENDPROC(cpu_resume_turn_mmu_on) cpu_resume_after_mmu: str r5, [r2, r4, lsl #2] @ restore old mapping mcr p15, 0, r0, c1, c0, 0 @ turn on D-cache - mov pc, lr + bl cpu_init @ restore the und/abt/irq banked regs + mov r0, #0 @ return zero on success + ldmfd sp!, {r4 - r11, pc} ENDPROC(cpu_resume_after_mmu) /* @@ -120,20 +119,11 @@ ENTRY(cpu_resume) ldr r0, sleep_save_sp @ stack phys addr #endif setmode PSR_I_BIT | PSR_F_BIT | SVC_MODE, r1 @ set SVC, irqs off -#ifdef MULTI_CPU - @ load v:p, stack, return fn, resume fn - ARM( ldmia r0!, {r1, sp, lr, pc} ) -THUMB( ldmia r0!, {r1, r2, r3, r4} ) + @ load v:p, stack, resume fn + ARM( ldmia r0!, {r1, sp, pc} ) +THUMB( ldmia r0!, {r1, r2, r3} ) THUMB( mov sp, r2 ) -THUMB( mov lr, r3 ) -THUMB( bx r4 ) -#else - @ load v:p, stack, return fn - ARM( ldmia r0!, {r1, sp, lr} ) -THUMB( ldmia r0!, {r1, r2, lr} ) -THUMB( mov sp, r2 ) - b cpu_do_resume -#endif +THUMB( bx r3 ) ENDPROC(cpu_resume) sleep_save_sp: diff --git a/arch/arm/kernel/smp.c b/arch/arm/kernel/smp.c index e7f92a4..d88ff02 100644 --- a/arch/arm/kernel/smp.c +++ b/arch/arm/kernel/smp.c @@ -27,7 +27,7 @@ #include #include -#include +#include #include #include #include @@ -365,8 +365,7 @@ void __init smp_prepare_cpus(unsigned int max_cpus) */ if (max_cpus > ncores) max_cpus = ncores; - - if (max_cpus > 1) { + if (ncores > 1 && max_cpus) { /* * Enable the local timer or broadcast device for the * boot CPU, but only if we have more than one CPU. @@ -374,6 +373,14 @@ void __init smp_prepare_cpus(unsigned int max_cpus) percpu_timer_setup(); /* + * Initialise the present map, which describes the set of CPUs + * actually populated at the present time. A platform should + * re-initialize the map in platform_smp_prepare_cpus() if + * present != possible (e.g. physical hotplug). + */ + init_cpu_present(&cpu_possible_map); + + /* * Initialise the SCU if there are more than one CPU * and let them know where to start. */ diff --git a/arch/arm/kernel/smp_scu.c b/arch/arm/kernel/smp_scu.c index a1e757c..79ed5e7 100644 --- a/arch/arm/kernel/smp_scu.c +++ b/arch/arm/kernel/smp_scu.c @@ -20,6 +20,7 @@ #define SCU_INVALIDATE 0x0c #define SCU_FPGA_REVISION 0x10 +#ifdef CONFIG_SMP /* * Get the number of CPU cores from the SCU configuration */ @@ -50,6 +51,7 @@ void __init scu_enable(void __iomem *scu_base) */ flush_cache_all(); } +#endif /* * Set the executing CPUs power mode as defined. This will be in diff --git a/arch/arm/kernel/swp_emulate.c b/arch/arm/kernel/swp_emulate.c index 40ee7e5..5f452f8 100644 --- a/arch/arm/kernel/swp_emulate.c +++ b/arch/arm/kernel/swp_emulate.c @@ -183,7 +183,7 @@ static int swp_handler(struct pt_regs *regs, unsigned int instr) unsigned int address, destreg, data, type; unsigned int res = 0; - perf_sw_event(PERF_COUNT_SW_EMULATION_FAULTS, 1, 0, regs, regs->ARM_pc); + perf_sw_event(PERF_COUNT_SW_EMULATION_FAULTS, 1, regs, regs->ARM_pc); if (current->pid != previous_pid) { pr_debug("\"%s\" (%ld) uses deprecated SWP{B} instruction\n", diff --git a/arch/arm/kernel/tcm.c b/arch/arm/kernel/tcm.c index f5cf660..30e302d 100644 --- a/arch/arm/kernel/tcm.c +++ b/arch/arm/kernel/tcm.c @@ -19,6 +19,8 @@ #include "tcm.h" static struct gen_pool *tcm_pool; +static bool dtcm_present; +static bool itcm_present; /* TCM section definitions from the linker */ extern char __itcm_start, __sitcm_text, __eitcm_text; @@ -90,6 +92,18 @@ void tcm_free(void *addr, size_t len) } EXPORT_SYMBOL(tcm_free); +bool tcm_dtcm_present(void) +{ + return dtcm_present; +} +EXPORT_SYMBOL(tcm_dtcm_present); + +bool tcm_itcm_present(void) +{ + return itcm_present; +} +EXPORT_SYMBOL(tcm_itcm_present); + static int __init setup_tcm_bank(u8 type, u8 bank, u8 banks, u32 *offset) { @@ -134,6 +148,10 @@ static int __init setup_tcm_bank(u8 type, u8 bank, u8 banks, (tcm_region & 1) ? "" : "not "); } + /* Not much fun you can do with a size 0 bank */ + if (tcm_size == 0) + return 0; + /* Force move the TCM bank to where we want it, enable */ tcm_region = *offset | (tcm_region & 0x00000ffeU) | 1; @@ -165,12 +183,20 @@ void __init tcm_init(void) u32 tcm_status = read_cpuid_tcmstatus(); u8 dtcm_banks = (tcm_status >> 16) & 0x03; u8 itcm_banks = (tcm_status & 0x03); + size_t dtcm_code_sz = &__edtcm_data - &__sdtcm_data; + size_t itcm_code_sz = &__eitcm_text - &__sitcm_text; char *start; char *end; char *ram; int ret; int i; + /* Values greater than 2 for D/ITCM banks are "reserved" */ + if (dtcm_banks > 2) + dtcm_banks = 0; + if (itcm_banks > 2) + itcm_banks = 0; + /* Setup DTCM if present */ if (dtcm_banks > 0) { for (i = 0; i < dtcm_banks; i++) { @@ -178,6 +204,13 @@ void __init tcm_init(void) if (ret) return; } + /* This means you compiled more code than fits into DTCM */ + if (dtcm_code_sz > (dtcm_end - DTCM_OFFSET)) { + pr_info("CPU DTCM: %u bytes of code compiled to " + "DTCM but only %lu bytes of DTCM present\n", + dtcm_code_sz, (dtcm_end - DTCM_OFFSET)); + goto no_dtcm; + } dtcm_res.end = dtcm_end - 1; request_resource(&iomem_resource, &dtcm_res); dtcm_iomap[0].length = dtcm_end - DTCM_OFFSET; @@ -186,12 +219,16 @@ void __init tcm_init(void) start = &__sdtcm_data; end = &__edtcm_data; ram = &__dtcm_start; - /* This means you compiled more code than fits into DTCM */ - BUG_ON((end - start) > (dtcm_end - DTCM_OFFSET)); - memcpy(start, ram, (end-start)); - pr_debug("CPU DTCM: copied data from %p - %p\n", start, end); + memcpy(start, ram, dtcm_code_sz); + pr_debug("CPU DTCM: copied data from %p - %p\n", + start, end); + dtcm_present = true; + } else if (dtcm_code_sz) { + pr_info("CPU DTCM: %u bytes of code compiled to DTCM but no " + "DTCM banks present in CPU\n", dtcm_code_sz); } +no_dtcm: /* Setup ITCM if present */ if (itcm_banks > 0) { for (i = 0; i < itcm_banks; i++) { @@ -199,6 +236,13 @@ void __init tcm_init(void) if (ret) return; } + /* This means you compiled more code than fits into ITCM */ + if (itcm_code_sz > (itcm_end - ITCM_OFFSET)) { + pr_info("CPU ITCM: %u bytes of code compiled to " + "ITCM but only %lu bytes of ITCM present\n", + itcm_code_sz, (itcm_end - ITCM_OFFSET)); + return; + } itcm_res.end = itcm_end - 1; request_resource(&iomem_resource, &itcm_res); itcm_iomap[0].length = itcm_end - ITCM_OFFSET; @@ -207,10 +251,13 @@ void __init tcm_init(void) start = &__sitcm_text; end = &__eitcm_text; ram = &__itcm_start; - /* This means you compiled more code than fits into ITCM */ - BUG_ON((end - start) > (itcm_end - ITCM_OFFSET)); - memcpy(start, ram, (end-start)); - pr_debug("CPU ITCM: copied code from %p - %p\n", start, end); + memcpy(start, ram, itcm_code_sz); + pr_debug("CPU ITCM: copied code from %p - %p\n", + start, end); + itcm_present = true; + } else if (itcm_code_sz) { + pr_info("CPU ITCM: %u bytes of code compiled to ITCM but no " + "ITCM banks present in CPU\n", itcm_code_sz); } } @@ -221,7 +268,6 @@ void __init tcm_init(void) */ static int __init setup_tcm_pool(void) { - u32 tcm_status = read_cpuid_tcmstatus(); u32 dtcm_pool_start = (u32) &__edtcm_data; u32 itcm_pool_start = (u32) &__eitcm_text; int ret; @@ -236,7 +282,7 @@ static int __init setup_tcm_pool(void) pr_debug("Setting up TCM memory pool\n"); /* Add the rest of DTCM to the TCM pool */ - if (tcm_status & (0x03 << 16)) { + if (dtcm_present) { if (dtcm_pool_start < dtcm_end) { ret = gen_pool_add(tcm_pool, dtcm_pool_start, dtcm_end - dtcm_pool_start, -1); @@ -253,7 +299,7 @@ static int __init setup_tcm_pool(void) } /* Add the rest of ITCM to the TCM pool */ - if (tcm_status & 0x03) { + if (itcm_present) { if (itcm_pool_start < itcm_end) { ret = gen_pool_add(tcm_pool, itcm_pool_start, itcm_end - itcm_pool_start, -1); diff --git a/arch/arm/kernel/traps.c b/arch/arm/kernel/traps.c index 6807cb1..bc9f9da 100644 --- a/arch/arm/kernel/traps.c +++ b/arch/arm/kernel/traps.c @@ -25,7 +25,7 @@ #include #include -#include +#include #include #include #include @@ -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); } diff --git a/arch/arm/kernel/vmlinux.lds.S b/arch/arm/kernel/vmlinux.lds.S index e5287f2..bf977f8 100644 --- a/arch/arm/kernel/vmlinux.lds.S +++ b/arch/arm/kernel/vmlinux.lds.S @@ -38,57 +38,6 @@ jiffies = jiffies_64 + 4; SECTIONS { -#ifdef CONFIG_XIP_KERNEL - . = XIP_VIRT_ADDR(CONFIG_XIP_PHYS_ADDR); -#else - . = PAGE_OFFSET + TEXT_OFFSET; -#endif - - .init : { /* Init code and data */ - _stext = .; - _sinittext = .; - HEAD_TEXT - INIT_TEXT - ARM_EXIT_KEEP(EXIT_TEXT) - _einittext = .; - ARM_CPU_DISCARD(PROC_INFO) - __arch_info_begin = .; - *(.arch.info.init) - __arch_info_end = .; - __tagtable_begin = .; - *(.taglist.init) - __tagtable_end = .; -#ifdef CONFIG_SMP_ON_UP - __smpalt_begin = .; - *(.alt.smp.init) - __smpalt_end = .; -#endif - - __pv_table_begin = .; - *(.pv_table) - __pv_table_end = .; - - INIT_SETUP(16) - - INIT_CALLS - CON_INITCALL - SECURITY_INITCALL - INIT_RAM_FS - -#ifndef CONFIG_XIP_KERNEL - __init_begin = _stext; - INIT_DATA - ARM_EXIT_KEEP(EXIT_DATA) -#endif - } - - PERCPU_SECTION(32) - -#ifndef CONFIG_XIP_KERNEL - . = ALIGN(PAGE_SIZE); - __init_end = .; -#endif - /* * unwind exit sections must be discarded before the rest of the * unwind sections get included. @@ -106,10 +55,22 @@ SECTIONS *(.fixup) *(__ex_table) #endif +#ifndef CONFIG_SMP_ON_UP + *(.alt.smp.init) +#endif } +#ifdef CONFIG_XIP_KERNEL + . = XIP_VIRT_ADDR(CONFIG_XIP_PHYS_ADDR); +#else + . = PAGE_OFFSET + TEXT_OFFSET; +#endif + .head.text : { + _text = .; + HEAD_TEXT + } .text : { /* Real text segment */ - _text = .; /* Text and read-only data */ + _stext = .; /* Text and read-only data */ __exception_text_start = .; *(.exception.text) __exception_text_end = .; @@ -122,8 +83,6 @@ SECTIONS *(.fixup) #endif *(.gnu.warning) - *(.rodata) - *(.rodata.*) *(.glue_7) *(.glue_7t) . = ALIGN(4); @@ -152,10 +111,63 @@ SECTIONS _etext = .; /* End of text and rodata section */ +#ifndef CONFIG_XIP_KERNEL + . = ALIGN(PAGE_SIZE); + __init_begin = .; +#endif + + INIT_TEXT_SECTION(8) + .exit.text : { + ARM_EXIT_KEEP(EXIT_TEXT) + } + .init.proc.info : { + ARM_CPU_DISCARD(PROC_INFO) + } + .init.arch.info : { + __arch_info_begin = .; + *(.arch.info.init) + __arch_info_end = .; + } + .init.tagtable : { + __tagtable_begin = .; + *(.taglist.init) + __tagtable_end = .; + } +#ifdef CONFIG_SMP_ON_UP + .init.smpalt : { + __smpalt_begin = .; + *(.alt.smp.init) + __smpalt_end = .; + } +#endif + .init.pv_table : { + __pv_table_begin = .; + *(.pv_table) + __pv_table_end = .; + } + .init.data : { +#ifndef CONFIG_XIP_KERNEL + INIT_DATA +#endif + INIT_SETUP(16) + INIT_CALLS + CON_INITCALL + SECURITY_INITCALL + INIT_RAM_FS + } +#ifndef CONFIG_XIP_KERNEL + .exit.data : { + ARM_EXIT_KEEP(EXIT_DATA) + } +#endif + + PERCPU_SECTION(32) + #ifdef CONFIG_XIP_KERNEL __data_loc = ALIGN(4); /* location in binary */ . = PAGE_OFFSET + TEXT_OFFSET; #else + __init_end = .; . = ALIGN(THREAD_SIZE); __data_loc = .; #endif @@ -270,12 +282,6 @@ SECTIONS /* Default discards */ DISCARDS - -#ifndef CONFIG_SMP_ON_UP - /DISCARD/ : { - *(.alt.smp.init) - } -#endif } /* diff --git a/arch/arm/lib/ecard.S b/arch/arm/lib/ecard.S index 8678eb2..e6057fa 100644 --- a/arch/arm/lib/ecard.S +++ b/arch/arm/lib/ecard.S @@ -12,7 +12,6 @@ */ #include #include -#include #define CPSR2SPSR(rt) \ mrs rt, cpsr; \ diff --git a/arch/arm/lib/io-readsw-armv3.S b/arch/arm/lib/io-readsw-armv3.S index 9aaf7c7..88487c8 100644 --- a/arch/arm/lib/io-readsw-armv3.S +++ b/arch/arm/lib/io-readsw-armv3.S @@ -9,7 +9,6 @@ */ #include #include -#include .Linsw_bad_alignment: adr r0, .Linsw_bad_align_msg diff --git a/arch/arm/lib/io-writesw-armv3.S b/arch/arm/lib/io-writesw-armv3.S index cd34503..49b8004 100644 --- a/arch/arm/lib/io-writesw-armv3.S +++ b/arch/arm/lib/io-writesw-armv3.S @@ -9,7 +9,6 @@ */ #include #include -#include .Loutsw_bad_alignment: adr r0, .Loutsw_bad_align_msg diff --git a/arch/arm/mach-at91/at91sam9261_devices.c b/arch/arm/mach-at91/at91sam9261_devices.c index 5004bf0..0f91792 100644 --- a/arch/arm/mach-at91/at91sam9261_devices.c +++ b/arch/arm/mach-at91/at91sam9261_devices.c @@ -525,7 +525,7 @@ void __init at91_add_device_lcdc(struct atmel_lcdfb_info *data) if (ARRAY_SIZE(lcdc_resources) > 2) { void __iomem *fb; struct resource *fb_res = &lcdc_resources[2]; - size_t fb_len = fb_res->end - fb_res->start + 1; + size_t fb_len = resource_size(fb_res); fb = ioremap(fb_res->start, fb_len); if (fb) { diff --git a/arch/arm/mach-at91/board-snapper9260.c b/arch/arm/mach-at91/board-snapper9260.c index 3eb0a11..6010ce1 100644 --- a/arch/arm/mach-at91/board-snapper9260.c +++ b/arch/arm/mach-at91/board-snapper9260.c @@ -4,7 +4,7 @@ * Copyright (C) 2010 Bluewater System Ltd * * Author: Andre Renaud - * Author: Ryan Mallon + * Author: Ryan Mallon * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/arch/arm/mach-at91/include/mach/at91_mci.h b/arch/arm/mach-at91/include/mach/at91_mci.h deleted file mode 100644 index 02182c1..0000000 --- a/arch/arm/mach-at91/include/mach/at91_mci.h +++ /dev/null @@ -1,115 +0,0 @@ -/* - * arch/arm/mach-at91/include/mach/at91_mci.h - * - * Copyright (C) 2005 Ivan Kokshaysky - * Copyright (C) SAN People - * - * MultiMedia Card Interface (MCI) registers. - * Based on AT91RM9200 datasheet revision F. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - */ - -#ifndef AT91_MCI_H -#define AT91_MCI_H - -#define AT91_MCI_CR 0x00 /* Control Register */ -#define AT91_MCI_MCIEN (1 << 0) /* Multi-Media Interface Enable */ -#define AT91_MCI_MCIDIS (1 << 1) /* Multi-Media Interface Disable */ -#define AT91_MCI_PWSEN (1 << 2) /* Power Save Mode Enable */ -#define AT91_MCI_PWSDIS (1 << 3) /* Power Save Mode Disable */ -#define AT91_MCI_SWRST (1 << 7) /* Software Reset */ - -#define AT91_MCI_MR 0x04 /* Mode Register */ -#define AT91_MCI_CLKDIV (0xff << 0) /* Clock Divider */ -#define AT91_MCI_PWSDIV (7 << 8) /* Power Saving Divider */ -#define AT91_MCI_RDPROOF (1 << 11) /* Read Proof Enable [SAM926[03] only] */ -#define AT91_MCI_WRPROOF (1 << 12) /* Write Proof Enable [SAM926[03] only] */ -#define AT91_MCI_PDCFBYTE (1 << 13) /* PDC Force Byte Transfer [SAM926[03] only] */ -#define AT91_MCI_PDCPADV (1 << 14) /* PDC Padding Value */ -#define AT91_MCI_PDCMODE (1 << 15) /* PDC-orientated Mode */ -#define AT91_MCI_BLKLEN (0xfff << 18) /* Data Block Length */ - -#define AT91_MCI_DTOR 0x08 /* Data Timeout Register */ -#define AT91_MCI_DTOCYC (0xf << 0) /* Data Timeout Cycle Number */ -#define AT91_MCI_DTOMUL (7 << 4) /* Data Timeout Multiplier */ -#define AT91_MCI_DTOMUL_1 (0 << 4) -#define AT91_MCI_DTOMUL_16 (1 << 4) -#define AT91_MCI_DTOMUL_128 (2 << 4) -#define AT91_MCI_DTOMUL_256 (3 << 4) -#define AT91_MCI_DTOMUL_1K (4 << 4) -#define AT91_MCI_DTOMUL_4K (5 << 4) -#define AT91_MCI_DTOMUL_64K (6 << 4) -#define AT91_MCI_DTOMUL_1M (7 << 4) - -#define AT91_MCI_SDCR 0x0c /* SD Card Register */ -#define AT91_MCI_SDCSEL (3 << 0) /* SD Card Selector */ -#define AT91_MCI_SDCBUS (1 << 7) /* 1-bit or 4-bit bus */ - -#define AT91_MCI_ARGR 0x10 /* Argument Register */ - -#define AT91_MCI_CMDR 0x14 /* Command Register */ -#define AT91_MCI_CMDNB (0x3f << 0) /* Command Number */ -#define AT91_MCI_RSPTYP (3 << 6) /* Response Type */ -#define AT91_MCI_RSPTYP_NONE (0 << 6) -#define AT91_MCI_RSPTYP_48 (1 << 6) -#define AT91_MCI_RSPTYP_136 (2 << 6) -#define AT91_MCI_SPCMD (7 << 8) /* Special Command */ -#define AT91_MCI_SPCMD_NONE (0 << 8) -#define AT91_MCI_SPCMD_INIT (1 << 8) -#define AT91_MCI_SPCMD_SYNC (2 << 8) -#define AT91_MCI_SPCMD_ICMD (4 << 8) -#define AT91_MCI_SPCMD_IRESP (5 << 8) -#define AT91_MCI_OPDCMD (1 << 11) /* Open Drain Command */ -#define AT91_MCI_MAXLAT (1 << 12) /* Max Latency for Command to Response */ -#define AT91_MCI_TRCMD (3 << 16) /* Transfer Command */ -#define AT91_MCI_TRCMD_NONE (0 << 16) -#define AT91_MCI_TRCMD_START (1 << 16) -#define AT91_MCI_TRCMD_STOP (2 << 16) -#define AT91_MCI_TRDIR (1 << 18) /* Transfer Direction */ -#define AT91_MCI_TRTYP (3 << 19) /* Transfer Type */ -#define AT91_MCI_TRTYP_BLOCK (0 << 19) -#define AT91_MCI_TRTYP_MULTIPLE (1 << 19) -#define AT91_MCI_TRTYP_STREAM (2 << 19) -#define AT91_MCI_TRTYP_SDIO_BYTE (4 << 19) -#define AT91_MCI_TRTYP_SDIO_BLOCK (5 << 19) - -#define AT91_MCI_BLKR 0x18 /* Block Register */ -#define AT91_MCI_BLKR_BCNT(n) ((0xffff & (n)) << 0) /* Block count */ -#define AT91_MCI_BLKR_BLKLEN(n) ((0xffff & (n)) << 16) /* Block length */ - -#define AT91_MCI_RSPR(n) (0x20 + ((n) * 4)) /* Response Registers 0-3 */ -#define AT91_MCR_RDR 0x30 /* Receive Data Register */ -#define AT91_MCR_TDR 0x34 /* Transmit Data Register */ - -#define AT91_MCI_SR 0x40 /* Status Register */ -#define AT91_MCI_CMDRDY (1 << 0) /* Command Ready */ -#define AT91_MCI_RXRDY (1 << 1) /* Receiver Ready */ -#define AT91_MCI_TXRDY (1 << 2) /* Transmit Ready */ -#define AT91_MCI_BLKE (1 << 3) /* Data Block Ended */ -#define AT91_MCI_DTIP (1 << 4) /* Data Transfer in Progress */ -#define AT91_MCI_NOTBUSY (1 << 5) /* Data Not Busy */ -#define AT91_MCI_ENDRX (1 << 6) /* End of RX Buffer */ -#define AT91_MCI_ENDTX (1 << 7) /* End fo TX Buffer */ -#define AT91_MCI_SDIOIRQA (1 << 8) /* SDIO Interrupt for Slot A */ -#define AT91_MCI_SDIOIRQB (1 << 9) /* SDIO Interrupt for Slot B */ -#define AT91_MCI_RXBUFF (1 << 14) /* RX Buffer Full */ -#define AT91_MCI_TXBUFE (1 << 15) /* TX Buffer Empty */ -#define AT91_MCI_RINDE (1 << 16) /* Response Index Error */ -#define AT91_MCI_RDIRE (1 << 17) /* Response Direction Error */ -#define AT91_MCI_RCRCE (1 << 18) /* Response CRC Error */ -#define AT91_MCI_RENDE (1 << 19) /* Response End Bit Error */ -#define AT91_MCI_RTOE (1 << 20) /* Response Time-out Error */ -#define AT91_MCI_DCRCE (1 << 21) /* Data CRC Error */ -#define AT91_MCI_DTOE (1 << 22) /* Data Time-out Error */ -#define AT91_MCI_OVRE (1 << 30) /* Overrun */ -#define AT91_MCI_UNRE (1 << 31) /* Underrun */ - -#define AT91_MCI_IER 0x44 /* Interrupt Enable Register */ -#define AT91_MCI_IDR 0x48 /* Interrupt Disable Register */ -#define AT91_MCI_IMR 0x4c /* Interrupt Mask Register */ - -#endif diff --git a/arch/arm/mach-at91/include/mach/clkdev.h b/arch/arm/mach-at91/include/mach/clkdev.h deleted file mode 100644 index 04b37a8..0000000 --- a/arch/arm/mach-at91/include/mach/clkdev.h +++ /dev/null @@ -1,7 +0,0 @@ -#ifndef __ASM_MACH_CLKDEV_H -#define __ASM_MACH_CLKDEV_H - -#define __clk_get(clk) ({ 1; }) -#define __clk_put(clk) do { } while (0) - -#endif diff --git a/arch/arm/mach-at91/pm.c b/arch/arm/mach-at91/pm.c index ea53f4d..4159eca 100644 --- a/arch/arm/mach-at91/pm.c +++ b/arch/arm/mach-at91/pm.c @@ -20,7 +20,7 @@ #include #include -#include +#include #include #include diff --git a/arch/arm/mach-bcmring/dma.c b/arch/arm/mach-bcmring/dma.c index d87ad30..0ca0005 100644 --- a/arch/arm/mach-bcmring/dma.c +++ b/arch/arm/mach-bcmring/dma.c @@ -34,7 +34,7 @@ #include #include -#include +#include #include /* I don't quite understand why dc4 fails when this is set to 1 and DMA is enabled */ @@ -835,7 +835,7 @@ int dma_init(void) /* Create /proc/dma/channels and /proc/dma/devices */ - gDmaDir = create_proc_entry("dma", S_IFDIR | S_IRUGO | S_IXUGO, NULL); + gDmaDir = proc_mkdir("dma", NULL); if (gDmaDir == NULL) { printk(KERN_ERR "Unable to create /proc/dma\n"); diff --git a/arch/arm/mach-bcmring/include/mach/clkdev.h b/arch/arm/mach-bcmring/include/mach/clkdev.h deleted file mode 100644 index 04b37a8..0000000 --- a/arch/arm/mach-bcmring/include/mach/clkdev.h +++ /dev/null @@ -1,7 +0,0 @@ -#ifndef __ASM_MACH_CLKDEV_H -#define __ASM_MACH_CLKDEV_H - -#define __clk_get(clk) ({ 1; }) -#define __clk_put(clk) do { } while (0) - -#endif diff --git a/arch/arm/mach-bcmring/include/mach/entry-macro.S b/arch/arm/mach-bcmring/include/mach/entry-macro.S index 7d393ca..94c950d 100644 --- a/arch/arm/mach-bcmring/include/mach/entry-macro.S +++ b/arch/arm/mach-bcmring/include/mach/entry-macro.S @@ -80,7 +80,3 @@ .macro arch_ret_to_user, tmp1, tmp2 .endm - - .macro irq_prio_table - .endm - diff --git a/arch/arm/mach-bcmring/include/mach/hardware.h b/arch/arm/mach-bcmring/include/mach/hardware.h index 8bf3564..ed78aab 100644 --- a/arch/arm/mach-bcmring/include/mach/hardware.h +++ b/arch/arm/mach-bcmring/include/mach/hardware.h @@ -36,8 +36,6 @@ #define RAM_SIZE (CFG_GLOBAL_RAM_SIZE-CFG_GLOBAL_RAM_SIZE_RESERVED) #define RAM_BASE PAGE_OFFSET -#define pcibios_assign_all_busses() 1 - /* Macros to make managing spinlocks a bit more controlled in terms of naming. */ /* See reg_gpio.h, reg_irq.h, arch.c, gpio.c for example usage. */ #if defined(__KERNEL__) diff --git a/arch/arm/mach-cns3xxx/cns3420vb.c b/arch/arm/mach-cns3xxx/cns3420vb.c index 08e5c87..3e7d149 100644 --- a/arch/arm/mach-cns3xxx/cns3420vb.c +++ b/arch/arm/mach-cns3xxx/cns3420vb.c @@ -29,7 +29,6 @@ #include #include #include -#include #include #include #include "core.h" @@ -170,6 +169,8 @@ static struct platform_device *cns3420_pdevs[] __initdata = { static void __init cns3420_init(void) { + cns3xxx_l2x0_init(); + platform_add_devices(cns3420_pdevs, ARRAY_SIZE(cns3420_pdevs)); cns3xxx_ahci_init(); diff --git a/arch/arm/mach-cns3xxx/core.c b/arch/arm/mach-cns3xxx/core.c index da30078..941a308 100644 --- a/arch/arm/mach-cns3xxx/core.c +++ b/arch/arm/mach-cns3xxx/core.c @@ -16,6 +16,7 @@ #include #include #include +#include #include #include "core.h" @@ -244,3 +245,45 @@ static void __init cns3xxx_timer_init(void) struct sys_timer cns3xxx_timer = { .init = cns3xxx_timer_init, }; + +#ifdef CONFIG_CACHE_L2X0 + +void __init cns3xxx_l2x0_init(void) +{ + void __iomem *base = ioremap(CNS3XXX_L2C_BASE, SZ_4K); + u32 val; + + if (WARN_ON(!base)) + return; + + /* + * Tag RAM Control register + * + * bit[10:8] - 1 cycle of write accesses latency + * bit[6:4] - 1 cycle of read accesses latency + * bit[3:0] - 1 cycle of setup latency + * + * 1 cycle of latency for setup, read and write accesses + */ + val = readl(base + L2X0_TAG_LATENCY_CTRL); + val &= 0xfffff888; + writel(val, base + L2X0_TAG_LATENCY_CTRL); + + /* + * Data RAM Control register + * + * bit[10:8] - 1 cycles of write accesses latency + * bit[6:4] - 1 cycles of read accesses latency + * bit[3:0] - 1 cycle of setup latency + * + * 1 cycle of latency for setup, read and write accesses + */ + val = readl(base + L2X0_DATA_LATENCY_CTRL); + val &= 0xfffff888; + writel(val, base + L2X0_DATA_LATENCY_CTRL); + + /* 32 KiB, 8-way, parity disable */ + l2x0_init(base, 0x00540000, 0xfe000fff); +} + +#endif /* CONFIG_CACHE_L2X0 */ diff --git a/arch/arm/mach-cns3xxx/core.h b/arch/arm/mach-cns3xxx/core.h index ffeb3a8..fcd2253 100644 --- a/arch/arm/mach-cns3xxx/core.h +++ b/arch/arm/mach-cns3xxx/core.h @@ -13,6 +13,12 @@ extern struct sys_timer cns3xxx_timer; +#ifdef CONFIG_CACHE_L2X0 +void __init cns3xxx_l2x0_init(void); +#else +static inline void cns3xxx_l2x0_init(void) {} +#endif /* CONFIG_CACHE_L2X0 */ + void __init cns3xxx_map_io(void); void __init cns3xxx_init_irq(void); void cns3xxx_power_off(void); diff --git a/arch/arm/mach-cns3xxx/include/mach/hardware.h b/arch/arm/mach-cns3xxx/include/mach/hardware.h deleted file mode 100644 index 57e0983..0000000 --- a/arch/arm/mach-cns3xxx/include/mach/hardware.h +++ /dev/null @@ -1,22 +0,0 @@ -/* - * This file contains the hardware definitions of the Cavium Networks boards. - * - * Copyright 2003 ARM Limited. - * Copyright 2008 Cavium Networks - * - * This file is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License, Version 2, as - * published by the Free Software Foundation. - */ - -#ifndef __MACH_HARDWARE_H -#define __MACH_HARDWARE_H - -#include - -/* macro to get at IO space when running virtually */ -#define PCIBIOS_MIN_IO 0x00000000 -#define PCIBIOS_MIN_MEM 0x00000000 -#define pcibios_assign_all_busses() 1 - -#endif diff --git a/arch/arm/mach-cns3xxx/include/mach/pm.h b/arch/arm/mach-cns3xxx/include/mach/pm.h index 6eae7f7..c2588cc 100644 --- a/arch/arm/mach-cns3xxx/include/mach/pm.h +++ b/arch/arm/mach-cns3xxx/include/mach/pm.h @@ -11,7 +11,7 @@ #ifndef __CNS3XXX_PM_H #define __CNS3XXX_PM_H -#include +#include void cns3xxx_pwr_clk_en(unsigned int block); void cns3xxx_pwr_clk_dis(unsigned int block); diff --git a/arch/arm/mach-cns3xxx/include/mach/vmalloc.h b/arch/arm/mach-cns3xxx/include/mach/vmalloc.h index 4d381ec..1dd231d 100644 --- a/arch/arm/mach-cns3xxx/include/mach/vmalloc.h +++ b/arch/arm/mach-cns3xxx/include/mach/vmalloc.h @@ -8,4 +8,4 @@ * published by the Free Software Foundation. */ -#define VMALLOC_END 0xd8000000 +#define VMALLOC_END 0xd8000000UL diff --git a/arch/arm/mach-cns3xxx/pcie.c b/arch/arm/mach-cns3xxx/pcie.c index 78defd7..a4ec080 100644 --- a/arch/arm/mach-cns3xxx/pcie.c +++ b/arch/arm/mach-cns3xxx/pcie.c @@ -369,6 +369,9 @@ static int __init cns3xxx_pcie_init(void) { int i; + pcibios_min_io = 0; + pcibios_min_mem = 0; + hook_fault_code(16 + 6, cns3xxx_pcie_abort_handler, SIGBUS, 0, "imprecise external abort"); diff --git a/arch/arm/mach-cns3xxx/pm.c b/arch/arm/mach-cns3xxx/pm.c index 5e57955..0c04678 100644 --- a/arch/arm/mach-cns3xxx/pm.c +++ b/arch/arm/mach-cns3xxx/pm.c @@ -10,7 +10,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/arch/arm/mach-davinci/board-da830-evm.c b/arch/arm/mach-davinci/board-da830-evm.c index 8bc3701..84fd786 100644 --- a/arch/arm/mach-davinci/board-da830-evm.c +++ b/arch/arm/mach-davinci/board-da830-evm.c @@ -681,4 +681,5 @@ MACHINE_START(DAVINCI_DA830_EVM, "DaVinci DA830/OMAP-L137/AM17x EVM") .init_irq = cp_intc_init, .timer = &davinci_timer, .init_machine = da830_evm_init, + .dma_zone_size = SZ_128M, MACHINE_END diff --git a/arch/arm/mach-davinci/board-da850-evm.c b/arch/arm/mach-davinci/board-da850-evm.c index a7b41bf..bd53945 100644 --- a/arch/arm/mach-davinci/board-da850-evm.c +++ b/arch/arm/mach-davinci/board-da850-evm.c @@ -1117,6 +1117,8 @@ static __init int da850_evm_init_cpufreq(void) static __init int da850_evm_init_cpufreq(void) { return 0; } #endif +#define DA850EVM_SATA_REFCLKPN_RATE (100 * 1000 * 1000) + static __init void da850_evm_init(void) { int ret; @@ -1237,6 +1239,11 @@ static __init void da850_evm_init(void) if (ret) pr_warning("da850_evm_init: spi 1 registration failed: %d\n", ret); + + ret = da850_register_sata(DA850EVM_SATA_REFCLKPN_RATE); + if (ret) + pr_warning("da850_evm_init: sata registration failed: %d\n", + ret); } #ifdef CONFIG_SERIAL_8250_CONSOLE @@ -1261,4 +1268,5 @@ MACHINE_START(DAVINCI_DA850_EVM, "DaVinci DA850/OMAP-L138/AM18x EVM") .init_irq = cp_intc_init, .timer = &davinci_timer, .init_machine = da850_evm_init, + .dma_zone_size = SZ_128M, MACHINE_END diff --git a/arch/arm/mach-davinci/board-dm355-evm.c b/arch/arm/mach-davinci/board-dm355-evm.c index 6e7cad13..241a6bd 100644 --- a/arch/arm/mach-davinci/board-dm355-evm.c +++ b/arch/arm/mach-davinci/board-dm355-evm.c @@ -356,4 +356,5 @@ MACHINE_START(DAVINCI_DM355_EVM, "DaVinci DM355 EVM") .init_irq = davinci_irq_init, .timer = &davinci_timer, .init_machine = dm355_evm_init, + .dma_zone_size = SZ_128M, MACHINE_END diff --git a/arch/arm/mach-davinci/board-dm355-leopard.c b/arch/arm/mach-davinci/board-dm355-leopard.c index 543f991..bee284c 100644 --- a/arch/arm/mach-davinci/board-dm355-leopard.c +++ b/arch/arm/mach-davinci/board-dm355-leopard.c @@ -275,4 +275,5 @@ MACHINE_START(DM355_LEOPARD, "DaVinci DM355 leopard") .init_irq = davinci_irq_init, .timer = &davinci_timer, .init_machine = dm355_leopard_init, + .dma_zone_size = SZ_128M, MACHINE_END diff --git a/arch/arm/mach-davinci/board-dm365-evm.c b/arch/arm/mach-davinci/board-dm365-evm.c index 09a87e6..9818f21 100644 --- a/arch/arm/mach-davinci/board-dm365-evm.c +++ b/arch/arm/mach-davinci/board-dm365-evm.c @@ -617,5 +617,6 @@ MACHINE_START(DAVINCI_DM365_EVM, "DaVinci DM365 EVM") .init_irq = davinci_irq_init, .timer = &davinci_timer, .init_machine = dm365_evm_init, + .dma_zone_size = SZ_128M, MACHINE_END diff --git a/arch/arm/mach-davinci/board-dm644x-evm.c b/arch/arm/mach-davinci/board-dm644x-evm.c index 556bbd4..95607a1 100644 --- a/arch/arm/mach-davinci/board-dm644x-evm.c +++ b/arch/arm/mach-davinci/board-dm644x-evm.c @@ -717,4 +717,5 @@ MACHINE_START(DAVINCI_EVM, "DaVinci DM644x EVM") .init_irq = davinci_irq_init, .timer = &davinci_timer, .init_machine = davinci_evm_init, + .dma_zone_size = SZ_128M, MACHINE_END diff --git a/arch/arm/mach-davinci/board-dm646x-evm.c b/arch/arm/mach-davinci/board-dm646x-evm.c index f6ac9ba..993a314 100644 --- a/arch/arm/mach-davinci/board-dm646x-evm.c +++ b/arch/arm/mach-davinci/board-dm646x-evm.c @@ -719,9 +719,15 @@ static void __init cdce_clk_init(void) } } +#define DM6467T_EVM_REF_FREQ 33000000 + static void __init davinci_map_io(void) { dm646x_init(); + + if (machine_is_davinci_dm6467tevm()) + davinci_set_refclk_rate(DM6467T_EVM_REF_FREQ); + cdce_clk_init(); } @@ -785,23 +791,13 @@ static __init void evm_init(void) soc_info->emac_pdata->phy_id = DM646X_EVM_PHY_ID; } -#define DM646X_EVM_REF_FREQ 27000000 -#define DM6467T_EVM_REF_FREQ 33000000 - -void __init dm646x_board_setup_refclk(struct clk *clk) -{ - if (machine_is_davinci_dm6467tevm()) - clk->rate = DM6467T_EVM_REF_FREQ; - else - clk->rate = DM646X_EVM_REF_FREQ; -} - MACHINE_START(DAVINCI_DM6467_EVM, "DaVinci DM646x EVM") .boot_params = (0x80000100), .map_io = davinci_map_io, .init_irq = davinci_irq_init, .timer = &davinci_timer, .init_machine = evm_init, + .dma_zone_size = SZ_128M, MACHINE_END MACHINE_START(DAVINCI_DM6467TEVM, "DaVinci DM6467T EVM") @@ -810,5 +806,6 @@ MACHINE_START(DAVINCI_DM6467TEVM, "DaVinci DM6467T EVM") .init_irq = davinci_irq_init, .timer = &davinci_timer, .init_machine = evm_init, + .dma_zone_size = SZ_128M, MACHINE_END diff --git a/arch/arm/mach-davinci/board-mityomapl138.c b/arch/arm/mach-davinci/board-mityomapl138.c index 606a6f2..c278226 100644 --- a/arch/arm/mach-davinci/board-mityomapl138.c +++ b/arch/arm/mach-davinci/board-mityomapl138.c @@ -20,6 +20,7 @@ #include #include +#include #include #include #include @@ -570,4 +571,5 @@ MACHINE_START(MITYOMAPL138, "MityDSP-L138/MityARM-1808") .init_irq = cp_intc_init, .timer = &davinci_timer, .init_machine = mityomapl138_init, + .dma_zone_size = SZ_128M, MACHINE_END diff --git a/arch/arm/mach-davinci/board-neuros-osd2.c b/arch/arm/mach-davinci/board-neuros-osd2.c index 3e7be2d..d60a800 100644 --- a/arch/arm/mach-davinci/board-neuros-osd2.c +++ b/arch/arm/mach-davinci/board-neuros-osd2.c @@ -277,4 +277,5 @@ MACHINE_START(NEUROS_OSD2, "Neuros OSD2") .init_irq = davinci_irq_init, .timer = &davinci_timer, .init_machine = davinci_ntosd2_init, + .dma_zone_size = SZ_128M, MACHINE_END diff --git a/arch/arm/mach-davinci/board-omapl138-hawk.c b/arch/arm/mach-davinci/board-omapl138-hawk.c index 67c38d0..237332a 100644 --- a/arch/arm/mach-davinci/board-omapl138-hawk.c +++ b/arch/arm/mach-davinci/board-omapl138-hawk.c @@ -343,4 +343,5 @@ MACHINE_START(OMAPL138_HAWKBOARD, "AM18x/OMAP-L138 Hawkboard") .init_irq = cp_intc_init, .timer = &davinci_timer, .init_machine = omapl138_hawk_init, + .dma_zone_size = SZ_128M, MACHINE_END diff --git a/arch/arm/mach-davinci/board-sffsdr.c b/arch/arm/mach-davinci/board-sffsdr.c index 61ac96d..5f4385c 100644 --- a/arch/arm/mach-davinci/board-sffsdr.c +++ b/arch/arm/mach-davinci/board-sffsdr.c @@ -156,4 +156,5 @@ MACHINE_START(SFFSDR, "Lyrtech SFFSDR") .init_irq = davinci_irq_init, .timer = &davinci_timer, .init_machine = davinci_sffsdr_init, + .dma_zone_size = SZ_128M, MACHINE_END diff --git a/arch/arm/mach-davinci/board-tnetv107x-evm.c b/arch/arm/mach-davinci/board-tnetv107x-evm.c index 1a656e8..7828920 100644 --- a/arch/arm/mach-davinci/board-tnetv107x-evm.c +++ b/arch/arm/mach-davinci/board-tnetv107x-evm.c @@ -282,4 +282,5 @@ MACHINE_START(TNETV107X, "TNETV107X EVM") .init_irq = cp_intc_init, .timer = &davinci_timer, .init_machine = tnetv107x_evm_board_init, + .dma_zone_size = SZ_128M, MACHINE_END diff --git a/arch/arm/mach-davinci/clock.c b/arch/arm/mach-davinci/clock.c index e4e3af1..0086113 100644 --- a/arch/arm/mach-davinci/clock.c +++ b/arch/arm/mach-davinci/clock.c @@ -44,7 +44,7 @@ static void __clk_enable(struct clk *clk) __clk_enable(clk->parent); if (clk->usecount++ == 0 && (clk->flags & CLK_PSC)) davinci_psc_config(psc_domain(clk), clk->gpsc, clk->lpsc, - PSC_STATE_ENABLE); + true, clk->flags); } static void __clk_disable(struct clk *clk) @@ -54,8 +54,7 @@ static void __clk_disable(struct clk *clk) if (--clk->usecount == 0 && !(clk->flags & CLK_PLL) && (clk->flags & CLK_PSC)) davinci_psc_config(psc_domain(clk), clk->gpsc, clk->lpsc, - (clk->flags & PSC_SWRSTDISABLE) ? - PSC_STATE_SWRSTDISABLE : PSC_STATE_DISABLE); + false, clk->flags); if (clk->parent) __clk_disable(clk->parent); } @@ -239,8 +238,7 @@ static int __init clk_disable_unused(void) pr_debug("Clocks: disable unused %s\n", ck->name); davinci_psc_config(psc_domain(ck), ck->gpsc, ck->lpsc, - (ck->flags & PSC_SWRSTDISABLE) ? - PSC_STATE_SWRSTDISABLE : PSC_STATE_DISABLE); + false, ck->flags); } spin_unlock_irq(&clockfw_lock); @@ -368,6 +366,12 @@ static unsigned long clk_leafclk_recalc(struct clk *clk) return clk->parent->rate; } +int davinci_simple_set_rate(struct clk *clk, unsigned long rate) +{ + clk->rate = rate; + return 0; +} + static unsigned long clk_pllclk_recalc(struct clk *clk) { u32 ctrl, mult = 1, prediv = 1, postdiv = 1; @@ -506,6 +510,38 @@ int davinci_set_pllrate(struct pll_data *pll, unsigned int prediv, } EXPORT_SYMBOL(davinci_set_pllrate); +/** + * davinci_set_refclk_rate() - Set the reference clock rate + * @rate: The new rate. + * + * Sets the reference clock rate to a given value. This will most likely + * result in the entire clock tree getting updated. + * + * This is used to support boards which use a reference clock different + * than that used by default in .c file. The reference clock rate + * should be updated early in the boot process; ideally soon after the + * clock tree has been initialized once with the default reference clock + * rate (davinci_common_init()). + * + * Returns 0 on success, error otherwise. + */ +int davinci_set_refclk_rate(unsigned long rate) +{ + struct clk *refclk; + + refclk = clk_get(NULL, "ref"); + if (IS_ERR(refclk)) { + pr_err("%s: failed to get reference clock.\n", __func__); + return PTR_ERR(refclk); + } + + clk_set_rate(refclk, rate); + + clk_put(refclk); + + return 0; +} + int __init davinci_clk_init(struct clk_lookup *clocks) { struct clk_lookup *c; diff --git a/arch/arm/mach-davinci/clock.h b/arch/arm/mach-davinci/clock.h index 0dd2203..a705f36 100644 --- a/arch/arm/mach-davinci/clock.h +++ b/arch/arm/mach-davinci/clock.h @@ -111,6 +111,7 @@ struct clk { #define CLK_PLL BIT(4) /* PLL-derived clock */ #define PRE_PLL BIT(5) /* source is before PLL mult/div */ #define PSC_SWRSTDISABLE BIT(6) /* Disable state is SwRstDisable */ +#define PSC_FORCE BIT(7) /* Force module state transtition */ #define CLK(dev, con, ck) \ { \ @@ -123,6 +124,8 @@ int davinci_clk_init(struct clk_lookup *clocks); int davinci_set_pllrate(struct pll_data *pll, unsigned int prediv, unsigned int mult, unsigned int postdiv); int davinci_set_sysclk_rate(struct clk *clk, unsigned long rate); +int davinci_set_refclk_rate(unsigned long rate); +int davinci_simple_set_rate(struct clk *clk, unsigned long rate); extern struct platform_device davinci_wdt_device; extern void davinci_watchdog_reset(struct platform_device *); diff --git a/arch/arm/mach-davinci/da850.c b/arch/arm/mach-davinci/da850.c index 133aac4..935dbed 100644 --- a/arch/arm/mach-davinci/da850.c +++ b/arch/arm/mach-davinci/da850.c @@ -58,6 +58,7 @@ static struct pll_data pll0_data = { static struct clk ref_clk = { .name = "ref_clk", .rate = DA850_REF_FREQ, + .set_rate = davinci_simple_set_rate, }; static struct clk pll0_clk = { @@ -373,6 +374,14 @@ static struct clk spi1_clk = { .flags = DA850_CLK_ASYNC3, }; +static struct clk sata_clk = { + .name = "sata", + .parent = &pll0_sysclk2, + .lpsc = DA850_LPSC1_SATA, + .gpsc = 1, + .flags = PSC_FORCE, +}; + static struct clk_lookup da850_clks[] = { CLK(NULL, "ref", &ref_clk), CLK(NULL, "pll0", &pll0_clk), @@ -419,6 +428,7 @@ static struct clk_lookup da850_clks[] = { CLK(NULL, "usb20", &usb20_clk), CLK("spi_davinci.0", NULL, &spi0_clk), CLK("spi_davinci.1", NULL, &spi1_clk), + CLK("ahci", NULL, &sata_clk), CLK(NULL, NULL, NULL), }; diff --git a/arch/arm/mach-davinci/devices-da8xx.c b/arch/arm/mach-davinci/devices-da8xx.c index fc4e98e..2f7e719 100644 --- a/arch/arm/mach-davinci/devices-da8xx.c +++ b/arch/arm/mach-davinci/devices-da8xx.c @@ -14,6 +14,8 @@ #include #include #include +#include +#include #include #include @@ -33,6 +35,7 @@ #define DA8XX_SPI0_BASE 0x01c41000 #define DA830_SPI1_BASE 0x01e12000 #define DA8XX_LCD_CNTRL_BASE 0x01e13000 +#define DA850_SATA_BASE 0x01e18000 #define DA850_MMCSD1_BASE 0x01e1b000 #define DA8XX_EMAC_CPPI_PORT_BASE 0x01e20000 #define DA8XX_EMAC_CPGMACSS_BASE 0x01e22000 @@ -842,3 +845,126 @@ int __init da8xx_register_spi(int instance, struct spi_board_info *info, return platform_device_register(&da8xx_spi_device[instance]); } + +#ifdef CONFIG_ARCH_DAVINCI_DA850 + +static struct resource da850_sata_resources[] = { + { + .start = DA850_SATA_BASE, + .end = DA850_SATA_BASE + 0x1fff, + .flags = IORESOURCE_MEM, + }, + { + .start = IRQ_DA850_SATAINT, + .flags = IORESOURCE_IRQ, + }, +}; + +/* SATA PHY Control Register offset from AHCI base */ +#define SATA_P0PHYCR_REG 0x178 + +#define SATA_PHY_MPY(x) ((x) << 0) +#define SATA_PHY_LOS(x) ((x) << 6) +#define SATA_PHY_RXCDR(x) ((x) << 10) +#define SATA_PHY_RXEQ(x) ((x) << 13) +#define SATA_PHY_TXSWING(x) ((x) << 19) +#define SATA_PHY_ENPLL(x) ((x) << 31) + +static struct clk *da850_sata_clk; +static unsigned long da850_sata_refclkpn; + +/* Supported DA850 SATA crystal frequencies */ +#define KHZ_TO_HZ(freq) ((freq) * 1000) +static unsigned long da850_sata_xtal[] = { + KHZ_TO_HZ(300000), + KHZ_TO_HZ(250000), + 0, /* Reserved */ + KHZ_TO_HZ(187500), + KHZ_TO_HZ(150000), + KHZ_TO_HZ(125000), + KHZ_TO_HZ(120000), + KHZ_TO_HZ(100000), + KHZ_TO_HZ(75000), + KHZ_TO_HZ(60000), +}; + +static int da850_sata_init(struct device *dev, void __iomem *addr) +{ + int i, ret; + unsigned int val; + + da850_sata_clk = clk_get(dev, NULL); + if (IS_ERR(da850_sata_clk)) + return PTR_ERR(da850_sata_clk); + + ret = clk_enable(da850_sata_clk); + if (ret) + goto err0; + + /* Enable SATA clock receiver */ + val = __raw_readl(DA8XX_SYSCFG1_VIRT(DA8XX_PWRDN_REG)); + val &= ~BIT(0); + __raw_writel(val, DA8XX_SYSCFG1_VIRT(DA8XX_PWRDN_REG)); + + /* Get the multiplier needed for 1.5GHz PLL output */ + for (i = 0; i < ARRAY_SIZE(da850_sata_xtal); i++) + if (da850_sata_xtal[i] == da850_sata_refclkpn) + break; + + if (i == ARRAY_SIZE(da850_sata_xtal)) { + ret = -EINVAL; + goto err1; + } + + val = SATA_PHY_MPY(i + 1) | + SATA_PHY_LOS(1) | + SATA_PHY_RXCDR(4) | + SATA_PHY_RXEQ(1) | + SATA_PHY_TXSWING(3) | + SATA_PHY_ENPLL(1); + + __raw_writel(val, addr + SATA_P0PHYCR_REG); + + return 0; + +err1: + clk_disable(da850_sata_clk); +err0: + clk_put(da850_sata_clk); + return ret; +} + +static void da850_sata_exit(struct device *dev) +{ + clk_disable(da850_sata_clk); + clk_put(da850_sata_clk); +} + +static struct ahci_platform_data da850_sata_pdata = { + .init = da850_sata_init, + .exit = da850_sata_exit, +}; + +static u64 da850_sata_dmamask = DMA_BIT_MASK(32); + +static struct platform_device da850_sata_device = { + .name = "ahci", + .id = -1, + .dev = { + .platform_data = &da850_sata_pdata, + .dma_mask = &da850_sata_dmamask, + .coherent_dma_mask = DMA_BIT_MASK(32), + }, + .num_resources = ARRAY_SIZE(da850_sata_resources), + .resource = da850_sata_resources, +}; + +int __init da850_register_sata(unsigned long refclkpn) +{ + da850_sata_refclkpn = refclkpn; + if (!da850_sata_refclkpn) + return -EINVAL; + + return platform_device_register(&da850_sata_device); +} +#endif diff --git a/arch/arm/mach-davinci/dm646x.c b/arch/arm/mach-davinci/dm646x.c index 1e0f809..1802e71 100644 --- a/arch/arm/mach-davinci/dm646x.c +++ b/arch/arm/mach-davinci/dm646x.c @@ -8,6 +8,7 @@ * is licensed "as is" without any warranty of any kind, whether express * or implied. */ +#include #include #include #include @@ -42,6 +43,7 @@ /* * Device specific clocks */ +#define DM646X_REF_FREQ 27000000 #define DM646X_AUX_FREQ 24000000 static struct pll_data pll1_data = { @@ -56,6 +58,8 @@ static struct pll_data pll2_data = { static struct clk ref_clk = { .name = "ref_clk", + .rate = DM646X_REF_FREQ, + .set_rate = davinci_simple_set_rate, }; static struct clk aux_clkin = { @@ -901,7 +905,6 @@ int __init dm646x_init_edma(struct edma_rsv_info *rsv) void __init dm646x_init(void) { - dm646x_board_setup_refclk(&ref_clk); davinci_common_init(&davinci_soc_info_dm646x); } diff --git a/arch/arm/mach-davinci/include/mach/clkdev.h b/arch/arm/mach-davinci/include/mach/clkdev.h deleted file mode 100644 index 14a5048..0000000 --- a/arch/arm/mach-davinci/include/mach/clkdev.h +++ /dev/null @@ -1,15 +0,0 @@ -#ifndef __MACH_CLKDEV_H -#define __MACH_CLKDEV_H - -struct clk; - -static inline int __clk_get(struct clk *clk) -{ - return 1; -} - -static inline void __clk_put(struct clk *clk) -{ -} - -#endif diff --git a/arch/arm/mach-davinci/include/mach/da8xx.h b/arch/arm/mach-davinci/include/mach/da8xx.h index ad64da7..eaca7d8 100644 --- a/arch/arm/mach-davinci/include/mach/da8xx.h +++ b/arch/arm/mach-davinci/include/mach/da8xx.h @@ -57,6 +57,7 @@ extern unsigned int da850_max_speed; #define DA8XX_SYSCFG1_BASE (IO_PHYS + 0x22C000) #define DA8XX_SYSCFG1_VIRT(x) (da8xx_syscfg1_base + (x)) #define DA8XX_DEEPSLEEP_REG 0x8 +#define DA8XX_PWRDN_REG 0x18 #define DA8XX_PSC0_BASE 0x01c10000 #define DA8XX_PLL0_BASE 0x01c11000 @@ -89,6 +90,7 @@ int da850_register_cpufreq(char *async_clk); int da8xx_register_cpuidle(void); void __iomem * __init da8xx_get_mem_ctlr(void); int da850_register_pm(struct platform_device *pdev); +int __init da850_register_sata(unsigned long refclkpn); extern struct platform_device da8xx_serial_device; extern struct emac_platform_data da8xx_emac_pdata; diff --git a/arch/arm/mach-davinci/include/mach/dm646x.h b/arch/arm/mach-davinci/include/mach/dm646x.h index 7a27f3f..2a00fe5 100644 --- a/arch/arm/mach-davinci/include/mach/dm646x.h +++ b/arch/arm/mach-davinci/include/mach/dm646x.h @@ -15,7 +15,6 @@ #include #include #include -#include #include #define DM646X_EMAC_BASE (0x01C80000) @@ -31,7 +30,6 @@ void __init dm646x_init(void); void __init dm646x_init_mcasp0(struct snd_platform_data *pdata); void __init dm646x_init_mcasp1(struct snd_platform_data *pdata); -void __init dm646x_board_setup_refclk(struct clk *clk); int __init dm646x_init_edma(struct edma_rsv_info *rsv); void dm646x_video_init(void); diff --git a/arch/arm/mach-davinci/include/mach/entry-macro.S b/arch/arm/mach-davinci/include/mach/entry-macro.S index fbdebc7..e14c0dc 100644 --- a/arch/arm/mach-davinci/include/mach/entry-macro.S +++ b/arch/arm/mach-davinci/include/mach/entry-macro.S @@ -46,6 +46,3 @@ #endif 1002: .endm - - .macro irq_prio_table - .endm diff --git a/arch/arm/mach-davinci/include/mach/memory.h b/arch/arm/mach-davinci/include/mach/memory.h index 491249e..7873194 100644 --- a/arch/arm/mach-davinci/include/mach/memory.h +++ b/arch/arm/mach-davinci/include/mach/memory.h @@ -41,11 +41,4 @@ */ #define CONSISTENT_DMA_SIZE (14<<20) -/* - * Restrict DMA-able region to workaround silicon bug. The bug - * restricts buffers available for DMA to video hardware to be - * below 128M - */ -#define ARM_DMA_ZONE_SIZE SZ_128M - #endif /* __ASM_ARCH_MEMORY_H */ diff --git a/arch/arm/mach-davinci/include/mach/psc.h b/arch/arm/mach-davinci/include/mach/psc.h index a47e6f2..47fd0bc 100644 --- a/arch/arm/mach-davinci/include/mach/psc.h +++ b/arch/arm/mach-davinci/include/mach/psc.h @@ -30,47 +30,47 @@ #define DAVINCI_PWR_SLEEP_CNTRL_BASE 0x01C41000 /* Power and Sleep Controller (PSC) Domains */ -#define DAVINCI_GPSC_ARMDOMAIN 0 -#define DAVINCI_GPSC_DSPDOMAIN 1 +#define DAVINCI_GPSC_ARMDOMAIN 0 +#define DAVINCI_GPSC_DSPDOMAIN 1 -#define DAVINCI_LPSC_VPSSMSTR 0 -#define DAVINCI_LPSC_VPSSSLV 1 -#define DAVINCI_LPSC_TPCC 2 -#define DAVINCI_LPSC_TPTC0 3 -#define DAVINCI_LPSC_TPTC1 4 -#define DAVINCI_LPSC_EMAC 5 -#define DAVINCI_LPSC_EMAC_WRAPPER 6 -#define DAVINCI_LPSC_USB 9 -#define DAVINCI_LPSC_ATA 10 -#define DAVINCI_LPSC_VLYNQ 11 -#define DAVINCI_LPSC_UHPI 12 -#define DAVINCI_LPSC_DDR_EMIF 13 -#define DAVINCI_LPSC_AEMIF 14 -#define DAVINCI_LPSC_MMC_SD 15 -#define DAVINCI_LPSC_McBSP 17 -#define DAVINCI_LPSC_I2C 18 -#define DAVINCI_LPSC_UART0 19 -#define DAVINCI_LPSC_UART1 20 -#define DAVINCI_LPSC_UART2 21 -#define DAVINCI_LPSC_SPI 22 -#define DAVINCI_LPSC_PWM0 23 -#define DAVINCI_LPSC_PWM1 24 -#define DAVINCI_LPSC_PWM2 25 -#define DAVINCI_LPSC_GPIO 26 -#define DAVINCI_LPSC_TIMER0 27 -#define DAVINCI_LPSC_TIMER1 28 -#define DAVINCI_LPSC_TIMER2 29 -#define DAVINCI_LPSC_SYSTEM_SUBSYS 30 -#define DAVINCI_LPSC_ARM 31 -#define DAVINCI_LPSC_SCR2 32 -#define DAVINCI_LPSC_SCR3 33 -#define DAVINCI_LPSC_SCR4 34 -#define DAVINCI_LPSC_CROSSBAR 35 -#define DAVINCI_LPSC_CFG27 36 -#define DAVINCI_LPSC_CFG3 37 -#define DAVINCI_LPSC_CFG5 38 -#define DAVINCI_LPSC_GEM 39 -#define DAVINCI_LPSC_IMCOP 40 +#define DAVINCI_LPSC_VPSSMSTR 0 +#define DAVINCI_LPSC_VPSSSLV 1 +#define DAVINCI_LPSC_TPCC 2 +#define DAVINCI_LPSC_TPTC0 3 +#define DAVINCI_LPSC_TPTC1 4 +#define DAVINCI_LPSC_EMAC 5 +#define DAVINCI_LPSC_EMAC_WRAPPER 6 +#define DAVINCI_LPSC_USB 9 +#define DAVINCI_LPSC_ATA 10 +#define DAVINCI_LPSC_VLYNQ 11 +#define DAVINCI_LPSC_UHPI 12 +#define DAVINCI_LPSC_DDR_EMIF 13 +#define DAVINCI_LPSC_AEMIF 14 +#define DAVINCI_LPSC_MMC_SD 15 +#define DAVINCI_LPSC_McBSP 17 +#define DAVINCI_LPSC_I2C 18 +#define DAVINCI_LPSC_UART0 19 +#define DAVINCI_LPSC_UART1 20 +#define DAVINCI_LPSC_UART2 21 +#define DAVINCI_LPSC_SPI 22 +#define DAVINCI_LPSC_PWM0 23 +#define DAVINCI_LPSC_PWM1 24 +#define DAVINCI_LPSC_PWM2 25 +#define DAVINCI_LPSC_GPIO 26 +#define DAVINCI_LPSC_TIMER0 27 +#define DAVINCI_LPSC_TIMER1 28 +#define DAVINCI_LPSC_TIMER2 29 +#define DAVINCI_LPSC_SYSTEM_SUBSYS 30 +#define DAVINCI_LPSC_ARM 31 +#define DAVINCI_LPSC_SCR2 32 +#define DAVINCI_LPSC_SCR3 33 +#define DAVINCI_LPSC_SCR4 34 +#define DAVINCI_LPSC_CROSSBAR 35 +#define DAVINCI_LPSC_CFG27 36 +#define DAVINCI_LPSC_CFG3 37 +#define DAVINCI_LPSC_CFG5 38 +#define DAVINCI_LPSC_GEM 39 +#define DAVINCI_LPSC_IMCOP 40 #define DM355_LPSC_TIMER3 5 #define DM355_LPSC_SPI1 6 @@ -102,39 +102,39 @@ /* * LPSC Assignments */ -#define DM646X_LPSC_ARM 0 -#define DM646X_LPSC_C64X_CPU 1 -#define DM646X_LPSC_HDVICP0 2 -#define DM646X_LPSC_HDVICP1 3 -#define DM646X_LPSC_TPCC 4 -#define DM646X_LPSC_TPTC0 5 -#define DM646X_LPSC_TPTC1 6 -#define DM646X_LPSC_TPTC2 7 -#define DM646X_LPSC_TPTC3 8 -#define DM646X_LPSC_PCI 13 -#define DM646X_LPSC_EMAC 14 -#define DM646X_LPSC_VDCE 15 -#define DM646X_LPSC_VPSSMSTR 16 -#define DM646X_LPSC_VPSSSLV 17 -#define DM646X_LPSC_TSIF0 18 -#define DM646X_LPSC_TSIF1 19 -#define DM646X_LPSC_DDR_EMIF 20 -#define DM646X_LPSC_AEMIF 21 -#define DM646X_LPSC_McASP0 22 -#define DM646X_LPSC_McASP1 23 -#define DM646X_LPSC_CRGEN0 24 -#define DM646X_LPSC_CRGEN1 25 -#define DM646X_LPSC_UART0 26 -#define DM646X_LPSC_UART1 27 -#define DM646X_LPSC_UART2 28 -#define DM646X_LPSC_PWM0 29 -#define DM646X_LPSC_PWM1 30 -#define DM646X_LPSC_I2C 31 -#define DM646X_LPSC_SPI 32 -#define DM646X_LPSC_GPIO 33 -#define DM646X_LPSC_TIMER0 34 -#define DM646X_LPSC_TIMER1 35 -#define DM646X_LPSC_ARM_INTC 45 +#define DM646X_LPSC_ARM 0 +#define DM646X_LPSC_C64X_CPU 1 +#define DM646X_LPSC_HDVICP0 2 +#define DM646X_LPSC_HDVICP1 3 +#define DM646X_LPSC_TPCC 4 +#define DM646X_LPSC_TPTC0 5 +#define DM646X_LPSC_TPTC1 6 +#define DM646X_LPSC_TPTC2 7 +#define DM646X_LPSC_TPTC3 8 +#define DM646X_LPSC_PCI 13 +#define DM646X_LPSC_EMAC 14 +#define DM646X_LPSC_VDCE 15 +#define DM646X_LPSC_VPSSMSTR 16 +#define DM646X_LPSC_VPSSSLV 17 +#define DM646X_LPSC_TSIF0 18 +#define DM646X_LPSC_TSIF1 19 +#define DM646X_LPSC_DDR_EMIF 20 +#define DM646X_LPSC_AEMIF 21 +#define DM646X_LPSC_McASP0 22 +#define DM646X_LPSC_McASP1 23 +#define DM646X_LPSC_CRGEN0 24 +#define DM646X_LPSC_CRGEN1 25 +#define DM646X_LPSC_UART0 26 +#define DM646X_LPSC_UART1 27 +#define DM646X_LPSC_UART2 28 +#define DM646X_LPSC_PWM0 29 +#define DM646X_LPSC_PWM1 30 +#define DM646X_LPSC_I2C 31 +#define DM646X_LPSC_SPI 32 +#define DM646X_LPSC_GPIO 33 +#define DM646X_LPSC_TIMER0 34 +#define DM646X_LPSC_TIMER1 35 +#define DM646X_LPSC_ARM_INTC 45 /* PSC0 defines */ #define DA8XX_LPSC0_TPCC 0 @@ -243,13 +243,14 @@ #define PSC_STATE_DISABLE 2 #define PSC_STATE_ENABLE 3 -#define MDSTAT_STATE_MASK 0x1f +#define MDSTAT_STATE_MASK 0x1f +#define MDCTL_FORCE BIT(31) #ifndef __ASSEMBLER__ extern int davinci_psc_is_clk_active(unsigned int ctlr, unsigned int id); extern void davinci_psc_config(unsigned int domain, unsigned int ctlr, - unsigned int id, u32 next_state); + unsigned int id, bool enable, u32 flags); #endif diff --git a/arch/arm/mach-davinci/pm.c b/arch/arm/mach-davinci/pm.c index 1bd73a0..04c49f7 100644 --- a/arch/arm/mach-davinci/pm.c +++ b/arch/arm/mach-davinci/pm.c @@ -17,6 +17,7 @@ #include #include +#include #include #include diff --git a/arch/arm/mach-davinci/psc.c b/arch/arm/mach-davinci/psc.c index a415804..1fb6bdf 100644 --- a/arch/arm/mach-davinci/psc.c +++ b/arch/arm/mach-davinci/psc.c @@ -25,6 +25,8 @@ #include #include +#include "clock.h" + /* Return nonzero iff the domain's clock is active */ int __init davinci_psc_is_clk_active(unsigned int ctlr, unsigned int id) { @@ -48,11 +50,12 @@ int __init davinci_psc_is_clk_active(unsigned int ctlr, unsigned int id) /* Enable or disable a PSC domain */ void davinci_psc_config(unsigned int domain, unsigned int ctlr, - unsigned int id, u32 next_state) + unsigned int id, bool enable, u32 flags) { u32 epcpr, ptcmd, ptstat, pdstat, pdctl1, mdstat, mdctl; void __iomem *psc_base; struct davinci_soc_info *soc_info = &davinci_soc_info; + u32 next_state = PSC_STATE_ENABLE; if (!soc_info->psc_bases || (ctlr >= soc_info->psc_bases_num)) { pr_warning("PSC: Bad psc data: 0x%x[%d]\n", @@ -62,9 +65,18 @@ void davinci_psc_config(unsigned int domain, unsigned int ctlr, psc_base = ioremap(soc_info->psc_bases[ctlr], SZ_4K); + if (!enable) { + if (flags & PSC_SWRSTDISABLE) + next_state = PSC_STATE_SWRSTDISABLE; + else + next_state = PSC_STATE_DISABLE; + } + mdctl = __raw_readl(psc_base + MDCTL + 4 * id); mdctl &= ~MDSTAT_STATE_MASK; mdctl |= next_state; + if (flags & PSC_FORCE) + mdctl |= MDCTL_FORCE; __raw_writel(mdctl, psc_base + MDCTL + 4 * id); pdstat = __raw_readl(psc_base + PDSTAT); diff --git a/arch/arm/mach-dove/common.c b/arch/arm/mach-dove/common.c index 5ed51b8..83dce85 100644 --- a/arch/arm/mach-dove/common.c +++ b/arch/arm/mach-dove/common.c @@ -13,11 +13,9 @@ #include #include #include -#include #include #include #include -#include #include #include #include diff --git a/arch/arm/mach-dove/include/mach/hardware.h b/arch/arm/mach-dove/include/mach/hardware.h index 32b0826..f1368b9 100644 --- a/arch/arm/mach-dove/include/mach/hardware.h +++ b/arch/arm/mach-dove/include/mach/hardware.h @@ -11,13 +11,6 @@ #include "dove.h" -#define pcibios_assign_all_busses() 1 - -#define PCIBIOS_MIN_IO 0x1000 -#define PCIBIOS_MIN_MEM 0x01000000 -#define PCIMEM_BASE DOVE_PCIE0_MEM_PHYS_BASE - - /* Macros below are required for compatibility with PXA AC'97 driver. */ #define __REG(x) (*((volatile u32 *)((x) - DOVE_SB_REGS_PHYS_BASE + \ DOVE_SB_REGS_VIRT_BASE))) diff --git a/arch/arm/mach-dove/pcie.c b/arch/arm/mach-dove/pcie.c index 502d1ca..c2f1c47 100644 --- a/arch/arm/mach-dove/pcie.c +++ b/arch/arm/mach-dove/pcie.c @@ -11,6 +11,7 @@ #include #include #include +#include