diff --git a/bsp/fri2/fri2-preempt-rt.scc b/bsp/fri2/fri2-preempt-rt.scc index c474c711b652bb762c5cac43454e498853762887..a7cc7bb6519eee0497a00cdde48780c29530732f 100644 --- a/bsp/fri2/fri2-preempt-rt.scc +++ b/bsp/fri2/fri2-preempt-rt.scc @@ -14,5 +14,4 @@ include cfg/usb-mass-storage.scc include cfg/boot-live.scc include features/latencytop/latencytop.scc include features/profiling/profiling.scc -patch pch_uart-Add-eg20t_port-lock-field-avoid-recursive-s.patch patch pch_uart-Correct-spin_lock-and-irqsave-usage-in-pch_.patch diff --git a/bsp/fri2/pch_uart-Add-eg20t_port-lock-field-avoid-recursive-s.patch b/bsp/fri2/pch_uart-Add-eg20t_port-lock-field-avoid-recursive-s.patch deleted file mode 100644 index 12a72bbaafe871bd9ceca957bd7b9ba95aaefddf..0000000000000000000000000000000000000000 --- a/bsp/fri2/pch_uart-Add-eg20t_port-lock-field-avoid-recursive-s.patch +++ /dev/null @@ -1,148 +0,0 @@ -From 120899d27d5ffc9e1fc73684ffd60642ed0fc605 Mon Sep 17 00:00:00 2001 -From: Darren Hart <dvhart@linux.intel.com> -Date: Thu, 31 May 2012 00:37:51 -0700 -Subject: [PATCH 1/2] pch_uart: Add eg20t_port lock field, avoid recursive - spinlocks - -pch_uart_interrupt() takes priv->port.lock which leads to two recursive -spinlock calls if low_latency==1 or CONFIG_PREEMPT_RT_FULL=y (one -otherwise): - -pch_uart_interrupt - spin_lock_irqsave(priv->port.lock, flags) - case PCH_UART_IID_RDR_TO (data ready) - handle_rx_to - push_rx - tty_port_tty_get - spin_lock_irqsave(&port->lock, flags) <--- already hold this lock - ... - tty_flip_buffer_push - ... - flush_to_ldisc - spin_lock_irqsave(&tty->buf.lock) - spin_lock_irqsave(&tty->buf.lock) - disc->ops->receive_buf(tty, char_buf) - n_tty_receive_buf - tty->ops->flush_chars() - uart_flush_chars - uart_start - spin_lock_irqsave(&port->lock) <--- already hold this lock - -Avoid this by using a dedicated lock to protect the eg20t_port structure -and IO access to its membase. This is more consistent with the 8250 -driver. Ensure priv->lock is always take prior to priv->port.lock when -taken at the same time. - -Signed-off-by: Darren Hart <dvhart@linux.intel.com> -CC: Tomoya MORINAGA <tomoya.rohm@gmail.com> -CC: Feng Tang <feng.tang@intel.com> -CC: Alexander Stein <alexander.stein@systec-electronic.com> -CC: Greg Kroah-Hartman <gregkh@linuxfoundation.org> -CC: Alan Cox <alan@linux.intel.com> -CC: linux-serial@vger.kernel.org ---- - drivers/tty/serial/pch_uart.c | 23 +++++++++++++++++------ - 1 files changed, 17 insertions(+), 6 deletions(-) - -diff --git a/drivers/tty/serial/pch_uart.c b/drivers/tty/serial/pch_uart.c -index c2816f4..f11ee7b 100644 ---- a/drivers/tty/serial/pch_uart.c -+++ b/drivers/tty/serial/pch_uart.c -@@ -251,6 +251,9 @@ struct eg20t_port { - void *rx_buf_virt; - dma_addr_t rx_buf_dma; - -+ /* protect the eg20t_port private structure and io access to membase */ -+ spinlock_t lock; -+ - struct dentry *debugfs; - }; - -@@ -1056,7 +1059,7 @@ static irqreturn_t pch_uart_interrupt(int irq, void *dev_id) - unsigned int iid; - unsigned long flags; - -- spin_lock_irqsave(&priv->port.lock, flags); -+ spin_lock_irqsave(&priv->lock, flags); - handled = 0; - while ((iid = pch_uart_hal_get_iid(priv)) > 1) { - switch (iid) { -@@ -1107,7 +1110,7 @@ static irqreturn_t pch_uart_interrupt(int irq, void *dev_id) - priv->int_dis_flag = 0; - } - -- spin_unlock_irqrestore(&priv->port.lock, flags); -+ spin_unlock_irqrestore(&priv->lock, flags); - return IRQ_RETVAL(handled); - } - -@@ -1218,9 +1221,9 @@ static void pch_uart_break_ctl(struct uart_port *port, int ctl) - unsigned long flags; - - priv = container_of(port, struct eg20t_port, port); -- spin_lock_irqsave(&port->lock, flags); -+ spin_lock_irqsave(&priv->lock, flags); - pch_uart_hal_set_break(priv, ctl); -- spin_unlock_irqrestore(&port->lock, flags); -+ spin_unlock_irqrestore(&priv->lock, flags); - } - - /* Grab any interrupt resources and initialise any low level driver state. */ -@@ -1368,7 +1371,8 @@ static void pch_uart_set_termios(struct uart_port *port, - - baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk / 16); - -- spin_lock_irqsave(&port->lock, flags); -+ spin_lock_irqsave(&priv->lock, flags); -+ spin_lock(&port->lock); - - uart_update_timeout(port, termios->c_cflag, baud); - rtn = pch_uart_hal_set_line(priv, baud, parity, bits, stb); -@@ -1381,7 +1385,8 @@ static void pch_uart_set_termios(struct uart_port *port, - tty_termios_encode_baud_rate(termios, baud, baud); - - out: -- spin_unlock_irqrestore(&port->lock, flags); -+ spin_unlock(&port->lock); -+ spin_unlock_irqrestore(&priv->lock, flags); - } - - static const char *pch_uart_type(struct uart_port *port) -@@ -1539,6 +1544,7 @@ pch_console_write(struct console *co, const char *s, unsigned int count) - touch_nmi_watchdog(); - - local_irq_save(flags); -+ spin_lock(&priv->lock); - if (priv->port.sysrq) { - /* serial8250_handle_port() already took the lock */ - locked = 0; -@@ -1547,6 +1553,7 @@ pch_console_write(struct console *co, const char *s, unsigned int count) - } else - spin_lock(&priv->port.lock); - -+ - /* - * First save the IER then disable the interrupts - */ -@@ -1565,7 +1572,9 @@ pch_console_write(struct console *co, const char *s, unsigned int count) - - if (locked) - spin_unlock(&priv->port.lock); -+ spin_unlock(&priv->lock); - local_irq_restore(flags); -+ - } - - static int __init pch_console_setup(struct console *co, char *options) -@@ -1662,6 +1671,8 @@ static struct eg20t_port *pch_uart_init_port(struct pci_dev *pdev, - pci_enable_msi(pdev); - pci_set_master(pdev); - -+ spin_lock_init(&priv->lock); -+ - iobase = pci_resource_start(pdev, 0); - mapbase = pci_resource_start(pdev, 1); - priv->mapbase = mapbase; --- -1.7.5.4 - diff --git a/bsp/fri2/pch_uart-Correct-spin_lock-and-irqsave-usage-in-pch_.patch b/bsp/fri2/pch_uart-Correct-spin_lock-and-irqsave-usage-in-pch_.patch index a1e5472724a8e2edac4efc344ee9a67bbea1e84a..4e6a81e229ac8d3ef00afbae605e4bad86f4576d 100644 --- a/bsp/fri2/pch_uart-Correct-spin_lock-and-irqsave-usage-in-pch_.patch +++ b/bsp/fri2/pch_uart-Correct-spin_lock-and-irqsave-usage-in-pch_.patch @@ -38,32 +38,25 @@ CC: Alan Cox <alan@linux.intel.com> CC: Steven Rostedt <rostedt@goodmis.org> CC: Peter Zijlstra <peterz@infradead.org> CC: linux-serial@vger.kernel.org ---- - drivers/tty/serial/pch_uart.c | 4 ++-- - 1 files changed, 2 insertions(+), 2 deletions(-) - diff --git a/drivers/tty/serial/pch_uart.c b/drivers/tty/serial/pch_uart.c -index f11ee7b..7f5c998 100644 +index 558ce85..7bc887b 100644 --- a/drivers/tty/serial/pch_uart.c +++ b/drivers/tty/serial/pch_uart.c -@@ -1543,7 +1543,7 @@ pch_console_write(struct console *co, const char *s, unsigned int count) +@@ -1558,7 +1558,7 @@ pch_console_write(struct console *co, const char *s, unsigned int count) touch_nmi_watchdog(); - local_irq_save(flags); + local_irq_save_nort(flags); - spin_lock(&priv->lock); if (priv->port.sysrq) { - /* serial8250_handle_port() already took the lock */ -@@ -1573,7 +1573,7 @@ pch_console_write(struct console *co, const char *s, unsigned int count) - if (locked) + spin_lock(&priv->lock); + /* serial8250_handle_port() already took the port lock */ +@@ -1591,7 +1591,7 @@ pch_console_write(struct console *co, const char *s, unsigned int count) spin_unlock(&priv->port.lock); - spin_unlock(&priv->lock); + if (priv_locked) + spin_unlock(&priv->lock); - local_irq_restore(flags); + local_irq_restore_nort(flags); - } --- -1.7.5.4 - + static int __init pch_console_setup(struct console *co, char *options) diff --git a/bsp/routerstationpro/441-block2mtd_refresh.patch b/bsp/routerstationpro/441-block2mtd_refresh.patch index 8ee98bc81b54ab5ca4c8498255f347a85f762932..c0b3761ce2fd41e818a14e3bdca648157a70d961 100644 --- a/bsp/routerstationpro/441-block2mtd_refresh.patch +++ b/bsp/routerstationpro/441-block2mtd_refresh.patch @@ -19,12 +19,8 @@ Path to patch in the repo is: target/linux/generic/patches-3.3 Repo is: git://nbd.name/openwrt.git Signed-off-by: Paul Gortmaker <paul.gortmaker@windriver.com> ---- - drivers/mtd/devices/block2mtd.c | 185 +++++++++++++++++++++++++++++---------- - 1 file changed, 141 insertions(+), 44 deletions(-) - diff --git a/drivers/mtd/devices/block2mtd.c b/drivers/mtd/devices/block2mtd.c -index 2ebb4c6..4052874 100644 +index d1c2b88..c2766ab 100644 --- a/drivers/mtd/devices/block2mtd.c +++ b/drivers/mtd/devices/block2mtd.c @@ -29,6 +29,8 @@ struct block2mtd_dev { @@ -36,7 +32,7 @@ index 2ebb4c6..4052874 100644 }; -@@ -81,6 +83,12 @@ static int block2mtd_erase(struct mtd_info *mtd, struct erase_info *instr) +@@ -79,6 +81,12 @@ static int block2mtd_erase(struct mtd_info *mtd, struct erase_info *instr) size_t len = instr->len; int err; @@ -49,7 +45,7 @@ index 2ebb4c6..4052874 100644 instr->state = MTD_ERASING; mutex_lock(&dev->write_mutex); err = _block2mtd_erase(dev, from, len); -@@ -92,6 +100,10 @@ static int block2mtd_erase(struct mtd_info *mtd, struct erase_info *instr) +@@ -90,6 +98,10 @@ static int block2mtd_erase(struct mtd_info *mtd, struct erase_info *instr) instr->state = MTD_ERASE_DONE; mtd_erase_callback(instr); @@ -60,7 +56,7 @@ index 2ebb4c6..4052874 100644 return err; } -@@ -103,7 +115,13 @@ static int block2mtd_read(struct mtd_info *mtd, loff_t from, size_t len, +@@ -101,7 +113,13 @@ static int block2mtd_read(struct mtd_info *mtd, loff_t from, size_t len, struct page *page; int index = from >> PAGE_SHIFT; int offset = from & (PAGE_SIZE-1); @@ -75,18 +71,13 @@ index 2ebb4c6..4052874 100644 while (len) { if ((offset + len) > PAGE_SIZE) -@@ -113,10 +131,14 @@ static int block2mtd_read(struct mtd_info *mtd, loff_t from, size_t len, +@@ -111,8 +129,11 @@ static int block2mtd_read(struct mtd_info *mtd, loff_t from, size_t len, len = len - cpylen; page = page_read(dev->blkdev->bd_inode->i_mapping, index); -- if (!page) -- return -ENOMEM; - if (IS_ERR(page)) - return PTR_ERR(page); -+ if (!page) { -+ err = -ENOMEM; -+ goto done; -+ } ++ + if (IS_ERR(page)) { + err = PTR_ERR(page); + goto done; @@ -94,7 +85,7 @@ index 2ebb4c6..4052874 100644 memcpy(buf, page_address(page) + offset, cpylen); page_cache_release(page); -@@ -127,7 +149,10 @@ static int block2mtd_read(struct mtd_info *mtd, loff_t from, size_t len, +@@ -123,7 +144,10 @@ static int block2mtd_read(struct mtd_info *mtd, loff_t from, size_t len, offset = 0; index++; } @@ -106,7 +97,7 @@ index 2ebb4c6..4052874 100644 } -@@ -140,6 +165,13 @@ static int _block2mtd_write(struct block2mtd_dev *dev, const u_char *buf, +@@ -136,6 +160,13 @@ static int _block2mtd_write(struct block2mtd_dev *dev, const u_char *buf, int index = to >> PAGE_SHIFT; // page index int offset = to & ~PAGE_MASK; // page offset int cpylen; @@ -120,18 +111,13 @@ index 2ebb4c6..4052874 100644 while (len) { if ((offset+len) > PAGE_SIZE) -@@ -149,10 +181,14 @@ static int _block2mtd_write(struct block2mtd_dev *dev, const u_char *buf, +@@ -145,8 +176,11 @@ static int _block2mtd_write(struct block2mtd_dev *dev, const u_char *buf, len = len - cpylen; page = page_read(mapping, index); -- if (!page) -- return -ENOMEM; - if (IS_ERR(page)) - return PTR_ERR(page); -+ if (!page) { -+ err = -ENOMEM; -+ goto done; -+ } ++ + if (IS_ERR(page)) { + err = PTR_ERR(page); + goto done; @@ -139,7 +125,7 @@ index 2ebb4c6..4052874 100644 if (memcmp(page_address(page)+offset, buf, cpylen)) { lock_page(page); -@@ -169,7 +205,9 @@ static int _block2mtd_write(struct block2mtd_dev *dev, const u_char *buf, +@@ -163,7 +197,9 @@ static int _block2mtd_write(struct block2mtd_dev *dev, const u_char *buf, offset = 0; index++; } @@ -150,7 +136,7 @@ index 2ebb4c6..4052874 100644 } -@@ -192,33 +230,110 @@ static int block2mtd_write(struct mtd_info *mtd, loff_t to, size_t len, +@@ -186,33 +222,110 @@ static int block2mtd_write(struct mtd_info *mtd, loff_t to, size_t len, static void block2mtd_sync(struct mtd_info *mtd) { struct block2mtd_dev *dev = mtd->priv; @@ -271,7 +257,7 @@ index 2ebb4c6..4052874 100644 struct block2mtd_dev *dev; struct mtd_partition *part; char *name; -@@ -226,36 +341,17 @@ static struct block2mtd_dev *add_device(char *devname, int erase_size, const cha +@@ -220,36 +333,17 @@ static struct block2mtd_dev *add_device(char *devname, int erase_size, const cha if (!devname) return NULL; @@ -287,7 +273,8 @@ index 2ebb4c6..4052874 100644 - - /* We might not have rootfs mounted at this point. Try - to resolve the device name by other means. */ -- ++ strcpy(dev->devname, devname); + - dev_t devt = name_to_dev_t(devname); - if (devt) - bdev = blkdev_get_by_dev(devt, mode, dev); @@ -296,15 +283,14 @@ index 2ebb4c6..4052874 100644 - - if (IS_ERR(bdev)) { - ERROR("error: cannot open device %s", devname); -- goto devinit_err; ++ if (_open_bdev(dev)) + goto devinit_err; - } - dev->blkdev = bdev; -+ strcpy(dev->devname, devname); - +- - if (MAJOR(bdev->bd_dev) == MTD_BLOCK_MAJOR) { - ERROR("attempting to use an MTD device as a block device"); -+ if (_open_bdev(dev)) - goto devinit_err; +- goto devinit_err; - } mutex_init(&dev->write_mutex); @@ -312,7 +298,7 @@ index 2ebb4c6..4052874 100644 /* Setup the MTD structure */ /* make the name contain the block device in */ -@@ -281,6 +377,7 @@ static struct block2mtd_dev *add_device(char *devname, int erase_size, const cha +@@ -274,6 +368,7 @@ static struct block2mtd_dev *add_device(char *devname, int erase_size, const cha dev->mtd._read = block2mtd_read; dev->mtd.priv = dev; dev->mtd.owner = THIS_MODULE; @@ -320,6 +306,3 @@ index 2ebb4c6..4052874 100644 part = kzalloc(sizeof(struct mtd_partition), GFP_KERNEL); part->name = name; --- -1.7.9.7 - diff --git a/bsp/routerstationpro/473-mtd_m25p80_add_w25q128.patch b/bsp/routerstationpro/473-mtd_m25p80_add_w25q128.patch index 1fbbe4a8fb7120280cc0bd6de73b679a6777032a..6af74c744008cb9e73becad6fbdca7618e4d2b33 100644 --- a/bsp/routerstationpro/473-mtd_m25p80_add_w25q128.patch +++ b/bsp/routerstationpro/473-mtd_m25p80_add_w25q128.patch @@ -19,22 +19,15 @@ Path to patch in the repo is: target/linux/generic/patches-3.3 Repo is: git://nbd.name/openwrt.git Signed-off-by: Paul Gortmaker <paul.gortmaker@windriver.com> ---- - drivers/mtd/devices/m25p80.c | 1 + - 1 file changed, 1 insertion(+) - diff --git a/drivers/mtd/devices/m25p80.c b/drivers/mtd/devices/m25p80.c -index 0351b17..4ee1352 100644 +index 363ecc9..04882c1 100644 --- a/drivers/mtd/devices/m25p80.c +++ b/drivers/mtd/devices/m25p80.c -@@ -734,6 +734,7 @@ static const struct spi_device_id m25p_ids[] = { - { "w25q32", INFO(0xef4016, 0, 64 * 1024, 64, SECT_4K) }, +@@ -739,6 +739,7 @@ static const struct spi_device_id m25p_ids[] = { { "w25x64", INFO(0xef3017, 0, 64 * 1024, 128, SECT_4K) }, { "w25q64", INFO(0xef4017, 0, 64 * 1024, 128, SECT_4K) }, + { "w25q80", INFO(0xef5014, 0, 64 * 1024, 16, SECT_4K) }, + { "w25q128", INFO(0xef4018, 0, 64 * 1024, 256, SECT_4K) }, /* Catalyst / On Semiconductor -- non-JEDEC */ { "cat25c11", CAT25_INFO( 16, 8, 16, 1) }, --- -1.7.9.7 - diff --git a/bsp/routerstationpro/721-phy_packets.patch b/bsp/routerstationpro/721-phy_packets.patch index 69893b0c35f02c1f4287ae2aa3c44db6926b44c4..927555824d965b3a079c14f5172781e1290fb74a 100644 --- a/bsp/routerstationpro/721-phy_packets.patch +++ b/bsp/routerstationpro/721-phy_packets.patch @@ -19,33 +19,24 @@ Path to patch in the repo is: target/linux/generic/patches-3.3 Repo is: git://nbd.name/openwrt.git Signed-off-by: Paul Gortmaker <paul.gortmaker@windriver.com> ---- - include/linux/if.h | 1 + - include/linux/netdevice.h | 8 ++++++++ - include/linux/skbuff.h | 14 ++++---------- - net/Kconfig | 6 ++++++ - net/core/dev.c | 32 ++++++++++++++++++++++++++------ - net/core/skbuff.c | 17 +++++++++++++++++ - net/ethernet/eth.c | 6 ++++++ - 7 files changed, 68 insertions(+), 16 deletions(-) - diff --git a/include/linux/if.h b/include/linux/if.h -index f995c66..99bd777 100644 +index 1ec407b..dadb899 100644 --- a/include/linux/if.h +++ b/include/linux/if.h -@@ -81,6 +81,7 @@ - #define IFF_UNICAST_FLT 0x20000 /* Supports unicast filtering */ - #define IFF_TEAM_PORT 0x40000 /* device used as team port */ - #define IFF_SUPP_NOFCS 0x80000 /* device supports sending custom FCS */ -+#define IFF_NO_IP_ALIGN 0x100000 /* do not ip-align allocated rx pkts */ +@@ -84,6 +84,8 @@ + #define IFF_LIVE_ADDR_CHANGE 0x100000 /* device supports hardware address + * change when it's running */ ++#define IFF_NO_IP_ALIGN 0x200000 /* do not ip-align allocated rx pkts */ ++ #define IF_GET_IFACE 0x0001 /* for querying only */ + #define IF_GET_PROTO 0x0002 diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h -index 33900a5..879d8db 100644 +index 59dc05f3..0d87c9d 100644 --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h -@@ -1079,6 +1079,11 @@ struct net_device { +@@ -1102,6 +1102,11 @@ struct net_device { const struct net_device_ops *netdev_ops; const struct ethtool_ops *ethtool_ops; @@ -57,7 +48,7 @@ index 33900a5..879d8db 100644 /* Hardware header description */ const struct header_ops *header_ops; -@@ -1136,6 +1141,9 @@ struct net_device { +@@ -1158,6 +1163,9 @@ struct net_device { void *ax25_ptr; /* AX.25 specific data */ struct wireless_dev *ieee80211_ptr; /* IEEE 802.11 specific data, assign before registering */ @@ -68,24 +59,24 @@ index 33900a5..879d8db 100644 /* * Cache lines mostly used on receive path (including eth_type_trans()) diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h -index 111f26b..6ea1851 100644 +index 7632c87..033fa6e 100644 --- a/include/linux/skbuff.h +++ b/include/linux/skbuff.h -@@ -1690,6 +1690,10 @@ extern struct sk_buff *dev_alloc_skb(unsigned int length); - extern struct sk_buff *__netdev_alloc_skb(struct net_device *dev, - unsigned int length, gfp_t gfp_mask); +@@ -1687,6 +1687,10 @@ static inline void skb_orphan(struct sk_buff *skb) + skb->sk = NULL; + } +extern struct sk_buff *__netdev_alloc_skb_ip_align(struct net_device *dev, + unsigned int length, gfp_t gfp); + + /** - * netdev_alloc_skb - allocate an skbuff for rx on a specific device - * @dev: network device to receive on -@@ -1709,16 +1713,6 @@ static inline struct sk_buff *netdev_alloc_skb(struct net_device *dev, - return __netdev_alloc_skb(dev, length, GFP_ATOMIC); + * skb_orphan_frags - orphan the frags contained in a buffer + * @skb: buffer to orphan frags from +@@ -1758,16 +1762,6 @@ static inline struct sk_buff *dev_alloc_skb(unsigned int length) } + -static inline struct sk_buff *__netdev_alloc_skb_ip_align(struct net_device *dev, - unsigned int length, gfp_t gfp) -{ @@ -100,7 +91,7 @@ index 111f26b..6ea1851 100644 unsigned int length) { diff --git a/net/Kconfig b/net/Kconfig -index e07272d..b3904e8 100644 +index 245831b..900e9dd 100644 --- a/net/Kconfig +++ b/net/Kconfig @@ -23,6 +23,12 @@ menuconfig NET @@ -117,10 +108,10 @@ index e07272d..b3904e8 100644 bool help diff --git a/net/core/dev.c b/net/core/dev.c -index 99e1d75..47c8660 100644 +index 8398836..374a4e8 100644 --- a/net/core/dev.c +++ b/net/core/dev.c -@@ -2231,9 +2231,19 @@ int dev_hard_start_xmit(struct sk_buff *skb, struct net_device *dev, +@@ -2242,9 +2242,19 @@ int dev_hard_start_xmit(struct sk_buff *skb, struct net_device *dev, } } @@ -143,7 +134,7 @@ index 99e1d75..47c8660 100644 if (rc == NETDEV_TX_OK) txq_trans_update(txq); return rc; -@@ -2253,9 +2263,19 @@ gso: +@@ -2264,9 +2274,19 @@ gso: if (dev->priv_flags & IFF_XMIT_DST_RELEASE) skb_dst_drop(nskb); @@ -167,10 +158,10 @@ index 99e1d75..47c8660 100644 if (rc & ~NETDEV_TX_MASK) goto out_kfree_gso_skb; diff --git a/net/core/skbuff.c b/net/core/skbuff.c -index e598400..66f366f 100644 +index fe00d12..9b77747 100644 --- a/net/core/skbuff.c +++ b/net/core/skbuff.c -@@ -58,6 +58,7 @@ +@@ -60,6 +60,7 @@ #include <linux/scatterlist.h> #include <linux/errqueue.h> #include <linux/prefetch.h> @@ -178,7 +169,7 @@ index e598400..66f366f 100644 #include <net/protocol.h> #include <net/dst.h> -@@ -319,6 +320,22 @@ struct sk_buff *__netdev_alloc_skb(struct net_device *dev, +@@ -441,6 +442,22 @@ struct sk_buff *__netdev_alloc_skb(struct net_device *dev, } EXPORT_SYMBOL(__netdev_alloc_skb); @@ -202,7 +193,7 @@ index e598400..66f366f 100644 int size, unsigned int truesize) { diff --git a/net/ethernet/eth.c b/net/ethernet/eth.c -index bf10a31..54ec04a 100644 +index 4efad53..20de891 100644 --- a/net/ethernet/eth.c +++ b/net/ethernet/eth.c @@ -159,6 +159,12 @@ __be16 eth_type_trans(struct sk_buff *skb, struct net_device *dev) @@ -218,6 +209,3 @@ index bf10a31..54ec04a 100644 skb_reset_mac_header(skb); skb_pull_inline(skb, ETH_HLEN); eth = eth_hdr(skb); --- -1.7.9.7 - diff --git a/bsp/routerstationpro/MIPS-ath79-add-AR934X-specific-glue-to-ath79_device_.patch b/bsp/routerstationpro/MIPS-ath79-add-AR934X-specific-glue-to-ath79_device_.patch deleted file mode 100644 index c47a625494a5a0a0dc8d90dfd17f720ae0e111f4..0000000000000000000000000000000000000000 --- a/bsp/routerstationpro/MIPS-ath79-add-AR934X-specific-glue-to-ath79_device_.patch +++ /dev/null @@ -1,71 +0,0 @@ -From 9393ad8cc039e33c60f0c2677654bf2df61ccd06 Mon Sep 17 00:00:00 2001 -From: Gabor Juhos <juhosg@openwrt.org> -Date: Wed, 14 Mar 2012 10:45:26 +0100 -Subject: [PATCH 058/123] MIPS: ath79: add AR934X specific glue to - ath79_device_reset_{clear,set} - -commit 42184768b36b2dad88a3705d689891b5da884c85 upstream. - -Signed-off-by: Gabor Juhos <juhosg@openwrt.org> -Acked-by: Luis R. Rodriguez <mcgrof@qca.qualcomm.com> -Cc: linux-mips@linux-mips.org -Cc: mcgrof@infradead.org -Patchwork: https://patchwork.linux-mips.org/patch/3511/ -Signed-off-by: Ralf Baechle <ralf@linux-mips.org> -Signed-off-by: Paul Gortmaker <paul.gortmaker@windriver.com> ---- - arch/mips/ath79/common.c | 9 ++++++++- - arch/mips/include/asm/mach-ath79/ar71xx_regs.h | 1 + - 2 files changed, 9 insertions(+), 1 deletion(-) - -diff --git a/arch/mips/ath79/common.c b/arch/mips/ath79/common.c -index f0fda98..5a4adfc 100644 ---- a/arch/mips/ath79/common.c -+++ b/arch/mips/ath79/common.c -@@ -1,9 +1,12 @@ - /* - * Atheros AR71XX/AR724X/AR913X common routines - * -- * Copyright (C) 2008-2010 Gabor Juhos <juhosg@openwrt.org> -+ * Copyright (C) 2010-2011 Jaiganesh Narayanan <jnarayanan@atheros.com> -+ * Copyright (C) 2008-2011 Gabor Juhos <juhosg@openwrt.org> - * Copyright (C) 2008 Imre Kaloz <kaloz@openwrt.org> - * -+ * Parts of this file are based on Atheros' 2.6.15/2.6.31 BSP -+ * - * 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. -@@ -67,6 +70,8 @@ void ath79_device_reset_set(u32 mask) - reg = AR913X_RESET_REG_RESET_MODULE; - else if (soc_is_ar933x()) - reg = AR933X_RESET_REG_RESET_MODULE; -+ else if (soc_is_ar934x()) -+ reg = AR934X_RESET_REG_RESET_MODULE; - else - BUG(); - -@@ -91,6 +96,8 @@ void ath79_device_reset_clear(u32 mask) - reg = AR913X_RESET_REG_RESET_MODULE; - else if (soc_is_ar933x()) - reg = AR933X_RESET_REG_RESET_MODULE; -+ else if (soc_is_ar934x()) -+ reg = AR934X_RESET_REG_RESET_MODULE; - else - BUG(); - -diff --git a/arch/mips/include/asm/mach-ath79/ar71xx_regs.h b/arch/mips/include/asm/mach-ath79/ar71xx_regs.h -index d6af4eb..32abbf9 100644 ---- a/arch/mips/include/asm/mach-ath79/ar71xx_regs.h -+++ b/arch/mips/include/asm/mach-ath79/ar71xx_regs.h -@@ -227,6 +227,7 @@ - #define AR933X_RESET_REG_RESET_MODULE 0x1c - #define AR933X_RESET_REG_BOOTSTRAP 0xac - -+#define AR934X_RESET_REG_RESET_MODULE 0x1c - #define AR934X_RESET_REG_BOOTSTRAP 0xb0 - #define AR934X_RESET_REG_PCIE_WMAC_INT_STATUS 0xac - --- -1.7.9.7 - diff --git a/bsp/routerstationpro/MIPS-ath79-add-GPIO-support-code-for-AR934X.patch b/bsp/routerstationpro/MIPS-ath79-add-GPIO-support-code-for-AR934X.patch deleted file mode 100644 index 3d4ff5542be50c397c2ab109aceff9c6f1693579..0000000000000000000000000000000000000000 --- a/bsp/routerstationpro/MIPS-ath79-add-GPIO-support-code-for-AR934X.patch +++ /dev/null @@ -1,112 +0,0 @@ -From 1888cc4c0970b6ce35613fae377714c9e84009c4 Mon Sep 17 00:00:00 2001 -From: Gabor Juhos <juhosg@openwrt.org> -Date: Wed, 14 Mar 2012 10:45:23 +0100 -Subject: [PATCH 055/123] MIPS: ath79: add GPIO support code for AR934X - -commit 5b5b544ed32a1b6ad4d7706fcee530eb67670e71 upstream. - -Signed-off-by: Gabor Juhos <juhosg@openwrt.org> -Acked-by: Luis R. Rodriguez <mcgrof@qca.qualcomm.com> -Cc: linux-mips@linux-mips.org -Cc: mcgrof@infradead.org -Patchwork: https://patchwork.linux-mips.org/patch/3508/ -Signed-off-by: Ralf Baechle <ralf@linux-mips.org> -Signed-off-by: Paul Gortmaker <paul.gortmaker@windriver.com> ---- - arch/mips/ath79/gpio.c | 47 +++++++++++++++++++++++- - arch/mips/include/asm/mach-ath79/ar71xx_regs.h | 1 + - 2 files changed, 47 insertions(+), 1 deletion(-) - -diff --git a/arch/mips/ath79/gpio.c b/arch/mips/ath79/gpio.c -index a2f8ca6..29054f2 100644 ---- a/arch/mips/ath79/gpio.c -+++ b/arch/mips/ath79/gpio.c -@@ -1,9 +1,12 @@ - /* - * Atheros AR71XX/AR724X/AR913X GPIO API support - * -- * Copyright (C) 2008-2010 Gabor Juhos <juhosg@openwrt.org> -+ * Copyright (C) 2010-2011 Jaiganesh Narayanan <jnarayanan@atheros.com> -+ * Copyright (C) 2008-2011 Gabor Juhos <juhosg@openwrt.org> - * Copyright (C) 2008 Imre Kaloz <kaloz@openwrt.org> - * -+ * Parts of this file are based on Atheros' 2.6.15/2.6.31 BSP -+ * - * 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. -@@ -89,6 +92,42 @@ static int ath79_gpio_direction_output(struct gpio_chip *chip, - return 0; - } - -+static int ar934x_gpio_direction_input(struct gpio_chip *chip, unsigned offset) -+{ -+ void __iomem *base = ath79_gpio_base; -+ unsigned long flags; -+ -+ spin_lock_irqsave(&ath79_gpio_lock, flags); -+ -+ __raw_writel(__raw_readl(base + AR71XX_GPIO_REG_OE) | (1 << offset), -+ base + AR71XX_GPIO_REG_OE); -+ -+ spin_unlock_irqrestore(&ath79_gpio_lock, flags); -+ -+ return 0; -+} -+ -+static int ar934x_gpio_direction_output(struct gpio_chip *chip, unsigned offset, -+ int value) -+{ -+ void __iomem *base = ath79_gpio_base; -+ unsigned long flags; -+ -+ spin_lock_irqsave(&ath79_gpio_lock, flags); -+ -+ if (value) -+ __raw_writel(1 << offset, base + AR71XX_GPIO_REG_SET); -+ else -+ __raw_writel(1 << offset, base + AR71XX_GPIO_REG_CLEAR); -+ -+ __raw_writel(__raw_readl(base + AR71XX_GPIO_REG_OE) & ~(1 << offset), -+ base + AR71XX_GPIO_REG_OE); -+ -+ spin_unlock_irqrestore(&ath79_gpio_lock, flags); -+ -+ return 0; -+} -+ - static struct gpio_chip ath79_gpio_chip = { - .label = "ath79", - .get = ath79_gpio_get_value, -@@ -155,11 +194,17 @@ void __init ath79_gpio_init(void) - ath79_gpio_count = AR913X_GPIO_COUNT; - else if (soc_is_ar933x()) - ath79_gpio_count = AR933X_GPIO_COUNT; -+ else if (soc_is_ar934x()) -+ ath79_gpio_count = AR934X_GPIO_COUNT; - else - BUG(); - - ath79_gpio_base = ioremap_nocache(AR71XX_GPIO_BASE, AR71XX_GPIO_SIZE); - ath79_gpio_chip.ngpio = ath79_gpio_count; -+ if (soc_is_ar934x()) { -+ ath79_gpio_chip.direction_input = ar934x_gpio_direction_input; -+ ath79_gpio_chip.direction_output = ar934x_gpio_direction_output; -+ } - - err = gpiochip_add(&ath79_gpio_chip); - if (err) -diff --git a/arch/mips/include/asm/mach-ath79/ar71xx_regs.h b/arch/mips/include/asm/mach-ath79/ar71xx_regs.h -index bc1c345..1a9234b 100644 ---- a/arch/mips/include/asm/mach-ath79/ar71xx_regs.h -+++ b/arch/mips/include/asm/mach-ath79/ar71xx_regs.h -@@ -367,5 +367,6 @@ - #define AR724X_GPIO_COUNT 18 - #define AR913X_GPIO_COUNT 22 - #define AR933X_GPIO_COUNT 30 -+#define AR934X_GPIO_COUNT 23 - - #endif /* __ASM_MACH_AR71XX_REGS_H */ --- -1.7.9.7 - diff --git a/bsp/routerstationpro/MIPS-ath79-add-IRQ-handling-code-for-AR934X.patch b/bsp/routerstationpro/MIPS-ath79-add-IRQ-handling-code-for-AR934X.patch deleted file mode 100644 index f4b83c609962abe9c1ca33a21a4e6972d70205a2..0000000000000000000000000000000000000000 --- a/bsp/routerstationpro/MIPS-ath79-add-IRQ-handling-code-for-AR934X.patch +++ /dev/null @@ -1,206 +0,0 @@ -From ccc78b5eb7858c59cf6e1a55baa5a45c7ce6d461 Mon Sep 17 00:00:00 2001 -From: Gabor Juhos <juhosg@openwrt.org> -Date: Wed, 14 Mar 2012 10:45:25 +0100 -Subject: [PATCH 057/123] MIPS: ath79: add IRQ handling code for AR934X - -commit fce5cc6e0ddc601e504063548034766c5c5a78d1 upstream. - -Signed-off-by: Gabor Juhos <juhosg@openwrt.org> -Acked-by: Luis R. Rodriguez <mcgrof@qca.qualcomm.com> -Cc: linux-mips@linux-mips.org -Cc: mcgrof@infradead.org -Patchwork: https://patchwork.linux-mips.org/patch/3510/ -Signed-off-by: Ralf Baechle <ralf@linux-mips.org> -Signed-off-by: Paul Gortmaker <paul.gortmaker@windriver.com> ---- - arch/mips/ath79/irq.c | 55 +++++++++++++++++++++++- - arch/mips/include/asm/mach-ath79/ar71xx_regs.h | 25 +++++++++++ - arch/mips/include/asm/mach-ath79/irq.h | 6 ++- - 3 files changed, 83 insertions(+), 3 deletions(-) - -diff --git a/arch/mips/ath79/irq.c b/arch/mips/ath79/irq.c -index 9f87ade..90d09fc 100644 ---- a/arch/mips/ath79/irq.c -+++ b/arch/mips/ath79/irq.c -@@ -1,10 +1,11 @@ - /* - * Atheros AR71xx/AR724x/AR913x specific interrupt handling - * -+ * Copyright (C) 2010-2011 Jaiganesh Narayanan <jnarayanan@atheros.com> - * Copyright (C) 2008-2011 Gabor Juhos <juhosg@openwrt.org> - * Copyright (C) 2008 Imre Kaloz <kaloz@openwrt.org> - * -- * Parts of this file are based on Atheros' 2.6.15 BSP -+ * Parts of this file are based on Atheros' 2.6.15/2.6.31 BSP - * - * 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 -@@ -129,7 +130,7 @@ static void __init ath79_misc_irq_init(void) - - if (soc_is_ar71xx() || soc_is_ar913x()) - ath79_misc_irq_chip.irq_mask_ack = ar71xx_misc_irq_mask; -- else if (soc_is_ar724x() || soc_is_ar933x()) -+ else if (soc_is_ar724x() || soc_is_ar933x() || soc_is_ar934x()) - ath79_misc_irq_chip.irq_ack = ar724x_misc_irq_ack; - else - BUG(); -@@ -143,6 +144,39 @@ static void __init ath79_misc_irq_init(void) - irq_set_chained_handler(ATH79_CPU_IRQ_MISC, ath79_misc_irq_handler); - } - -+static void ar934x_ip2_irq_dispatch(unsigned int irq, struct irq_desc *desc) -+{ -+ u32 status; -+ -+ disable_irq_nosync(irq); -+ -+ status = ath79_reset_rr(AR934X_RESET_REG_PCIE_WMAC_INT_STATUS); -+ -+ if (status & AR934X_PCIE_WMAC_INT_PCIE_ALL) { -+ ath79_ddr_wb_flush(AR934X_DDR_REG_FLUSH_PCIE); -+ generic_handle_irq(ATH79_IP2_IRQ(0)); -+ } else if (status & AR934X_PCIE_WMAC_INT_WMAC_ALL) { -+ ath79_ddr_wb_flush(AR934X_DDR_REG_FLUSH_WMAC); -+ generic_handle_irq(ATH79_IP2_IRQ(1)); -+ } else { -+ spurious_interrupt(); -+ } -+ -+ enable_irq(irq); -+} -+ -+static void ar934x_ip2_irq_init(void) -+{ -+ int i; -+ -+ for (i = ATH79_IP2_IRQ_BASE; -+ i < ATH79_IP2_IRQ_BASE + ATH79_IP2_IRQ_COUNT; i++) -+ irq_set_chip_and_handler(i, &dummy_irq_chip, -+ handle_level_irq); -+ -+ irq_set_chained_handler(ATH79_CPU_IRQ_IP2, ar934x_ip2_irq_dispatch); -+} -+ - asmlinkage void plat_irq_dispatch(void) - { - unsigned long pending; -@@ -202,6 +236,11 @@ static void ar933x_ip2_handler(void) - do_IRQ(ATH79_CPU_IRQ_IP2); - } - -+static void ar934x_ip2_handler(void) -+{ -+ do_IRQ(ATH79_CPU_IRQ_IP2); -+} -+ - static void ar71xx_ip3_handler(void) - { - ath79_ddr_wb_flush(AR71XX_DDR_REG_FLUSH_USB); -@@ -226,6 +265,12 @@ static void ar933x_ip3_handler(void) - do_IRQ(ATH79_CPU_IRQ_USB); - } - -+static void ar934x_ip3_handler(void) -+{ -+ ath79_ddr_wb_flush(AR934X_DDR_REG_FLUSH_USB); -+ do_IRQ(ATH79_CPU_IRQ_USB); -+} -+ - void __init arch_init_irq(void) - { - if (soc_is_ar71xx()) { -@@ -240,6 +285,9 @@ void __init arch_init_irq(void) - } else if (soc_is_ar933x()) { - ath79_ip2_handler = ar933x_ip2_handler; - ath79_ip3_handler = ar933x_ip3_handler; -+ } else if (soc_is_ar934x()) { -+ ath79_ip2_handler = ar934x_ip2_handler; -+ ath79_ip3_handler = ar934x_ip3_handler; - } else { - BUG(); - } -@@ -247,4 +295,7 @@ void __init arch_init_irq(void) - cp0_perfcount_irq = ATH79_MISC_IRQ_PERFC; - mips_cpu_irq_init(); - ath79_misc_irq_init(); -+ -+ if (soc_is_ar934x()) -+ ar934x_ip2_irq_init(); - } -diff --git a/arch/mips/include/asm/mach-ath79/ar71xx_regs.h b/arch/mips/include/asm/mach-ath79/ar71xx_regs.h -index 1a9234b..d6af4eb 100644 ---- a/arch/mips/include/asm/mach-ath79/ar71xx_regs.h -+++ b/arch/mips/include/asm/mach-ath79/ar71xx_regs.h -@@ -92,6 +92,12 @@ - #define AR933X_DDR_REG_FLUSH_USB 0x84 - #define AR933X_DDR_REG_FLUSH_WMAC 0x88 - -+#define AR934X_DDR_REG_FLUSH_GE0 0x9c -+#define AR934X_DDR_REG_FLUSH_GE1 0xa0 -+#define AR934X_DDR_REG_FLUSH_USB 0xa4 -+#define AR934X_DDR_REG_FLUSH_PCIE 0xa8 -+#define AR934X_DDR_REG_FLUSH_WMAC 0xac -+ - /* - * PLL block - */ -@@ -222,6 +228,7 @@ - #define AR933X_RESET_REG_BOOTSTRAP 0xac - - #define AR934X_RESET_REG_BOOTSTRAP 0xb0 -+#define AR934X_RESET_REG_PCIE_WMAC_INT_STATUS 0xac - - #define MISC_INT_ETHSW BIT(12) - #define MISC_INT_TIMER4 BIT(10) -@@ -295,6 +302,24 @@ - #define AR934X_BOOTSTRAP_SDRAM_DISABLED BIT(1) - #define AR934X_BOOTSTRAP_DDR1 BIT(0) - -+#define AR934X_PCIE_WMAC_INT_WMAC_MISC BIT(0) -+#define AR934X_PCIE_WMAC_INT_WMAC_TX BIT(1) -+#define AR934X_PCIE_WMAC_INT_WMAC_RXLP BIT(2) -+#define AR934X_PCIE_WMAC_INT_WMAC_RXHP BIT(3) -+#define AR934X_PCIE_WMAC_INT_PCIE_RC BIT(4) -+#define AR934X_PCIE_WMAC_INT_PCIE_RC0 BIT(5) -+#define AR934X_PCIE_WMAC_INT_PCIE_RC1 BIT(6) -+#define AR934X_PCIE_WMAC_INT_PCIE_RC2 BIT(7) -+#define AR934X_PCIE_WMAC_INT_PCIE_RC3 BIT(8) -+#define AR934X_PCIE_WMAC_INT_WMAC_ALL \ -+ (AR934X_PCIE_WMAC_INT_WMAC_MISC | AR934X_PCIE_WMAC_INT_WMAC_TX | \ -+ AR934X_PCIE_WMAC_INT_WMAC_RXLP | AR934X_PCIE_WMAC_INT_WMAC_RXHP) -+ -+#define AR934X_PCIE_WMAC_INT_PCIE_ALL \ -+ (AR934X_PCIE_WMAC_INT_PCIE_RC | AR934X_PCIE_WMAC_INT_PCIE_RC0 | \ -+ AR934X_PCIE_WMAC_INT_PCIE_RC1 | AR934X_PCIE_WMAC_INT_PCIE_RC2 | \ -+ AR934X_PCIE_WMAC_INT_PCIE_RC3) -+ - #define REV_ID_MAJOR_MASK 0xfff0 - #define REV_ID_MAJOR_AR71XX 0x00a0 - #define REV_ID_MAJOR_AR913X 0x00b0 -diff --git a/arch/mips/include/asm/mach-ath79/irq.h b/arch/mips/include/asm/mach-ath79/irq.h -index 6ae2646..0968f69 100644 ---- a/arch/mips/include/asm/mach-ath79/irq.h -+++ b/arch/mips/include/asm/mach-ath79/irq.h -@@ -10,7 +10,7 @@ - #define __ASM_MACH_ATH79_IRQ_H - - #define MIPS_CPU_IRQ_BASE 0 --#define NR_IRQS 46 -+#define NR_IRQS 48 - - #define ATH79_MISC_IRQ_BASE 8 - #define ATH79_MISC_IRQ_COUNT 32 -@@ -19,6 +19,10 @@ - #define ATH79_PCI_IRQ_COUNT 6 - #define ATH79_PCI_IRQ(_x) (ATH79_PCI_IRQ_BASE + (_x)) - -+#define ATH79_IP2_IRQ_BASE (ATH79_PCI_IRQ_BASE + ATH79_PCI_IRQ_COUNT) -+#define ATH79_IP2_IRQ_COUNT 2 -+#define ATH79_IP2_IRQ(_x) (ATH79_IP2_IRQ_BASE + (_x)) -+ - #define ATH79_CPU_IRQ_IP2 (MIPS_CPU_IRQ_BASE + 2) - #define ATH79_CPU_IRQ_USB (MIPS_CPU_IRQ_BASE + 3) - #define ATH79_CPU_IRQ_GE0 (MIPS_CPU_IRQ_BASE + 4) --- -1.7.9.7 - diff --git a/bsp/routerstationpro/MIPS-ath79-add-PCI-IRQ-handling-code-for-AR724X-SoCs.patch b/bsp/routerstationpro/MIPS-ath79-add-PCI-IRQ-handling-code-for-AR724X-SoCs.patch deleted file mode 100644 index 7456b0db743c41602a3f55a6929bf42e39a7fe43..0000000000000000000000000000000000000000 --- a/bsp/routerstationpro/MIPS-ath79-add-PCI-IRQ-handling-code-for-AR724X-SoCs.patch +++ /dev/null @@ -1,226 +0,0 @@ -From 2ca92e63aa807d3daccb6af4b11a9bf2ec1809b5 Mon Sep 17 00:00:00 2001 -From: Gabor Juhos <juhosg@openwrt.org> -Date: Wed, 14 Mar 2012 10:36:07 +0100 -Subject: [PATCH 043/123] MIPS: ath79: add PCI IRQ handling code for AR724X - SoCs - -commit 4c07c7dfa0f3575dc3276c544349fbf181381167 upstream. - -The PCI Host Controller of the AR724x SoC has a -built-in IRQ controller. The current code does -not supports that, so the IRQ lines wired to this -controller are not usable. This leads to failed -'request_irq' calls: - - ath9k 0000:00:00.0: request_irq failed - ath9k: probe of 0000:00:00.0 failed with error -89 - -This patch adds support for the IRQ controller -in order to make PCI IRQs work. - -Signed-off-by: Gabor Juhos <juhosg@openwrt.org> -Cc: linux-mips@linux-mips.org -Patchwork: https://patchwork.linux-mips.org/patch/3496/ -Signed-off-by: Ralf Baechle <ralf@linux-mips.org> -Signed-off-by: Paul Gortmaker <paul.gortmaker@windriver.com> ---- - arch/mips/ath79/pci.c | 3 +- - arch/mips/include/asm/mach-ath79/pci.h | 4 +- - arch/mips/pci/pci-ar724x.c | 118 +++++++++++++++++++++++++++++++- - 3 files changed, 120 insertions(+), 5 deletions(-) - -diff --git a/arch/mips/ath79/pci.c b/arch/mips/ath79/pci.c -index 72281fb..14f981c2 100644 ---- a/arch/mips/ath79/pci.c -+++ b/arch/mips/ath79/pci.c -@@ -10,6 +10,7 @@ - - #include <linux/pci.h> - #include <asm/mach-ath79/ath79.h> -+#include <asm/mach-ath79/irq.h> - #include <asm/mach-ath79/pci.h> - #include "pci.h" - -@@ -50,7 +51,7 @@ int pcibios_plat_dev_init(struct pci_dev *dev) - int __init ath79_register_pci(void) - { - if (soc_is_ar724x()) -- return ar724x_pcibios_init(); -+ return ar724x_pcibios_init(ATH79_CPU_IRQ_IP2); - - return -ENODEV; - } -diff --git a/arch/mips/include/asm/mach-ath79/pci.h b/arch/mips/include/asm/mach-ath79/pci.h -index 6d7a837..2eb0181 100644 ---- a/arch/mips/include/asm/mach-ath79/pci.h -+++ b/arch/mips/include/asm/mach-ath79/pci.h -@@ -12,9 +12,9 @@ - #define __ASM_MACH_ATH79_PCI_H - - #if defined(CONFIG_PCI) && defined(CONFIG_SOC_AR724X) --int ar724x_pcibios_init(void); -+int ar724x_pcibios_init(int irq); - #else --static inline int ar724x_pcibios_init(void) { return 0; } -+static inline int ar724x_pcibios_init(int irq) { return 0; } - #endif - - #endif /* __ASM_MACH_ATH79_PCI_H */ -diff --git a/arch/mips/pci/pci-ar724x.c b/arch/mips/pci/pci-ar724x.c -index 07b7e30..04f433a 100644 ---- a/arch/mips/pci/pci-ar724x.c -+++ b/arch/mips/pci/pci-ar724x.c -@@ -8,19 +8,32 @@ - * by the Free Software Foundation. - */ - -+#include <linux/irq.h> - #include <linux/pci.h> - #include <asm/mach-ath79/ath79.h> -+#include <asm/mach-ath79/ar71xx_regs.h> - #include <asm/mach-ath79/pci.h> - - #define AR724X_PCI_CFG_BASE 0x14000000 - #define AR724X_PCI_CFG_SIZE 0x1000 -+#define AR724X_PCI_CTRL_BASE (AR71XX_APB_BASE + 0x000f0000) -+#define AR724X_PCI_CTRL_SIZE 0x100 -+ - #define AR724X_PCI_MEM_BASE 0x10000000 - #define AR724X_PCI_MEM_SIZE 0x08000000 - -+#define AR724X_PCI_REG_INT_STATUS 0x4c -+#define AR724X_PCI_REG_INT_MASK 0x50 -+ -+#define AR724X_PCI_INT_DEV0 BIT(14) -+ -+#define AR724X_PCI_IRQ_COUNT 1 -+ - #define AR7240_BAR0_WAR_VALUE 0xffff - - static DEFINE_SPINLOCK(ar724x_pci_lock); - static void __iomem *ar724x_pci_devcfg_base; -+static void __iomem *ar724x_pci_ctrl_base; - - static u32 ar724x_pci_bar0_value; - static bool ar724x_pci_bar0_is_cached; -@@ -164,14 +177,115 @@ static struct pci_controller ar724x_pci_controller = { - .mem_resource = &ar724x_mem_resource, - }; - --int __init ar724x_pcibios_init(void) -+static void ar724x_pci_irq_handler(unsigned int irq, struct irq_desc *desc) -+{ -+ void __iomem *base; -+ u32 pending; -+ -+ base = ar724x_pci_ctrl_base; -+ -+ pending = __raw_readl(base + AR724X_PCI_REG_INT_STATUS) & -+ __raw_readl(base + AR724X_PCI_REG_INT_MASK); -+ -+ if (pending & AR724X_PCI_INT_DEV0) -+ generic_handle_irq(ATH79_PCI_IRQ(0)); -+ -+ else -+ spurious_interrupt(); -+} -+ -+static void ar724x_pci_irq_unmask(struct irq_data *d) -+{ -+ void __iomem *base; -+ u32 t; -+ -+ base = ar724x_pci_ctrl_base; -+ -+ switch (d->irq) { -+ case ATH79_PCI_IRQ(0): -+ t = __raw_readl(base + AR724X_PCI_REG_INT_MASK); -+ __raw_writel(t | AR724X_PCI_INT_DEV0, -+ base + AR724X_PCI_REG_INT_MASK); -+ /* flush write */ -+ __raw_readl(base + AR724X_PCI_REG_INT_MASK); -+ } -+} -+ -+static void ar724x_pci_irq_mask(struct irq_data *d) -+{ -+ void __iomem *base; -+ u32 t; -+ -+ base = ar724x_pci_ctrl_base; -+ -+ switch (d->irq) { -+ case ATH79_PCI_IRQ(0): -+ t = __raw_readl(base + AR724X_PCI_REG_INT_MASK); -+ __raw_writel(t & ~AR724X_PCI_INT_DEV0, -+ base + AR724X_PCI_REG_INT_MASK); -+ -+ /* flush write */ -+ __raw_readl(base + AR724X_PCI_REG_INT_MASK); -+ -+ t = __raw_readl(base + AR724X_PCI_REG_INT_STATUS); -+ __raw_writel(t | AR724X_PCI_INT_DEV0, -+ base + AR724X_PCI_REG_INT_STATUS); -+ -+ /* flush write */ -+ __raw_readl(base + AR724X_PCI_REG_INT_STATUS); -+ } -+} -+ -+static struct irq_chip ar724x_pci_irq_chip = { -+ .name = "AR724X PCI ", -+ .irq_mask = ar724x_pci_irq_mask, -+ .irq_unmask = ar724x_pci_irq_unmask, -+ .irq_mask_ack = ar724x_pci_irq_mask, -+}; -+ -+static void __init ar724x_pci_irq_init(int irq) -+{ -+ void __iomem *base; -+ int i; -+ -+ base = ar724x_pci_ctrl_base; -+ -+ __raw_writel(0, base + AR724X_PCI_REG_INT_MASK); -+ __raw_writel(0, base + AR724X_PCI_REG_INT_STATUS); -+ -+ BUILD_BUG_ON(ATH79_PCI_IRQ_COUNT < AR724X_PCI_IRQ_COUNT); -+ -+ for (i = ATH79_PCI_IRQ_BASE; -+ i < ATH79_PCI_IRQ_BASE + AR724X_PCI_IRQ_COUNT; i++) -+ irq_set_chip_and_handler(i, &ar724x_pci_irq_chip, -+ handle_level_irq); -+ -+ irq_set_chained_handler(irq, ar724x_pci_irq_handler); -+} -+ -+int __init ar724x_pcibios_init(int irq) - { -+ int ret; -+ -+ ret = -ENOMEM; -+ - ar724x_pci_devcfg_base = ioremap(AR724X_PCI_CFG_BASE, - AR724X_PCI_CFG_SIZE); - if (ar724x_pci_devcfg_base == NULL) -- return -ENOMEM; -+ goto err; - -+ ar724x_pci_ctrl_base = ioremap(AR724X_PCI_CTRL_BASE, -+ AR724X_PCI_CTRL_SIZE); -+ if (ar724x_pci_ctrl_base == NULL) -+ goto err_unmap_devcfg; -+ -+ ar724x_pci_irq_init(irq); - register_pci_controller(&ar724x_pci_controller); - - return PCIBIOS_SUCCESSFUL; -+ -+err_unmap_devcfg: -+ iounmap(ar724x_pci_devcfg_base); -+err: -+ return ret; - } --- -1.7.9.7 - diff --git a/bsp/routerstationpro/MIPS-ath79-add-PCI-registration-code-for-AR934X.patch b/bsp/routerstationpro/MIPS-ath79-add-PCI-registration-code-for-AR934X.patch deleted file mode 100644 index 8ed3bc8ab7365fb767b13ad646474a93e019dc31..0000000000000000000000000000000000000000 --- a/bsp/routerstationpro/MIPS-ath79-add-PCI-registration-code-for-AR934X.patch +++ /dev/null @@ -1,72 +0,0 @@ -From 948c9cb436fa221a59d92774151d99c1e0e8a3f6 Mon Sep 17 00:00:00 2001 -From: Gabor Juhos <juhosg@openwrt.org> -Date: Wed, 14 Mar 2012 10:45:30 +0100 -Subject: [PATCH 062/123] MIPS: ath79: add PCI registration code for AR934X - -commit ec9502599cd837c8e4e279585817d1ffb1249126 upstream. - -Signed-off-by: Gabor Juhos <juhosg@openwrt.org> -Acked-by: Luis R. Rodriguez <mcgrof@qca.qualcomm.com> -Cc: linux-mips@linux-mips.org -Cc: mcgrof@infradead.org -Patchwork: https://patchwork.linux-mips.org/patch/3516/ -Signed-off-by: Ralf Baechle <ralf@linux-mips.org> -Signed-off-by: Paul Gortmaker <paul.gortmaker@windriver.com> ---- - arch/mips/ath79/Kconfig | 2 ++ - arch/mips/ath79/pci.c | 13 ++++++++++++- - 2 files changed, 14 insertions(+), 1 deletion(-) - -diff --git a/arch/mips/ath79/Kconfig b/arch/mips/ath79/Kconfig -index 123cc37..ea28e89 100644 ---- a/arch/mips/ath79/Kconfig -+++ b/arch/mips/ath79/Kconfig -@@ -72,6 +72,8 @@ config SOC_AR933X - - config SOC_AR934X - select USB_ARCH_HAS_EHCI -+ select HW_HAS_PCI -+ select PCI_AR724X if PCI - def_bool n - - config PCI_AR724X -diff --git a/arch/mips/ath79/pci.c b/arch/mips/ath79/pci.c -index bc40070..ca83abd 100644 ---- a/arch/mips/ath79/pci.c -+++ b/arch/mips/ath79/pci.c -@@ -14,6 +14,7 @@ - - #include <linux/init.h> - #include <linux/pci.h> -+#include <asm/mach-ath79/ar71xx_regs.h> - #include <asm/mach-ath79/ath79.h> - #include <asm/mach-ath79/irq.h> - #include <asm/mach-ath79/pci.h> -@@ -57,7 +58,9 @@ int __init pcibios_map_irq(const struct pci_dev *dev, uint8_t slot, uint8_t pin) - if (soc_is_ar71xx()) { - ath79_pci_irq_map = ar71xx_pci_irq_map; - ath79_pci_nr_irqs = ARRAY_SIZE(ar71xx_pci_irq_map); -- } else if (soc_is_ar724x()) { -+ } else if (soc_is_ar724x() || -+ soc_is_ar9342() || -+ soc_is_ar9344()) { - ath79_pci_irq_map = ar724x_pci_irq_map; - ath79_pci_nr_irqs = ARRAY_SIZE(ar724x_pci_irq_map); - } else { -@@ -115,5 +118,13 @@ int __init ath79_register_pci(void) - if (soc_is_ar724x()) - return ar724x_pcibios_init(ATH79_CPU_IRQ_IP2); - -+ if (soc_is_ar9342() || soc_is_ar9344()) { -+ u32 bootstrap; -+ -+ bootstrap = ath79_reset_rr(AR934X_RESET_REG_BOOTSTRAP); -+ if (bootstrap & AR934X_BOOTSTRAP_PCIE_RC) -+ return ar724x_pcibios_init(ATH79_IP2_IRQ(0)); -+ } -+ - return -ENODEV; - } --- -1.7.9.7 - diff --git a/bsp/routerstationpro/MIPS-ath79-add-PCI_AR724X-Kconfig-symbol.patch b/bsp/routerstationpro/MIPS-ath79-add-PCI_AR724X-Kconfig-symbol.patch deleted file mode 100644 index b4b6e55ea736ec2536233dc2277ffb14d09c6538..0000000000000000000000000000000000000000 --- a/bsp/routerstationpro/MIPS-ath79-add-PCI_AR724X-Kconfig-symbol.patch +++ /dev/null @@ -1,78 +0,0 @@ -From d3d4cb2e7177db47d9200a0a50db11fafc20b5d9 Mon Sep 17 00:00:00 2001 -From: Gabor Juhos <juhosg@openwrt.org> -Date: Wed, 14 Mar 2012 10:45:29 +0100 -Subject: [PATCH 061/123] MIPS: ath79: add PCI_AR724X Kconfig symbol - -commit 67644c547fef2739f49c80e5eb1ace82f3e916e2 upstream. - -The AR724X specific PCI code can be used for the -AR934X SoCs, however it can be selected only if -SOC_AR724X is set. - -Introduce a new Kconfig symbol in order to be able -to use the code for AR934X as well. - -Signed-off-by: Gabor Juhos <juhosg@openwrt.org> -Acked-by: Luis R. Rodriguez <mcgrof@qca.qualcomm.com> -Cc: linux-mips@linux-mips.org -Cc: mcgrof@infradead.org -Patchwork: https://patchwork.linux-mips.org/patch/3514/ -Signed-off-by: Ralf Baechle <ralf@linux-mips.org> -Signed-off-by: Paul Gortmaker <paul.gortmaker@windriver.com> ---- - arch/mips/ath79/Kconfig | 4 ++++ - arch/mips/include/asm/mach-ath79/pci.h | 2 +- - arch/mips/pci/Makefile | 2 +- - 3 files changed, 6 insertions(+), 2 deletions(-) - -diff --git a/arch/mips/ath79/Kconfig b/arch/mips/ath79/Kconfig -index 5fa3d7b..123cc37 100644 ---- a/arch/mips/ath79/Kconfig -+++ b/arch/mips/ath79/Kconfig -@@ -59,6 +59,7 @@ config SOC_AR724X - select USB_ARCH_HAS_EHCI - select USB_ARCH_HAS_OHCI - select HW_HAS_PCI -+ select PCI_AR724X if PCI - def_bool n - - config SOC_AR913X -@@ -73,6 +74,9 @@ config SOC_AR934X - select USB_ARCH_HAS_EHCI - def_bool n - -+config PCI_AR724X -+ def_bool n -+ - config ATH79_DEV_GPIO_BUTTONS - def_bool n - -diff --git a/arch/mips/include/asm/mach-ath79/pci.h b/arch/mips/include/asm/mach-ath79/pci.h -index 4f2222d..7868f7f 100644 ---- a/arch/mips/include/asm/mach-ath79/pci.h -+++ b/arch/mips/include/asm/mach-ath79/pci.h -@@ -19,7 +19,7 @@ int ar71xx_pcibios_init(void); - static inline int ar71xx_pcibios_init(void) { return 0; } - #endif - --#if defined(CONFIG_PCI) && defined(CONFIG_SOC_AR724X) -+#if defined(CONFIG_PCI_AR724X) - int ar724x_pcibios_init(int irq); - #else - static inline int ar724x_pcibios_init(int irq) { return 0; } -diff --git a/arch/mips/pci/Makefile b/arch/mips/pci/Makefile -index b1c0a1c..43c5138 100644 ---- a/arch/mips/pci/Makefile -+++ b/arch/mips/pci/Makefile -@@ -20,7 +20,7 @@ obj-$(CONFIG_BCM63XX) += pci-bcm63xx.o fixup-bcm63xx.o \ - ops-bcm63xx.o - obj-$(CONFIG_MIPS_ALCHEMY) += pci-alchemy.o - obj-$(CONFIG_SOC_AR71XX) += pci-ar71xx.o --obj-$(CONFIG_SOC_AR724X) += pci-ar724x.o -+obj-$(CONFIG_PCI_AR724X) += pci-ar724x.o - - # - # These are still pretty much in the old state, watch, go blind. --- -1.7.9.7 - diff --git a/bsp/routerstationpro/MIPS-ath79-add-SoC-detection-code-for-AR934X.patch b/bsp/routerstationpro/MIPS-ath79-add-SoC-detection-code-for-AR934X.patch deleted file mode 100644 index 80fea083f04687bbe39933b82eb138aec5c04f69..0000000000000000000000000000000000000000 --- a/bsp/routerstationpro/MIPS-ath79-add-SoC-detection-code-for-AR934X.patch +++ /dev/null @@ -1,138 +0,0 @@ -From 7f3d182ab0f3ad8b4a4be610c1d5372de11882a4 Mon Sep 17 00:00:00 2001 -From: Gabor Juhos <juhosg@openwrt.org> -Date: Wed, 14 Mar 2012 10:45:21 +0100 -Subject: [PATCH 053/123] MIPS: ath79: add SoC detection code for AR934X - -commit d84114660a65e89e27ebd3fb21ce71ff579ee882 upstream. - -Also add 'soc_is_ar934[124x]' helper functions and a Kconfig -symbol for the AR934X SoCs. - -Signed-off-by: Gabor Juhos <juhosg@openwrt.org> -Acked-by: Luis R. Rodriguez <mcgrof@qca.qualcomm.com> -Cc: linux-mips@linux-mips.org -Cc: mcgrof@infradead.org -Patchwork: https://patchwork.linux-mips.org/patch/3506/ -Signed-off-by: Ralf Baechle <ralf@linux-mips.org> -Signed-off-by: Paul Gortmaker <paul.gortmaker@windriver.com> ---- - arch/mips/ath79/Kconfig | 4 ++++ - arch/mips/ath79/setup.c | 21 ++++++++++++++++++++- - arch/mips/include/asm/mach-ath79/ar71xx_regs.h | 2 ++ - arch/mips/include/asm/mach-ath79/ath79.h | 23 +++++++++++++++++++++++ - 4 files changed, 49 insertions(+), 1 deletion(-) - -diff --git a/arch/mips/ath79/Kconfig b/arch/mips/ath79/Kconfig -index bc6edad..7db8e89 100644 ---- a/arch/mips/ath79/Kconfig -+++ b/arch/mips/ath79/Kconfig -@@ -69,6 +69,10 @@ config SOC_AR933X - select USB_ARCH_HAS_EHCI - def_bool n - -+config SOC_AR934X -+ select USB_ARCH_HAS_EHCI -+ def_bool n -+ - config ATH79_DEV_GPIO_BUTTONS - def_bool n - -diff --git a/arch/mips/ath79/setup.c b/arch/mips/ath79/setup.c -index 24dfedf..60d212e 100644 ---- a/arch/mips/ath79/setup.c -+++ b/arch/mips/ath79/setup.c -@@ -1,10 +1,11 @@ - /* - * Atheros AR71XX/AR724X/AR913X specific setup - * -+ * Copyright (C) 2010-2011 Jaiganesh Narayanan <jnarayanan@atheros.com> - * Copyright (C) 2008-2011 Gabor Juhos <juhosg@openwrt.org> - * Copyright (C) 2008 Imre Kaloz <kaloz@openwrt.org> - * -- * Parts of this file are based on Atheros' 2.6.15 BSP -+ * Parts of this file are based on Atheros' 2.6.15/2.6.31 BSP - * - * 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 -@@ -145,6 +146,24 @@ static void __init ath79_detect_sys_type(void) - rev = id & AR933X_REV_ID_REVISION_MASK; - break; - -+ case REV_ID_MAJOR_AR9341: -+ ath79_soc = ATH79_SOC_AR9341; -+ chip = "9341"; -+ rev = id & AR934X_REV_ID_REVISION_MASK; -+ break; -+ -+ case REV_ID_MAJOR_AR9342: -+ ath79_soc = ATH79_SOC_AR9342; -+ chip = "9342"; -+ rev = id & AR934X_REV_ID_REVISION_MASK; -+ break; -+ -+ case REV_ID_MAJOR_AR9344: -+ ath79_soc = ATH79_SOC_AR9344; -+ chip = "9344"; -+ rev = id & AR934X_REV_ID_REVISION_MASK; -+ break; -+ - default: - panic("ath79: unknown SoC, id:0x%08x", id); - } -diff --git a/arch/mips/include/asm/mach-ath79/ar71xx_regs.h b/arch/mips/include/asm/mach-ath79/ar71xx_regs.h -index b7df674..4e3c55d 100644 ---- a/arch/mips/include/asm/mach-ath79/ar71xx_regs.h -+++ b/arch/mips/include/asm/mach-ath79/ar71xx_regs.h -@@ -271,6 +271,8 @@ - - #define AR724X_REV_ID_REVISION_MASK 0x3 - -+#define AR934X_REV_ID_REVISION_MASK 0xf -+ - /* - * SPI block - */ -diff --git a/arch/mips/include/asm/mach-ath79/ath79.h b/arch/mips/include/asm/mach-ath79/ath79.h -index 6d0c6c9..4f248c3 100644 ---- a/arch/mips/include/asm/mach-ath79/ath79.h -+++ b/arch/mips/include/asm/mach-ath79/ath79.h -@@ -29,6 +29,9 @@ enum ath79_soc_type { - ATH79_SOC_AR9132, - ATH79_SOC_AR9330, - ATH79_SOC_AR9331, -+ ATH79_SOC_AR9341, -+ ATH79_SOC_AR9342, -+ ATH79_SOC_AR9344, - }; - - extern enum ath79_soc_type ath79_soc; -@@ -75,6 +78,26 @@ static inline int soc_is_ar933x(void) - ath79_soc == ATH79_SOC_AR9331); - } - -+static inline int soc_is_ar9341(void) -+{ -+ return (ath79_soc == ATH79_SOC_AR9341); -+} -+ -+static inline int soc_is_ar9342(void) -+{ -+ return (ath79_soc == ATH79_SOC_AR9342); -+} -+ -+static inline int soc_is_ar9344(void) -+{ -+ return (ath79_soc == ATH79_SOC_AR9344); -+} -+ -+static inline int soc_is_ar934x(void) -+{ -+ return soc_is_ar9341() || soc_is_ar9342() || soc_is_ar9344(); -+} -+ - extern void __iomem *ath79_ddr_base; - extern void __iomem *ath79_pll_base; - extern void __iomem *ath79_reset_base; --- -1.7.9.7 - diff --git a/bsp/routerstationpro/MIPS-ath79-add-WMAC-registration-code-for-AR934X.patch b/bsp/routerstationpro/MIPS-ath79-add-WMAC-registration-code-for-AR934X.patch deleted file mode 100644 index 9132133e13a2c431b39a52994367a208860f1f31..0000000000000000000000000000000000000000 --- a/bsp/routerstationpro/MIPS-ath79-add-WMAC-registration-code-for-AR934X.patch +++ /dev/null @@ -1,128 +0,0 @@ -From eeed43de7f1608439208d463b702ce999c2df92d Mon Sep 17 00:00:00 2001 -From: Gabor Juhos <juhosg@openwrt.org> -Date: Wed, 14 Mar 2012 10:45:28 +0100 -Subject: [PATCH 060/123] MIPS: ath79: add WMAC registration code for AR934X - -commit 574d6e70ea25a8d5dd4b77464ae7314d40f1caf2 upstream. - -Signed-off-by: Gabor Juhos <juhosg@openwrt.org> -Acked-by: Luis R. Rodriguez <mcgrof@qca.qualcomm.com> -Cc: linux-mips@linux-mips.org -Cc: mcgrof@infradead.org -Patchwork: https://patchwork.linux-mips.org/patch/3513/ -Signed-off-by: Ralf Baechle <ralf@linux-mips.org> -Signed-off-by: Paul Gortmaker <paul.gortmaker@windriver.com> ---- - arch/mips/ath79/Kconfig | 2 +- - arch/mips/ath79/dev-wmac.c | 30 ++++++++++++++++++++++-- - arch/mips/include/asm/mach-ath79/ar71xx_regs.h | 3 +++ - 3 files changed, 32 insertions(+), 3 deletions(-) - -diff --git a/arch/mips/ath79/Kconfig b/arch/mips/ath79/Kconfig -index 7db8e89..5fa3d7b 100644 ---- a/arch/mips/ath79/Kconfig -+++ b/arch/mips/ath79/Kconfig -@@ -86,7 +86,7 @@ config ATH79_DEV_USB - def_bool n - - config ATH79_DEV_WMAC -- depends on (SOC_AR913X || SOC_AR933X) -+ depends on (SOC_AR913X || SOC_AR933X || SOC_AR934X) - def_bool n - - endif -diff --git a/arch/mips/ath79/dev-wmac.c b/arch/mips/ath79/dev-wmac.c -index 9c717bf..d6d893c 100644 ---- a/arch/mips/ath79/dev-wmac.c -+++ b/arch/mips/ath79/dev-wmac.c -@@ -1,9 +1,12 @@ - /* - * Atheros AR913X/AR933X SoC built-in WMAC device support - * -+ * Copyright (C) 2010-2011 Jaiganesh Narayanan <jnarayanan@atheros.com> - * Copyright (C) 2008-2011 Gabor Juhos <juhosg@openwrt.org> - * Copyright (C) 2008 Imre Kaloz <kaloz@openwrt.org> - * -+ * Parts of this file are based on Atheros 2.6.15/2.6.31 BSP -+ * - * 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. -@@ -26,8 +29,7 @@ static struct resource ath79_wmac_resources[] = { - /* .start and .end fields are filled dynamically */ - .flags = IORESOURCE_MEM, - }, { -- .start = ATH79_CPU_IRQ_IP2, -- .end = ATH79_CPU_IRQ_IP2, -+ /* .start and .end fields are filled dynamically */ - .flags = IORESOURCE_IRQ, - }, - }; -@@ -53,6 +55,8 @@ static void __init ar913x_wmac_setup(void) - - ath79_wmac_resources[0].start = AR913X_WMAC_BASE; - ath79_wmac_resources[0].end = AR913X_WMAC_BASE + AR913X_WMAC_SIZE - 1; -+ ath79_wmac_resources[1].start = ATH79_CPU_IRQ_IP2; -+ ath79_wmac_resources[1].end = ATH79_CPU_IRQ_IP2; - } - - -@@ -79,6 +83,8 @@ static void __init ar933x_wmac_setup(void) - - ath79_wmac_resources[0].start = AR933X_WMAC_BASE; - ath79_wmac_resources[0].end = AR933X_WMAC_BASE + AR933X_WMAC_SIZE - 1; -+ ath79_wmac_resources[1].start = ATH79_CPU_IRQ_IP2; -+ ath79_wmac_resources[1].end = ATH79_CPU_IRQ_IP2; - - t = ath79_reset_rr(AR933X_RESET_REG_BOOTSTRAP); - if (t & AR933X_BOOTSTRAP_REF_CLK_40) -@@ -92,12 +98,32 @@ static void __init ar933x_wmac_setup(void) - ath79_wmac_data.external_reset = ar933x_wmac_reset; - } - -+static void ar934x_wmac_setup(void) -+{ -+ u32 t; -+ -+ ath79_wmac_device.name = "ar934x_wmac"; -+ -+ ath79_wmac_resources[0].start = AR934X_WMAC_BASE; -+ ath79_wmac_resources[0].end = AR934X_WMAC_BASE + AR934X_WMAC_SIZE - 1; -+ ath79_wmac_resources[1].start = ATH79_IP2_IRQ(1); -+ ath79_wmac_resources[1].start = ATH79_IP2_IRQ(1); -+ -+ t = ath79_reset_rr(AR934X_RESET_REG_BOOTSTRAP); -+ if (t & AR934X_BOOTSTRAP_REF_CLK_40) -+ ath79_wmac_data.is_clk_25mhz = false; -+ else -+ ath79_wmac_data.is_clk_25mhz = true; -+} -+ - void __init ath79_register_wmac(u8 *cal_data) - { - if (soc_is_ar913x()) - ar913x_wmac_setup(); - else if (soc_is_ar933x()) - ar933x_wmac_setup(); -+ else if (soc_is_ar934x()) -+ ar934x_wmac_setup(); - else - BUG(); - -diff --git a/arch/mips/include/asm/mach-ath79/ar71xx_regs.h b/arch/mips/include/asm/mach-ath79/ar71xx_regs.h -index 32abbf9..1caa78a 100644 ---- a/arch/mips/include/asm/mach-ath79/ar71xx_regs.h -+++ b/arch/mips/include/asm/mach-ath79/ar71xx_regs.h -@@ -61,6 +61,9 @@ - #define AR933X_EHCI_BASE 0x1b000000 - #define AR933X_EHCI_SIZE 0x1000 - -+#define AR934X_WMAC_BASE (AR71XX_APB_BASE + 0x00100000) -+#define AR934X_WMAC_SIZE 0x20000 -+ - /* - * DDR_CTRL block - */ --- -1.7.9.7 - diff --git a/bsp/routerstationpro/MIPS-ath79-add-a-common-PCI-registration-function.patch b/bsp/routerstationpro/MIPS-ath79-add-a-common-PCI-registration-function.patch deleted file mode 100644 index 1656642e91dcfd317bba6e0374a99227c761b944..0000000000000000000000000000000000000000 --- a/bsp/routerstationpro/MIPS-ath79-add-a-common-PCI-registration-function.patch +++ /dev/null @@ -1,92 +0,0 @@ -From ef2ca80937f45011e5fb105de35db8581be0d556 Mon Sep 17 00:00:00 2001 -From: Gabor Juhos <juhosg@openwrt.org> -Date: Wed, 14 Mar 2012 10:29:24 +0100 -Subject: [PATCH 035/123] MIPS: ath79: add a common PCI registration function - -commit 6335aef59c55f50e6d8017a28c0ee985b533ea29 upstream. - -The current code unconditionally registers the AR724X -specific PCI controller, even if the kernel is running -on a different SoC. - -Add a common function for PCI controller registration, -and only register the AR724X PCI controller if the kernel -is running on an AR724X SoC. - -Signed-off-by: Gabor Juhos <juhosg@openwrt.org> -Cc: linux-mips@linux-mips.org -Patchwork: https://patchwork.linux-mips.org/patch/3488/ -Signed-off-by: Ralf Baechle <ralf@linux-mips.org> -Signed-off-by: Paul Gortmaker <paul.gortmaker@windriver.com> ---- - arch/mips/ath79/mach-ubnt-xm.c | 1 + - arch/mips/ath79/pci.c | 10 ++++++++++ - arch/mips/ath79/pci.h | 6 ++++++ - arch/mips/pci/pci-ath724x.c | 2 -- - 4 files changed, 17 insertions(+), 2 deletions(-) - -diff --git a/arch/mips/ath79/mach-ubnt-xm.c b/arch/mips/ath79/mach-ubnt-xm.c -index a043500..edbc093 100644 ---- a/arch/mips/ath79/mach-ubnt-xm.c -+++ b/arch/mips/ath79/mach-ubnt-xm.c -@@ -111,6 +111,7 @@ static void __init ubnt_xm_init(void) - ath724x_pci_add_data(ubnt_xm_pci_data, ARRAY_SIZE(ubnt_xm_pci_data)); - #endif /* CONFIG_PCI */ - -+ ath79_register_pci(); - } - - MIPS_MACHINE(ATH79_MACH_UBNT_XM, -diff --git a/arch/mips/ath79/pci.c b/arch/mips/ath79/pci.c -index 4957428..855a69d 100644 ---- a/arch/mips/ath79/pci.c -+++ b/arch/mips/ath79/pci.c -@@ -9,6 +9,8 @@ - */ - - #include <linux/pci.h> -+#include <asm/mach-ath79/ath79.h> -+#include <asm/mach-ath79/pci.h> - #include "pci.h" - - static struct ath724x_pci_data *pci_data; -@@ -44,3 +46,11 @@ int pcibios_plat_dev_init(struct pci_dev *dev) - - return PCIBIOS_SUCCESSFUL; - } -+ -+int __init ath79_register_pci(void) -+{ -+ if (soc_is_ar724x()) -+ return ath724x_pcibios_init(); -+ -+ return -ENODEV; -+} -diff --git a/arch/mips/ath79/pci.h b/arch/mips/ath79/pci.h -index 454885f..787fac2 100644 ---- a/arch/mips/ath79/pci.h -+++ b/arch/mips/ath79/pci.h -@@ -18,4 +18,10 @@ struct ath724x_pci_data { - - void ath724x_pci_add_data(struct ath724x_pci_data *data, int size); - -+#ifdef CONFIG_PCI -+int ath79_register_pci(void); -+#else -+static inline int ath79_register_pci(void) { return 0; } -+#endif -+ - #endif /* __ASM_MACH_ATH79_PCI_ATH724X_H */ -diff --git a/arch/mips/pci/pci-ath724x.c b/arch/mips/pci/pci-ath724x.c -index be01b7f..ebefc16 100644 ---- a/arch/mips/pci/pci-ath724x.c -+++ b/arch/mips/pci/pci-ath724x.c -@@ -137,5 +137,3 @@ int __init ath724x_pcibios_init(void) - - return PCIBIOS_SUCCESSFUL; - } -- --arch_initcall(ath724x_pcibios_init); --- -1.7.9.7 - diff --git a/bsp/routerstationpro/MIPS-ath79-add-a-workaround-for-a-PCI-controller-bug.patch b/bsp/routerstationpro/MIPS-ath79-add-a-workaround-for-a-PCI-controller-bug.patch deleted file mode 100644 index 6b9bb6d34d0deac23ab71c98d82a0da41869a88d..0000000000000000000000000000000000000000 --- a/bsp/routerstationpro/MIPS-ath79-add-a-workaround-for-a-PCI-controller-bug.patch +++ /dev/null @@ -1,143 +0,0 @@ -From 8ee7c348d8c2898872bc2b016c98bfa46b463317 Mon Sep 17 00:00:00 2001 -From: Gabor Juhos <juhosg@openwrt.org> -Date: Wed, 14 Mar 2012 10:36:05 +0100 -Subject: [PATCH 041/123] MIPS: ath79: add a workaround for a PCI controller - bug in AR7240 SoCs - -commit 6015a856f16ccf33e9f83643d04c2e15be2384eb upstream. - -The PCI controller of the AR724X SoCs has a hardware -bag. If the BAR0 register of the PCI device is set to -the proper base address, the memory address space of -the device is not accessible. - -When the device driver tries to access the memory -address space of the PCI device, it leads to data -bus error, similiar to this: - -Data bus error, epc == 801f69a0, ra == 801f698c -Oops[#1]: -Cpu 0 -$ 0 : 00000000 00000061 deadbeef 000000ff -$ 4 : 00000000 000000ff 00000014 00000000 -$ 8 : ff000000 fffffffc 00000000 00000000 -$12 : 000001f5 00000006 00000000 6e637920 -$16 : 81ca4000 81ca0260 81ca4000 804d70f0 -$20 : fffffff4 0000002b 803ad4c4 00000000 -$24 : 00000003 00000000 -$28 : 81c20000 81c21c60 00000000 801f698c -Hi : 00000000 -Lo : 00000000 -epc : 801f69a0 ath9k_hw_init+0xd0/0xa70 - Not tainted -ra : 801f698c ath9k_hw_init+0xbc/0xa70 -Status: 1000c103 KERNEL EXL IE -Cause : 1080001c -PrId : 00019374 (MIPS 24Kc) -Modules linked in: -Process swapper (pid: 1, threadinfo=81c20000, task=81c18000, tls=00000000) -Stack : 00000000 00000000 00000000 00000000 81c21c78 81ca0260 00000000 804d70f0 - 81ca0260 81c21cc0 81ca0e80 81ca0260 81ca4000 804d70f0 fffffff4 0000002b - 803ad4c4 00000000 00000000 801e3ae8 81c9d080 81ca0e80 b0000000 800b9b9c - 00000008 81c9d000 8031aeb0 802d38a0 00000000 81c14c00 81c14c60 00000000 - 81ca0e80 81ca0260 b0000000 801f08a4 81c9c820 81c21d48 81c9c820 80144320 - ... -Call Trace: -[<801f69a0>] ath9k_hw_init+0xd0/0xa70 -[<801e3ae8>] ath9k_init_device+0x174/0x680 -[<801f08a4>] ath_pci_probe+0x27c/0x380 -[<8019e490>] pci_device_probe+0x74/0x9c -[<801bfadc>] driver_probe_device+0x9c/0x1b4 -[<801bfcb0>] __driver_attach+0xbc/0xc4 -[<801bea0c>] bus_for_each_dev+0x5c/0x98 -[<801bf394>] bus_add_driver+0x1d0/0x2a4 -[<801c0364>] driver_register+0x8c/0x16c -[<8019e72c>] __pci_register_driver+0x4c/0xe4 -[<803d3d40>] ath9k_init+0x3c/0x88 -[<80060930>] do_one_initcall+0x3c/0x1cc -[<803c297c>] kernel_init+0xa4/0x138 -[<80063c04>] kernel_thread_helper+0x10/0x18 - -Signed-off-by: Gabor Juhos <juhosg@openwrt.org> -Cc: linux-mips@linux-mips.org -Patchwork: https://patchwork.linux-mips.org/patch/3494/ -Signed-off-by: Ralf Baechle <ralf@linux-mips.org> -Signed-off-by: Paul Gortmaker <paul.gortmaker@windriver.com> ---- - arch/mips/pci/pci-ar724x.c | 36 +++++++++++++++++++++++++++++++++++- - 1 file changed, 35 insertions(+), 1 deletion(-) - -diff --git a/arch/mips/pci/pci-ar724x.c b/arch/mips/pci/pci-ar724x.c -index bb4f216..07b7e30 100644 ---- a/arch/mips/pci/pci-ar724x.c -+++ b/arch/mips/pci/pci-ar724x.c -@@ -9,6 +9,7 @@ - */ - - #include <linux/pci.h> -+#include <asm/mach-ath79/ath79.h> - #include <asm/mach-ath79/pci.h> - - #define AR724X_PCI_CFG_BASE 0x14000000 -@@ -16,9 +17,14 @@ - #define AR724X_PCI_MEM_BASE 0x10000000 - #define AR724X_PCI_MEM_SIZE 0x08000000 - -+#define AR7240_BAR0_WAR_VALUE 0xffff -+ - static DEFINE_SPINLOCK(ar724x_pci_lock); - static void __iomem *ar724x_pci_devcfg_base; - -+static u32 ar724x_pci_bar0_value; -+static bool ar724x_pci_bar0_is_cached; -+ - static int ar724x_pci_read(struct pci_bus *bus, unsigned int devfn, int where, - int size, uint32_t *value) - { -@@ -56,7 +62,14 @@ static int ar724x_pci_read(struct pci_bus *bus, unsigned int devfn, int where, - } - - spin_unlock_irqrestore(&ar724x_pci_lock, flags); -- *value = data; -+ -+ if (where == PCI_BASE_ADDRESS_0 && size == 4 && -+ ar724x_pci_bar0_is_cached) { -+ /* use the cached value */ -+ *value = ar724x_pci_bar0_value; -+ } else { -+ *value = data; -+ } - - return PCIBIOS_SUCCESSFUL; - } -@@ -72,6 +85,27 @@ static int ar724x_pci_write(struct pci_bus *bus, unsigned int devfn, int where, - if (devfn) - return PCIBIOS_DEVICE_NOT_FOUND; - -+ if (soc_is_ar7240() && where == PCI_BASE_ADDRESS_0 && size == 4) { -+ if (value != 0xffffffff) { -+ /* -+ * WAR for a hw issue. If the BAR0 register of the -+ * device is set to the proper base address, the -+ * memory space of the device is not accessible. -+ * -+ * Cache the intended value so it can be read back, -+ * and write a SoC specific constant value to the -+ * BAR0 register in order to make the device memory -+ * accessible. -+ */ -+ ar724x_pci_bar0_is_cached = true; -+ ar724x_pci_bar0_value = value; -+ -+ value = AR7240_BAR0_WAR_VALUE; -+ } else { -+ ar724x_pci_bar0_is_cached = false; -+ } -+ } -+ - base = ar724x_pci_devcfg_base; - - spin_lock_irqsave(&ar724x_pci_lock, flags); --- -1.7.9.7 - diff --git a/bsp/routerstationpro/MIPS-ath79-add-clock-initialization-code-for-AR934X.patch b/bsp/routerstationpro/MIPS-ath79-add-clock-initialization-code-for-AR934X.patch deleted file mode 100644 index 1d5b36771feee857d49c8ca0fe64c88d71a9439b..0000000000000000000000000000000000000000 --- a/bsp/routerstationpro/MIPS-ath79-add-clock-initialization-code-for-AR934X.patch +++ /dev/null @@ -1,209 +0,0 @@ -From 7e45fa2d4ced8609fe0178e77a86ba2e9e152567 Mon Sep 17 00:00:00 2001 -From: Gabor Juhos <juhosg@openwrt.org> -Date: Wed, 14 Mar 2012 10:45:22 +0100 -Subject: [PATCH 054/123] MIPS: ath79: add clock initialization code for - AR934X - -commit 8889612b3e2054617219581ae10dbe33cf3bddfe upstream. - -Signed-off-by: Gabor Juhos <juhosg@openwrt.org> -Acked-by: Luis R. Rodriguez <mcgrof@qca.qualcomm.com> -Cc: linux-mips@linux-mips.org -Cc: mcgrof@infradead.org -Patchwork: https://patchwork.linux-mips.org/patch/3507/ -Signed-off-by: Ralf Baechle <ralf@linux-mips.org> -Signed-off-by: Paul Gortmaker <paul.gortmaker@windriver.com> ---- - arch/mips/ath79/clock.c | 81 ++++++++++++++++++++++++ - arch/mips/include/asm/mach-ath79/ar71xx_regs.h | 53 ++++++++++++++++ - 2 files changed, 134 insertions(+) - -diff --git a/arch/mips/ath79/clock.c b/arch/mips/ath79/clock.c -index 54d0eb4db..b91ad3e 100644 ---- a/arch/mips/ath79/clock.c -+++ b/arch/mips/ath79/clock.c -@@ -1,8 +1,11 @@ - /* - * Atheros AR71XX/AR724X/AR913X common routines - * -+ * Copyright (C) 2010-2011 Jaiganesh Narayanan <jnarayanan@atheros.com> - * Copyright (C) 2011 Gabor Juhos <juhosg@openwrt.org> - * -+ * Parts of this file are based on Atheros' 2.6.15/2.6.31 BSP -+ * - * 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. -@@ -163,6 +166,82 @@ static void __init ar933x_clocks_init(void) - ath79_uart_clk.rate = ath79_ref_clk.rate; - } - -+static void __init ar934x_clocks_init(void) -+{ -+ u32 pll, out_div, ref_div, nint, frac, clk_ctrl, postdiv; -+ u32 cpu_pll, ddr_pll; -+ u32 bootstrap; -+ -+ bootstrap = ath79_reset_rr(AR934X_RESET_REG_BOOTSTRAP); -+ if (bootstrap & AR934X_BOOTSTRAP_REF_CLK_40) -+ ath79_ref_clk.rate = 40 * 1000 * 1000; -+ else -+ ath79_ref_clk.rate = 25 * 1000 * 1000; -+ -+ pll = ath79_pll_rr(AR934X_PLL_CPU_CONFIG_REG); -+ out_div = (pll >> AR934X_PLL_CPU_CONFIG_OUTDIV_SHIFT) & -+ AR934X_PLL_CPU_CONFIG_OUTDIV_MASK; -+ ref_div = (pll >> AR934X_PLL_CPU_CONFIG_REFDIV_SHIFT) & -+ AR934X_PLL_CPU_CONFIG_REFDIV_MASK; -+ nint = (pll >> AR934X_PLL_CPU_CONFIG_NINT_SHIFT) & -+ AR934X_PLL_CPU_CONFIG_NINT_MASK; -+ frac = (pll >> AR934X_PLL_CPU_CONFIG_NFRAC_SHIFT) & -+ AR934X_PLL_CPU_CONFIG_NFRAC_MASK; -+ -+ cpu_pll = nint * ath79_ref_clk.rate / ref_div; -+ cpu_pll += frac * ath79_ref_clk.rate / (ref_div * (2 << 6)); -+ cpu_pll /= (1 << out_div); -+ -+ pll = ath79_pll_rr(AR934X_PLL_DDR_CONFIG_REG); -+ out_div = (pll >> AR934X_PLL_DDR_CONFIG_OUTDIV_SHIFT) & -+ AR934X_PLL_DDR_CONFIG_OUTDIV_MASK; -+ ref_div = (pll >> AR934X_PLL_DDR_CONFIG_REFDIV_SHIFT) & -+ AR934X_PLL_DDR_CONFIG_REFDIV_MASK; -+ nint = (pll >> AR934X_PLL_DDR_CONFIG_NINT_SHIFT) & -+ AR934X_PLL_DDR_CONFIG_NINT_MASK; -+ frac = (pll >> AR934X_PLL_DDR_CONFIG_NFRAC_SHIFT) & -+ AR934X_PLL_DDR_CONFIG_NFRAC_MASK; -+ -+ ddr_pll = nint * ath79_ref_clk.rate / ref_div; -+ ddr_pll += frac * ath79_ref_clk.rate / (ref_div * (2 << 10)); -+ ddr_pll /= (1 << out_div); -+ -+ clk_ctrl = ath79_pll_rr(AR934X_PLL_CPU_DDR_CLK_CTRL_REG); -+ -+ postdiv = (clk_ctrl >> AR934X_PLL_CPU_DDR_CLK_CTRL_CPU_POST_DIV_SHIFT) & -+ AR934X_PLL_CPU_DDR_CLK_CTRL_CPU_POST_DIV_MASK; -+ -+ if (clk_ctrl & AR934X_PLL_CPU_DDR_CLK_CTRL_CPU_PLL_BYPASS) -+ ath79_cpu_clk.rate = ath79_ref_clk.rate; -+ else if (clk_ctrl & AR934X_PLL_CPU_DDR_CLK_CTRL_CPUCLK_FROM_CPUPLL) -+ ath79_cpu_clk.rate = cpu_pll / (postdiv + 1); -+ else -+ ath79_cpu_clk.rate = ddr_pll / (postdiv + 1); -+ -+ postdiv = (clk_ctrl >> AR934X_PLL_CPU_DDR_CLK_CTRL_DDR_POST_DIV_SHIFT) & -+ AR934X_PLL_CPU_DDR_CLK_CTRL_DDR_POST_DIV_MASK; -+ -+ if (clk_ctrl & AR934X_PLL_CPU_DDR_CLK_CTRL_DDR_PLL_BYPASS) -+ ath79_ddr_clk.rate = ath79_ref_clk.rate; -+ else if (clk_ctrl & AR934X_PLL_CPU_DDR_CLK_CTRL_DDRCLK_FROM_DDRPLL) -+ ath79_ddr_clk.rate = ddr_pll / (postdiv + 1); -+ else -+ ath79_ddr_clk.rate = cpu_pll / (postdiv + 1); -+ -+ postdiv = (clk_ctrl >> AR934X_PLL_CPU_DDR_CLK_CTRL_AHB_POST_DIV_SHIFT) & -+ AR934X_PLL_CPU_DDR_CLK_CTRL_AHB_POST_DIV_MASK; -+ -+ if (clk_ctrl & AR934X_PLL_CPU_DDR_CLK_CTRL_AHB_PLL_BYPASS) -+ ath79_ahb_clk.rate = ath79_ref_clk.rate; -+ else if (clk_ctrl & AR934X_PLL_CPU_DDR_CLK_CTRL_AHBCLK_FROM_DDRPLL) -+ ath79_ahb_clk.rate = ddr_pll / (postdiv + 1); -+ else -+ ath79_ahb_clk.rate = cpu_pll / (postdiv + 1); -+ -+ ath79_wdt_clk.rate = ath79_ref_clk.rate; -+ ath79_uart_clk.rate = ath79_ref_clk.rate; -+} -+ - void __init ath79_clocks_init(void) - { - if (soc_is_ar71xx()) -@@ -173,6 +252,8 @@ void __init ath79_clocks_init(void) - ar913x_clocks_init(); - else if (soc_is_ar933x()) - ar933x_clocks_init(); -+ else if (soc_is_ar934x()) -+ ar934x_clocks_init(); - else - BUG(); - -diff --git a/arch/mips/include/asm/mach-ath79/ar71xx_regs.h b/arch/mips/include/asm/mach-ath79/ar71xx_regs.h -index 4e3c55d..bc1c345 100644 ---- a/arch/mips/include/asm/mach-ath79/ar71xx_regs.h -+++ b/arch/mips/include/asm/mach-ath79/ar71xx_regs.h -@@ -151,6 +151,41 @@ - #define AR933X_PLL_CLOCK_CTRL_AHB_DIV_SHIFT 15 - #define AR933X_PLL_CLOCK_CTRL_AHB_DIV_MASK 0x7 - -+#define AR934X_PLL_CPU_CONFIG_REG 0x00 -+#define AR934X_PLL_DDR_CONFIG_REG 0x04 -+#define AR934X_PLL_CPU_DDR_CLK_CTRL_REG 0x08 -+ -+#define AR934X_PLL_CPU_CONFIG_NFRAC_SHIFT 0 -+#define AR934X_PLL_CPU_CONFIG_NFRAC_MASK 0x3f -+#define AR934X_PLL_CPU_CONFIG_NINT_SHIFT 6 -+#define AR934X_PLL_CPU_CONFIG_NINT_MASK 0x3f -+#define AR934X_PLL_CPU_CONFIG_REFDIV_SHIFT 12 -+#define AR934X_PLL_CPU_CONFIG_REFDIV_MASK 0x1f -+#define AR934X_PLL_CPU_CONFIG_OUTDIV_SHIFT 19 -+#define AR934X_PLL_CPU_CONFIG_OUTDIV_MASK 0x3 -+ -+#define AR934X_PLL_DDR_CONFIG_NFRAC_SHIFT 0 -+#define AR934X_PLL_DDR_CONFIG_NFRAC_MASK 0x3ff -+#define AR934X_PLL_DDR_CONFIG_NINT_SHIFT 10 -+#define AR934X_PLL_DDR_CONFIG_NINT_MASK 0x3f -+#define AR934X_PLL_DDR_CONFIG_REFDIV_SHIFT 16 -+#define AR934X_PLL_DDR_CONFIG_REFDIV_MASK 0x1f -+#define AR934X_PLL_DDR_CONFIG_OUTDIV_SHIFT 23 -+#define AR934X_PLL_DDR_CONFIG_OUTDIV_MASK 0x7 -+ -+#define AR934X_PLL_CPU_DDR_CLK_CTRL_CPU_PLL_BYPASS BIT(2) -+#define AR934X_PLL_CPU_DDR_CLK_CTRL_DDR_PLL_BYPASS BIT(3) -+#define AR934X_PLL_CPU_DDR_CLK_CTRL_AHB_PLL_BYPASS BIT(4) -+#define AR934X_PLL_CPU_DDR_CLK_CTRL_CPU_POST_DIV_SHIFT 5 -+#define AR934X_PLL_CPU_DDR_CLK_CTRL_CPU_POST_DIV_MASK 0x1f -+#define AR934X_PLL_CPU_DDR_CLK_CTRL_DDR_POST_DIV_SHIFT 10 -+#define AR934X_PLL_CPU_DDR_CLK_CTRL_DDR_POST_DIV_MASK 0x1f -+#define AR934X_PLL_CPU_DDR_CLK_CTRL_AHB_POST_DIV_SHIFT 15 -+#define AR934X_PLL_CPU_DDR_CLK_CTRL_AHB_POST_DIV_MASK 0x1f -+#define AR934X_PLL_CPU_DDR_CLK_CTRL_CPUCLK_FROM_CPUPLL BIT(20) -+#define AR934X_PLL_CPU_DDR_CLK_CTRL_DDRCLK_FROM_DDRPLL BIT(21) -+#define AR934X_PLL_CPU_DDR_CLK_CTRL_AHBCLK_FROM_DDRPLL BIT(24) -+ - /* - * USB_CONFIG block - */ -@@ -186,6 +221,8 @@ - #define AR933X_RESET_REG_RESET_MODULE 0x1c - #define AR933X_RESET_REG_BOOTSTRAP 0xac - -+#define AR934X_RESET_REG_BOOTSTRAP 0xb0 -+ - #define MISC_INT_ETHSW BIT(12) - #define MISC_INT_TIMER4 BIT(10) - #define MISC_INT_TIMER3 BIT(9) -@@ -242,6 +279,22 @@ - - #define AR933X_BOOTSTRAP_REF_CLK_40 BIT(0) - -+#define AR934X_BOOTSTRAP_SW_OPTION8 BIT(23) -+#define AR934X_BOOTSTRAP_SW_OPTION7 BIT(22) -+#define AR934X_BOOTSTRAP_SW_OPTION6 BIT(21) -+#define AR934X_BOOTSTRAP_SW_OPTION5 BIT(20) -+#define AR934X_BOOTSTRAP_SW_OPTION4 BIT(19) -+#define AR934X_BOOTSTRAP_SW_OPTION3 BIT(18) -+#define AR934X_BOOTSTRAP_SW_OPTION2 BIT(17) -+#define AR934X_BOOTSTRAP_SW_OPTION1 BIT(16) -+#define AR934X_BOOTSTRAP_USB_MODE_DEVICE BIT(7) -+#define AR934X_BOOTSTRAP_PCIE_RC BIT(6) -+#define AR934X_BOOTSTRAP_EJTAG_MODE BIT(5) -+#define AR934X_BOOTSTRAP_REF_CLK_40 BIT(4) -+#define AR934X_BOOTSTRAP_BOOT_FROM_SPI BIT(2) -+#define AR934X_BOOTSTRAP_SDRAM_DISABLED BIT(1) -+#define AR934X_BOOTSTRAP_DDR1 BIT(0) -+ - #define REV_ID_MAJOR_MASK 0xfff0 - #define REV_ID_MAJOR_AR71XX 0x00a0 - #define REV_ID_MAJOR_AR913X 0x00b0 --- -1.7.9.7 - diff --git a/bsp/routerstationpro/MIPS-ath79-add-early_printk-support-for-AR934X.patch b/bsp/routerstationpro/MIPS-ath79-add-early_printk-support-for-AR934X.patch deleted file mode 100644 index 0d484471eaf124511a95e9233127f14d45abfa3d..0000000000000000000000000000000000000000 --- a/bsp/routerstationpro/MIPS-ath79-add-early_printk-support-for-AR934X.patch +++ /dev/null @@ -1,66 +0,0 @@ -From 3802fecde5ef3e16312b4fd4ddfb9bd9a427885b Mon Sep 17 00:00:00 2001 -From: Gabor Juhos <juhosg@openwrt.org> -Date: Wed, 14 Mar 2012 10:45:19 +0100 -Subject: [PATCH 051/123] MIPS: ath79: add early_printk support for AR934X - -commit 703327ddcc736a054f4e2c132235a8370d2f7870 upstream. - -The patch allows to see kernel messages on AR934X SoCs in -early boot stage. - -Signed-off-by: Gabor Juhos <juhosg@openwrt.org> -Acked-by: Luis R. Rodriguez <mcgrof@qca.qualcomm.com> -Cc: linux-mips@linux-mips.org -Cc: mcgrof@infradead.org -Patchwork: https://patchwork.linux-mips.org/patch/3504/ -Signed-off-by: Ralf Baechle <ralf@linux-mips.org> -Signed-off-by: Paul Gortmaker <paul.gortmaker@windriver.com> ---- - arch/mips/ath79/early_printk.c | 3 +++ - arch/mips/include/asm/mach-ath79/ar71xx_regs.h | 6 +++++- - 2 files changed, 8 insertions(+), 1 deletion(-) - -diff --git a/arch/mips/ath79/early_printk.c b/arch/mips/ath79/early_printk.c -index 6a51ced..dc938cb 100644 ---- a/arch/mips/ath79/early_printk.c -+++ b/arch/mips/ath79/early_printk.c -@@ -71,6 +71,9 @@ static void prom_putchar_init(void) - case REV_ID_MAJOR_AR7241: - case REV_ID_MAJOR_AR7242: - case REV_ID_MAJOR_AR913X: -+ case REV_ID_MAJOR_AR9341: -+ case REV_ID_MAJOR_AR9342: -+ case REV_ID_MAJOR_AR9344: - _prom_putchar = prom_putchar_ar71xx; - break; - -diff --git a/arch/mips/include/asm/mach-ath79/ar71xx_regs.h b/arch/mips/include/asm/mach-ath79/ar71xx_regs.h -index 2f0becb..b7df674 100644 ---- a/arch/mips/include/asm/mach-ath79/ar71xx_regs.h -+++ b/arch/mips/include/asm/mach-ath79/ar71xx_regs.h -@@ -1,10 +1,11 @@ - /* - * Atheros AR71XX/AR724X/AR913X SoC register definitions - * -+ * Copyright (C) 2010-2011 Jaiganesh Narayanan <jnarayanan@atheros.com> - * Copyright (C) 2008-2010 Gabor Juhos <juhosg@openwrt.org> - * Copyright (C) 2008 Imre Kaloz <kaloz@openwrt.org> - * -- * Parts of this file are based on Atheros' 2.6.15 BSP -+ * Parts of this file are based on Atheros' 2.6.15/2.6.31 BSP - * - * 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 -@@ -249,6 +250,9 @@ - #define REV_ID_MAJOR_AR7242 0x1100 - #define REV_ID_MAJOR_AR9330 0x0110 - #define REV_ID_MAJOR_AR9331 0x1110 -+#define REV_ID_MAJOR_AR9341 0x0120 -+#define REV_ID_MAJOR_AR9342 0x1120 -+#define REV_ID_MAJOR_AR9344 0x2120 - - #define AR71XX_REV_ID_MINOR_MASK 0x3 - #define AR71XX_REV_ID_MINOR_AR7130 0x0 --- -1.7.9.7 - diff --git a/bsp/routerstationpro/MIPS-ath79-add-initial-support-for-the-Atheros-DB120.patch b/bsp/routerstationpro/MIPS-ath79-add-initial-support-for-the-Atheros-DB120.patch deleted file mode 100644 index c5f4e074aa803d01e3d2c13985415cd46b94b478..0000000000000000000000000000000000000000 --- a/bsp/routerstationpro/MIPS-ath79-add-initial-support-for-the-Atheros-DB120.patch +++ /dev/null @@ -1,212 +0,0 @@ -From 325a993a7a611442509543c363cc7077bae51b02 Mon Sep 17 00:00:00 2001 -From: Gabor Juhos <juhosg@openwrt.org> -Date: Wed, 14 Mar 2012 20:39:35 +0100 -Subject: [PATCH 063/123] MIPS: ath79: add initial support for the Atheros - DB120 board - -commit 9598111f49ade848aa44f431ee81a42a000c8b3c upstream. - -Signed-off-by: Gabor Juhos <juhosg@openwrt.org> -Acked-by: Luis R. Rodriguez <mcgrof@qca.qualcomm.com> -Cc: linux-mips@linux-mips.org -Cc: mcgrof@infradead.org -Patchwork: https://patchwork.linux-mips.org/patch/3517/ -Signed-off-by: Ralf Baechle <ralf@linux-mips.org> -Signed-off-by: Paul Gortmaker <paul.gortmaker@windriver.com> ---- - arch/mips/ath79/Kconfig | 12 ++++ - arch/mips/ath79/Makefile | 1 + - arch/mips/ath79/mach-db120.c | 134 ++++++++++++++++++++++++++++++++++++++++++ - arch/mips/ath79/machtypes.h | 1 + - 4 files changed, 148 insertions(+) - create mode 100644 arch/mips/ath79/mach-db120.c - -diff --git a/arch/mips/ath79/Kconfig b/arch/mips/ath79/Kconfig -index ea28e89..f44feee 100644 ---- a/arch/mips/ath79/Kconfig -+++ b/arch/mips/ath79/Kconfig -@@ -26,6 +26,18 @@ config ATH79_MACH_AP81 - Say 'Y' here if you want your kernel to support the - Atheros AP81 reference board. - -+config ATH79_MACH_DB120 -+ bool "Atheros DB120 reference board" -+ select SOC_AR934X -+ select ATH79_DEV_GPIO_BUTTONS -+ select ATH79_DEV_LEDS_GPIO -+ select ATH79_DEV_SPI -+ select ATH79_DEV_USB -+ select ATH79_DEV_WMAC -+ help -+ Say 'Y' here if you want your kernel to support the -+ Atheros DB120 reference board. -+ - config ATH79_MACH_PB44 - bool "Atheros PB44 reference board" - select SOC_AR71XX -diff --git a/arch/mips/ath79/Makefile b/arch/mips/ath79/Makefile -index 221a76a..2b54d98 100644 ---- a/arch/mips/ath79/Makefile -+++ b/arch/mips/ath79/Makefile -@@ -28,5 +28,6 @@ obj-$(CONFIG_ATH79_DEV_WMAC) += dev-wmac.o - # - obj-$(CONFIG_ATH79_MACH_AP121) += mach-ap121.o - obj-$(CONFIG_ATH79_MACH_AP81) += mach-ap81.o -+obj-$(CONFIG_ATH79_MACH_DB120) += mach-db120.o - obj-$(CONFIG_ATH79_MACH_PB44) += mach-pb44.o - obj-$(CONFIG_ATH79_MACH_UBNT_XM) += mach-ubnt-xm.o -diff --git a/arch/mips/ath79/mach-db120.c b/arch/mips/ath79/mach-db120.c -new file mode 100644 -index 0000000..1983e4d ---- /dev/null -+++ b/arch/mips/ath79/mach-db120.c -@@ -0,0 +1,134 @@ -+/* -+ * Atheros DB120 reference board support -+ * -+ * Copyright (c) 2011 Qualcomm Atheros -+ * Copyright (c) 2011 Gabor Juhos <juhosg@openwrt.org> -+ * -+ * Permission to use, copy, modify, and/or distribute this software for any -+ * purpose with or without fee is hereby granted, provided that the above -+ * copyright notice and this permission notice appear in all copies. -+ * -+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -+ * -+ */ -+ -+#include <linux/pci.h> -+#include <linux/ath9k_platform.h> -+ -+#include "machtypes.h" -+#include "dev-gpio-buttons.h" -+#include "dev-leds-gpio.h" -+#include "dev-spi.h" -+#include "dev-wmac.h" -+#include "pci.h" -+ -+#define DB120_GPIO_LED_WLAN_5G 12 -+#define DB120_GPIO_LED_WLAN_2G 13 -+#define DB120_GPIO_LED_STATUS 14 -+#define DB120_GPIO_LED_WPS 15 -+ -+#define DB120_GPIO_BTN_WPS 16 -+ -+#define DB120_KEYS_POLL_INTERVAL 20 /* msecs */ -+#define DB120_KEYS_DEBOUNCE_INTERVAL (3 * DB120_KEYS_POLL_INTERVAL) -+ -+#define DB120_WMAC_CALDATA_OFFSET 0x1000 -+#define DB120_PCIE_CALDATA_OFFSET 0x5000 -+ -+static struct gpio_led db120_leds_gpio[] __initdata = { -+ { -+ .name = "db120:green:status", -+ .gpio = DB120_GPIO_LED_STATUS, -+ .active_low = 1, -+ }, -+ { -+ .name = "db120:green:wps", -+ .gpio = DB120_GPIO_LED_WPS, -+ .active_low = 1, -+ }, -+ { -+ .name = "db120:green:wlan-5g", -+ .gpio = DB120_GPIO_LED_WLAN_5G, -+ .active_low = 1, -+ }, -+ { -+ .name = "db120:green:wlan-2g", -+ .gpio = DB120_GPIO_LED_WLAN_2G, -+ .active_low = 1, -+ }, -+}; -+ -+static struct gpio_keys_button db120_gpio_keys[] __initdata = { -+ { -+ .desc = "WPS button", -+ .type = EV_KEY, -+ .code = KEY_WPS_BUTTON, -+ .debounce_interval = DB120_KEYS_DEBOUNCE_INTERVAL, -+ .gpio = DB120_GPIO_BTN_WPS, -+ .active_low = 1, -+ }, -+}; -+ -+static struct spi_board_info db120_spi_info[] = { -+ { -+ .bus_num = 0, -+ .chip_select = 0, -+ .max_speed_hz = 25000000, -+ .modalias = "s25sl064a", -+ } -+}; -+ -+static struct ath79_spi_platform_data db120_spi_data = { -+ .bus_num = 0, -+ .num_chipselect = 1, -+}; -+ -+#ifdef CONFIG_PCI -+static struct ath9k_platform_data db120_ath9k_data; -+ -+static int db120_pci_plat_dev_init(struct pci_dev *dev) -+{ -+ switch (PCI_SLOT(dev->devfn)) { -+ case 0: -+ dev->dev.platform_data = &db120_ath9k_data; -+ break; -+ } -+ -+ return 0; -+} -+ -+static void __init db120_pci_init(u8 *eeprom) -+{ -+ memcpy(db120_ath9k_data.eeprom_data, eeprom, -+ sizeof(db120_ath9k_data.eeprom_data)); -+ -+ ath79_pci_set_plat_dev_init(db120_pci_plat_dev_init); -+ ath79_register_pci(); -+} -+#else -+static inline void db120_pci_init(void) {} -+#endif /* CONFIG_PCI */ -+ -+static void __init db120_setup(void) -+{ -+ u8 *art = (u8 *) KSEG1ADDR(0x1fff0000); -+ -+ ath79_register_leds_gpio(-1, ARRAY_SIZE(db120_leds_gpio), -+ db120_leds_gpio); -+ ath79_register_gpio_keys_polled(-1, DB120_KEYS_POLL_INTERVAL, -+ ARRAY_SIZE(db120_gpio_keys), -+ db120_gpio_keys); -+ ath79_register_spi(&db120_spi_data, db120_spi_info, -+ ARRAY_SIZE(db120_spi_info)); -+ ath79_register_wmac(art + DB120_WMAC_CALDATA_OFFSET); -+ db120_pci_init(art + DB120_PCIE_CALDATA_OFFSET); -+} -+ -+MIPS_MACHINE(ATH79_MACH_DB120, "DB120", "Atheros DB120 reference board", -+ db120_setup); -diff --git a/arch/mips/ath79/machtypes.h b/arch/mips/ath79/machtypes.h -index 9a1f382..af92e5c 100644 ---- a/arch/mips/ath79/machtypes.h -+++ b/arch/mips/ath79/machtypes.h -@@ -18,6 +18,7 @@ enum ath79_mach_type { - ATH79_MACH_GENERIC = 0, - ATH79_MACH_AP121, /* Atheros AP121 reference board */ - ATH79_MACH_AP81, /* Atheros AP81 reference board */ -+ ATH79_MACH_DB120, /* Atheros DB120 reference board */ - ATH79_MACH_PB44, /* Atheros PB44 reference board */ - ATH79_MACH_UBNT_XM, /* Ubiquiti Networks XM board rev 1.0 */ - }; --- -1.7.9.7 - diff --git a/bsp/routerstationpro/MIPS-ath79-add-support-for-the-PCI-host-controller-o.patch b/bsp/routerstationpro/MIPS-ath79-add-support-for-the-PCI-host-controller-o.patch deleted file mode 100644 index 2b7d54c511b84cc6eae833f2dd45c0179a6c73b8..0000000000000000000000000000000000000000 --- a/bsp/routerstationpro/MIPS-ath79-add-support-for-the-PCI-host-controller-o.patch +++ /dev/null @@ -1,452 +0,0 @@ -From c24ea8439eef5b7e0f7c74d76472e0f7025fa0a9 Mon Sep 17 00:00:00 2001 -From: Gabor Juhos <juhosg@openwrt.org> -Date: Wed, 14 Mar 2012 10:36:10 +0100 -Subject: [PATCH 046/123] MIPS: ath79: add support for the PCI host controller - of the AR71XX SoCs - -commit f8365ec4e1b945f70a86e9514dd67ba5f9f2915b upstream. - -The Atheros AR71XX SoCs have a built-in PCI Host Controller. -This patch adds a driver for that, and modifies the relevant -files in order to allow to register the PCI controller from -board specific setup. - -Signed-off-by: Gabor Juhos <juhosg@openwrt.org> -Signed-off-by: Imre Kaloz <kaloz@openwrt.org> -Cc: linux-mips@linux-mips.org -Patchwork: https://patchwork.linux-mips.org/patch/3498/ -Signed-off-by: Ralf Baechle <ralf@linux-mips.org> -Signed-off-by: Paul Gortmaker <paul.gortmaker@windriver.com> ---- - arch/mips/ath79/Kconfig | 1 + - arch/mips/include/asm/mach-ath79/pci.h | 6 + - arch/mips/pci/Makefile | 1 + - arch/mips/pci/pci-ar71xx.c | 375 ++++++++++++++++++++++++++++++++ - 4 files changed, 383 insertions(+) - create mode 100644 arch/mips/pci/pci-ar71xx.c - -diff --git a/arch/mips/ath79/Kconfig b/arch/mips/ath79/Kconfig -index e0fae8f..bc6edad 100644 ---- a/arch/mips/ath79/Kconfig -+++ b/arch/mips/ath79/Kconfig -@@ -52,6 +52,7 @@ endmenu - config SOC_AR71XX - select USB_ARCH_HAS_EHCI - select USB_ARCH_HAS_OHCI -+ select HW_HAS_PCI - def_bool n - - config SOC_AR724X -diff --git a/arch/mips/include/asm/mach-ath79/pci.h b/arch/mips/include/asm/mach-ath79/pci.h -index 2eb0181..b12b087 100644 ---- a/arch/mips/include/asm/mach-ath79/pci.h -+++ b/arch/mips/include/asm/mach-ath79/pci.h -@@ -11,6 +11,12 @@ - #ifndef __ASM_MACH_ATH79_PCI_H - #define __ASM_MACH_ATH79_PCI_H - -+#if defined(CONFIG_PCI) && defined(CONFIG_SOC_AR71XX) -+int ar71xx_pcibios_init(void); -+#else -+static inline int ar71xx_pcibios_init(void) { return 0; } -+#endif -+ - #if defined(CONFIG_PCI) && defined(CONFIG_SOC_AR724X) - int ar724x_pcibios_init(int irq); - #else -diff --git a/arch/mips/pci/Makefile b/arch/mips/pci/Makefile -index 172277c..b1c0a1c 100644 ---- a/arch/mips/pci/Makefile -+++ b/arch/mips/pci/Makefile -@@ -19,6 +19,7 @@ obj-$(CONFIG_BCM47XX) += pci-bcm47xx.o - obj-$(CONFIG_BCM63XX) += pci-bcm63xx.o fixup-bcm63xx.o \ - ops-bcm63xx.o - obj-$(CONFIG_MIPS_ALCHEMY) += pci-alchemy.o -+obj-$(CONFIG_SOC_AR71XX) += pci-ar71xx.o - obj-$(CONFIG_SOC_AR724X) += pci-ar724x.o - - # -diff --git a/arch/mips/pci/pci-ar71xx.c b/arch/mips/pci/pci-ar71xx.c -new file mode 100644 -index 0000000..1552522 ---- /dev/null -+++ b/arch/mips/pci/pci-ar71xx.c -@@ -0,0 +1,375 @@ -+/* -+ * Atheros AR71xx PCI host controller driver -+ * -+ * Copyright (C) 2008-2011 Gabor Juhos <juhosg@openwrt.org> -+ * Copyright (C) 2008 Imre Kaloz <kaloz@openwrt.org> -+ * -+ * Parts of this file are based on Atheros' 2.6.15 BSP -+ * -+ * This program is free software; you can redistribute it and/or modify it -+ * under the terms of the GNU General Public License version 2 as published -+ * by the Free Software Foundation. -+ */ -+ -+#include <linux/resource.h> -+#include <linux/types.h> -+#include <linux/delay.h> -+#include <linux/bitops.h> -+#include <linux/pci.h> -+#include <linux/pci_regs.h> -+#include <linux/interrupt.h> -+ -+#include <asm/mach-ath79/ar71xx_regs.h> -+#include <asm/mach-ath79/ath79.h> -+#include <asm/mach-ath79/pci.h> -+ -+#define AR71XX_PCI_MEM_BASE 0x10000000 -+#define AR71XX_PCI_MEM_SIZE 0x08000000 -+ -+#define AR71XX_PCI_WIN0_OFFS 0x10000000 -+#define AR71XX_PCI_WIN1_OFFS 0x11000000 -+#define AR71XX_PCI_WIN2_OFFS 0x12000000 -+#define AR71XX_PCI_WIN3_OFFS 0x13000000 -+#define AR71XX_PCI_WIN4_OFFS 0x14000000 -+#define AR71XX_PCI_WIN5_OFFS 0x15000000 -+#define AR71XX_PCI_WIN6_OFFS 0x16000000 -+#define AR71XX_PCI_WIN7_OFFS 0x07000000 -+ -+#define AR71XX_PCI_CFG_BASE \ -+ (AR71XX_PCI_MEM_BASE + AR71XX_PCI_WIN7_OFFS + 0x10000) -+#define AR71XX_PCI_CFG_SIZE 0x100 -+ -+#define AR71XX_PCI_REG_CRP_AD_CBE 0x00 -+#define AR71XX_PCI_REG_CRP_WRDATA 0x04 -+#define AR71XX_PCI_REG_CRP_RDDATA 0x08 -+#define AR71XX_PCI_REG_CFG_AD 0x0c -+#define AR71XX_PCI_REG_CFG_CBE 0x10 -+#define AR71XX_PCI_REG_CFG_WRDATA 0x14 -+#define AR71XX_PCI_REG_CFG_RDDATA 0x18 -+#define AR71XX_PCI_REG_PCI_ERR 0x1c -+#define AR71XX_PCI_REG_PCI_ERR_ADDR 0x20 -+#define AR71XX_PCI_REG_AHB_ERR 0x24 -+#define AR71XX_PCI_REG_AHB_ERR_ADDR 0x28 -+ -+#define AR71XX_PCI_CRP_CMD_WRITE 0x00010000 -+#define AR71XX_PCI_CRP_CMD_READ 0x00000000 -+#define AR71XX_PCI_CFG_CMD_READ 0x0000000a -+#define AR71XX_PCI_CFG_CMD_WRITE 0x0000000b -+ -+#define AR71XX_PCI_INT_CORE BIT(4) -+#define AR71XX_PCI_INT_DEV2 BIT(2) -+#define AR71XX_PCI_INT_DEV1 BIT(1) -+#define AR71XX_PCI_INT_DEV0 BIT(0) -+ -+#define AR71XX_PCI_IRQ_COUNT 5 -+ -+static DEFINE_SPINLOCK(ar71xx_pci_lock); -+static void __iomem *ar71xx_pcicfg_base; -+ -+/* Byte lane enable bits */ -+static const u8 ar71xx_pci_ble_table[4][4] = { -+ {0x0, 0xf, 0xf, 0xf}, -+ {0xe, 0xd, 0xb, 0x7}, -+ {0xc, 0xf, 0x3, 0xf}, -+ {0xf, 0xf, 0xf, 0xf}, -+}; -+ -+static const u32 ar71xx_pci_read_mask[8] = { -+ 0, 0xff, 0xffff, 0, 0xffffffff, 0, 0, 0 -+}; -+ -+static inline u32 ar71xx_pci_get_ble(int where, int size, int local) -+{ -+ u32 t; -+ -+ t = ar71xx_pci_ble_table[size & 3][where & 3]; -+ BUG_ON(t == 0xf); -+ t <<= (local) ? 20 : 4; -+ -+ return t; -+} -+ -+static inline u32 ar71xx_pci_bus_addr(struct pci_bus *bus, unsigned int devfn, -+ int where) -+{ -+ u32 ret; -+ -+ if (!bus->number) { -+ /* type 0 */ -+ ret = (1 << PCI_SLOT(devfn)) | (PCI_FUNC(devfn) << 8) | -+ (where & ~3); -+ } else { -+ /* type 1 */ -+ ret = (bus->number << 16) | (PCI_SLOT(devfn) << 11) | -+ (PCI_FUNC(devfn) << 8) | (where & ~3) | 1; -+ } -+ -+ return ret; -+} -+ -+static int ar71xx_pci_check_error(int quiet) -+{ -+ void __iomem *base = ar71xx_pcicfg_base; -+ u32 pci_err; -+ u32 ahb_err; -+ -+ pci_err = __raw_readl(base + AR71XX_PCI_REG_PCI_ERR) & 3; -+ if (pci_err) { -+ if (!quiet) { -+ u32 addr; -+ -+ addr = __raw_readl(base + AR71XX_PCI_REG_PCI_ERR_ADDR); -+ pr_crit("ar71xx: %s bus error %d at addr 0x%x\n", -+ "PCI", pci_err, addr); -+ } -+ -+ /* clear PCI error status */ -+ __raw_writel(pci_err, base + AR71XX_PCI_REG_PCI_ERR); -+ } -+ -+ ahb_err = __raw_readl(base + AR71XX_PCI_REG_AHB_ERR) & 1; -+ if (ahb_err) { -+ if (!quiet) { -+ u32 addr; -+ -+ addr = __raw_readl(base + AR71XX_PCI_REG_AHB_ERR_ADDR); -+ pr_crit("ar71xx: %s bus error %d at addr 0x%x\n", -+ "AHB", ahb_err, addr); -+ } -+ -+ /* clear AHB error status */ -+ __raw_writel(ahb_err, base + AR71XX_PCI_REG_AHB_ERR); -+ } -+ -+ return !!(ahb_err | pci_err); -+} -+ -+static inline void ar71xx_pci_local_write(int where, int size, u32 value) -+{ -+ void __iomem *base = ar71xx_pcicfg_base; -+ u32 ad_cbe; -+ -+ value = value << (8 * (where & 3)); -+ -+ ad_cbe = AR71XX_PCI_CRP_CMD_WRITE | (where & ~3); -+ ad_cbe |= ar71xx_pci_get_ble(where, size, 1); -+ -+ __raw_writel(ad_cbe, base + AR71XX_PCI_REG_CRP_AD_CBE); -+ __raw_writel(value, base + AR71XX_PCI_REG_CRP_WRDATA); -+} -+ -+static inline int ar71xx_pci_set_cfgaddr(struct pci_bus *bus, -+ unsigned int devfn, -+ int where, int size, u32 cmd) -+{ -+ void __iomem *base = ar71xx_pcicfg_base; -+ u32 addr; -+ -+ addr = ar71xx_pci_bus_addr(bus, devfn, where); -+ -+ __raw_writel(addr, base + AR71XX_PCI_REG_CFG_AD); -+ __raw_writel(cmd | ar71xx_pci_get_ble(where, size, 0), -+ base + AR71XX_PCI_REG_CFG_CBE); -+ -+ return ar71xx_pci_check_error(1); -+} -+ -+static int ar71xx_pci_read_config(struct pci_bus *bus, unsigned int devfn, -+ int where, int size, u32 *value) -+{ -+ void __iomem *base = ar71xx_pcicfg_base; -+ unsigned long flags; -+ u32 data; -+ int err; -+ int ret; -+ -+ ret = PCIBIOS_SUCCESSFUL; -+ data = ~0; -+ -+ spin_lock_irqsave(&ar71xx_pci_lock, flags); -+ -+ err = ar71xx_pci_set_cfgaddr(bus, devfn, where, size, -+ AR71XX_PCI_CFG_CMD_READ); -+ if (err) -+ ret = PCIBIOS_DEVICE_NOT_FOUND; -+ else -+ data = __raw_readl(base + AR71XX_PCI_REG_CFG_RDDATA); -+ -+ spin_unlock_irqrestore(&ar71xx_pci_lock, flags); -+ -+ *value = (data >> (8 * (where & 3))) & ar71xx_pci_read_mask[size & 7]; -+ -+ return ret; -+} -+ -+static int ar71xx_pci_write_config(struct pci_bus *bus, unsigned int devfn, -+ int where, int size, u32 value) -+{ -+ void __iomem *base = ar71xx_pcicfg_base; -+ unsigned long flags; -+ int err; -+ int ret; -+ -+ value = value << (8 * (where & 3)); -+ ret = PCIBIOS_SUCCESSFUL; -+ -+ spin_lock_irqsave(&ar71xx_pci_lock, flags); -+ -+ err = ar71xx_pci_set_cfgaddr(bus, devfn, where, size, -+ AR71XX_PCI_CFG_CMD_WRITE); -+ if (err) -+ ret = PCIBIOS_DEVICE_NOT_FOUND; -+ else -+ __raw_writel(value, base + AR71XX_PCI_REG_CFG_WRDATA); -+ -+ spin_unlock_irqrestore(&ar71xx_pci_lock, flags); -+ -+ return ret; -+} -+ -+static struct pci_ops ar71xx_pci_ops = { -+ .read = ar71xx_pci_read_config, -+ .write = ar71xx_pci_write_config, -+}; -+ -+static struct resource ar71xx_pci_io_resource = { -+ .name = "PCI IO space", -+ .start = 0, -+ .end = 0, -+ .flags = IORESOURCE_IO, -+}; -+ -+static struct resource ar71xx_pci_mem_resource = { -+ .name = "PCI memory space", -+ .start = AR71XX_PCI_MEM_BASE, -+ .end = AR71XX_PCI_MEM_BASE + AR71XX_PCI_MEM_SIZE - 1, -+ .flags = IORESOURCE_MEM -+}; -+ -+static struct pci_controller ar71xx_pci_controller = { -+ .pci_ops = &ar71xx_pci_ops, -+ .mem_resource = &ar71xx_pci_mem_resource, -+ .io_resource = &ar71xx_pci_io_resource, -+}; -+ -+static void ar71xx_pci_irq_handler(unsigned int irq, struct irq_desc *desc) -+{ -+ void __iomem *base = ath79_reset_base; -+ u32 pending; -+ -+ pending = __raw_readl(base + AR71XX_RESET_REG_PCI_INT_STATUS) & -+ __raw_readl(base + AR71XX_RESET_REG_PCI_INT_ENABLE); -+ -+ if (pending & AR71XX_PCI_INT_DEV0) -+ generic_handle_irq(ATH79_PCI_IRQ(0)); -+ -+ else if (pending & AR71XX_PCI_INT_DEV1) -+ generic_handle_irq(ATH79_PCI_IRQ(1)); -+ -+ else if (pending & AR71XX_PCI_INT_DEV2) -+ generic_handle_irq(ATH79_PCI_IRQ(2)); -+ -+ else if (pending & AR71XX_PCI_INT_CORE) -+ generic_handle_irq(ATH79_PCI_IRQ(4)); -+ -+ else -+ spurious_interrupt(); -+} -+ -+static void ar71xx_pci_irq_unmask(struct irq_data *d) -+{ -+ unsigned int irq = d->irq - ATH79_PCI_IRQ_BASE; -+ void __iomem *base = ath79_reset_base; -+ u32 t; -+ -+ t = __raw_readl(base + AR71XX_RESET_REG_PCI_INT_ENABLE); -+ __raw_writel(t | (1 << irq), base + AR71XX_RESET_REG_PCI_INT_ENABLE); -+ -+ /* flush write */ -+ __raw_readl(base + AR71XX_RESET_REG_PCI_INT_ENABLE); -+} -+ -+static void ar71xx_pci_irq_mask(struct irq_data *d) -+{ -+ unsigned int irq = d->irq - ATH79_PCI_IRQ_BASE; -+ void __iomem *base = ath79_reset_base; -+ u32 t; -+ -+ t = __raw_readl(base + AR71XX_RESET_REG_PCI_INT_ENABLE); -+ __raw_writel(t & ~(1 << irq), base + AR71XX_RESET_REG_PCI_INT_ENABLE); -+ -+ /* flush write */ -+ __raw_readl(base + AR71XX_RESET_REG_PCI_INT_ENABLE); -+} -+ -+static struct irq_chip ar71xx_pci_irq_chip = { -+ .name = "AR71XX PCI", -+ .irq_mask = ar71xx_pci_irq_mask, -+ .irq_unmask = ar71xx_pci_irq_unmask, -+ .irq_mask_ack = ar71xx_pci_irq_mask, -+}; -+ -+static __init void ar71xx_pci_irq_init(void) -+{ -+ void __iomem *base = ath79_reset_base; -+ int i; -+ -+ __raw_writel(0, base + AR71XX_RESET_REG_PCI_INT_ENABLE); -+ __raw_writel(0, base + AR71XX_RESET_REG_PCI_INT_STATUS); -+ -+ BUILD_BUG_ON(ATH79_PCI_IRQ_COUNT < AR71XX_PCI_IRQ_COUNT); -+ -+ for (i = ATH79_PCI_IRQ_BASE; -+ i < ATH79_PCI_IRQ_BASE + AR71XX_PCI_IRQ_COUNT; i++) -+ irq_set_chip_and_handler(i, &ar71xx_pci_irq_chip, -+ handle_level_irq); -+ -+ irq_set_chained_handler(ATH79_CPU_IRQ_IP2, ar71xx_pci_irq_handler); -+} -+ -+static __init void ar71xx_pci_reset(void) -+{ -+ void __iomem *ddr_base = ath79_ddr_base; -+ -+ ath79_device_reset_set(AR71XX_RESET_PCI_BUS | AR71XX_RESET_PCI_CORE); -+ mdelay(100); -+ -+ ath79_device_reset_clear(AR71XX_RESET_PCI_BUS | AR71XX_RESET_PCI_CORE); -+ mdelay(100); -+ -+ __raw_writel(AR71XX_PCI_WIN0_OFFS, ddr_base + AR71XX_DDR_REG_PCI_WIN0); -+ __raw_writel(AR71XX_PCI_WIN1_OFFS, ddr_base + AR71XX_DDR_REG_PCI_WIN1); -+ __raw_writel(AR71XX_PCI_WIN2_OFFS, ddr_base + AR71XX_DDR_REG_PCI_WIN2); -+ __raw_writel(AR71XX_PCI_WIN3_OFFS, ddr_base + AR71XX_DDR_REG_PCI_WIN3); -+ __raw_writel(AR71XX_PCI_WIN4_OFFS, ddr_base + AR71XX_DDR_REG_PCI_WIN4); -+ __raw_writel(AR71XX_PCI_WIN5_OFFS, ddr_base + AR71XX_DDR_REG_PCI_WIN5); -+ __raw_writel(AR71XX_PCI_WIN6_OFFS, ddr_base + AR71XX_DDR_REG_PCI_WIN6); -+ __raw_writel(AR71XX_PCI_WIN7_OFFS, ddr_base + AR71XX_DDR_REG_PCI_WIN7); -+ -+ mdelay(100); -+} -+ -+__init int ar71xx_pcibios_init(void) -+{ -+ u32 t; -+ -+ ar71xx_pcicfg_base = ioremap(AR71XX_PCI_CFG_BASE, AR71XX_PCI_CFG_SIZE); -+ if (ar71xx_pcicfg_base == NULL) -+ return -ENOMEM; -+ -+ ar71xx_pci_reset(); -+ -+ /* setup COMMAND register */ -+ t = PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER | PCI_COMMAND_INVALIDATE -+ | PCI_COMMAND_PARITY | PCI_COMMAND_SERR | PCI_COMMAND_FAST_BACK; -+ ar71xx_pci_local_write(PCI_COMMAND, 4, t); -+ -+ /* clear bus errors */ -+ ar71xx_pci_check_error(1); -+ -+ ar71xx_pci_irq_init(); -+ -+ register_pci_controller(&ar71xx_pci_controller); -+ -+ return 0; -+} --- -1.7.9.7 - diff --git a/bsp/routerstationpro/MIPS-ath79-allow-to-use-SoC-specific-PCI-IRQ-maps.patch b/bsp/routerstationpro/MIPS-ath79-allow-to-use-SoC-specific-PCI-IRQ-maps.patch deleted file mode 100644 index 07c595685c94f2bc885d2fa122514156dd60f56a..0000000000000000000000000000000000000000 --- a/bsp/routerstationpro/MIPS-ath79-allow-to-use-SoC-specific-PCI-IRQ-maps.patch +++ /dev/null @@ -1,174 +0,0 @@ -From b68f1f900f397be079c2d6c3c0b42595d7b2c8c5 Mon Sep 17 00:00:00 2001 -From: Gabor Juhos <juhosg@openwrt.org> -Date: Wed, 14 Mar 2012 10:36:11 +0100 -Subject: [PATCH 047/123] MIPS: ath79: allow to use SoC specific PCI IRQ maps - -commit d22ce25f870dff2521d352e20d0fd2a7598fbf87 upstream. - -The PCI controllers in the AR71XX and in the -AR724X SoCs are different, and both of them -uses different IRQ wiring. - -The patch modifies the 'pcibios_map_irq' function -in order to allow to use different IRQ maps for -the different SoCs. The patch also adds a function, -which lets the board setup code to override the -default IRQ map. - -Signed-off-by: Gabor Juhos <juhosg@openwrt.org> -Cc: linux-mips@linux-mips.org -Patchwork: https://patchwork.linux-mips.org/patch/3500/ -Signed-off-by: Ralf Baechle <ralf@linux-mips.org> -Signed-off-by: Paul Gortmaker <paul.gortmaker@windriver.com> ---- - arch/mips/ath79/pci.c | 72 ++++++++++++++++++++++++++++++++++++++++++++++--- - arch/mips/ath79/pci.h | 9 +++++++ - 2 files changed, 77 insertions(+), 4 deletions(-) - -diff --git a/arch/mips/ath79/pci.c b/arch/mips/ath79/pci.c -index 2b4c730..365a8b6 100644 ---- a/arch/mips/ath79/pci.c -+++ b/arch/mips/ath79/pci.c -@@ -8,6 +8,7 @@ - * by the Free Software Foundation. - */ - -+#include <linux/init.h> - #include <linux/pci.h> - #include <asm/mach-ath79/ath79.h> - #include <asm/mach-ath79/irq.h> -@@ -15,9 +16,35 @@ - #include "pci.h" - - static int (*ath79_pci_plat_dev_init)(struct pci_dev *dev); -+static const struct ath79_pci_irq *ath79_pci_irq_map __initdata; -+static unsigned ath79_pci_nr_irqs __initdata; - static struct ar724x_pci_data *pci_data; - static int pci_data_size; - -+static const struct ath79_pci_irq ar71xx_pci_irq_map[] __initconst = { -+ { -+ .slot = 17, -+ .pin = 1, -+ .irq = ATH79_PCI_IRQ(0), -+ }, { -+ .slot = 18, -+ .pin = 1, -+ .irq = ATH79_PCI_IRQ(1), -+ }, { -+ .slot = 19, -+ .pin = 1, -+ .irq = ATH79_PCI_IRQ(2), -+ } -+}; -+ -+static const struct ath79_pci_irq ar724x_pci_irq_map[] __initconst = { -+ { -+ .slot = 0, -+ .pin = 1, -+ .irq = ATH79_PCI_IRQ(0), -+ } -+}; -+ - void ar724x_pci_add_data(struct ar724x_pci_data *data, int size) - { - pci_data = data; -@@ -26,13 +53,40 @@ void ar724x_pci_add_data(struct ar724x_pci_data *data, int size) - - int __init pcibios_map_irq(const struct pci_dev *dev, uint8_t slot, uint8_t pin) - { -- unsigned int devfn = dev->devfn; - int irq = -1; -+ int i; -+ -+ if (ath79_pci_nr_irqs == 0 || -+ ath79_pci_irq_map == NULL) { -+ if (soc_is_ar71xx()) { -+ ath79_pci_irq_map = ar71xx_pci_irq_map; -+ ath79_pci_nr_irqs = ARRAY_SIZE(ar71xx_pci_irq_map); -+ } else if (soc_is_ar724x()) { -+ ath79_pci_irq_map = ar724x_pci_irq_map; -+ ath79_pci_nr_irqs = ARRAY_SIZE(ar724x_pci_irq_map); -+ } else { -+ pr_crit("pci %s: invalid irq map\n", -+ pci_name((struct pci_dev *) dev)); -+ return irq; -+ } -+ } -+ -+ for (i = 0; i < ath79_pci_nr_irqs; i++) { -+ const struct ath79_pci_irq *entry; - -- if (devfn > pci_data_size - 1) -- return irq; -+ entry = &ath79_pci_irq_map[i]; -+ if (entry->slot == slot && entry->pin == pin) { -+ irq = entry->irq; -+ break; -+ } -+ } - -- irq = pci_data[devfn].irq; -+ if (irq < 0) -+ pr_crit("pci %s: no irq found for pin %u\n", -+ pci_name((struct pci_dev *) dev), pin); -+ else -+ pr_info("pci %s: using irq %d for pin %u\n", -+ pci_name((struct pci_dev *) dev), irq, pin); - - return irq; - } -@@ -45,6 +99,13 @@ int pcibios_plat_dev_init(struct pci_dev *dev) - return 0; - } - -+void __init ath79_pci_set_irq_map(unsigned nr_irqs, -+ const struct ath79_pci_irq *map) -+{ -+ ath79_pci_nr_irqs = nr_irqs; -+ ath79_pci_irq_map = map; -+} -+ - void __init ath79_pci_set_plat_dev_init(int (*func)(struct pci_dev *dev)) - { - ath79_pci_plat_dev_init = func; -@@ -52,6 +113,9 @@ void __init ath79_pci_set_plat_dev_init(int (*func)(struct pci_dev *dev)) - - int __init ath79_register_pci(void) - { -+ if (soc_is_ar71xx()) -+ return ar71xx_pcibios_init(); -+ - if (soc_is_ar724x()) - return ar724x_pcibios_init(ATH79_CPU_IRQ_IP2); - -diff --git a/arch/mips/ath79/pci.h b/arch/mips/ath79/pci.h -index de30e15..a5c4e58 100644 ---- a/arch/mips/ath79/pci.h -+++ b/arch/mips/ath79/pci.h -@@ -15,13 +15,22 @@ struct ar724x_pci_data { - int irq; - }; - -+struct ath79_pci_irq { -+ u8 slot; -+ u8 pin; -+ int irq; -+}; -+ - void ar724x_pci_add_data(struct ar724x_pci_data *data, int size); - - #ifdef CONFIG_PCI -+void ath79_pci_set_irq_map(unsigned nr_irqs, const struct ath79_pci_irq *map); - void ath79_pci_set_plat_dev_init(int (*func)(struct pci_dev *dev)); - int ath79_register_pci(void); - #else - static inline void -+ath79_pci_set_irq_map(unsigned nr_irqs, const struct ath79_pci_irq *map) {} -+static inline void - ath79_pci_set_plat_dev_init(int (*func)(struct pci_dev *)) {} - static inline int ath79_register_pci(void) { return 0; } - #endif --- -1.7.9.7 - diff --git a/bsp/routerstationpro/MIPS-ath79-allow-to-use-board-specific-pci_plat_dev_.patch b/bsp/routerstationpro/MIPS-ath79-allow-to-use-board-specific-pci_plat_dev_.patch deleted file mode 100644 index dee885cdbb5ab4584dc7136c561147e905c0aa15..0000000000000000000000000000000000000000 --- a/bsp/routerstationpro/MIPS-ath79-allow-to-use-board-specific-pci_plat_dev_.patch +++ /dev/null @@ -1,154 +0,0 @@ -From 9b85ac356af33b18d70fc7417e94178b77a744cb Mon Sep 17 00:00:00 2001 -From: Gabor Juhos <juhosg@openwrt.org> -Date: Wed, 14 Mar 2012 10:36:09 +0100 -Subject: [PATCH 045/123] MIPS: ath79: allow to use board specific - pci_plat_dev_init functions - -commit f8365ec4e1b945f70a86e9514dd67ba5f9f2915b upstream. - -Th current implementation causes NULL pointer dereference -if 'pci_data' is not set: - -pci 0000:00:00.0: BAR 0: assigned [mem 0x10000000-0x1000ffff 64bit] -pci 0000:00:00.0: BAR 0: set to [mem 0x10000000-0x1000ffff 64bit] (PCI -address [0x10000000-0x1000ffff]) -CPU 0 Unable to handle kernel paging request at virtual address 00000000, epc == 802daca0, ra == 802e78a4 -Oops[#1]: -Cpu 0 -$ 0 : 00000000 80420000 00000000 00000000 -$ 4 : 00000000 00000000 00000001 00000001 -$ 8 : 00000001 0000032c 81c54700 00000001 -$12 : 0000032d 0000000f 00000000 ffffffff -$16 : 81c14c00 00000001 802dac74 80195f98 -$20 : 802ea050 00000000 00000000 00000000 -$24 : 00000003 800617f0 -$28 : 81c20000 81c21e70 00000000 802e78a4 -Hi : 00000000 -Lo : 4190ab00 -epc : 802daca0 0x802daca0 - Not tainted -ra : 802e78a4 0x802e78a4 -Status: 1000c003 KERNEL EXL IE -Cause : 00800008 -BadVA : 00000000 -PrId : 00019374 (MIPS 24Kc) -Modules linked in: -Process swapper (pid: 1, threadinfo=81c20000, task=81c18000, tls=00000000) -Stack : 00000000 8027d5d8 802e8ae0 00000000 01000000 802e8b5c 81c50600 00000000 - 802ff290 00000000 80420000 802ea0bc 00000000 00000000 80420000 802ff290 - 80420000 80060930 33390000 00000000 00002308 80140a80 00000028 802d0000 - 00000000 800ba024 802ff004 802ff0c8 802ff290 00000000 00000000 00000000 - 00000000 802d897c 01234567 7f827068 00000000 0045f798 00460000 00000000 - -This can be avoided by calling the 'ar724x_pci_add_data' -function from the board specific setup code. However it -makes no sense to use that function for every board, -especially when the board does not needs to set the -platform_data field of any PCI device. - -The patch allows the board setup code to specify a board -specific function if that is required. - -Signed-off-by: Gabor Juhos <juhosg@openwrt.org> -Cc: linux-mips@linux-mips.org -Patchwork: https://patchwork.linux-mips.org/patch/3499/ -Signed-off-by: Ralf Baechle <ralf@linux-mips.org> -Signed-off-by: Paul Gortmaker <paul.gortmaker@windriver.com> ---- - arch/mips/ath79/mach-ubnt-xm.c | 13 ++++++++++++- - arch/mips/ath79/pci.c | 14 ++++++++------ - arch/mips/ath79/pci.h | 4 +++- - 3 files changed, 23 insertions(+), 8 deletions(-) - -diff --git a/arch/mips/ath79/mach-ubnt-xm.c b/arch/mips/ath79/mach-ubnt-xm.c -index 1e6b986..ca47ba5 100644 ---- a/arch/mips/ath79/mach-ubnt-xm.c -+++ b/arch/mips/ath79/mach-ubnt-xm.c -@@ -85,16 +85,27 @@ static struct ath9k_platform_data ubnt_xm_eeprom_data; - static struct ar724x_pci_data ubnt_xm_pci_data[] = { - { - .irq = ATH79_PCI_IRQ(0), -- .pdata = &ubnt_xm_eeprom_data, - }, - }; - -+static int ubnt_xm_pci_plat_dev_init(struct pci_dev *dev) -+{ -+ switch (PCI_SLOT(dev->devfn)) { -+ case 0: -+ dev->dev.platform_data = &ubnt_xm_eeprom_data; -+ break; -+ } -+ -+ return 0; -+} -+ - static void __init ubnt_xm_pci_init(void) - { - memcpy(ubnt_xm_eeprom_data.eeprom_data, UBNT_XM_EEPROM_ADDR, - sizeof(ubnt_xm_eeprom_data.eeprom_data)); - - ar724x_pci_add_data(ubnt_xm_pci_data, ARRAY_SIZE(ubnt_xm_pci_data)); -+ ath79_pci_set_plat_dev_init(ubnt_xm_pci_plat_dev_init); - ath79_register_pci(); - } - #else -diff --git a/arch/mips/ath79/pci.c b/arch/mips/ath79/pci.c -index 14f981c2..2b4c730 100644 ---- a/arch/mips/ath79/pci.c -+++ b/arch/mips/ath79/pci.c -@@ -14,6 +14,7 @@ - #include <asm/mach-ath79/pci.h> - #include "pci.h" - -+static int (*ath79_pci_plat_dev_init)(struct pci_dev *dev); - static struct ar724x_pci_data *pci_data; - static int pci_data_size; - -@@ -38,14 +39,15 @@ int __init pcibios_map_irq(const struct pci_dev *dev, uint8_t slot, uint8_t pin) - - int pcibios_plat_dev_init(struct pci_dev *dev) - { -- unsigned int devfn = dev->devfn; -- -- if (devfn > pci_data_size - 1) -- return PCIBIOS_DEVICE_NOT_FOUND; -+ if (ath79_pci_plat_dev_init) -+ return ath79_pci_plat_dev_init(dev); - -- dev->dev.platform_data = pci_data[devfn].pdata; -+ return 0; -+} - -- return PCIBIOS_SUCCESSFUL; -+void __init ath79_pci_set_plat_dev_init(int (*func)(struct pci_dev *dev)) -+{ -+ ath79_pci_plat_dev_init = func; - } - - int __init ath79_register_pci(void) -diff --git a/arch/mips/ath79/pci.h b/arch/mips/ath79/pci.h -index e0601c4..de30e15 100644 ---- a/arch/mips/ath79/pci.h -+++ b/arch/mips/ath79/pci.h -@@ -13,14 +13,16 @@ - - struct ar724x_pci_data { - int irq; -- void *pdata; - }; - - void ar724x_pci_add_data(struct ar724x_pci_data *data, int size); - - #ifdef CONFIG_PCI -+void ath79_pci_set_plat_dev_init(int (*func)(struct pci_dev *dev)); - int ath79_register_pci(void); - #else -+static inline void -+ath79_pci_set_plat_dev_init(int (*func)(struct pci_dev *)) {} - static inline int ath79_register_pci(void) { return 0; } - #endif - --- -1.7.9.7 - diff --git a/bsp/routerstationpro/MIPS-ath79-fix-a-wrong-IRQ-number.patch b/bsp/routerstationpro/MIPS-ath79-fix-a-wrong-IRQ-number.patch deleted file mode 100644 index e6e9b64518c26a3f6f5e3c7fecc443c5b56086b0..0000000000000000000000000000000000000000 --- a/bsp/routerstationpro/MIPS-ath79-fix-a-wrong-IRQ-number.patch +++ /dev/null @@ -1,83 +0,0 @@ -From 17f083f3d3500e02010b9168ed842936a70c9ad9 Mon Sep 17 00:00:00 2001 -From: Gabor Juhos <juhosg@openwrt.org> -Date: Wed, 14 Mar 2012 10:36:06 +0100 -Subject: [PATCH 042/123] MIPS: ath79: fix a wrong IRQ number - -commit 93ef85b5598ad2cc23f38d97ed565027b969c0aa upstream - -The Ubiquiti XM board setup code uses an invalid -IRQ number, because it if above of NR_IRQS. This -leads to failed 'request_irq' calls: - - ath9k 0000:00:00.0: request_irq failed - ath9k: probe of 0000:00:00.0 failed with error -22 - -Preserve some IRQ numbers for the built-in IRQ -controller of PCI host controllers in the -AR71XX/AR724X SoCs, and use the correct IRQ -number in the board setup code. - -Signed-off-by: Gabor Juhos <juhosg@openwrt.org> -Cc: linux-mips@linux-mips.org -Patchwork: https://patchwork.linux-mips.org/patch/3495/ -Signed-off-by: Ralf Baechle <ralf@linux-mips.org> -Signed-off-by: Paul Gortmaker <paul.gortmaker@windriver.com> ---- - arch/mips/ath79/mach-ubnt-xm.c | 5 +++-- - arch/mips/include/asm/mach-ath79/irq.h | 6 +++++- - 2 files changed, 8 insertions(+), 3 deletions(-) - -diff --git a/arch/mips/ath79/mach-ubnt-xm.c b/arch/mips/ath79/mach-ubnt-xm.c -index 3266ee0..0d95b67 100644 ---- a/arch/mips/ath79/mach-ubnt-xm.c -+++ b/arch/mips/ath79/mach-ubnt-xm.c -@@ -17,6 +17,8 @@ - #include <linux/ath9k_platform.h> - #endif /* CONFIG_PCI */ - -+#include <asm/mach-ath79/irq.h> -+ - #include "machtypes.h" - #include "dev-gpio-buttons.h" - #include "dev-leds-gpio.h" -@@ -33,7 +35,6 @@ - #define UBNT_XM_KEYS_POLL_INTERVAL 20 - #define UBNT_XM_KEYS_DEBOUNCE_INTERVAL (3 * UBNT_XM_KEYS_POLL_INTERVAL) - --#define UBNT_XM_PCI_IRQ 48 - #define UBNT_XM_EEPROM_ADDR (u8 *) KSEG1ADDR(0x1fff1000) - - static struct gpio_led ubnt_xm_leds_gpio[] __initdata = { -@@ -86,7 +87,7 @@ static struct ath9k_platform_data ubnt_xm_eeprom_data; - - static struct ar724x_pci_data ubnt_xm_pci_data[] = { - { -- .irq = UBNT_XM_PCI_IRQ, -+ .irq = ATH79_PCI_IRQ(0), - .pdata = &ubnt_xm_eeprom_data, - }, - }; -diff --git a/arch/mips/include/asm/mach-ath79/irq.h b/arch/mips/include/asm/mach-ath79/irq.h -index 519958f..6ae2646 100644 ---- a/arch/mips/include/asm/mach-ath79/irq.h -+++ b/arch/mips/include/asm/mach-ath79/irq.h -@@ -10,11 +10,15 @@ - #define __ASM_MACH_ATH79_IRQ_H - - #define MIPS_CPU_IRQ_BASE 0 --#define NR_IRQS 40 -+#define NR_IRQS 46 - - #define ATH79_MISC_IRQ_BASE 8 - #define ATH79_MISC_IRQ_COUNT 32 - -+#define ATH79_PCI_IRQ_BASE (ATH79_MISC_IRQ_BASE + ATH79_MISC_IRQ_COUNT) -+#define ATH79_PCI_IRQ_COUNT 6 -+#define ATH79_PCI_IRQ(_x) (ATH79_PCI_IRQ_BASE + (_x)) -+ - #define ATH79_CPU_IRQ_IP2 (MIPS_CPU_IRQ_BASE + 2) - #define ATH79_CPU_IRQ_USB (MIPS_CPU_IRQ_BASE + 3) - #define ATH79_CPU_IRQ_GE0 (MIPS_CPU_IRQ_BASE + 4) --- -1.7.9.7 - diff --git a/bsp/routerstationpro/MIPS-ath79-fix-broken-ar724x_pci_-read-write-functio.patch b/bsp/routerstationpro/MIPS-ath79-fix-broken-ar724x_pci_-read-write-functio.patch deleted file mode 100644 index cbe9da22354d2dd5f26521f49fbbc0b5f000a729..0000000000000000000000000000000000000000 --- a/bsp/routerstationpro/MIPS-ath79-fix-broken-ar724x_pci_-read-write-functio.patch +++ /dev/null @@ -1,143 +0,0 @@ -From 73aeacbca50ec49cdc3581eb43731763fc82b7e1 Mon Sep 17 00:00:00 2001 -From: Gabor Juhos <juhosg@openwrt.org> -Date: Wed, 14 Mar 2012 10:36:04 +0100 -Subject: [PATCH 040/123] MIPS: ath79: fix broken ar724x_pci_{read,write} - functions - -commit 64adb6bb62bee11ad04c2f9c3c797799e329c351 upstream. - -The current ar724x_pci_{read,write} functions are -broken. Due to that, pci_read_config_byte returns -with bogus values, and pci_write_config_{byte,word} -unconditionally clears the accessed PCI configuration -registers instead of changing the value of them. - -The patch fixes the broken functions, thus the PCI -configuration space can be accessed correctly. - -Signed-off-by: Gabor Juhos <juhosg@openwrt.org> -Cc: linux-mips@linux-mips.org -Patchwork: https://patchwork.linux-mips.org/patch/3493/ -Signed-off-by: Ralf Baechle <ralf@linux-mips.org> -Signed-off-by: Paul Gortmaker <paul.gortmaker@windriver.com> ---- - arch/mips/pci/pci-ar724x.c | 52 ++++++++++++++++++++++---------------------- - 1 file changed, 26 insertions(+), 26 deletions(-) - -diff --git a/arch/mips/pci/pci-ar724x.c b/arch/mips/pci/pci-ar724x.c -index 342bf4a..bb4f216 100644 ---- a/arch/mips/pci/pci-ar724x.c -+++ b/arch/mips/pci/pci-ar724x.c -@@ -22,8 +22,9 @@ static void __iomem *ar724x_pci_devcfg_base; - static int ar724x_pci_read(struct pci_bus *bus, unsigned int devfn, int where, - int size, uint32_t *value) - { -- unsigned long flags, addr, tval, mask; -+ unsigned long flags; - void __iomem *base; -+ u32 data; - - if (devfn) - return PCIBIOS_DEVICE_NOT_FOUND; -@@ -31,24 +32,22 @@ static int ar724x_pci_read(struct pci_bus *bus, unsigned int devfn, int where, - base = ar724x_pci_devcfg_base; - - spin_lock_irqsave(&ar724x_pci_lock, flags); -+ data = __raw_readl(base + (where & ~3)); - - switch (size) { - case 1: -- addr = where & ~3; -- mask = 0xff000000 >> ((where % 4) * 8); -- tval = __raw_readl(base + addr); -- tval = tval & ~mask; -- *value = (tval >> ((4 - (where % 4))*8)); -+ if (where & 1) -+ data >>= 8; -+ if (where & 2) -+ data >>= 16; -+ data &= 0xff; - break; - case 2: -- addr = where & ~3; -- mask = 0xffff0000 >> ((where % 4)*8); -- tval = __raw_readl(base + addr); -- tval = tval & ~mask; -- *value = (tval >> ((4 - (where % 4))*8)); -+ if (where & 2) -+ data >>= 16; -+ data &= 0xffff; - break; - case 4: -- *value = __raw_readl(base + where); - break; - default: - spin_unlock_irqrestore(&ar724x_pci_lock, flags); -@@ -57,6 +56,7 @@ static int ar724x_pci_read(struct pci_bus *bus, unsigned int devfn, int where, - } - - spin_unlock_irqrestore(&ar724x_pci_lock, flags); -+ *value = data; - - return PCIBIOS_SUCCESSFUL; - } -@@ -64,8 +64,10 @@ static int ar724x_pci_read(struct pci_bus *bus, unsigned int devfn, int where, - static int ar724x_pci_write(struct pci_bus *bus, unsigned int devfn, int where, - int size, uint32_t value) - { -- unsigned long flags, tval, addr, mask; -+ unsigned long flags; - void __iomem *base; -+ u32 data; -+ int s; - - if (devfn) - return PCIBIOS_DEVICE_NOT_FOUND; -@@ -73,26 +75,21 @@ static int ar724x_pci_write(struct pci_bus *bus, unsigned int devfn, int where, - base = ar724x_pci_devcfg_base; - - spin_lock_irqsave(&ar724x_pci_lock, flags); -+ data = __raw_readl(base + (where & ~3)); - - switch (size) { - case 1: -- addr = where & ~3; -- mask = 0xff000000 >> ((where % 4)*8); -- tval = __raw_readl(base + addr); -- tval = tval & ~mask; -- tval |= (value << ((4 - (where % 4))*8)) & mask; -- __raw_writel(tval, base + addr); -+ s = ((where & 3) * 8); -+ data &= ~(0xff << s); -+ data |= ((value & 0xff) << s); - break; - case 2: -- addr = where & ~3; -- mask = 0xffff0000 >> ((where % 4)*8); -- tval = __raw_readl(base + addr); -- tval = tval & ~mask; -- tval |= (value << ((4 - (where % 4))*8)) & mask; -- __raw_writel(tval, base + addr); -+ s = ((where & 2) * 8); -+ data &= ~(0xffff << s); -+ data |= ((value & 0xffff) << s); - break; - case 4: -- __raw_writel(value, (base + where)); -+ data = value; - break; - default: - spin_unlock_irqrestore(&ar724x_pci_lock, flags); -@@ -100,6 +97,9 @@ static int ar724x_pci_write(struct pci_bus *bus, unsigned int devfn, int where, - return PCIBIOS_BAD_REGISTER_NUMBER; - } - -+ __raw_writel(data, base + (where & ~3)); -+ /* flush write */ -+ __raw_readl(base + (where & ~3)); - spin_unlock_irqrestore(&ar724x_pci_lock, flags); - - return PCIBIOS_SUCCESSFUL; --- -1.7.9.7 - diff --git a/bsp/routerstationpro/MIPS-ath79-get-rid-of-some-ifdefs-in-mach-ubnt-xm.c.patch b/bsp/routerstationpro/MIPS-ath79-get-rid-of-some-ifdefs-in-mach-ubnt-xm.c.patch deleted file mode 100644 index 42f99b0351b4f3e0fa496b63adb8ba9285fc4cc4..0000000000000000000000000000000000000000 --- a/bsp/routerstationpro/MIPS-ath79-get-rid-of-some-ifdefs-in-mach-ubnt-xm.c.patch +++ /dev/null @@ -1,73 +0,0 @@ -From 0916c892f3d85ad70f4b11bfd2de2f60392b8cbb Mon Sep 17 00:00:00 2001 -From: Gabor Juhos <juhosg@openwrt.org> -Date: Wed, 14 Mar 2012 10:36:08 +0100 -Subject: [PATCH 044/123] MIPS: ath79: get rid of some ifdefs in - mach-ubnt-xm.c - -commit 881b6ef0cca3395ac0171472a1ce768fede7535b upstream - -Remove a superfluous ifdef around an include. Also -reorganize the board setup code a bit, so another -ifdef can be removed. - -Signed-off-by: Gabor Juhos <juhosg@openwrt.org> -Cc: linux-mips@linux-mips.org -Patchwork: https://patchwork.linux-mips.org/patch/3497/ -Signed-off-by: Ralf Baechle <ralf@linux-mips.org> -Signed-off-by: Paul Gortmaker <paul.gortmaker@windriver.com> ---- - arch/mips/ath79/mach-ubnt-xm.c | 23 ++++++++++++----------- - 1 file changed, 12 insertions(+), 11 deletions(-) - -diff --git a/arch/mips/ath79/mach-ubnt-xm.c b/arch/mips/ath79/mach-ubnt-xm.c -index 0d95b67..1e6b986 100644 ---- a/arch/mips/ath79/mach-ubnt-xm.c -+++ b/arch/mips/ath79/mach-ubnt-xm.c -@@ -12,10 +12,7 @@ - - #include <linux/init.h> - #include <linux/pci.h> -- --#ifdef CONFIG_PCI - #include <linux/ath9k_platform.h> --#endif /* CONFIG_PCI */ - - #include <asm/mach-ath79/irq.h> - -@@ -91,6 +88,17 @@ static struct ar724x_pci_data ubnt_xm_pci_data[] = { - .pdata = &ubnt_xm_eeprom_data, - }, - }; -+ -+static void __init ubnt_xm_pci_init(void) -+{ -+ memcpy(ubnt_xm_eeprom_data.eeprom_data, UBNT_XM_EEPROM_ADDR, -+ sizeof(ubnt_xm_eeprom_data.eeprom_data)); -+ -+ ar724x_pci_add_data(ubnt_xm_pci_data, ARRAY_SIZE(ubnt_xm_pci_data)); -+ ath79_register_pci(); -+} -+#else -+static inline void ubnt_xm_pci_init(void) {} - #endif /* CONFIG_PCI */ - - static void __init ubnt_xm_init(void) -@@ -105,14 +113,7 @@ static void __init ubnt_xm_init(void) - ath79_register_spi(&ubnt_xm_spi_data, ubnt_xm_spi_info, - ARRAY_SIZE(ubnt_xm_spi_info)); - --#ifdef CONFIG_PCI -- memcpy(ubnt_xm_eeprom_data.eeprom_data, UBNT_XM_EEPROM_ADDR, -- sizeof(ubnt_xm_eeprom_data.eeprom_data)); -- -- ar724x_pci_add_data(ubnt_xm_pci_data, ARRAY_SIZE(ubnt_xm_pci_data)); --#endif /* CONFIG_PCI */ -- -- ath79_register_pci(); -+ ubnt_xm_pci_init(); - } - - MIPS_MACHINE(ATH79_MACH_UBNT_XM, --- -1.7.9.7 - diff --git a/bsp/routerstationpro/MIPS-ath79-make-ath724x_pcibios_init-visible-for-ext.patch b/bsp/routerstationpro/MIPS-ath79-make-ath724x_pcibios_init-visible-for-ext.patch deleted file mode 100644 index 8af42f47b85ebc9843b39358b54447b46f827d65..0000000000000000000000000000000000000000 --- a/bsp/routerstationpro/MIPS-ath79-make-ath724x_pcibios_init-visible-for-ext.patch +++ /dev/null @@ -1,73 +0,0 @@ -From 5e82fcc92b5b4e6386e429cce08e1e1c04c80d9a Mon Sep 17 00:00:00 2001 -From: Gabor Juhos <juhosg@openwrt.org> -Date: Wed, 14 Mar 2012 10:29:23 +0100 -Subject: [PATCH 034/123] MIPS: ath79: make ath724x_pcibios_init visible for - external code -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -commit 659243ccaf296ae122c159d4c573f93561e1b8d6 upstream - -Signed-off-by: René Bolldorf <xsecute@googlemail.com> -Signed-off-by: Gabor Juhos <juhosg@openwrt.org> -Cc: linux-mips@linux-mips.org -Patchwork: https://patchwork.linux-mips.org/patch/3487/ -Signed-off-by: Ralf Baechle <ralf@linux-mips.org> -Signed-off-by: Paul Gortmaker <paul.gortmaker@windriver.com> ---- - arch/mips/include/asm/mach-ath79/pci.h | 20 ++++++++++++++++++++ - arch/mips/pci/pci-ath724x.c | 3 ++- - 2 files changed, 22 insertions(+), 1 deletion(-) - create mode 100644 arch/mips/include/asm/mach-ath79/pci.h - -diff --git a/arch/mips/include/asm/mach-ath79/pci.h b/arch/mips/include/asm/mach-ath79/pci.h -new file mode 100644 -index 0000000..e0c4b53 ---- /dev/null -+++ b/arch/mips/include/asm/mach-ath79/pci.h -@@ -0,0 +1,20 @@ -+/* -+ * Atheros 724x PCI support -+ * -+ * Copyright (C) 2011 René Bolldorf <xsecute@googlemail.com> -+ * -+ * This program is free software; you can redistribute it and/or modify it -+ * under the terms of the GNU General Public License version 2 as published -+ * by the Free Software Foundation. -+ */ -+ -+#ifndef __ASM_MACH_ATH79_PCI_H -+#define __ASM_MACH_ATH79_PCI_H -+ -+#if defined(CONFIG_PCI) && defined(CONFIG_SOC_AR724X) -+int ath724x_pcibios_init(void); -+#else -+static inline int ath724x_pcibios_init(void) { return 0; } -+#endif -+ -+#endif /* __ASM_MACH_ATH79_PCI_H */ -diff --git a/arch/mips/pci/pci-ath724x.c b/arch/mips/pci/pci-ath724x.c -index 1e810be..be01b7f 100644 ---- a/arch/mips/pci/pci-ath724x.c -+++ b/arch/mips/pci/pci-ath724x.c -@@ -9,6 +9,7 @@ - */ - - #include <linux/pci.h> -+#include <asm/mach-ath79/pci.h> - - #define reg_read(_phys) (*(unsigned int *) KSEG1ADDR(_phys)) - #define reg_write(_phys, _val) ((*(unsigned int *) KSEG1ADDR(_phys)) = (_val)) -@@ -130,7 +131,7 @@ static struct pci_controller ath724x_pci_controller = { - .mem_resource = &ath724x_mem_resource, - }; - --static int __init ath724x_pcibios_init(void) -+int __init ath724x_pcibios_init(void) - { - register_pci_controller(&ath724x_pci_controller); - --- -1.7.9.7 - diff --git a/bsp/routerstationpro/MIPS-ath79-register-PCI-controller-on-the-PB44-board.patch b/bsp/routerstationpro/MIPS-ath79-register-PCI-controller-on-the-PB44-board.patch deleted file mode 100644 index db5e11befbcd392ef719144911036a777a5a670c..0000000000000000000000000000000000000000 --- a/bsp/routerstationpro/MIPS-ath79-register-PCI-controller-on-the-PB44-board.patch +++ /dev/null @@ -1,43 +0,0 @@ -From 4a98ff40ecc3899a537cc6cf5ac356abb90ed0c7 Mon Sep 17 00:00:00 2001 -From: Gabor Juhos <juhosg@openwrt.org> -Date: Wed, 14 Mar 2012 10:36:13 +0100 -Subject: [PATCH 049/123] MIPS: ath79: register PCI controller on the PB44 - board - -commit 1f3a92de2a5081077799a51f39b1010ed0492264 upstream. - -The PB44 reference board has two miniPCI slots. Register -the PCI controller to make those usable. - -Signed-off-by: Gabor Juhos <juhosg@openwrt.org> -Cc: linux-mips@linux-mips.org -Patchwork: https://patchwork.linux-mips.org/patch/3502/ -Signed-off-by: Ralf Baechle <ralf@linux-mips.org> -Signed-off-by: Paul Gortmaker <paul.gortmaker@windriver.com> ---- - arch/mips/ath79/mach-pb44.c | 2 ++ - 1 file changed, 2 insertions(+) - -diff --git a/arch/mips/ath79/mach-pb44.c b/arch/mips/ath79/mach-pb44.c -index fe9701a..c5f0ea5 100644 ---- a/arch/mips/ath79/mach-pb44.c -+++ b/arch/mips/ath79/mach-pb44.c -@@ -19,6 +19,7 @@ - #include "dev-leds-gpio.h" - #include "dev-spi.h" - #include "dev-usb.h" -+#include "pci.h" - - #define PB44_GPIO_I2C_SCL 0 - #define PB44_GPIO_I2C_SDA 1 -@@ -114,6 +115,7 @@ static void __init pb44_init(void) - ath79_register_spi(&pb44_spi_data, pb44_spi_info, - ARRAY_SIZE(pb44_spi_info)); - ath79_register_usb(); -+ ath79_register_pci(); - } - - MIPS_MACHINE(ATH79_MACH_PB44, "PB44", "Atheros PB44 reference board", --- -1.7.9.7 - diff --git a/bsp/routerstationpro/MIPS-ath79-register-UART-device-for-AR934X-SoCs.patch b/bsp/routerstationpro/MIPS-ath79-register-UART-device-for-AR934X-SoCs.patch deleted file mode 100644 index e2302dd452c9093cbe2e2dda7478094d72cb0376..0000000000000000000000000000000000000000 --- a/bsp/routerstationpro/MIPS-ath79-register-UART-device-for-AR934X-SoCs.patch +++ /dev/null @@ -1,35 +0,0 @@ -From 0a6aac16cbc02c0f8c6ce6504e87d43718a39909 Mon Sep 17 00:00:00 2001 -From: Gabor Juhos <juhosg@openwrt.org> -Date: Wed, 14 Mar 2012 10:45:27 +0100 -Subject: [PATCH 059/123] MIPS: ath79: register UART device for AR934X SoCs - -commit 9800bdc797b12835e1e36ebe8b82874c606bc11d upstream. - -Signed-off-by: Gabor Juhos <juhosg@openwrt.org> -Acked-by: Luis R. Rodriguez <mcgrof@qca.qualcomm.com> -Cc: linux-mips@linux-mips.org -Cc: mcgrof@infradead.org -Patchwork: https://patchwork.linux-mips.org/patch/3512/ -Signed-off-by: Ralf Baechle <ralf@linux-mips.org> -Signed-off-by: Paul Gortmaker <paul.gortmaker@windriver.com> ---- - arch/mips/ath79/dev-common.c | 3 ++- - 1 file changed, 2 insertions(+), 1 deletion(-) - -diff --git a/arch/mips/ath79/dev-common.c b/arch/mips/ath79/dev-common.c -index f4956f8..45efc63 100644 ---- a/arch/mips/ath79/dev-common.c -+++ b/arch/mips/ath79/dev-common.c -@@ -89,7 +89,8 @@ void __init ath79_register_uart(void) - - if (soc_is_ar71xx() || - soc_is_ar724x() || -- soc_is_ar913x()) { -+ soc_is_ar913x() || -+ soc_is_ar934x()) { - ath79_uart_data[0].uartclk = clk_get_rate(clk); - platform_device_register(&ath79_uart_device); - } else if (soc_is_ar933x()) { --- -1.7.9.7 - diff --git a/bsp/routerstationpro/MIPS-ath79-remove-ar724x_pci_add_data-function.patch b/bsp/routerstationpro/MIPS-ath79-remove-ar724x_pci_add_data-function.patch deleted file mode 100644 index 9035a061af09c84eac86478e1868f30e3dba9a37..0000000000000000000000000000000000000000 --- a/bsp/routerstationpro/MIPS-ath79-remove-ar724x_pci_add_data-function.patch +++ /dev/null @@ -1,98 +0,0 @@ -From 95d7f2ee27ea6170fc307f857f11daab39ca7b3e Mon Sep 17 00:00:00 2001 -From: Gabor Juhos <juhosg@openwrt.org> -Date: Wed, 14 Mar 2012 10:36:12 +0100 -Subject: [PATCH 048/123] MIPS: ath79: remove ar724x_pci_add_data function - -commit 52c28be371e33b99700811dbed009913b854c44d upstream. - -The variables set by this function are not used anymore. -Remove the function and the relevant variables as well. - -Signed-off-by: Gabor Juhos <juhosg@openwrt.org> -Cc: linux-mips@linux-mips.org -Patchwork: https://patchwork.linux-mips.org/patch/3501/ -Signed-off-by: Ralf Baechle <ralf@linux-mips.org> -Signed-off-by: Paul Gortmaker <paul.gortmaker@windriver.com> ---- - arch/mips/ath79/mach-ubnt-xm.c | 7 ------- - arch/mips/ath79/pci.c | 8 -------- - arch/mips/ath79/pci.h | 6 ------ - 3 files changed, 21 deletions(-) - -diff --git a/arch/mips/ath79/mach-ubnt-xm.c b/arch/mips/ath79/mach-ubnt-xm.c -index ca47ba5..4a3c606 100644 ---- a/arch/mips/ath79/mach-ubnt-xm.c -+++ b/arch/mips/ath79/mach-ubnt-xm.c -@@ -82,12 +82,6 @@ static struct ath79_spi_platform_data ubnt_xm_spi_data = { - #ifdef CONFIG_PCI - static struct ath9k_platform_data ubnt_xm_eeprom_data; - --static struct ar724x_pci_data ubnt_xm_pci_data[] = { -- { -- .irq = ATH79_PCI_IRQ(0), -- }, --}; -- - static int ubnt_xm_pci_plat_dev_init(struct pci_dev *dev) - { - switch (PCI_SLOT(dev->devfn)) { -@@ -104,7 +98,6 @@ static void __init ubnt_xm_pci_init(void) - memcpy(ubnt_xm_eeprom_data.eeprom_data, UBNT_XM_EEPROM_ADDR, - sizeof(ubnt_xm_eeprom_data.eeprom_data)); - -- ar724x_pci_add_data(ubnt_xm_pci_data, ARRAY_SIZE(ubnt_xm_pci_data)); - ath79_pci_set_plat_dev_init(ubnt_xm_pci_plat_dev_init); - ath79_register_pci(); - } -diff --git a/arch/mips/ath79/pci.c b/arch/mips/ath79/pci.c -index 365a8b6..253a382 100644 ---- a/arch/mips/ath79/pci.c -+++ b/arch/mips/ath79/pci.c -@@ -18,8 +18,6 @@ - static int (*ath79_pci_plat_dev_init)(struct pci_dev *dev); - static const struct ath79_pci_irq *ath79_pci_irq_map __initdata; - static unsigned ath79_pci_nr_irqs __initdata; --static struct ar724x_pci_data *pci_data; --static int pci_data_size; - - static const struct ath79_pci_irq ar71xx_pci_irq_map[] __initconst = { - { -@@ -45,12 +43,6 @@ static const struct ath79_pci_irq ar724x_pci_irq_map[] __initconst = { - } - }; - --void ar724x_pci_add_data(struct ar724x_pci_data *data, int size) --{ -- pci_data = data; -- pci_data_size = size; --} -- - int __init pcibios_map_irq(const struct pci_dev *dev, uint8_t slot, uint8_t pin) - { - int irq = -1; -diff --git a/arch/mips/ath79/pci.h b/arch/mips/ath79/pci.h -index a5c4e58..5ebed21 100644 ---- a/arch/mips/ath79/pci.h -+++ b/arch/mips/ath79/pci.h -@@ -11,18 +11,12 @@ - #ifndef _ATH79_PCI_H - #define _ATH79_PCI_H - --struct ar724x_pci_data { -- int irq; --}; -- - struct ath79_pci_irq { - u8 slot; - u8 pin; - int irq; - }; - --void ar724x_pci_add_data(struct ar724x_pci_data *data, int size); -- - #ifdef CONFIG_PCI - void ath79_pci_set_irq_map(unsigned nr_irqs, const struct ath79_pci_irq *map); - void ath79_pci_set_plat_dev_init(int (*func)(struct pci_dev *dev)); --- -1.7.9.7 - diff --git a/bsp/routerstationpro/MIPS-ath79-remove-superfluous-alignment-checks-from-.patch b/bsp/routerstationpro/MIPS-ath79-remove-superfluous-alignment-checks-from-.patch deleted file mode 100644 index 2a9f0ef628bbd0dc765ab0ca9482d5acb721a0ae..0000000000000000000000000000000000000000 --- a/bsp/routerstationpro/MIPS-ath79-remove-superfluous-alignment-checks-from-.patch +++ /dev/null @@ -1,47 +0,0 @@ -From 7218e77665e26bb90d733b30766554b7519a94c8 Mon Sep 17 00:00:00 2001 -From: Gabor Juhos <juhosg@openwrt.org> -Date: Wed, 14 Mar 2012 10:36:03 +0100 -Subject: [PATCH 039/123] MIPS: ath79: remove superfluous alignment checks - from pci-ar724x.c - -commit ffdce4668234a113e767edd27aa1331903959106 upstream. - -The alignment of the 'where' parameters are checked -in the core PCI code already. - -Signed-off-by: Gabor Juhos <juhosg@openwrt.org> -Cc: linux-mips@linux-mips.org -Patchwork: https://patchwork.linux-mips.org/patch/3492/ -Signed-off-by: Ralf Baechle <ralf@linux-mips.org> -Signed-off-by: Paul Gortmaker <paul.gortmaker@windriver.com> ---- - arch/mips/pci/pci-ar724x.c | 6 ------ - 1 file changed, 6 deletions(-) - -diff --git a/arch/mips/pci/pci-ar724x.c b/arch/mips/pci/pci-ar724x.c -index 22f5e5b..342bf4a 100644 ---- a/arch/mips/pci/pci-ar724x.c -+++ b/arch/mips/pci/pci-ar724x.c -@@ -28,9 +28,6 @@ static int ar724x_pci_read(struct pci_bus *bus, unsigned int devfn, int where, - if (devfn) - return PCIBIOS_DEVICE_NOT_FOUND; - -- if (where & (size - 1)) -- return PCIBIOS_BAD_REGISTER_NUMBER; -- - base = ar724x_pci_devcfg_base; - - spin_lock_irqsave(&ar724x_pci_lock, flags); -@@ -73,9 +70,6 @@ static int ar724x_pci_write(struct pci_bus *bus, unsigned int devfn, int where, - if (devfn) - return PCIBIOS_DEVICE_NOT_FOUND; - -- if (where & (size - 1)) -- return PCIBIOS_BAD_REGISTER_NUMBER; -- - base = ar724x_pci_devcfg_base; - - spin_lock_irqsave(&ar724x_pci_lock, flags); --- -1.7.9.7 - diff --git a/bsp/routerstationpro/MIPS-ath79-rename-pci-ath724x.c-to-make-it-reflect-t.patch b/bsp/routerstationpro/MIPS-ath79-rename-pci-ath724x.c-to-make-it-reflect-t.patch deleted file mode 100644 index 5599ebd129173f80a2e6e7bc06ca247c109cc4b6..0000000000000000000000000000000000000000 --- a/bsp/routerstationpro/MIPS-ath79-rename-pci-ath724x.c-to-make-it-reflect-t.patch +++ /dev/null @@ -1,331 +0,0 @@ -From 1e1dbfcfa5315bf21f08c9d712f6ccf9feb0078b Mon Sep 17 00:00:00 2001 -From: Gabor Juhos <juhosg@openwrt.org> -Date: Wed, 14 Mar 2012 10:29:25 +0100 -Subject: [PATCH 036/123] MIPS: ath79: rename pci-ath724x.c to make it reflect - the real SoC name -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -commit 692183ef12c4ba9dcdc9a54065ca92072cd79493 upstream. - -Signed-off-by: Gabor Juhos <juhosg@openwrt.org> -Acked-by: René Bolldorf <xsecute@googlemail.com> -Cc: linux-mips@linux-mips.org -Patchwork: https://patchwork.linux-mips.org/patch/3489/ -Signed-off-by: Ralf Baechle <ralf@linux-mips.org> -Signed-off-by: Paul Gortmaker <paul.gortmaker@windriver.com> ---- - arch/mips/pci/Makefile | 2 +- - arch/mips/pci/pci-ar724x.c | 139 +++++++++++++++++++++++++++++++++++++++++++ - arch/mips/pci/pci-ath724x.c | 139 ------------------------------------------- - 3 files changed, 140 insertions(+), 140 deletions(-) - create mode 100644 arch/mips/pci/pci-ar724x.c - delete mode 100644 arch/mips/pci/pci-ath724x.c - -diff --git a/arch/mips/pci/Makefile b/arch/mips/pci/Makefile -index c3ac4b0..172277c 100644 ---- a/arch/mips/pci/Makefile -+++ b/arch/mips/pci/Makefile -@@ -19,7 +19,7 @@ obj-$(CONFIG_BCM47XX) += pci-bcm47xx.o - obj-$(CONFIG_BCM63XX) += pci-bcm63xx.o fixup-bcm63xx.o \ - ops-bcm63xx.o - obj-$(CONFIG_MIPS_ALCHEMY) += pci-alchemy.o --obj-$(CONFIG_SOC_AR724X) += pci-ath724x.o -+obj-$(CONFIG_SOC_AR724X) += pci-ar724x.o - - # - # These are still pretty much in the old state, watch, go blind. -diff --git a/arch/mips/pci/pci-ar724x.c b/arch/mips/pci/pci-ar724x.c -new file mode 100644 -index 0000000..ebefc16 ---- /dev/null -+++ b/arch/mips/pci/pci-ar724x.c -@@ -0,0 +1,139 @@ -+/* -+ * Atheros 724x PCI support -+ * -+ * Copyright (C) 2011 René Bolldorf <xsecute@googlemail.com> -+ * -+ * This program is free software; you can redistribute it and/or modify it -+ * under the terms of the GNU General Public License version 2 as published -+ * by the Free Software Foundation. -+ */ -+ -+#include <linux/pci.h> -+#include <asm/mach-ath79/pci.h> -+ -+#define reg_read(_phys) (*(unsigned int *) KSEG1ADDR(_phys)) -+#define reg_write(_phys, _val) ((*(unsigned int *) KSEG1ADDR(_phys)) = (_val)) -+ -+#define ATH724X_PCI_DEV_BASE 0x14000000 -+#define ATH724X_PCI_MEM_BASE 0x10000000 -+#define ATH724X_PCI_MEM_SIZE 0x08000000 -+ -+static DEFINE_SPINLOCK(ath724x_pci_lock); -+ -+static int ath724x_pci_read(struct pci_bus *bus, unsigned int devfn, int where, -+ int size, uint32_t *value) -+{ -+ unsigned long flags, addr, tval, mask; -+ -+ if (devfn) -+ return PCIBIOS_DEVICE_NOT_FOUND; -+ -+ if (where & (size - 1)) -+ return PCIBIOS_BAD_REGISTER_NUMBER; -+ -+ spin_lock_irqsave(&ath724x_pci_lock, flags); -+ -+ switch (size) { -+ case 1: -+ addr = where & ~3; -+ mask = 0xff000000 >> ((where % 4) * 8); -+ tval = reg_read(ATH724X_PCI_DEV_BASE + addr); -+ tval = tval & ~mask; -+ *value = (tval >> ((4 - (where % 4))*8)); -+ break; -+ case 2: -+ addr = where & ~3; -+ mask = 0xffff0000 >> ((where % 4)*8); -+ tval = reg_read(ATH724X_PCI_DEV_BASE + addr); -+ tval = tval & ~mask; -+ *value = (tval >> ((4 - (where % 4))*8)); -+ break; -+ case 4: -+ *value = reg_read(ATH724X_PCI_DEV_BASE + where); -+ break; -+ default: -+ spin_unlock_irqrestore(&ath724x_pci_lock, flags); -+ -+ return PCIBIOS_BAD_REGISTER_NUMBER; -+ } -+ -+ spin_unlock_irqrestore(&ath724x_pci_lock, flags); -+ -+ return PCIBIOS_SUCCESSFUL; -+} -+ -+static int ath724x_pci_write(struct pci_bus *bus, unsigned int devfn, int where, -+ int size, uint32_t value) -+{ -+ unsigned long flags, tval, addr, mask; -+ -+ if (devfn) -+ return PCIBIOS_DEVICE_NOT_FOUND; -+ -+ if (where & (size - 1)) -+ return PCIBIOS_BAD_REGISTER_NUMBER; -+ -+ spin_lock_irqsave(&ath724x_pci_lock, flags); -+ -+ switch (size) { -+ case 1: -+ addr = (ATH724X_PCI_DEV_BASE + where) & ~3; -+ mask = 0xff000000 >> ((where % 4)*8); -+ tval = reg_read(addr); -+ tval = tval & ~mask; -+ tval |= (value << ((4 - (where % 4))*8)) & mask; -+ reg_write(addr, tval); -+ break; -+ case 2: -+ addr = (ATH724X_PCI_DEV_BASE + where) & ~3; -+ mask = 0xffff0000 >> ((where % 4)*8); -+ tval = reg_read(addr); -+ tval = tval & ~mask; -+ tval |= (value << ((4 - (where % 4))*8)) & mask; -+ reg_write(addr, tval); -+ break; -+ case 4: -+ reg_write((ATH724X_PCI_DEV_BASE + where), value); -+ break; -+ default: -+ spin_unlock_irqrestore(&ath724x_pci_lock, flags); -+ -+ return PCIBIOS_BAD_REGISTER_NUMBER; -+ } -+ -+ spin_unlock_irqrestore(&ath724x_pci_lock, flags); -+ -+ return PCIBIOS_SUCCESSFUL; -+} -+ -+static struct pci_ops ath724x_pci_ops = { -+ .read = ath724x_pci_read, -+ .write = ath724x_pci_write, -+}; -+ -+static struct resource ath724x_io_resource = { -+ .name = "PCI IO space", -+ .start = 0, -+ .end = 0, -+ .flags = IORESOURCE_IO, -+}; -+ -+static struct resource ath724x_mem_resource = { -+ .name = "PCI memory space", -+ .start = ATH724X_PCI_MEM_BASE, -+ .end = ATH724X_PCI_MEM_BASE + ATH724X_PCI_MEM_SIZE - 1, -+ .flags = IORESOURCE_MEM, -+}; -+ -+static struct pci_controller ath724x_pci_controller = { -+ .pci_ops = &ath724x_pci_ops, -+ .io_resource = &ath724x_io_resource, -+ .mem_resource = &ath724x_mem_resource, -+}; -+ -+int __init ath724x_pcibios_init(void) -+{ -+ register_pci_controller(&ath724x_pci_controller); -+ -+ return PCIBIOS_SUCCESSFUL; -+} -diff --git a/arch/mips/pci/pci-ath724x.c b/arch/mips/pci/pci-ath724x.c -deleted file mode 100644 -index ebefc16..0000000 ---- a/arch/mips/pci/pci-ath724x.c -+++ /dev/null -@@ -1,139 +0,0 @@ --/* -- * Atheros 724x PCI support -- * -- * Copyright (C) 2011 René Bolldorf <xsecute@googlemail.com> -- * -- * This program is free software; you can redistribute it and/or modify it -- * under the terms of the GNU General Public License version 2 as published -- * by the Free Software Foundation. -- */ -- --#include <linux/pci.h> --#include <asm/mach-ath79/pci.h> -- --#define reg_read(_phys) (*(unsigned int *) KSEG1ADDR(_phys)) --#define reg_write(_phys, _val) ((*(unsigned int *) KSEG1ADDR(_phys)) = (_val)) -- --#define ATH724X_PCI_DEV_BASE 0x14000000 --#define ATH724X_PCI_MEM_BASE 0x10000000 --#define ATH724X_PCI_MEM_SIZE 0x08000000 -- --static DEFINE_SPINLOCK(ath724x_pci_lock); -- --static int ath724x_pci_read(struct pci_bus *bus, unsigned int devfn, int where, -- int size, uint32_t *value) --{ -- unsigned long flags, addr, tval, mask; -- -- if (devfn) -- return PCIBIOS_DEVICE_NOT_FOUND; -- -- if (where & (size - 1)) -- return PCIBIOS_BAD_REGISTER_NUMBER; -- -- spin_lock_irqsave(&ath724x_pci_lock, flags); -- -- switch (size) { -- case 1: -- addr = where & ~3; -- mask = 0xff000000 >> ((where % 4) * 8); -- tval = reg_read(ATH724X_PCI_DEV_BASE + addr); -- tval = tval & ~mask; -- *value = (tval >> ((4 - (where % 4))*8)); -- break; -- case 2: -- addr = where & ~3; -- mask = 0xffff0000 >> ((where % 4)*8); -- tval = reg_read(ATH724X_PCI_DEV_BASE + addr); -- tval = tval & ~mask; -- *value = (tval >> ((4 - (where % 4))*8)); -- break; -- case 4: -- *value = reg_read(ATH724X_PCI_DEV_BASE + where); -- break; -- default: -- spin_unlock_irqrestore(&ath724x_pci_lock, flags); -- -- return PCIBIOS_BAD_REGISTER_NUMBER; -- } -- -- spin_unlock_irqrestore(&ath724x_pci_lock, flags); -- -- return PCIBIOS_SUCCESSFUL; --} -- --static int ath724x_pci_write(struct pci_bus *bus, unsigned int devfn, int where, -- int size, uint32_t value) --{ -- unsigned long flags, tval, addr, mask; -- -- if (devfn) -- return PCIBIOS_DEVICE_NOT_FOUND; -- -- if (where & (size - 1)) -- return PCIBIOS_BAD_REGISTER_NUMBER; -- -- spin_lock_irqsave(&ath724x_pci_lock, flags); -- -- switch (size) { -- case 1: -- addr = (ATH724X_PCI_DEV_BASE + where) & ~3; -- mask = 0xff000000 >> ((where % 4)*8); -- tval = reg_read(addr); -- tval = tval & ~mask; -- tval |= (value << ((4 - (where % 4))*8)) & mask; -- reg_write(addr, tval); -- break; -- case 2: -- addr = (ATH724X_PCI_DEV_BASE + where) & ~3; -- mask = 0xffff0000 >> ((where % 4)*8); -- tval = reg_read(addr); -- tval = tval & ~mask; -- tval |= (value << ((4 - (where % 4))*8)) & mask; -- reg_write(addr, tval); -- break; -- case 4: -- reg_write((ATH724X_PCI_DEV_BASE + where), value); -- break; -- default: -- spin_unlock_irqrestore(&ath724x_pci_lock, flags); -- -- return PCIBIOS_BAD_REGISTER_NUMBER; -- } -- -- spin_unlock_irqrestore(&ath724x_pci_lock, flags); -- -- return PCIBIOS_SUCCESSFUL; --} -- --static struct pci_ops ath724x_pci_ops = { -- .read = ath724x_pci_read, -- .write = ath724x_pci_write, --}; -- --static struct resource ath724x_io_resource = { -- .name = "PCI IO space", -- .start = 0, -- .end = 0, -- .flags = IORESOURCE_IO, --}; -- --static struct resource ath724x_mem_resource = { -- .name = "PCI memory space", -- .start = ATH724X_PCI_MEM_BASE, -- .end = ATH724X_PCI_MEM_BASE + ATH724X_PCI_MEM_SIZE - 1, -- .flags = IORESOURCE_MEM, --}; -- --static struct pci_controller ath724x_pci_controller = { -- .pci_ops = &ath724x_pci_ops, -- .io_resource = &ath724x_io_resource, -- .mem_resource = &ath724x_mem_resource, --}; -- --int __init ath724x_pcibios_init(void) --{ -- register_pci_controller(&ath724x_pci_controller); -- -- return PCIBIOS_SUCCESSFUL; --} --- -1.7.9.7 - diff --git a/bsp/routerstationpro/MIPS-ath79-rename-pci-ath724x.h.patch b/bsp/routerstationpro/MIPS-ath79-rename-pci-ath724x.h.patch deleted file mode 100644 index 0559d35b5ec46531342218a4167e5f76e5f18fe5..0000000000000000000000000000000000000000 --- a/bsp/routerstationpro/MIPS-ath79-rename-pci-ath724x.h.patch +++ /dev/null @@ -1,118 +0,0 @@ -From 29d44ff45b876963f723cfc4bf4d3773b9e54a72 Mon Sep 17 00:00:00 2001 -From: Gabor Juhos <juhosg@openwrt.org> -Date: Wed, 14 Mar 2012 10:29:22 +0100 -Subject: [PATCH 033/123] MIPS: ath79: rename pci-ath724x.h -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -commit 3a6208df8eb97e01fd8510762dd59dce375dd14d upstream. - -The declared function in this header file is used by the -ath79 platform code only. Move the header to the platform -directory. - -Signed-off-by: Gabor Juhos <juhosg@openwrt.org> -Acked-by: René Bolldorf <xsecute@googlemail.com> -Cc: linux-mips@linux-mips.org -Patchwork: https://patchwork.linux-mips.org/patch/3486/ -Signed-off-by: Ralf Baechle <ralf@linux-mips.org> -Signed-off-by: Paul Gortmaker <paul.gortmaker@windriver.com> ---- - arch/mips/ath79/mach-ubnt-xm.c | 2 +- - arch/mips/ath79/pci.c | 2 +- - arch/mips/ath79/pci.h | 21 +++++++++++++++++++++ - arch/mips/include/asm/mach-ath79/pci-ath724x.h | 21 --------------------- - 4 files changed, 23 insertions(+), 23 deletions(-) - create mode 100644 arch/mips/ath79/pci.h - delete mode 100644 arch/mips/include/asm/mach-ath79/pci-ath724x.h - -diff --git a/arch/mips/ath79/mach-ubnt-xm.c b/arch/mips/ath79/mach-ubnt-xm.c -index 3c311a5..a043500 100644 ---- a/arch/mips/ath79/mach-ubnt-xm.c -+++ b/arch/mips/ath79/mach-ubnt-xm.c -@@ -15,13 +15,13 @@ - - #ifdef CONFIG_PCI - #include <linux/ath9k_platform.h> --#include <asm/mach-ath79/pci-ath724x.h> - #endif /* CONFIG_PCI */ - - #include "machtypes.h" - #include "dev-gpio-buttons.h" - #include "dev-leds-gpio.h" - #include "dev-spi.h" -+#include "pci.h" - - #define UBNT_XM_GPIO_LED_L1 0 - #define UBNT_XM_GPIO_LED_L2 1 -diff --git a/arch/mips/ath79/pci.c b/arch/mips/ath79/pci.c -index 8db076e..4957428 100644 ---- a/arch/mips/ath79/pci.c -+++ b/arch/mips/ath79/pci.c -@@ -9,7 +9,7 @@ - */ - - #include <linux/pci.h> --#include <asm/mach-ath79/pci-ath724x.h> -+#include "pci.h" - - static struct ath724x_pci_data *pci_data; - static int pci_data_size; -diff --git a/arch/mips/ath79/pci.h b/arch/mips/ath79/pci.h -new file mode 100644 -index 0000000..454885f ---- /dev/null -+++ b/arch/mips/ath79/pci.h -@@ -0,0 +1,21 @@ -+/* -+ * Atheros 724x PCI support -+ * -+ * Copyright (C) 2011 René Bolldorf <xsecute@googlemail.com> -+ * -+ * This program is free software; you can redistribute it and/or modify it -+ * under the terms of the GNU General Public License version 2 as published -+ * by the Free Software Foundation. -+ */ -+ -+#ifndef __ASM_MACH_ATH79_PCI_ATH724X_H -+#define __ASM_MACH_ATH79_PCI_ATH724X_H -+ -+struct ath724x_pci_data { -+ int irq; -+ void *pdata; -+}; -+ -+void ath724x_pci_add_data(struct ath724x_pci_data *data, int size); -+ -+#endif /* __ASM_MACH_ATH79_PCI_ATH724X_H */ -diff --git a/arch/mips/include/asm/mach-ath79/pci-ath724x.h b/arch/mips/include/asm/mach-ath79/pci-ath724x.h -deleted file mode 100644 -index 454885f..0000000 ---- a/arch/mips/include/asm/mach-ath79/pci-ath724x.h -+++ /dev/null -@@ -1,21 +0,0 @@ --/* -- * Atheros 724x PCI support -- * -- * Copyright (C) 2011 René Bolldorf <xsecute@googlemail.com> -- * -- * This program is free software; you can redistribute it and/or modify it -- * under the terms of the GNU General Public License version 2 as published -- * by the Free Software Foundation. -- */ -- --#ifndef __ASM_MACH_ATH79_PCI_ATH724X_H --#define __ASM_MACH_ATH79_PCI_ATH724X_H -- --struct ath724x_pci_data { -- int irq; -- void *pdata; --}; -- --void ath724x_pci_add_data(struct ath724x_pci_data *data, int size); -- --#endif /* __ASM_MACH_ATH79_PCI_ATH724X_H */ --- -1.7.9.7 - diff --git a/bsp/routerstationpro/MIPS-ath79-replace-ath724x-to-ar724x.patch b/bsp/routerstationpro/MIPS-ath79-replace-ath724x-to-ar724x.patch deleted file mode 100644 index f1c0661955d51ed36aa1a30110ad265112146695..0000000000000000000000000000000000000000 --- a/bsp/routerstationpro/MIPS-ath79-replace-ath724x-to-ar724x.patch +++ /dev/null @@ -1,280 +0,0 @@ -From 0e30985c2e8b99e434ff69cedef85ee013402a90 Mon Sep 17 00:00:00 2001 -From: Gabor Juhos <juhosg@openwrt.org> -Date: Wed, 14 Mar 2012 10:29:26 +0100 -Subject: [PATCH 037/123] MIPS: ath79: replace ath724x to ar724x -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -commit d624bd3cf7835612b25b9ec8db4002624c2dbb32 upstream - -Replace the 'ath724x' to 'ar724x' in function, variable and -structure names to reflect the name of the real SoC. - -Signed-off-by: Gabor Juhos <juhosg@openwrt.org> -Acked-by: René Bolldorf <xsecute@googlemail.com> -Cc: linux-mips@linux-mips.org -Patchwork: https://patchwork.linux-mips.org/patch/3490/ -Signed-off-by: Ralf Baechle <ralf@linux-mips.org> -Signed-off-by: Paul Gortmaker <paul.gortmaker@windriver.com> ---- - arch/mips/ath79/mach-ubnt-xm.c | 4 +-- - arch/mips/ath79/pci.c | 6 ++-- - arch/mips/ath79/pci.h | 10 +++--- - arch/mips/include/asm/mach-ath79/pci.h | 4 +-- - arch/mips/pci/pci-ar724x.c | 62 ++++++++++++++++---------------- - 5 files changed, 43 insertions(+), 43 deletions(-) - -diff --git a/arch/mips/ath79/mach-ubnt-xm.c b/arch/mips/ath79/mach-ubnt-xm.c -index edbc093..3266ee0 100644 ---- a/arch/mips/ath79/mach-ubnt-xm.c -+++ b/arch/mips/ath79/mach-ubnt-xm.c -@@ -84,7 +84,7 @@ static struct ath79_spi_platform_data ubnt_xm_spi_data = { - #ifdef CONFIG_PCI - static struct ath9k_platform_data ubnt_xm_eeprom_data; - --static struct ath724x_pci_data ubnt_xm_pci_data[] = { -+static struct ar724x_pci_data ubnt_xm_pci_data[] = { - { - .irq = UBNT_XM_PCI_IRQ, - .pdata = &ubnt_xm_eeprom_data, -@@ -108,7 +108,7 @@ static void __init ubnt_xm_init(void) - memcpy(ubnt_xm_eeprom_data.eeprom_data, UBNT_XM_EEPROM_ADDR, - sizeof(ubnt_xm_eeprom_data.eeprom_data)); - -- ath724x_pci_add_data(ubnt_xm_pci_data, ARRAY_SIZE(ubnt_xm_pci_data)); -+ ar724x_pci_add_data(ubnt_xm_pci_data, ARRAY_SIZE(ubnt_xm_pci_data)); - #endif /* CONFIG_PCI */ - - ath79_register_pci(); -diff --git a/arch/mips/ath79/pci.c b/arch/mips/ath79/pci.c -index 855a69d..72281fb 100644 ---- a/arch/mips/ath79/pci.c -+++ b/arch/mips/ath79/pci.c -@@ -13,10 +13,10 @@ - #include <asm/mach-ath79/pci.h> - #include "pci.h" - --static struct ath724x_pci_data *pci_data; -+static struct ar724x_pci_data *pci_data; - static int pci_data_size; - --void ath724x_pci_add_data(struct ath724x_pci_data *data, int size) -+void ar724x_pci_add_data(struct ar724x_pci_data *data, int size) - { - pci_data = data; - pci_data_size = size; -@@ -50,7 +50,7 @@ int pcibios_plat_dev_init(struct pci_dev *dev) - int __init ath79_register_pci(void) - { - if (soc_is_ar724x()) -- return ath724x_pcibios_init(); -+ return ar724x_pcibios_init(); - - return -ENODEV; - } -diff --git a/arch/mips/ath79/pci.h b/arch/mips/ath79/pci.h -index 787fac2..e0601c4 100644 ---- a/arch/mips/ath79/pci.h -+++ b/arch/mips/ath79/pci.h -@@ -8,15 +8,15 @@ - * by the Free Software Foundation. - */ - --#ifndef __ASM_MACH_ATH79_PCI_ATH724X_H --#define __ASM_MACH_ATH79_PCI_ATH724X_H -+#ifndef _ATH79_PCI_H -+#define _ATH79_PCI_H - --struct ath724x_pci_data { -+struct ar724x_pci_data { - int irq; - void *pdata; - }; - --void ath724x_pci_add_data(struct ath724x_pci_data *data, int size); -+void ar724x_pci_add_data(struct ar724x_pci_data *data, int size); - - #ifdef CONFIG_PCI - int ath79_register_pci(void); -@@ -24,4 +24,4 @@ int ath79_register_pci(void); - static inline int ath79_register_pci(void) { return 0; } - #endif - --#endif /* __ASM_MACH_ATH79_PCI_ATH724X_H */ -+#endif /* _ATH79_PCI_H */ -diff --git a/arch/mips/include/asm/mach-ath79/pci.h b/arch/mips/include/asm/mach-ath79/pci.h -index e0c4b53..6d7a837 100644 ---- a/arch/mips/include/asm/mach-ath79/pci.h -+++ b/arch/mips/include/asm/mach-ath79/pci.h -@@ -12,9 +12,9 @@ - #define __ASM_MACH_ATH79_PCI_H - - #if defined(CONFIG_PCI) && defined(CONFIG_SOC_AR724X) --int ath724x_pcibios_init(void); -+int ar724x_pcibios_init(void); - #else --static inline int ath724x_pcibios_init(void) { return 0; } -+static inline int ar724x_pcibios_init(void) { return 0; } - #endif - - #endif /* __ASM_MACH_ATH79_PCI_H */ -diff --git a/arch/mips/pci/pci-ar724x.c b/arch/mips/pci/pci-ar724x.c -index ebefc16..772d12c 100644 ---- a/arch/mips/pci/pci-ar724x.c -+++ b/arch/mips/pci/pci-ar724x.c -@@ -14,13 +14,13 @@ - #define reg_read(_phys) (*(unsigned int *) KSEG1ADDR(_phys)) - #define reg_write(_phys, _val) ((*(unsigned int *) KSEG1ADDR(_phys)) = (_val)) - --#define ATH724X_PCI_DEV_BASE 0x14000000 --#define ATH724X_PCI_MEM_BASE 0x10000000 --#define ATH724X_PCI_MEM_SIZE 0x08000000 -+#define AR724X_PCI_DEV_BASE 0x14000000 -+#define AR724X_PCI_MEM_BASE 0x10000000 -+#define AR724X_PCI_MEM_SIZE 0x08000000 - --static DEFINE_SPINLOCK(ath724x_pci_lock); -+static DEFINE_SPINLOCK(ar724x_pci_lock); - --static int ath724x_pci_read(struct pci_bus *bus, unsigned int devfn, int where, -+static int ar724x_pci_read(struct pci_bus *bus, unsigned int devfn, int where, - int size, uint32_t *value) - { - unsigned long flags, addr, tval, mask; -@@ -31,38 +31,38 @@ static int ath724x_pci_read(struct pci_bus *bus, unsigned int devfn, int where, - if (where & (size - 1)) - return PCIBIOS_BAD_REGISTER_NUMBER; - -- spin_lock_irqsave(&ath724x_pci_lock, flags); -+ spin_lock_irqsave(&ar724x_pci_lock, flags); - - switch (size) { - case 1: - addr = where & ~3; - mask = 0xff000000 >> ((where % 4) * 8); -- tval = reg_read(ATH724X_PCI_DEV_BASE + addr); -+ tval = reg_read(AR724X_PCI_DEV_BASE + addr); - tval = tval & ~mask; - *value = (tval >> ((4 - (where % 4))*8)); - break; - case 2: - addr = where & ~3; - mask = 0xffff0000 >> ((where % 4)*8); -- tval = reg_read(ATH724X_PCI_DEV_BASE + addr); -+ tval = reg_read(AR724X_PCI_DEV_BASE + addr); - tval = tval & ~mask; - *value = (tval >> ((4 - (where % 4))*8)); - break; - case 4: -- *value = reg_read(ATH724X_PCI_DEV_BASE + where); -+ *value = reg_read(AR724X_PCI_DEV_BASE + where); - break; - default: -- spin_unlock_irqrestore(&ath724x_pci_lock, flags); -+ spin_unlock_irqrestore(&ar724x_pci_lock, flags); - - return PCIBIOS_BAD_REGISTER_NUMBER; - } - -- spin_unlock_irqrestore(&ath724x_pci_lock, flags); -+ spin_unlock_irqrestore(&ar724x_pci_lock, flags); - - return PCIBIOS_SUCCESSFUL; - } - --static int ath724x_pci_write(struct pci_bus *bus, unsigned int devfn, int where, -+static int ar724x_pci_write(struct pci_bus *bus, unsigned int devfn, int where, - int size, uint32_t value) - { - unsigned long flags, tval, addr, mask; -@@ -73,11 +73,11 @@ static int ath724x_pci_write(struct pci_bus *bus, unsigned int devfn, int where, - if (where & (size - 1)) - return PCIBIOS_BAD_REGISTER_NUMBER; - -- spin_lock_irqsave(&ath724x_pci_lock, flags); -+ spin_lock_irqsave(&ar724x_pci_lock, flags); - - switch (size) { - case 1: -- addr = (ATH724X_PCI_DEV_BASE + where) & ~3; -+ addr = (AR724X_PCI_DEV_BASE + where) & ~3; - mask = 0xff000000 >> ((where % 4)*8); - tval = reg_read(addr); - tval = tval & ~mask; -@@ -85,7 +85,7 @@ static int ath724x_pci_write(struct pci_bus *bus, unsigned int devfn, int where, - reg_write(addr, tval); - break; - case 2: -- addr = (ATH724X_PCI_DEV_BASE + where) & ~3; -+ addr = (AR724X_PCI_DEV_BASE + where) & ~3; - mask = 0xffff0000 >> ((where % 4)*8); - tval = reg_read(addr); - tval = tval & ~mask; -@@ -93,47 +93,47 @@ static int ath724x_pci_write(struct pci_bus *bus, unsigned int devfn, int where, - reg_write(addr, tval); - break; - case 4: -- reg_write((ATH724X_PCI_DEV_BASE + where), value); -+ reg_write((AR724X_PCI_DEV_BASE + where), value); - break; - default: -- spin_unlock_irqrestore(&ath724x_pci_lock, flags); -+ spin_unlock_irqrestore(&ar724x_pci_lock, flags); - - return PCIBIOS_BAD_REGISTER_NUMBER; - } - -- spin_unlock_irqrestore(&ath724x_pci_lock, flags); -+ spin_unlock_irqrestore(&ar724x_pci_lock, flags); - - return PCIBIOS_SUCCESSFUL; - } - --static struct pci_ops ath724x_pci_ops = { -- .read = ath724x_pci_read, -- .write = ath724x_pci_write, -+static struct pci_ops ar724x_pci_ops = { -+ .read = ar724x_pci_read, -+ .write = ar724x_pci_write, - }; - --static struct resource ath724x_io_resource = { -+static struct resource ar724x_io_resource = { - .name = "PCI IO space", - .start = 0, - .end = 0, - .flags = IORESOURCE_IO, - }; - --static struct resource ath724x_mem_resource = { -+static struct resource ar724x_mem_resource = { - .name = "PCI memory space", -- .start = ATH724X_PCI_MEM_BASE, -- .end = ATH724X_PCI_MEM_BASE + ATH724X_PCI_MEM_SIZE - 1, -+ .start = AR724X_PCI_MEM_BASE, -+ .end = AR724X_PCI_MEM_BASE + AR724X_PCI_MEM_SIZE - 1, - .flags = IORESOURCE_MEM, - }; - --static struct pci_controller ath724x_pci_controller = { -- .pci_ops = &ath724x_pci_ops, -- .io_resource = &ath724x_io_resource, -- .mem_resource = &ath724x_mem_resource, -+static struct pci_controller ar724x_pci_controller = { -+ .pci_ops = &ar724x_pci_ops, -+ .io_resource = &ar724x_io_resource, -+ .mem_resource = &ar724x_mem_resource, - }; - --int __init ath724x_pcibios_init(void) -+int __init ar724x_pcibios_init(void) - { -- register_pci_controller(&ath724x_pci_controller); -+ register_pci_controller(&ar724x_pci_controller); - - return PCIBIOS_SUCCESSFUL; - } --- -1.7.9.7 - diff --git a/bsp/routerstationpro/MIPS-ath79-rework-IP2-IP3-interrupt-handling.patch b/bsp/routerstationpro/MIPS-ath79-rework-IP2-IP3-interrupt-handling.patch deleted file mode 100644 index fe63380b2f69cfca47e5af7c890f603310b8ad1d..0000000000000000000000000000000000000000 --- a/bsp/routerstationpro/MIPS-ath79-rework-IP2-IP3-interrupt-handling.patch +++ /dev/null @@ -1,166 +0,0 @@ -From fafb3babde6029242baae7b63f25c6064d9c8159 Mon Sep 17 00:00:00 2001 -From: Gabor Juhos <juhosg@openwrt.org> -Date: Wed, 14 Mar 2012 10:45:24 +0100 -Subject: [PATCH 056/123] MIPS: ath79: rework IP2/IP3 interrupt handling - -commit 4dbcbdf8135def8f704b130305721bdd42a8078b upstream - -The current implementation assumes that flushing the -DDR writeback buffer is required for IP2/IP3 interrupts, -however this is not true for all SoCs. - -Use SoC specific IP2/IP3 handlers instead of flushing -the buffers in the dispatcher code. - -Signed-off-by: Gabor Juhos <juhosg@openwrt.org> -Acked-by: Luis R. Rodriguez <mcgrof@qca.qualcomm.com> -Cc: linux-mips@linux-mips.org -Cc: mcgrof@infradead.org -Patchwork: https://patchwork.linux-mips.org/patch/3509/ -Signed-off-by: Ralf Baechle <ralf@linux-mips.org> -Signed-off-by: Paul Gortmaker <paul.gortmaker@windriver.com> ---- - arch/mips/ath79/irq.c | 92 ++++++++++++++++++++++++++++++++++++++----------- - 1 file changed, 72 insertions(+), 20 deletions(-) - -diff --git a/arch/mips/ath79/irq.c b/arch/mips/ath79/irq.c -index 1b073de..9f87ade 100644 ---- a/arch/mips/ath79/irq.c -+++ b/arch/mips/ath79/irq.c -@@ -1,7 +1,7 @@ - /* - * Atheros AR71xx/AR724x/AR913x specific interrupt handling - * -- * Copyright (C) 2008-2010 Gabor Juhos <juhosg@openwrt.org> -+ * Copyright (C) 2008-2011 Gabor Juhos <juhosg@openwrt.org> - * Copyright (C) 2008 Imre Kaloz <kaloz@openwrt.org> - * - * Parts of this file are based on Atheros' 2.6.15 BSP -@@ -23,8 +23,8 @@ - #include <asm/mach-ath79/ar71xx_regs.h> - #include "common.h" - --static unsigned int ath79_ip2_flush_reg; --static unsigned int ath79_ip3_flush_reg; -+static void (*ath79_ip2_handler)(void); -+static void (*ath79_ip3_handler)(void); - - static void ath79_misc_irq_handler(unsigned int irq, struct irq_desc *desc) - { -@@ -152,10 +152,8 @@ asmlinkage void plat_irq_dispatch(void) - if (pending & STATUSF_IP7) - do_IRQ(ATH79_CPU_IRQ_TIMER); - -- else if (pending & STATUSF_IP2) { -- ath79_ddr_wb_flush(ath79_ip2_flush_reg); -- do_IRQ(ATH79_CPU_IRQ_IP2); -- } -+ else if (pending & STATUSF_IP2) -+ ath79_ip2_handler(); - - else if (pending & STATUSF_IP4) - do_IRQ(ATH79_CPU_IRQ_GE0); -@@ -163,10 +161,8 @@ asmlinkage void plat_irq_dispatch(void) - else if (pending & STATUSF_IP5) - do_IRQ(ATH79_CPU_IRQ_GE1); - -- else if (pending & STATUSF_IP3) { -- ath79_ddr_wb_flush(ath79_ip3_flush_reg); -- do_IRQ(ATH79_CPU_IRQ_USB); -- } -+ else if (pending & STATUSF_IP3) -+ ath79_ip3_handler(); - - else if (pending & STATUSF_IP6) - do_IRQ(ATH79_CPU_IRQ_MISC); -@@ -175,22 +171,78 @@ asmlinkage void plat_irq_dispatch(void) - spurious_interrupt(); - } - -+/* -+ * The IP2/IP3 lines are tied to a PCI/WMAC/USB device. Drivers for -+ * these devices typically allocate coherent DMA memory, however the -+ * DMA controller may still have some unsynchronized data in the FIFO. -+ * Issue a flush in the handlers to ensure that the driver sees -+ * the update. -+ */ -+static void ar71xx_ip2_handler(void) -+{ -+ ath79_ddr_wb_flush(AR71XX_DDR_REG_FLUSH_PCI); -+ do_IRQ(ATH79_CPU_IRQ_IP2); -+} -+ -+static void ar724x_ip2_handler(void) -+{ -+ ath79_ddr_wb_flush(AR724X_DDR_REG_FLUSH_PCIE); -+ do_IRQ(ATH79_CPU_IRQ_IP2); -+} -+ -+static void ar913x_ip2_handler(void) -+{ -+ ath79_ddr_wb_flush(AR913X_DDR_REG_FLUSH_WMAC); -+ do_IRQ(ATH79_CPU_IRQ_IP2); -+} -+ -+static void ar933x_ip2_handler(void) -+{ -+ ath79_ddr_wb_flush(AR933X_DDR_REG_FLUSH_WMAC); -+ do_IRQ(ATH79_CPU_IRQ_IP2); -+} -+ -+static void ar71xx_ip3_handler(void) -+{ -+ ath79_ddr_wb_flush(AR71XX_DDR_REG_FLUSH_USB); -+ do_IRQ(ATH79_CPU_IRQ_USB); -+} -+ -+static void ar724x_ip3_handler(void) -+{ -+ ath79_ddr_wb_flush(AR724X_DDR_REG_FLUSH_USB); -+ do_IRQ(ATH79_CPU_IRQ_USB); -+} -+ -+static void ar913x_ip3_handler(void) -+{ -+ ath79_ddr_wb_flush(AR913X_DDR_REG_FLUSH_USB); -+ do_IRQ(ATH79_CPU_IRQ_USB); -+} -+ -+static void ar933x_ip3_handler(void) -+{ -+ ath79_ddr_wb_flush(AR933X_DDR_REG_FLUSH_USB); -+ do_IRQ(ATH79_CPU_IRQ_USB); -+} -+ - void __init arch_init_irq(void) - { - if (soc_is_ar71xx()) { -- ath79_ip2_flush_reg = AR71XX_DDR_REG_FLUSH_PCI; -- ath79_ip3_flush_reg = AR71XX_DDR_REG_FLUSH_USB; -+ ath79_ip2_handler = ar71xx_ip2_handler; -+ ath79_ip3_handler = ar71xx_ip3_handler; - } else if (soc_is_ar724x()) { -- ath79_ip2_flush_reg = AR724X_DDR_REG_FLUSH_PCIE; -- ath79_ip3_flush_reg = AR724X_DDR_REG_FLUSH_USB; -+ ath79_ip2_handler = ar724x_ip2_handler; -+ ath79_ip3_handler = ar724x_ip3_handler; - } else if (soc_is_ar913x()) { -- ath79_ip2_flush_reg = AR913X_DDR_REG_FLUSH_WMAC; -- ath79_ip3_flush_reg = AR913X_DDR_REG_FLUSH_USB; -+ ath79_ip2_handler = ar913x_ip2_handler; -+ ath79_ip3_handler = ar913x_ip3_handler; - } else if (soc_is_ar933x()) { -- ath79_ip2_flush_reg = AR933X_DDR_REG_FLUSH_WMAC; -- ath79_ip3_flush_reg = AR933X_DDR_REG_FLUSH_USB; -- } else -+ ath79_ip2_handler = ar933x_ip2_handler; -+ ath79_ip3_handler = ar933x_ip3_handler; -+ } else { - BUG(); -+ } - - cp0_perfcount_irq = ATH79_MISC_IRQ_PERFC; - mips_cpu_irq_init(); --- -1.7.9.7 - diff --git a/bsp/routerstationpro/MIPS-ath79-separate-common-PCI-code.patch b/bsp/routerstationpro/MIPS-ath79-separate-common-PCI-code.patch deleted file mode 100644 index 727332525deecd966b98a02f553f09dd79e35c8b..0000000000000000000000000000000000000000 --- a/bsp/routerstationpro/MIPS-ath79-separate-common-PCI-code.patch +++ /dev/null @@ -1,163 +0,0 @@ -From 2c65709cc98296282031deed473d83db2d8cf55a Mon Sep 17 00:00:00 2001 -From: Gabor Juhos <juhosg@openwrt.org> -Date: Wed, 14 Mar 2012 10:29:21 +0100 -Subject: [PATCH 032/123] MIPS: ath79: separate common PCI code -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -commit e2dbdc436b46250c8682ea57151a7afb45f271e1 upstream. - -The 'pcibios_map_irq' and 'pcibios_plat_dev_init' -are common functions and only instance one of them -can be present in a single kernel. - -Currently these functions can be built only if the -CONFIG_SOC_AR724X option is selected. However the -ath79 platform contain support for the AR71XX SoCs,. -The AR71XX SoCs have a differnet PCI controller, -and those will require a different code. - -Move the common PCI code into a separeate file in -order to be able to use that with other SoCs as -well. - -Signed-off-by: Gabor Juhos <juhosg@openwrt.org> -Acked-by: René Bolldorf <xsecute@googlemail.com> -Cc: linux-mips@linux-mips.org -Patchwork: https://patchwork.linux-mips.org/patch/3485/ -Signed-off-by: Ralf Baechle <ralf@linux-mips.org> -Signed-off-by: Paul Gortmaker <paul.gortmaker@windriver.com> ---- - arch/mips/ath79/Makefile | 1 + - arch/mips/ath79/pci.c | 46 +++++++++++++++++++++++++++++++++++++++++++ - arch/mips/pci/pci-ath724x.c | 34 -------------------------------- - 3 files changed, 47 insertions(+), 34 deletions(-) - create mode 100644 arch/mips/ath79/pci.c - -diff --git a/arch/mips/ath79/Makefile b/arch/mips/ath79/Makefile -index 3b911e09..221a76a 100644 ---- a/arch/mips/ath79/Makefile -+++ b/arch/mips/ath79/Makefile -@@ -11,6 +11,7 @@ - obj-y := prom.o setup.o irq.o common.o clock.o gpio.o - - obj-$(CONFIG_EARLY_PRINTK) += early_printk.o -+obj-$(CONFIG_PCI) += pci.o - - # - # Devices -diff --git a/arch/mips/ath79/pci.c b/arch/mips/ath79/pci.c -new file mode 100644 -index 0000000..8db076e ---- /dev/null -+++ b/arch/mips/ath79/pci.c -@@ -0,0 +1,46 @@ -+/* -+ * Atheros AR71XX/AR724X specific PCI setup code -+ * -+ * Copyright (C) 2011 René Bolldorf <xsecute@googlemail.com> -+ * -+ * This program is free software; you can redistribute it and/or modify it -+ * under the terms of the GNU General Public License version 2 as published -+ * by the Free Software Foundation. -+ */ -+ -+#include <linux/pci.h> -+#include <asm/mach-ath79/pci-ath724x.h> -+ -+static struct ath724x_pci_data *pci_data; -+static int pci_data_size; -+ -+void ath724x_pci_add_data(struct ath724x_pci_data *data, int size) -+{ -+ pci_data = data; -+ pci_data_size = size; -+} -+ -+int __init pcibios_map_irq(const struct pci_dev *dev, uint8_t slot, uint8_t pin) -+{ -+ unsigned int devfn = dev->devfn; -+ int irq = -1; -+ -+ if (devfn > pci_data_size - 1) -+ return irq; -+ -+ irq = pci_data[devfn].irq; -+ -+ return irq; -+} -+ -+int pcibios_plat_dev_init(struct pci_dev *dev) -+{ -+ unsigned int devfn = dev->devfn; -+ -+ if (devfn > pci_data_size - 1) -+ return PCIBIOS_DEVICE_NOT_FOUND; -+ -+ dev->dev.platform_data = pci_data[devfn].pdata; -+ -+ return PCIBIOS_SUCCESSFUL; -+} -diff --git a/arch/mips/pci/pci-ath724x.c b/arch/mips/pci/pci-ath724x.c -index a4dd24a..1e810be 100644 ---- a/arch/mips/pci/pci-ath724x.c -+++ b/arch/mips/pci/pci-ath724x.c -@@ -9,7 +9,6 @@ - */ - - #include <linux/pci.h> --#include <asm/mach-ath79/pci-ath724x.h> - - #define reg_read(_phys) (*(unsigned int *) KSEG1ADDR(_phys)) - #define reg_write(_phys, _val) ((*(unsigned int *) KSEG1ADDR(_phys)) = (_val)) -@@ -19,8 +18,6 @@ - #define ATH724X_PCI_MEM_SIZE 0x08000000 - - static DEFINE_SPINLOCK(ath724x_pci_lock); --static struct ath724x_pci_data *pci_data; --static int pci_data_size; - - static int ath724x_pci_read(struct pci_bus *bus, unsigned int devfn, int where, - int size, uint32_t *value) -@@ -133,37 +130,6 @@ static struct pci_controller ath724x_pci_controller = { - .mem_resource = &ath724x_mem_resource, - }; - --void ath724x_pci_add_data(struct ath724x_pci_data *data, int size) --{ -- pci_data = data; -- pci_data_size = size; --} -- --int __init pcibios_map_irq(const struct pci_dev *dev, uint8_t slot, uint8_t pin) --{ -- unsigned int devfn = dev->devfn; -- int irq = -1; -- -- if (devfn > pci_data_size - 1) -- return irq; -- -- irq = pci_data[devfn].irq; -- -- return irq; --} -- --int pcibios_plat_dev_init(struct pci_dev *dev) --{ -- unsigned int devfn = dev->devfn; -- -- if (devfn > pci_data_size - 1) -- return PCIBIOS_DEVICE_NOT_FOUND; -- -- dev->dev.platform_data = pci_data[devfn].pdata; -- -- return PCIBIOS_SUCCESSFUL; --} -- - static int __init ath724x_pcibios_init(void) - { - register_pci_controller(&ath724x_pci_controller); --- -1.7.9.7 - diff --git a/bsp/routerstationpro/MIPS-ath79-sort-case-statements-in-ath79_detect_sys_.patch b/bsp/routerstationpro/MIPS-ath79-sort-case-statements-in-ath79_detect_sys_.patch deleted file mode 100644 index 1cd86fe9f528dc83e31920736241a76fe37cafee..0000000000000000000000000000000000000000 --- a/bsp/routerstationpro/MIPS-ath79-sort-case-statements-in-ath79_detect_sys_.patch +++ /dev/null @@ -1,67 +0,0 @@ -From c36c1920448695bfaccf2879ec4ad3b4e2f4585d Mon Sep 17 00:00:00 2001 -From: Gabor Juhos <juhosg@openwrt.org> -Date: Wed, 14 Mar 2012 10:45:20 +0100 -Subject: [PATCH 052/123] MIPS: ath79: sort case statements in - ath79_detect_sys_type - -commit 80a7ed81a840aee97f7650cbeaabb3c2c1765e70 upstream. - -Sort the case statements alphabetically in order to improve -readability. - -Signed-off-by: Gabor Juhos <juhosg@openwrt.org> -Acked-by: Luis R. Rodriguez <mcgrof@qca.qualcomm.com> -Cc: linux-mips@linux-mips.org -Cc: mcgrof@infradead.org -Patchwork: https://patchwork.linux-mips.org/patch/3505/ -Signed-off-by: Ralf Baechle <ralf@linux-mips.org> -Signed-off-by: Paul Gortmaker <paul.gortmaker@windriver.com> ---- - arch/mips/ath79/setup.c | 24 ++++++++++++------------ - 1 file changed, 12 insertions(+), 12 deletions(-) - -diff --git a/arch/mips/ath79/setup.c b/arch/mips/ath79/setup.c -index 80a7d40..24dfedf 100644 ---- a/arch/mips/ath79/setup.c -+++ b/arch/mips/ath79/setup.c -@@ -116,18 +116,6 @@ static void __init ath79_detect_sys_type(void) - rev = id & AR724X_REV_ID_REVISION_MASK; - break; - -- case REV_ID_MAJOR_AR9330: -- ath79_soc = ATH79_SOC_AR9330; -- chip = "9330"; -- rev = id & AR933X_REV_ID_REVISION_MASK; -- break; -- -- case REV_ID_MAJOR_AR9331: -- ath79_soc = ATH79_SOC_AR9331; -- chip = "9331"; -- rev = id & AR933X_REV_ID_REVISION_MASK; -- break; -- - case REV_ID_MAJOR_AR913X: - minor = id & AR913X_REV_ID_MINOR_MASK; - rev = id >> AR913X_REV_ID_REVISION_SHIFT; -@@ -145,6 +133,18 @@ static void __init ath79_detect_sys_type(void) - } - break; - -+ case REV_ID_MAJOR_AR9330: -+ ath79_soc = ATH79_SOC_AR9330; -+ chip = "9330"; -+ rev = id & AR933X_REV_ID_REVISION_MASK; -+ break; -+ -+ case REV_ID_MAJOR_AR9331: -+ ath79_soc = ATH79_SOC_AR9331; -+ chip = "9331"; -+ rev = id & AR933X_REV_ID_REVISION_MASK; -+ break; -+ - default: - panic("ath79: unknown SoC, id:0x%08x", id); - } --- -1.7.9.7 - diff --git a/bsp/routerstationpro/MIPS-ath79-update-copyright-headers-of-PCI-related-f.patch b/bsp/routerstationpro/MIPS-ath79-update-copyright-headers-of-PCI-related-f.patch deleted file mode 100644 index 883cafb57bbfe2a86235609050015df5b2be6f27..0000000000000000000000000000000000000000 --- a/bsp/routerstationpro/MIPS-ath79-update-copyright-headers-of-PCI-related-f.patch +++ /dev/null @@ -1,86 +0,0 @@ -From 7fcf1022dfdc6e6864f6e6e7d4accd3782b651c7 Mon Sep 17 00:00:00 2001 -From: Gabor Juhos <juhosg@openwrt.org> -Date: Wed, 14 Mar 2012 10:36:14 +0100 -Subject: [PATCH 050/123] MIPS: ath79: update copyright headers of PCI related - files - -commit e9b62e8ef9d71ed977797529fc0dfc352448d50b upstream. - -Add copyright records according to the recent changes in -the PCI code. Also fix up the descriptions. - -Signed-off-by: Gabor Juhos <juhosg@openwrt.org> -Signed-off-by: Imre Kaloz <kaloz@openwrt.org> -Cc: linux-mips@linux-mips.org -Patchwork: https://patchwork.linux-mips.org/patch/3503/ -Signed-off-by: Ralf Baechle <ralf@linux-mips.org> -Signed-off-by: Paul Gortmaker <paul.gortmaker@windriver.com> ---- - arch/mips/ath79/pci.c | 4 ++++ - arch/mips/ath79/pci.h | 4 +++- - arch/mips/include/asm/mach-ath79/pci.h | 4 +++- - arch/mips/pci/pci-ar724x.c | 3 ++- - 4 files changed, 12 insertions(+), 3 deletions(-) - -diff --git a/arch/mips/ath79/pci.c b/arch/mips/ath79/pci.c -index 253a382..bc40070 100644 ---- a/arch/mips/ath79/pci.c -+++ b/arch/mips/ath79/pci.c -@@ -2,6 +2,10 @@ - * Atheros AR71XX/AR724X specific PCI setup code - * - * Copyright (C) 2011 René Bolldorf <xsecute@googlemail.com> -+ * Copyright (C) 2008-2011 Gabor Juhos <juhosg@openwrt.org> -+ * Copyright (C) 2008 Imre Kaloz <kaloz@openwrt.org> -+ * -+ * Parts of this file are based on Atheros' 2.6.15 BSP - * - * 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 -diff --git a/arch/mips/ath79/pci.h b/arch/mips/ath79/pci.h -index 5ebed21..51c6625 100644 ---- a/arch/mips/ath79/pci.h -+++ b/arch/mips/ath79/pci.h -@@ -1,7 +1,9 @@ - /* -- * Atheros 724x PCI support -+ * Atheros AR71XX/AR724X PCI support - * - * Copyright (C) 2011 René Bolldorf <xsecute@googlemail.com> -+ * Copyright (C) 2008-2011 Gabor Juhos <juhosg@openwrt.org> -+ * Copyright (C) 2008 Imre Kaloz <kaloz@openwrt.org> - * - * 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 -diff --git a/arch/mips/include/asm/mach-ath79/pci.h b/arch/mips/include/asm/mach-ath79/pci.h -index b12b087..4f2222d 100644 ---- a/arch/mips/include/asm/mach-ath79/pci.h -+++ b/arch/mips/include/asm/mach-ath79/pci.h -@@ -1,7 +1,9 @@ - /* -- * Atheros 724x PCI support -+ * Atheros AR71XX/AR724X PCI support - * - * Copyright (C) 2011 René Bolldorf <xsecute@googlemail.com> -+ * Copyright (C) 2008-2011 Gabor Juhos <juhosg@openwrt.org> -+ * Copyright (C) 2008 Imre Kaloz <kaloz@openwrt.org> - * - * 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 -diff --git a/arch/mips/pci/pci-ar724x.c b/arch/mips/pci/pci-ar724x.c -index 04f433a..414a745 100644 ---- a/arch/mips/pci/pci-ar724x.c -+++ b/arch/mips/pci/pci-ar724x.c -@@ -1,7 +1,8 @@ - /* -- * Atheros 724x PCI support -+ * Atheros AR724X PCI host controller driver - * - * Copyright (C) 2011 René Bolldorf <xsecute@googlemail.com> -+ * Copyright (C) 2009-2011 Gabor Juhos <juhosg@openwrt.org> - * - * 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 --- -1.7.9.7 - diff --git a/bsp/routerstationpro/MIPS-ath79-use-correct-IRQ-number-for-the-OHCI-contr.patch b/bsp/routerstationpro/MIPS-ath79-use-correct-IRQ-number-for-the-OHCI-contr.patch deleted file mode 100644 index 53056e657fc605c492fea46c3eebfc27b4a7dd3d..0000000000000000000000000000000000000000 --- a/bsp/routerstationpro/MIPS-ath79-use-correct-IRQ-number-for-the-OHCI-contr.patch +++ /dev/null @@ -1,44 +0,0 @@ -From ac0e95ade1684835d4e98be2897d02b266fc5076 Mon Sep 17 00:00:00 2001 -From: Gabor Juhos <juhosg@openwrt.org> -Date: Wed, 28 Mar 2012 11:00:19 +0200 -Subject: [PATCH 064/123] MIPS: ath79: use correct IRQ number for the OHCI - controller on AR7240 - -The currently assigned IRQ number to the OHCI -controller is incorrect for the AR7240 SoC, and -that leads to the following error message from -the OHCI driver: - -ohci_hcd: USB 1.1 'Open' Host Controller (OHCI) Driver -ath79-ohci ath79-ohci: Atheros built-in OHCI controller -ath79-ohci ath79-ohci: new USB bus registered, assigned bus number 1 -ath79-ohci ath79-ohci: irq 14, io mem 0x1b000000 -hub 1-0:1.0: USB hub found -hub 1-0:1.0: 1 port detected -usb 1-1: new full-speed USB device number 2 using ath79-ohci -ath79-ohci ath79-ohci: Unlink after no-IRQ? Controller is probably using the wrong IRQ. - -Fix this by using the correct IRQ number. - -Signed-off-by: Gabor Juhos <juhosg@openwrt.org> -Signed-off-by: Paul Gortmaker <paul.gortmaker@windriver.com> ---- - arch/mips/ath79/dev-usb.c | 2 ++ - 1 file changed, 2 insertions(+) - -diff --git a/arch/mips/ath79/dev-usb.c b/arch/mips/ath79/dev-usb.c -index 36e9570..b2a2311 100644 ---- a/arch/mips/ath79/dev-usb.c -+++ b/arch/mips/ath79/dev-usb.c -@@ -145,6 +145,8 @@ static void __init ar7240_usb_setup(void) - - ath79_ohci_resources[0].start = AR7240_OHCI_BASE; - ath79_ohci_resources[0].end = AR7240_OHCI_BASE + AR7240_OHCI_SIZE - 1; -+ ath79_ohci_resources[1].start = ATH79_CPU_IRQ_USB; -+ ath79_ohci_resources[1].end = ATH79_CPU_IRQ_USB; - platform_device_register(&ath79_ohci_device); - } - --- -1.7.9.7 - diff --git a/bsp/routerstationpro/MIPS-ath79-use-io-accessor-macros-in-pci-ar724x.c.patch b/bsp/routerstationpro/MIPS-ath79-use-io-accessor-macros-in-pci-ar724x.c.patch deleted file mode 100644 index 5b96926d16e2c98a4864d9766635f725e8e20a1b..0000000000000000000000000000000000000000 --- a/bsp/routerstationpro/MIPS-ath79-use-io-accessor-macros-in-pci-ar724x.c.patch +++ /dev/null @@ -1,139 +0,0 @@ -From 4ad8cc29bd428fffc4003ffaa2a1b60dbb02675d Mon Sep 17 00:00:00 2001 -From: Gabor Juhos <juhosg@openwrt.org> -Date: Wed, 14 Mar 2012 10:29:27 +0100 -Subject: [PATCH 038/123] MIPS: ath79: use io-accessor macros in pci-ar724x.c -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -commit c198441a3f3007752c551a32d5c426f48ae8712d upstream. - -Signed-off-by: Gabor Juhos <juhosg@openwrt.org> -Acked-by: René Bolldorf <xsecute@googlemail.com> -Cc: linux-mips@linux-mips.org -Patchwork: https://patchwork.linux-mips.org/patch/3491/ -Signed-off-by: Ralf Baechle <ralf@linux-mips.org> -Signed-off-by: Paul Gortmaker <paul.gortmaker@windriver.com> ---- - arch/mips/pci/pci-ar724x.c | 38 ++++++++++++++++++++++++-------------- - 1 file changed, 24 insertions(+), 14 deletions(-) - -diff --git a/arch/mips/pci/pci-ar724x.c b/arch/mips/pci/pci-ar724x.c -index 772d12c..22f5e5b 100644 ---- a/arch/mips/pci/pci-ar724x.c -+++ b/arch/mips/pci/pci-ar724x.c -@@ -11,19 +11,19 @@ - #include <linux/pci.h> - #include <asm/mach-ath79/pci.h> - --#define reg_read(_phys) (*(unsigned int *) KSEG1ADDR(_phys)) --#define reg_write(_phys, _val) ((*(unsigned int *) KSEG1ADDR(_phys)) = (_val)) -- --#define AR724X_PCI_DEV_BASE 0x14000000 -+#define AR724X_PCI_CFG_BASE 0x14000000 -+#define AR724X_PCI_CFG_SIZE 0x1000 - #define AR724X_PCI_MEM_BASE 0x10000000 - #define AR724X_PCI_MEM_SIZE 0x08000000 - - static DEFINE_SPINLOCK(ar724x_pci_lock); -+static void __iomem *ar724x_pci_devcfg_base; - - static int ar724x_pci_read(struct pci_bus *bus, unsigned int devfn, int where, - int size, uint32_t *value) - { - unsigned long flags, addr, tval, mask; -+ void __iomem *base; - - if (devfn) - return PCIBIOS_DEVICE_NOT_FOUND; -@@ -31,25 +31,27 @@ static int ar724x_pci_read(struct pci_bus *bus, unsigned int devfn, int where, - if (where & (size - 1)) - return PCIBIOS_BAD_REGISTER_NUMBER; - -+ base = ar724x_pci_devcfg_base; -+ - spin_lock_irqsave(&ar724x_pci_lock, flags); - - switch (size) { - case 1: - addr = where & ~3; - mask = 0xff000000 >> ((where % 4) * 8); -- tval = reg_read(AR724X_PCI_DEV_BASE + addr); -+ tval = __raw_readl(base + addr); - tval = tval & ~mask; - *value = (tval >> ((4 - (where % 4))*8)); - break; - case 2: - addr = where & ~3; - mask = 0xffff0000 >> ((where % 4)*8); -- tval = reg_read(AR724X_PCI_DEV_BASE + addr); -+ tval = __raw_readl(base + addr); - tval = tval & ~mask; - *value = (tval >> ((4 - (where % 4))*8)); - break; - case 4: -- *value = reg_read(AR724X_PCI_DEV_BASE + where); -+ *value = __raw_readl(base + where); - break; - default: - spin_unlock_irqrestore(&ar724x_pci_lock, flags); -@@ -66,6 +68,7 @@ static int ar724x_pci_write(struct pci_bus *bus, unsigned int devfn, int where, - int size, uint32_t value) - { - unsigned long flags, tval, addr, mask; -+ void __iomem *base; - - if (devfn) - return PCIBIOS_DEVICE_NOT_FOUND; -@@ -73,27 +76,29 @@ static int ar724x_pci_write(struct pci_bus *bus, unsigned int devfn, int where, - if (where & (size - 1)) - return PCIBIOS_BAD_REGISTER_NUMBER; - -+ base = ar724x_pci_devcfg_base; -+ - spin_lock_irqsave(&ar724x_pci_lock, flags); - - switch (size) { - case 1: -- addr = (AR724X_PCI_DEV_BASE + where) & ~3; -+ addr = where & ~3; - mask = 0xff000000 >> ((where % 4)*8); -- tval = reg_read(addr); -+ tval = __raw_readl(base + addr); - tval = tval & ~mask; - tval |= (value << ((4 - (where % 4))*8)) & mask; -- reg_write(addr, tval); -+ __raw_writel(tval, base + addr); - break; - case 2: -- addr = (AR724X_PCI_DEV_BASE + where) & ~3; -+ addr = where & ~3; - mask = 0xffff0000 >> ((where % 4)*8); -- tval = reg_read(addr); -+ tval = __raw_readl(base + addr); - tval = tval & ~mask; - tval |= (value << ((4 - (where % 4))*8)) & mask; -- reg_write(addr, tval); -+ __raw_writel(tval, base + addr); - break; - case 4: -- reg_write((AR724X_PCI_DEV_BASE + where), value); -+ __raw_writel(value, (base + where)); - break; - default: - spin_unlock_irqrestore(&ar724x_pci_lock, flags); -@@ -133,6 +138,11 @@ static struct pci_controller ar724x_pci_controller = { - - int __init ar724x_pcibios_init(void) - { -+ ar724x_pci_devcfg_base = ioremap(AR724X_PCI_CFG_BASE, -+ AR724X_PCI_CFG_SIZE); -+ if (ar724x_pci_devcfg_base == NULL) -+ return -ENOMEM; -+ - register_pci_controller(&ar724x_pci_controller); - - return PCIBIOS_SUCCESSFUL; --- -1.7.9.7 - diff --git a/bsp/routerstationpro/generic-openwrt-phy-files.patch b/bsp/routerstationpro/generic-openwrt-phy-files.patch index 26894fc7590884407b3147be55fc455a9bd7fba6..33e8d45cc6d8c82a27bc08c5694dc033a7167291 100644 --- a/bsp/routerstationpro/generic-openwrt-phy-files.patch +++ b/bsp/routerstationpro/generic-openwrt-phy-files.patch @@ -24,42 +24,6 @@ Path to files in the repo is: target/linux/generic/files Repo is: git://nbd.name/openwrt.git Signed-off-by: Paul Gortmaker <paul.gortmaker@windriver.com> ---- - drivers/net/phy/adm6996.c | 737 ++++++++++++++++ - drivers/net/phy/adm6996.h | 162 ++++ - drivers/net/phy/ar8216.c | 1535 +++++++++++++++++++++++++++++++++ - drivers/net/phy/ar8216.h | 341 ++++++++ - drivers/net/phy/ip17xx.c | 1410 +++++++++++++++++++++++++++++++ - drivers/net/phy/micrel.c | 270 ++---- - drivers/net/phy/mvswitch.c | 422 ++++++++++ - drivers/net/phy/mvswitch.h | 145 ++++ - drivers/net/phy/psb6970.c | 438 ++++++++++ - drivers/net/phy/rtl8306.c | 1055 +++++++++++++++++++++++ - drivers/net/phy/rtl8366_smi.c | 1350 +++++++++++++++++++++++++++++ - drivers/net/phy/rtl8366_smi.h | 148 ++++ - drivers/net/phy/rtl8366rb.c | 1269 ++++++++++++++++++++++++++++ - drivers/net/phy/rtl8366s.c | 1148 +++++++++++++++++++++++++ - drivers/net/phy/rtl8367.c | 1773 +++++++++++++++++++++++++++++++++++++++ - drivers/net/phy/swconfig.c | 1042 +++++++++++++++++++++++ - drivers/net/phy/swconfig_leds.c | 354 ++++++++ - 17 files changed, 13380 insertions(+), 219 deletions(-) - create mode 100644 drivers/net/phy/adm6996.c - create mode 100644 drivers/net/phy/adm6996.h - create mode 100644 drivers/net/phy/ar8216.c - create mode 100644 drivers/net/phy/ar8216.h - create mode 100644 drivers/net/phy/ip17xx.c - create mode 100644 drivers/net/phy/mvswitch.c - create mode 100644 drivers/net/phy/mvswitch.h - create mode 100644 drivers/net/phy/psb6970.c - create mode 100644 drivers/net/phy/rtl8306.c - create mode 100644 drivers/net/phy/rtl8366_smi.c - create mode 100644 drivers/net/phy/rtl8366_smi.h - create mode 100644 drivers/net/phy/rtl8366rb.c - create mode 100644 drivers/net/phy/rtl8366s.c - create mode 100644 drivers/net/phy/rtl8367.c - create mode 100644 drivers/net/phy/swconfig.c - create mode 100644 drivers/net/phy/swconfig_leds.c - diff --git a/drivers/net/phy/adm6996.c b/drivers/net/phy/adm6996.c new file mode 100644 index 0000000..d4fe553 @@ -4276,10 +4240,10 @@ index 0000000..c82c39e +module_init(ip17xx_init); +module_exit(ip17xx_exit); diff --git a/drivers/net/phy/micrel.c b/drivers/net/phy/micrel.c -index 590f902..1499d4a 100644 +index cf287e0..c34bbad 100644 --- a/drivers/net/phy/micrel.c +++ b/drivers/net/phy/micrel.c -@@ -1,251 +1,83 @@ +@@ -1,145 +1,62 @@ /* - * drivers/net/phy/micrel.c + * Driver for Micrel/Kendin PHYs @@ -4349,11 +4313,11 @@ index 590f902..1499d4a 100644 - KSZPHY_INTCS_ALL : 0; - return phy_write(phydev, MII_KSZPHY_INTCS, temp); -} -- + -static int kszphy_config_intr(struct phy_device *phydev) -{ - int temp, rc; - +- - /* set the interrupt pin active low */ - temp = phy_read(phydev, MII_KSZPHY_CTRL); - temp &= ~KSZPHY_CTRL_INT_ACTIVE_HIGH; @@ -4421,21 +4385,26 @@ index 590f902..1499d4a 100644 + return err; } --static struct phy_driver ks8737_driver = { +-static struct phy_driver ksphy_driver[] = { ++static struct phy_driver ksz8041_phy_driver[] = { + { - .phy_id = PHY_ID_KS8737, - .phy_id_mask = 0x00fffff0, - .name = "Micrel KS8737", - .features = (PHY_BASIC_FEATURES | SUPPORTED_Pause), - .flags = PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT, - .config_init = kszphy_config_init, -- .config_aneg = genphy_config_aneg, -- .read_status = genphy_read_status, ++ .phy_id = 0x00221512, ++ .name = "Micrel KSZ8041", ++ .phy_id_mask = 0x001fffff, ++ .features = PHY_BASIC_FEATURES, ++ .flags = PHY_HAS_INTERRUPT, + .config_aneg = genphy_config_aneg, + .read_status = genphy_read_status, - .ack_interrupt = kszphy_ack_interrupt, - .config_intr = ks8737_config_intr, - .driver = { .owner = THIS_MODULE,}, --}; -- --static struct phy_driver ks8041_driver = { +-}, { - .phy_id = PHY_ID_KS8041, - .phy_id_mask = 0x00fffff0, - .name = "Micrel KS8041", @@ -4448,110 +4417,31 @@ index 590f902..1499d4a 100644 - .ack_interrupt = kszphy_ack_interrupt, - .config_intr = kszphy_config_intr, - .driver = { .owner = THIS_MODULE,}, --}; -- --static struct phy_driver ks8051_driver = { -- .phy_id = PHY_ID_KS8051, -- .phy_id_mask = 0x00fffff0, -- .name = "Micrel KS8051", -- .features = (PHY_BASIC_FEATURES | SUPPORTED_Pause -- | SUPPORTED_Asym_Pause), -- .flags = PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT, -- .config_init = ks8051_config_init, -- .config_aneg = genphy_config_aneg, -- .read_status = genphy_read_status, -- .ack_interrupt = kszphy_ack_interrupt, -- .config_intr = kszphy_config_intr, -- .driver = { .owner = THIS_MODULE,}, --}; -- --static struct phy_driver ks8001_driver = { -- .phy_id = PHY_ID_KS8001, -- .name = "Micrel KS8001 or KS8721", -- .phy_id_mask = 0x00fffff0, -- .features = (PHY_BASIC_FEATURES | SUPPORTED_Pause), -- .flags = PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT, -- .config_init = kszphy_config_init, -- .config_aneg = genphy_config_aneg, -- .read_status = genphy_read_status, -- .ack_interrupt = kszphy_ack_interrupt, -- .config_intr = kszphy_config_intr, -- .driver = { .owner = THIS_MODULE,}, --}; -- --static struct phy_driver ksz9021_driver = { -- .phy_id = PHY_ID_KSZ9021, -- .phy_id_mask = 0x000fff10, -- .name = "Micrel KSZ9021 Gigabit PHY", -- .features = (PHY_GBIT_FEATURES | SUPPORTED_Pause -- | SUPPORTED_Asym_Pause), -- .flags = PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT, -- .config_init = kszphy_config_init, -+static struct phy_driver ksz8041_phy_driver = { -+ .phy_id = 0x00221512, -+ .name = "Micrel KSZ8041", -+ .phy_id_mask = 0x001fffff, -+ .features = PHY_BASIC_FEATURES, -+ .flags = PHY_HAS_INTERRUPT, - .config_aneg = genphy_config_aneg, - .read_status = genphy_read_status, -- .ack_interrupt = kszphy_ack_interrupt, -- .config_intr = ksz9021_config_intr, -- .driver = { .owner = THIS_MODULE, }, + .ack_interrupt = ksz8041_ack_interrupt, + .config_intr = ksz8041_config_intr, -+ .driver = { -+ .owner = THIS_MODULE, -+ }, - }; ++ .driver = { .owner = THIS_MODULE, }, + }, { + .phy_id = PHY_ID_KS8051, + .phy_id_mask = 0x00fffff0, +@@ -180,32 +97,25 @@ static struct phy_driver ksphy_driver[] = { + .driver = { .owner = THIS_MODULE, }, + } }; -static int __init ksphy_init(void) +static int __init micrel_phy_init(void) { -- int ret; -- -- ret = phy_driver_register(&ks8001_driver); -- if (ret) -- goto err1; -- -- ret = phy_driver_register(&ksz9021_driver); -- if (ret) -- goto err2; -- -- ret = phy_driver_register(&ks8737_driver); -- if (ret) -- goto err3; -- ret = phy_driver_register(&ks8041_driver); -- if (ret) -- goto err4; -- ret = phy_driver_register(&ks8051_driver); -- if (ret) -- goto err5; -- -- return 0; -- --err5: -- phy_driver_unregister(&ks8041_driver); --err4: -- phy_driver_unregister(&ks8737_driver); --err3: -- phy_driver_unregister(&ksz9021_driver); --err2: -- phy_driver_unregister(&ks8001_driver); --err1: -- return ret; -+ return phy_driver_register(&ksz8041_phy_driver); +- return phy_drivers_register(ksphy_driver, +- ARRAY_SIZE(ksphy_driver)); ++ return phy_driver_register(ksz8041_phy_driver, ++ ARRAY_SIZE(ksz8041_phy_driver)); } -static void __exit ksphy_exit(void) +static void __exit micrel_phy_exit(void) { -- phy_driver_unregister(&ks8001_driver); -- phy_driver_unregister(&ks8737_driver); -- phy_driver_unregister(&ksz9021_driver); -- phy_driver_unregister(&ks8041_driver); -- phy_driver_unregister(&ks8051_driver); -+ phy_driver_unregister(&ksz8041_phy_driver); +- phy_drivers_unregister(ksphy_driver, +- ARRAY_SIZE(ksphy_driver)); ++ phy_driver_unregister(ksz8041_phy_driver,ARRAY_SIZE(ksz8041_phy_driver) ); } -module_init(ksphy_init); @@ -4562,8 +4452,8 @@ index 590f902..1499d4a 100644 -MODULE_LICENSE("GPL"); - -static struct mdio_device_id __maybe_unused micrel_tbl[] = { -- { PHY_ID_KSZ9021, 0x000fff10 }, -- { PHY_ID_KS8001, 0x00fffff0 }, +- { PHY_ID_KSZ9021, 0x000ffffe }, +- { PHY_ID_KS8001, 0x00ffffff }, - { PHY_ID_KS8737, 0x00fffff0 }, - { PHY_ID_KS8041, 0x00fffff0 }, - { PHY_ID_KS8051, 0x00fffff0 }, @@ -13792,6 +13682,3 @@ index 0000000..6f54cc1 +static inline void +swconfig_destroy_led_trigger(struct switch_dev *swdev) { } +#endif /* CONFIG_SWCONFIG_LEDS */ --- -1.7.9.7 - diff --git a/bsp/routerstationpro/remaining-generic-openwrt-files.patch b/bsp/routerstationpro/remaining-generic-openwrt-files.patch index b00d1434b3e77be4e302f87eaead8fbfed14ddcb..db386531398b6d287af2b91a556ba87cc31c2b29 100644 --- a/bsp/routerstationpro/remaining-generic-openwrt-files.patch +++ b/bsp/routerstationpro/remaining-generic-openwrt-files.patch @@ -24,39 +24,6 @@ Path to files in the repo is: target/linux/generic/files Repo is: git://nbd.name/openwrt.git Signed-off-by: Paul Gortmaker <paul.gortmaker@windriver.com> ---- - Documentation/networking/adm6996.txt | 110 ++++++ - Documentation/pwm.txt | 259 ++++++++++++++ - arch/mips/fw/myloader/Makefile | 5 + - arch/mips/fw/myloader/myloader.c | 63 ++++ - drivers/char/gpio_dev.c | 179 ++++++++++ - drivers/input/misc/gpio_buttons.c | 232 ++++++++++++ - drivers/leds/ledtrig-morse.c | 366 +++++++++++++++++++ - drivers/leds/ledtrig-netdev.c | 451 ++++++++++++++++++++++++ - drivers/leds/ledtrig-usbdev.c | 348 ++++++++++++++++++ - drivers/mtd/myloader.c | 186 ++++++++++ - drivers/pwm/Kconfig | 31 ++ - drivers/pwm/Makefile | 6 + - drivers/pwm/atmel-pwm.c | 592 +++++++++++++++++++++++++++++++ - drivers/pwm/gpio-pwm.c | 298 ++++++++++++++++ - drivers/pwm/pwm.c | 643 ++++++++++++++++++++++++++++++++++ - 15 files changed, 3769 insertions(+) - create mode 100644 Documentation/networking/adm6996.txt - create mode 100644 Documentation/pwm.txt - create mode 100644 arch/mips/fw/myloader/Makefile - create mode 100644 arch/mips/fw/myloader/myloader.c - create mode 100644 drivers/char/gpio_dev.c - create mode 100644 drivers/input/misc/gpio_buttons.c - create mode 100644 drivers/leds/ledtrig-morse.c - create mode 100644 drivers/leds/ledtrig-netdev.c - create mode 100644 drivers/leds/ledtrig-usbdev.c - create mode 100644 drivers/mtd/myloader.c - create mode 100644 drivers/pwm/Kconfig - create mode 100644 drivers/pwm/Makefile - create mode 100644 drivers/pwm/atmel-pwm.c - create mode 100644 drivers/pwm/gpio-pwm.c - create mode 100644 drivers/pwm/pwm.c - diff --git a/Documentation/networking/adm6996.txt b/Documentation/networking/adm6996.txt new file mode 100644 index 0000000..0fca549 @@ -173,271 +140,6 @@ index 0000000..0fca549 + + Controlling the mapping between MACs and PHYs is usually done in platform- or + board-specific fixup code. The ADM6996 driver has no influence over this. -diff --git a/Documentation/pwm.txt b/Documentation/pwm.txt -new file mode 100644 -index 0000000..7112e66 ---- /dev/null -+++ b/Documentation/pwm.txt -@@ -0,0 +1,259 @@ -+ Generic PWM Device API -+ -+ February 1, 2010 -+ Bill Gatliff -+ <bgat@billgatliff.com> -+ -+ -+ -+The code in drivers/pwm and include/linux/pwm/ implements an API for -+applications involving pulse-width-modulation signals. This document -+describes how the API implementation facilitates both PWM-generating -+devices, and users of those devices. -+ -+ -+ -+Motivation -+ -+The primary goals for implementing the "generic PWM API" are to -+consolidate the various PWM implementations within a consistent and -+redundancy-reducing framework, and to facilitate the use of -+hotpluggable PWM devices. -+ -+Previous PWM-related implementations within the Linux kernel achieved -+their consistency via cut-and-paste, but did not need to (and didn't) -+facilitate more than one PWM-generating device within the system--- -+hotplug or otherwise. The Generic PWM Device API might be most -+appropriately viewed as an update to those implementations, rather -+than a complete rewrite. -+ -+ -+ -+Challenges -+ -+One of the difficulties in implementing a generic PWM framework is the -+fact that pulse-width-modulation applications involve real-world -+signals, which often must be carefully managed to prevent destruction -+of hardware that is linked to those signals. A DC motor that -+experiences a brief interruption in the PWM signal controlling it -+might destructively overheat; it could suddenly change speed, losing -+synchronization with a sensor; it could even suddenly change direction -+or torque, breaking the mechanical device connected to it. -+ -+(A generic PWM device framework is not directly responsible for -+preventing the above scenarios: that responsibility lies with the -+hardware designer, and the application and driver authors. But it -+must to the greatest extent possible make it easy to avoid such -+problems). -+ -+A generic PWM device framework must accommodate the substantial -+differences between available PWM-generating hardware devices, without -+becoming sub-optimal for any of them. -+ -+Finally, a generic PWM device framework must be relatively -+lightweight, computationally speaking. Some PWM users demand -+high-speed outputs, plus the ability to regulate those outputs -+quickly. A device framework must be able to "keep up" with such -+hardware, while still leaving time to do real work. -+ -+The Generic PWM Device API is an attempt to meet all of the above -+requirements. At its initial publication, the API was already in use -+managing small DC motors, sensors and solenoids through a -+custom-designed, optically-isolated H-bridge driver. -+ -+ -+ -+Functional Overview -+ -+The Generic PWM Device API framework is implemented in -+include/linux/pwm/pwm.h and drivers/pwm/pwm.c. The functions therein -+use information from pwm_device, pwm_channel and pwm_channel_config -+structures to invoke services in PWM peripheral device drivers. -+Consult drivers/pwm/atmel-pwm.c for an example driver. -+ -+There are two classes of adopters of the PWM framework: -+ -+ "Users" -- those wishing to employ the API merely to produce PWM -+ signals; once they have identified the appropriate physical output -+ on the platform in question, they don't care about the details of -+ the underlying hardware -+ -+ "Driver authors" -- those wishing to bind devices that can generate -+ PWM signals to the Generic PWM Device API, so that the services of -+ those devices become available to users. Assuming the hardware can -+ support the needs of a user, driver authors don't care about the -+ details of the user's application -+ -+Generally speaking, users will first invoke pwm_request() to obtain a -+handle to a PWM device. They will then pass that handle to functions -+like pwm_duty_ns() and pwm_period_ns() to set the duty cycle and -+period of the PWM signal, respectively. They will also invoke -+pwm_start() and pwm_stop() to turn the signal on and off. -+ -+The Generic PWM API framework also provides a sysfs interface to PWM -+devices, which is adequate for basic application needs and testing. -+ -+Driver authors fill out a pwm_device structure, which describes the -+capabilities of the PWM hardware being constructed--- including the -+number of distinct output "channels" the peripheral offers. They then -+invoke pwm_register() (usually from within their device's probe() -+handler) to make the PWM API aware of their device. The framework -+will call back to the methods described in the pwm_device structure as -+users begin to configure and utilize the hardware. -+ -+Note that PWM signals can be produced by a variety of peripherals, -+beyond the true "PWM hardware" offered by many system-on-chip devices. -+Other possibilities include timer/counters with compare-match -+capabilities, carefully-programmed synchronous serial ports -+(e.g. SPI), and GPIO pins driven by kernel interval timers. With a -+proper pwm_device structure, these devices and pseudo-devices can all -+be accommodated by the Generic PWM Device API framework. -+ -+ -+ -+Using the API to Generate PWM Signals -- Basic Functions for Users -+ -+ -+pwm_request() -- Returns a pwm_channel pointer, which is subsequently -+passed to the other user-related PWM functions. Once requested, a PWM -+channel is marked as in-use and subsequent requests prior to -+pwm_free() will fail. -+ -+The names used to refer to PWM devices are defined by driver authors. -+Typically they are platform device bus identifiers, and this -+convention is encouraged for consistency. -+ -+ -+pwm_free() -- Marks a PWM channel as no longer in use. The PWM device -+is stopped before it is released by the API. -+ -+ -+pwm_period_ns() -- Specifies the PWM signal's period, in nanoseconds. -+ -+ -+pwm_duty_ns() -- Specifies the PWM signal's active duration, in nanoseconds. -+ -+ -+pwm_duty_percent() -- Specifies the PWM signal's active duration, as a -+percentage of the current period of the signal. NOTE: this value is -+not recalculated if the period of the signal is subsequently changed. -+ -+ -+pwm_start(), pwm_stop() -- Turns the PWM signal on and off. Except -+where stated otherwise by a driver author, signals are stopped at the -+end of the current period, at which time the output is set to its -+inactive state. -+ -+ -+pwm_polarity() -- Defines whether the PWM signal output's active -+region is "1" or "0". A 10% duty-cycle, polarity=1 signal will -+conventionally be at 5V (or 3.3V, or 1000V, or whatever the platform -+hardware does) for 10% of the period. The same configuration of a -+polarity=0 signal will be at 5V (or 3.3V, or ...) for 90% of the -+period. -+ -+ -+ -+Using the API to Generate PWM Signals -- Advanced Functions -+ -+ -+pwm_config() -- Passes a pwm_channel_config structure to the -+associated device driver. This function is invoked by pwm_start(), -+pwm_duty_ns(), etc. and is one of two main entry points to the PWM -+driver for the hardware being used. The configuration change is -+guaranteed atomic if multiple configuration changes are specified. -+This function might sleep, depending on what the device driver has to -+do to satisfy the request. All PWM device drivers must support this -+entry point. -+ -+ -+pwm_config_nosleep() -- Passes a pwm_channel_config structure to the -+associated device driver. If the driver must sleep in order to -+implement the requested configuration change, -EWOULDBLOCK is -+returned. Users may call this function from interrupt handlers, for -+example. This is the other main entry point into the PWM hardware -+driver, but not all device drivers support this entry point. -+ -+ -+pwm_synchronize(), pwm_unsynchronize() -- "Synchronizes" two or more -+PWM channels, if the underlying hardware permits. (If it doesn't, the -+framework facilitates emulating this capability but it is not yet -+implemented). Synchronized channels will start and stop -+simultaneously when any single channel in the group is started or -+stopped. Use pwm_unsynchronize(..., NULL) to completely detach a -+channel from any other synchronized channels. By default, all PWM -+channels are unsynchronized. -+ -+ -+pwm_set_handler() -- Defines an end-of-period callback. The indicated -+function will be invoked in a worker thread at the end of each PWM -+period, and can subsequently invoke pwm_config(), etc. Must be used -+with extreme care for high-speed PWM outputs. Set the handler -+function to NULL to un-set the handler. -+ -+ -+ -+Implementing a PWM Device API Driver -- Functions for Driver Authors -+ -+ -+Fill out the appropriate fields in a pwm_device structure, and submit -+to pwm_register(): -+ -+ -+bus_id -- the plain-text name of the device. Users will bind to a -+channel on the device using this name plus the channel number. For -+example, the Atmel PWMC's bus_id is "atmel_pwmc", the same as used by -+the platform device driver (recommended). The first device registered -+thereby receives bus_id "atmel_pwmc.0", which is what you put in -+pwm_device.bus_id. Channels are then named "atmel_pwmc.0:[0-3]". -+(Hint: just use pdev->dev.bus_id in your probe() method). -+ -+ -+nchan -- the number of distinct output channels provided by the device. -+ -+ -+request -- (optional) Invoked each time a user requests a channel. -+Use to turn on clocks, clean up register states, etc. The framework -+takes care of device locking/unlocking; you will see only successful -+requests. -+ -+ -+free -- (optional) Callback for each time a user relinquishes a -+channel. The framework will have already stopped, unsynchronized and -+un-handled the channel. Use to turn off clocks, etc. as necessary. -+ -+ -+synchronize, unsynchronize -- (optional) Callbacks to -+synchronize/unsynchronize channels. Some devices provide this -+capability in hardware; for others, it can be emulated (see -+atmel_pwmc.c's sync_mask for an example). -+ -+ -+set_callback -- (optional) Invoked when a user requests a handler. If -+the hardware supports an end-of-period interrupt, invoke the function -+indicated during your interrupt handler. The callback function itself -+is always internal to the API, and does not map directly to the user's -+callback function. -+ -+ -+config -- Invoked to change the device configuration, always from a -+sleep-capable context. All the changes indicated must be performed -+atomically, ideally synchronized to an end-of-period event (so that -+you avoid short or long output pulses). You may sleep, etc. as -+necessary within this function. -+ -+ -+config_nosleep -- (optional) Invoked to change device configuration -+from within a context that is not allowed to sleep. If you cannot -+perform the requested configuration changes without sleeping, return -+-EWOULDBLOCK. -+ -+ -+ -+Acknowledgements -+ -+ -+The author expresses his gratitude to the countless developers who -+have reviewed and submitted feedback on the various versions of the -+Generic PWM Device API code, and those who have submitted drivers and -+applications that use the framework. You know who you are. ;) diff --git a/arch/mips/fw/myloader/Makefile b/arch/mips/fw/myloader/Makefile new file mode 100644 index 0000000..34acfd0 @@ -2316,55 +2018,6 @@ index 0000000..a13752d +MODULE_AUTHOR("Gabor Juhos <juhosg@openwrt.org>"); +MODULE_DESCRIPTION("Parsing code for MyLoader partition tables"); +MODULE_LICENSE("GPL v2"); -diff --git a/drivers/pwm/Kconfig b/drivers/pwm/Kconfig -new file mode 100644 -index 0000000..1c24e11 ---- /dev/null -+++ b/drivers/pwm/Kconfig -@@ -0,0 +1,31 @@ -+# -+# PWM infrastructure and devices -+# -+ -+menuconfig GENERIC_PWM -+ tristate "PWM Support" -+ depends on SYSFS -+ help -+ This enables PWM support through the generic PWM library. -+ If unsure, say N. -+ -+if GENERIC_PWM -+ -+config ATMEL_PWM -+ tristate "Atmel AT32/AT91 PWM support" -+ depends on AVR32 || ARCH_AT91 -+ help -+ This option enables device driver support for the PWMC -+ peripheral channels found on certain Atmel processors. -+ Pulse Width Modulation is used many for purposes, including -+ software controlled power-efficient backlights on LCD -+ displays, motor control, and waveform generation. If -+ unsure, say N. -+ -+config GPIO_PWM -+ tristate "PWM emulation using GPIO" -+ help -+ This option enables a single-channel PWM device using -+ a kernel interval timer and a GPIO pin. If unsure, say N. -+ -+endif -diff --git a/drivers/pwm/Makefile b/drivers/pwm/Makefile -new file mode 100644 -index 0000000..af22041 ---- /dev/null -+++ b/drivers/pwm/Makefile -@@ -0,0 +1,6 @@ -+# -+# Makefile for pwm devices -+# -+obj-$(CONFIG_GENERIC_PWM) := pwm.o -+obj-$(CONFIG_ATMEL_PWM) += atmel-pwm.o -+obj-$(CONFIG_GPIO_PWM) += gpio-pwm.o diff --git a/drivers/pwm/atmel-pwm.c b/drivers/pwm/atmel-pwm.c new file mode 100644 index 0000000..158bb92 @@ -3916,6 +3569,3 @@ index 0000000..c1596e9 + return 0; +} +postcore_initcall(pwm_init); --- -1.7.9.7 - diff --git a/bsp/routerstationpro/routerstationpro.scc b/bsp/routerstationpro/routerstationpro.scc index f37a4f2fd0911485b1e11d6dca433abcf008787f..356de125a36ac63af097a0ee8a643f07abab985d 100644 --- a/bsp/routerstationpro/routerstationpro.scc +++ b/bsp/routerstationpro/routerstationpro.scc @@ -10,7 +10,6 @@ patch remaining-generic-openwrt-files.patch patch openwrt-ar71xx-driver-files.patch patch openwrt-ar71xx-arch-mips-files.patch patch openwrt-include.patch -patch spi-Dont-call-prepare-unprepare-transfer-if-not-popu.patch patch 102-ehci_hcd_ignore_oc.patch patch 309-mips_fuse_workaround.patch patch 400-rootfs_split.patch @@ -35,95 +34,64 @@ patch 861-04_spi_gpio_implement_spi_delay.patch patch 862-gpio_spi_driver.patch patch 863-gpiommc.patch patch 864-gpiommc_configfs_locking.patch -patch MIPS-ath79-separate-common-PCI-code.patch -patch MIPS-ath79-rename-pci-ath724x.h.patch -patch MIPS-ath79-make-ath724x_pcibios_init-visible-for-ext.patch -patch MIPS-ath79-add-a-common-PCI-registration-function.patch -patch MIPS-ath79-rename-pci-ath724x.c-to-make-it-reflect-t.patch -patch MIPS-ath79-replace-ath724x-to-ar724x.patch -patch MIPS-ath79-use-io-accessor-macros-in-pci-ar724x.c.patch -patch MIPS-ath79-remove-superfluous-alignment-checks-from-.patch -patch MIPS-ath79-fix-broken-ar724x_pci_-read-write-functio.patch -patch MIPS-ath79-add-a-workaround-for-a-PCI-controller-bug.patch -patch MIPS-ath79-fix-a-wrong-IRQ-number.patch -patch MIPS-ath79-add-PCI-IRQ-handling-code-for-AR724X-SoCs.patch -patch MIPS-ath79-get-rid-of-some-ifdefs-in-mach-ubnt-xm.c.patch -patch MIPS-ath79-allow-to-use-board-specific-pci_plat_dev_.patch -patch MIPS-ath79-add-support-for-the-PCI-host-controller-o.patch -patch MIPS-ath79-allow-to-use-SoC-specific-PCI-IRQ-maps.patch -patch MIPS-ath79-remove-ar724x_pci_add_data-function.patch -patch MIPS-ath79-register-PCI-controller-on-the-PB44-board.patch -patch MIPS-ath79-update-copyright-headers-of-PCI-related-f.patch -patch MIPS-ath79-add-early_printk-support-for-AR934X.patch -patch MIPS-ath79-sort-case-statements-in-ath79_detect_sys_.patch -patch MIPS-ath79-add-SoC-detection-code-for-AR934X.patch -patch MIPS-ath79-add-clock-initialization-code-for-AR934X.patch -patch MIPS-ath79-add-GPIO-support-code-for-AR934X.patch -patch MIPS-ath79-rework-IP2-IP3-interrupt-handling.patch -patch MIPS-ath79-add-IRQ-handling-code-for-AR934X.patch -patch MIPS-ath79-add-AR934X-specific-glue-to-ath79_device_.patch -patch MIPS-ath79-register-UART-device-for-AR934X-SoCs.patch -patch MIPS-ath79-add-WMAC-registration-code-for-AR934X.patch -patch MIPS-ath79-add-PCI_AR724X-Kconfig-symbol.patch -patch MIPS-ath79-add-PCI-registration-code-for-AR934X.patch -patch MIPS-ath79-add-initial-support-for-the-Atheros-DB120.patch -patch MIPS-ath79-use-correct-IRQ-number-for-the-OHCI-contr.patch -patch MIPS-ath79-use-a-helper-function-for-USB-resource-in.patch -patch MIPS-pci-ar724x-avoid-data-bus-error-due-to-a-missin.patch -patch MIPS-pci-ar724x-use-correct-value-for-AR724X_PCI_MEM.patch -patch MIPS-pci-ar71xx-fix-AR71XX_PCI_MEM_SIZE.patch -patch MIPS-pci-ar724x-convert-to-a-platform-driver.patch -patch MIPS-pci-ar71xx-convert-to-a-platform-driver.patch -patch MIPS-ath79-move-global-PCI-defines-into-a-common-hea.patch -patch MIPS-ath79-register-platform-devices-for-the-PCI-con.patch -patch MIPS-ath79-remove-unused-ar7-1x-24-x_pcibios_init-fu.patch -patch MIPS-avoid-possible-resource-conflict-in-register_pc.patch -patch MIPS-pci-ar724x-use-dynamically-allocated-PCI-contro.patch -patch MIPS-pci-ar724x-remove-static-PCI-resources.patch -patch MIPS-pci-ar724x-use-per-controller-IRQ-base.patch -patch MIPS-pci-ar724x-setup-command-register-of-the-PCI-co.patch -patch MIPS-pci-ar71xx-use-dynamically-allocated-PCI-contro.patch -patch MIPS-pci-ar71xx-remove-static-PCI-controller-resourc.patch -patch MIPS-ath79-allow-to-specify-bus-number-in-PCI-IRQ-ma.patch -patch spi-ath79-add-delay-between-SCK-changes.patch -patch spi-ath79-add-missing-HIGH-LOW-SCK-transition.patch -patch spi-ath79-remove-superfluous-chip-select-code.patch -patch spi-ath79-use-gpio_request_one.patch -patch spi-ath79-avoid-multiple-initialization-of-the-SPI-c.patch -patch spi-ath79-add-shutdown-handler.patch -patch spi-ath79-make-chipselect-logic-more-flexible.patch -patch 401-mtd-physmap-add-lock-unlock.patch -patch 403-mtd_fix_cfi_cmdset_0002_status_check.patch -patch 406-mtd-m25p80-allow-to-specify-max-read-size.patch -patch 407-mtd-m25p80-allow-to-pass-probe-types-via-platfor.patch -patch 408-mtd-redboot_partition_scan.patch -patch 412-mtd-m25p80-zero-partition-parser-data.patch -patch 420-net-ar71xx_mac_driver.patch -patch 430-drivers-link-spi-before-mtd.patch -patch 431-spi-add-various-flags.patch -patch 434-spi-ap83_spi_controller.patch -patch 460-spi-bitbang-export-spi_bitbang_bufs.patch -patch 461-spi-add-type-field-to-spi_transfer.patch -patch 462-mtd-m25p80-set-spi-transfer-type.patch -patch 463-spi-ath79-add-fast-flash-read.patch -patch 470-MIPS-ath79-swizzle-pci-address-for-ar71xx.patch -patch 501-MIPS-ath79-add-mac-argument-to-ath79_register_wm.patch -patch 502-MIPS-ath79-export-ath79_gpio_base.patch -patch 503-MIPS-ath79-add-flash-acquire-release.patch -patch 504-MIPS-ath79-add-ath79_device_reset_get.patch -patch 505-MIPS-ath79-add-ath79_gpio_function_select.patch -patch 506-MIPS-ath79-prom-parse-redboot-args.patch -patch 507-MIPS-ath79-prom-add-myloader-support.patch -patch 508-MIPS-ath79-prom-image-command-line-hack.patch -patch 509-MIPS-ath79-process-board-kernel-option.patch -patch 510-MIPS-ath79-init-gpio-pin-of-wmac-device.patch -patch 511-MIPS-ath79-add-ath79_set_usb_power_gpio.patch -patch 520-MIPS-ath79-enable-UART-function.patch -patch 521-MIPS-ath79-enable-UART-for-early_serial.patch -patch 601-MIPS-ath79-add-more-register-defines.patch -patch 602-MIPS-ath79-add-openwrt-stuff.patch -patch 607-MIPS-ath79-ubnt-xm-fixes.patch -patch 608-MIPS-ath79-ubnt-xm-add-more-boards.patch -patch 610-MIPS-ath79-openwrt-machines.patch -patch ar71xx-fixups-for-not-carrying-QCA-platform.patch -patch ath79-fixup-for-not-carrying-Ubiquiti-LSX-LSS.patch + +# The following patches are pending uprev: + +# patch MIPS-ath79-use-a-helper-function-for-USB-resource-in.patch +# patch MIPS-pci-ar724x-avoid-data-bus-error-due-to-a-missin.patch +# patch MIPS-pci-ar724x-use-correct-value-for-AR724X_PCI_MEM.patch +# patch MIPS-pci-ar71xx-fix-AR71XX_PCI_MEM_SIZE.patch +# patch MIPS-pci-ar724x-convert-to-a-platform-driver.patch +# patch MIPS-pci-ar71xx-convert-to-a-platform-driver.patch +# patch MIPS-ath79-move-global-PCI-defines-into-a-common-hea.patch +# patch MIPS-ath79-register-platform-devices-for-the-PCI-con.patch +# patch MIPS-ath79-remove-unused-ar7-1x-24-x_pcibios_init-fu.patch +# patch MIPS-avoid-possible-resource-conflict-in-register_pc.patch +# patch MIPS-pci-ar724x-use-dynamically-allocated-PCI-contro.patch +# patch MIPS-pci-ar724x-remove-static-PCI-resources.patch +# patch MIPS-pci-ar724x-use-per-controller-IRQ-base.patch +# patch MIPS-pci-ar724x-setup-command-register-of-the-PCI-co.patch +# patch MIPS-pci-ar71xx-use-dynamically-allocated-PCI-contro.patch +# patch MIPS-pci-ar71xx-remove-static-PCI-controller-resourc.patch +# patch MIPS-ath79-allow-to-specify-bus-number-in-PCI-IRQ-ma.patch +# patch spi-ath79-add-delay-between-SCK-changes.patch +# patch spi-ath79-add-missing-HIGH-LOW-SCK-transition.patch +# patch spi-ath79-use-gpio_request_one.patch +# patch spi-ath79-avoid-multiple-initialization-of-the-SPI-c.patch +# patch spi-ath79-add-shutdown-handler.patch +# patch spi-ath79-make-chipselect-logic-more-flexible.patch +# patch 401-mtd-physmap-add-lock-unlock.patch +# patch 403-mtd_fix_cfi_cmdset_0002_status_check.patch +# patch 406-mtd-m25p80-allow-to-specify-max-read-size.patch +# patch 407-mtd-m25p80-allow-to-pass-probe-types-via-platfor.patch +# patch 408-mtd-redboot_partition_scan.patch +# patch 412-mtd-m25p80-zero-partition-parser-data.patch +# patch 420-net-ar71xx_mac_driver.patch +# patch 430-drivers-link-spi-before-mtd.patch +# patch 431-spi-add-various-flags.patch +# patch 434-spi-ap83_spi_controller.patch +# patch 460-spi-bitbang-export-spi_bitbang_bufs.patch +# patch 461-spi-add-type-field-to-spi_transfer.patch +# patch 462-mtd-m25p80-set-spi-transfer-type.patch +# patch 463-spi-ath79-add-fast-flash-read.patch +# patch 470-MIPS-ath79-swizzle-pci-address-for-ar71xx.patch +# patch 501-MIPS-ath79-add-mac-argument-to-ath79_register_wm.patch +# patch 502-MIPS-ath79-export-ath79_gpio_base.patch +# patch 503-MIPS-ath79-add-flash-acquire-release.patch +# patch 504-MIPS-ath79-add-ath79_device_reset_get.patch +# patch 505-MIPS-ath79-add-ath79_gpio_function_select.patch +# patch 506-MIPS-ath79-prom-parse-redboot-args.patch +# patch 507-MIPS-ath79-prom-add-myloader-support.patch +# patch 508-MIPS-ath79-prom-image-command-line-hack.patch +# patch 509-MIPS-ath79-process-board-kernel-option.patch +# patch 510-MIPS-ath79-init-gpio-pin-of-wmac-device.patch +# patch 511-MIPS-ath79-add-ath79_set_usb_power_gpio.patch +# patch 520-MIPS-ath79-enable-UART-function.patch +# patch 521-MIPS-ath79-enable-UART-for-early_serial.patch +# patch 601-MIPS-ath79-add-more-register-defines.patch +# patch 602-MIPS-ath79-add-openwrt-stuff.patch +# patch 607-MIPS-ath79-ubnt-xm-fixes.patch +# patch 608-MIPS-ath79-ubnt-xm-add-more-boards.patch +# patch 610-MIPS-ath79-openwrt-machines.patch +# patch ar71xx-fixups-for-not-carrying-QCA-platform.patch +# patch ath79-fixup-for-not-carrying-Ubiquiti-LSX-LSS.patch diff --git a/bsp/routerstationpro/spi-Dont-call-prepare-unprepare-transfer-if-not-popu.patch b/bsp/routerstationpro/spi-Dont-call-prepare-unprepare-transfer-if-not-popu.patch deleted file mode 100644 index d303fd6326b0e2cf5b687b82e4d7f350facf08ee..0000000000000000000000000000000000000000 --- a/bsp/routerstationpro/spi-Dont-call-prepare-unprepare-transfer-if-not-popu.patch +++ /dev/null @@ -1,46 +0,0 @@ -From 000e617c0f2ed18b4323a89a72a60f51f9a4ac43 Mon Sep 17 00:00:00 2001 -From: Shubhrajyoti D <shubhrajyoti@ti.com> -Date: Thu, 10 May 2012 19:20:41 +0530 -Subject: [PATCH 007/123] spi: Dont call prepare/unprepare transfer if not - populated - -Currently the prepare/unprepare transfer are called unconditionally. -The assumption is that every driver using the spi core queue infrastructure -has to populate the prepare and unprepare functions. This encourages -drivers to populate empty functions to prevent crashing. -This patch prevents the call to prepare/unprepare if not populated. - -Signed-off-by: Shubhrajyoti D <shubhrajyoti@ti.com> -Acked-by: Linus Walleij <linus.walleij@linaro.org> -[grant.likely: fix whitespace defect] -Signed-off-by: Grant Likely <grant.likely@secretlab.ca> -Signed-off-by: Paul Gortmaker <paul.gortmaker@windriver.com> ---- - drivers/spi/spi.c | 4 ++-- - 1 file changed, 2 insertions(+), 2 deletions(-) - -diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c -index 3d8f662..11e4d7f 100644 ---- a/drivers/spi/spi.c -+++ b/drivers/spi/spi.c -@@ -530,7 +530,7 @@ static void spi_pump_messages(struct kthread_work *work) - /* Lock queue and check for queue work */ - spin_lock_irqsave(&master->queue_lock, flags); - if (list_empty(&master->queue) || !master->running) { -- if (master->busy) { -+ if (master->busy && master->unprepare_transfer_hardware) { - ret = master->unprepare_transfer_hardware(master); - if (ret) { - spin_unlock_irqrestore(&master->queue_lock, flags); -@@ -560,7 +560,7 @@ static void spi_pump_messages(struct kthread_work *work) - master->busy = true; - spin_unlock_irqrestore(&master->queue_lock, flags); - -- if (!was_busy) { -+ if (!was_busy && master->prepare_transfer_hardware) { - ret = master->prepare_transfer_hardware(master); - if (ret) { - dev_err(&master->dev, --- -1.7.9.7 - diff --git a/bsp/routerstationpro/spi-ath79-remove-superfluous-chip-select-code.patch b/bsp/routerstationpro/spi-ath79-remove-superfluous-chip-select-code.patch deleted file mode 100644 index ac054f1c2589faa797b16683c0d4e7a629ddb4c4..0000000000000000000000000000000000000000 --- a/bsp/routerstationpro/spi-ath79-remove-superfluous-chip-select-code.patch +++ /dev/null @@ -1,36 +0,0 @@ -From 8bccd4f5a2394ac1312ba5be0a2e84fd8aa2195a Mon Sep 17 00:00:00 2001 -From: Gabor Juhos <juhosg@openwrt.org> -Date: Mon, 9 Jan 2012 15:03:28 +0100 -Subject: [PATCH 084/123] spi/ath79: remove superfluous chip select code - -The spi_bitbang driver calls the chipselect function -of the driver from spi_bitbang_setup in order to -deselect the given SPI chip, so we don't have to -initialize the CS line here. - -Signed-off-by: Gabor Juhos <juhosg@openwrt.org> -Signed-off-by: Paul Gortmaker <paul.gortmaker@windriver.com> ---- - drivers/spi/spi-ath79.c | 6 ------ - 1 file changed, 6 deletions(-) - -diff --git a/drivers/spi/spi-ath79.c b/drivers/spi/spi-ath79.c -index 2478cc2..864c40d 100644 ---- a/drivers/spi/spi-ath79.c -+++ b/drivers/spi/spi-ath79.c -@@ -128,12 +128,6 @@ static int ath79_spi_setup_cs(struct spi_device *spi) - gpio_free(cdata->gpio); - return status; - } -- } else { -- if (spi->mode & SPI_CS_HIGH) -- sp->ioc_base |= AR71XX_SPI_IOC_CS0; -- else -- sp->ioc_base &= ~AR71XX_SPI_IOC_CS0; -- ath79_spi_wr(sp, AR71XX_SPI_REG_IOC, sp->ioc_base); - } - - return 0; --- -1.7.9.7 - diff --git a/features/unionfs/unionfs-introduce-unionfs-2.5.10-core-support.patch b/features/unionfs/unionfs-introduce-unionfs-2.5.10-core-support.patch index 895357f348a0928dcae496fff3615c4b670c7bae..c2bf188bf4290364bc93aec1f5183b4e4dd0f088 100644 --- a/features/unionfs/unionfs-introduce-unionfs-2.5.10-core-support.patch +++ b/features/unionfs/unionfs-introduce-unionfs-2.5.10-core-support.patch @@ -540,12 +540,12 @@ index 0000000..1adde69 + +For more information, see <http://unionfs.filesystems.org/>. diff --git a/MAINTAINERS b/MAINTAINERS -index 3d11fa5..45b08c4 100644 +index fdc0119..91cc98a 100644 --- a/MAINTAINERS +++ b/MAINTAINERS -@@ -6868,6 +6868,14 @@ F: Documentation/cdrom/ - F: drivers/cdrom/cdrom.c - F: include/linux/cdrom.h +@@ -7065,6 +7065,14 @@ S: Supported + F: Documentation/scsi/ufs.txt + F: drivers/scsi/ufs/ +UNIONFS +P: Erez Zadok @@ -583,19 +583,19 @@ index 79b94eb..d094e94 100644 obj-$(CONFIG_NFS_FS) += nfs/ obj-$(CONFIG_EXPORTFS) += exportfs/ diff --git a/fs/namei.c b/fs/namei.c -index e615ff3..e27d250 100644 +index dd1ed1b..5e71f1b 100644 --- a/fs/namei.c +++ b/fs/namei.c -@@ -491,6 +491,7 @@ void release_open_intent(struct nameidata *nd) - fput(file); - } +@@ -506,6 +506,7 @@ err_root: + spin_unlock(&fs->lock); + return -ECHILD; } +EXPORT_SYMBOL_GPL(release_open_intent); - static inline int d_revalidate(struct dentry *dentry, struct nameidata *nd) + static inline int d_revalidate(struct dentry *dentry, unsigned int flags) { -@@ -1951,6 +1952,42 @@ struct dentry *lookup_one_len(const char *name, struct dentry *base, int len) - return __lookup_hash(&this, base, NULL); +@@ -2098,6 +2099,42 @@ struct dentry *lookup_one_len(const char *name, struct dentry *base, int len) + return __lookup_hash(&this, base, 0); } +/* pass nameidata from caller (useful for NFS) */ @@ -637,7 +637,7 @@ index e615ff3..e27d250 100644 int user_path_at_empty(int dfd, const char __user *name, unsigned flags, struct path *path, int *empty) { -@@ -3544,6 +3581,7 @@ EXPORT_SYMBOL(get_write_access); /* binfmt_aout */ +@@ -3975,6 +4012,7 @@ EXPORT_SYMBOL(get_write_access); /* binfmt_aout */ EXPORT_SYMBOL(getname); EXPORT_SYMBOL(lock_rename); EXPORT_SYMBOL(lookup_one_len); @@ -646,10 +646,10 @@ index e615ff3..e27d250 100644 EXPORT_SYMBOL(page_put_link); EXPORT_SYMBOL(page_readlink); diff --git a/fs/splice.c b/fs/splice.c -index 5f883de..59972c8 100644 +index 41514dd..aae192a 100644 --- a/fs/splice.c +++ b/fs/splice.c -@@ -1081,8 +1081,8 @@ EXPORT_SYMBOL(generic_splice_sendpage); +@@ -1093,8 +1093,8 @@ EXPORT_SYMBOL(generic_splice_sendpage); /* * Attempt to initiate a splice from pipe to file. */ @@ -660,7 +660,7 @@ index 5f883de..59972c8 100644 { ssize_t (*splice_write)(struct pipe_inode_info *, struct file *, loff_t *, size_t, unsigned int); -@@ -1105,13 +1105,14 @@ static long do_splice_from(struct pipe_inode_info *pipe, struct file *out, +@@ -1117,13 +1117,14 @@ static long do_splice_from(struct pipe_inode_info *pipe, struct file *out, return splice_write(pipe, out, ppos, len, flags); } @@ -678,7 +678,7 @@ index 5f883de..59972c8 100644 { ssize_t (*splice_read)(struct file *, loff_t *, struct pipe_inode_info *, size_t, unsigned int); -@@ -1131,6 +1132,7 @@ static long do_splice_to(struct file *in, loff_t *ppos, +@@ -1143,6 +1144,7 @@ static long do_splice_to(struct file *in, loff_t *ppos, return splice_read(in, ppos, pipe, len, flags); } @@ -686,7 +686,7 @@ index 5f883de..59972c8 100644 /** * splice_direct_to_actor - splices data directly between two non-pipes -@@ -1200,7 +1202,7 @@ ssize_t splice_direct_to_actor(struct file *in, struct splice_desc *sd, +@@ -1212,7 +1214,7 @@ ssize_t splice_direct_to_actor(struct file *in, struct splice_desc *sd, size_t read_len; loff_t pos = sd->pos, prev_pos = pos; @@ -695,7 +695,7 @@ index 5f883de..59972c8 100644 if (unlikely(ret <= 0)) goto out_release; -@@ -1259,8 +1261,8 @@ static int direct_splice_actor(struct pipe_inode_info *pipe, +@@ -1271,8 +1273,8 @@ static int direct_splice_actor(struct pipe_inode_info *pipe, { struct file *file = sd->u.file; @@ -706,7 +706,7 @@ index 5f883de..59972c8 100644 } /** -@@ -1345,7 +1347,7 @@ static long do_splice(struct file *in, loff_t __user *off_in, +@@ -1357,7 +1359,7 @@ static long do_splice(struct file *in, loff_t __user *off_in, } else off = &out->f_pos; @@ -715,7 +715,7 @@ index 5f883de..59972c8 100644 if (off_out && copy_to_user(off_out, off, sizeof(loff_t))) ret = -EFAULT; -@@ -1365,7 +1367,7 @@ static long do_splice(struct file *in, loff_t __user *off_in, +@@ -1377,7 +1379,7 @@ static long do_splice(struct file *in, loff_t __user *off_in, } else off = &in->f_pos; @@ -11337,13 +11337,13 @@ index e15192c..1d7370b 100644 #define CGROUP_SUPER_MAGIC 0x27e0eb diff --git a/include/linux/namei.h b/include/linux/namei.h -index ffc0213..99802c3 100644 +index 4bf19d8..d9d775c 100644 --- a/include/linux/namei.h +++ b/include/linux/namei.h -@@ -84,8 +84,11 @@ extern int vfs_path_lookup(struct dentry *, struct vfsmount *, - - extern struct file *lookup_instantiate_filp(struct nameidata *nd, struct dentry *dentry, - int (*open)(struct inode *, struct file *)); +@@ -71,8 +71,11 @@ extern void done_path_create(struct path *, struct dentry *); + extern struct dentry *kern_path_locked(const char *, struct path *); + extern int vfs_path_lookup(struct dentry *, struct vfsmount *, + const char *, unsigned int, struct path *); +extern void release_open_intent(struct nameidata *); extern struct dentry *lookup_one_len(const char *, struct dentry *, int); @@ -11353,10 +11353,10 @@ index ffc0213..99802c3 100644 extern int follow_down_one(struct path *); extern int follow_down(struct path *); diff --git a/include/linux/splice.h b/include/linux/splice.h -index 26e5b61..28213e6 100644 +index 09a545a..ebe231a 100644 --- a/include/linux/splice.h +++ b/include/linux/splice.h -@@ -81,6 +81,11 @@ extern ssize_t splice_to_pipe(struct pipe_inode_info *, +@@ -82,6 +82,11 @@ extern ssize_t splice_to_pipe(struct pipe_inode_info *, struct splice_pipe_desc *); extern ssize_t splice_direct_to_actor(struct file *, struct splice_desc *, splice_direct_actor *); @@ -11397,10 +11397,10 @@ index 0000000..c84d97e +#endif /* _LINUX_UNIONFS_H */ + diff --git a/security/security.c b/security/security.c -index bf619ff..57742c6 100644 +index 860aeb3..efe2b05 100644 --- a/security/security.c +++ b/security/security.c -@@ -526,6 +526,7 @@ int security_inode_permission(struct inode *inode, int mask) +@@ -530,6 +530,7 @@ int security_inode_permission(struct inode *inode, int mask) return 0; return security_ops->inode_permission(inode, mask); } diff --git a/features/uprobe/On-RISC-architectures-like-powerpc-instructions-are-.patch b/features/uprobe/On-RISC-architectures-like-powerpc-instructions-are-.patch deleted file mode 100644 index dc3c97a679961f2c9fb89a6bfaa378f83d4b1469..0000000000000000000000000000000000000000 --- a/features/uprobe/On-RISC-architectures-like-powerpc-instructions-are-.patch +++ /dev/null @@ -1,70 +0,0 @@ -From 2bc4597fbf93953222c5e9445472113e7b4bba03 Mon Sep 17 00:00:00 2001 -From: Ananth N Mavinakayanahalli <ananth@in.ibm.com> -Date: Wed, 13 Jun 2012 10:43:40 -0400 -Subject: [PATCH 22/24] On RISC architectures like powerpc, instructions are - fixed size. Instruction analysis on such platforms is - just a matter of (insn % 4). Pass the vaddr at which - the uprobe is to be inserted so that - arch_uprobe_analyze_insn() can flag misaligned - registration requests. - -Changes in V2: -Pass (unsigned long)addr instead of (loff_t)vaddr to -arch_uprobe_analyze_insn(). We need the loff_t vaddr to take care of -the offset of inode:offset pair for large file sizes on 32bit. - -Link: https://lkml.org/lkml/2012/6/6/139 - -Signed-off-by: Ananth N Mavinakaynahalli <ananth@in.ibm.com> -Signed-off-by: Paul Barrette <paul.barrette@windriver.com> ---- - arch/x86/include/asm/uprobes.h | 2 +- - arch/x86/kernel/uprobes.c | 3 ++- - kernel/events/uprobes.c | 2 +- - 3 files changed, 4 insertions(+), 3 deletions(-) - -diff --git a/arch/x86/include/asm/uprobes.h b/arch/x86/include/asm/uprobes.h -index 1e9bed1..f3971bb 100644 ---- a/arch/x86/include/asm/uprobes.h -+++ b/arch/x86/include/asm/uprobes.h -@@ -48,7 +48,7 @@ struct arch_uprobe_task { - #endif - }; - --extern int arch_uprobe_analyze_insn(struct arch_uprobe *aup, struct mm_struct *mm); -+extern int arch_uprobe_analyze_insn(struct arch_uprobe *aup, struct mm_struct *mm, unsigned long addr); - extern int arch_uprobe_pre_xol(struct arch_uprobe *aup, struct pt_regs *regs); - extern int arch_uprobe_post_xol(struct arch_uprobe *aup, struct pt_regs *regs); - extern bool arch_uprobe_xol_was_trapped(struct task_struct *tsk); -diff --git a/arch/x86/kernel/uprobes.c b/arch/x86/kernel/uprobes.c -index dc4e910..36fd420 100644 ---- a/arch/x86/kernel/uprobes.c -+++ b/arch/x86/kernel/uprobes.c -@@ -409,9 +409,10 @@ static int validate_insn_bits(struct arch_uprobe *auprobe, struct mm_struct *mm, - * arch_uprobe_analyze_insn - instruction analysis including validity and fixups. - * @mm: the probed address space. - * @arch_uprobe: the probepoint information. -+ * @addr: virtual address at which to install the probepoint - * Return 0 on success or a -ve number on error. - */ --int arch_uprobe_analyze_insn(struct arch_uprobe *auprobe, struct mm_struct *mm) -+int arch_uprobe_analyze_insn(struct arch_uprobe *auprobe, struct mm_struct *mm, unsigned long addr) - { - int ret; - struct insn insn; -diff --git a/kernel/events/uprobes.c b/kernel/events/uprobes.c -index 985be4d..577f717 100644 ---- a/kernel/events/uprobes.c -+++ b/kernel/events/uprobes.c -@@ -697,7 +697,7 @@ install_breakpoint(struct uprobe *uprobe, struct mm_struct *mm, - if (is_swbp_insn((uprobe_opcode_t *)uprobe->arch.insn)) - return -EEXIST; - -- ret = arch_uprobe_analyze_insn(&uprobe->arch, mm); -+ ret = arch_uprobe_analyze_insn(&uprobe->arch, mm, addr); - if (ret) - return ret; - --- -1.7.5.4 - diff --git a/features/uprobe/genirq-reimplement-exit_irq_thread-hook-via-task_wor.patch b/features/uprobe/genirq-reimplement-exit_irq_thread-hook-via-task_wor.patch deleted file mode 100644 index a11d0bfaa9a0449bfc828113fcf58791cc2a867d..0000000000000000000000000000000000000000 --- a/features/uprobe/genirq-reimplement-exit_irq_thread-hook-via-task_wor.patch +++ /dev/null @@ -1,228 +0,0 @@ -From 61bc7a87e8aa5b5651c21e8d9f76dea814fe5313 Mon Sep 17 00:00:00 2001 -From: Oleg Nesterov <oleg@redhat.com> -Date: Fri, 11 May 2012 10:59:08 +1000 -Subject: [PATCH 3/6] genirq: reimplement exit_irq_thread() hook via - task_work_add() - -commit 4d1d61a6b203d957777d73fcebf19d90b038b5b2 upstream. - -exit_irq_thread() and task->irq_thread are needed to handle the unexpected -(and unlikely) exit of irq-thread. - -We can use task_work instead and make this all private to -kernel/irq/manage.c, cleanup plus micro-optimization. - -1. rename exit_irq_thread() to irq_thread_dtor(), make it - static, and move it up before irq_thread(). - -2. change irq_thread() to do task_work_add(irq_thread_dtor) - at the start and task_work_cancel() before return. - - tracehook_notify_resume() can never play with kthreads, - only do_exit()->exit_task_work() can call the callback - and this is what we want. - -3. remove task_struct->irq_thread and the special hook - in do_exit(). - -Signed-off-by: Oleg Nesterov <oleg@redhat.com> -Reviewed-by: Thomas Gleixner <tglx@linutronix.de> -Cc: David Howells <dhowells@redhat.com> -Cc: Richard Kuo <rkuo@codeaurora.org> -Cc: Linus Torvalds <torvalds@linux-foundation.org> -Cc: Alexander Gordeev <agordeev@redhat.com> -Cc: Chris Zankel <chris@zankel.net> -Cc: David Smith <dsmith@redhat.com> -Cc: "Frank Ch. Eigler" <fche@redhat.com> -Cc: Geert Uytterhoeven <geert@linux-m68k.org> -Cc: Larry Woodman <lwoodman@redhat.com> -Cc: Peter Zijlstra <peterz@infradead.org> -Cc: Tejun Heo <tj@kernel.org> -Cc: Ingo Molnar <mingo@elte.hu> -Signed-off-by: Andrew Morton <akpm@linux-foundation.org> -Signed-off-by: Al Viro <viro@zeniv.linux.org.uk> -Signed-off-by: Paul Barrette <paul.barrette@windriver.com> ---- - include/linux/interrupt.h | 4 -- - include/linux/sched.h | 10 +----- - kernel/exit.c | 2 - - kernel/irq/manage.c | 69 +++++++++++++++++++++----------------------- - 4 files changed, 35 insertions(+), 50 deletions(-) - -diff --git a/include/linux/interrupt.h b/include/linux/interrupt.h -index 2aea5d2..1cdd4d0 100644 ---- a/include/linux/interrupt.h -+++ b/include/linux/interrupt.h -@@ -142,8 +142,6 @@ request_any_context_irq(unsigned int irq, irq_handler_t handler, - extern int __must_check - request_percpu_irq(unsigned int irq, irq_handler_t handler, - const char *devname, void __percpu *percpu_dev_id); -- --extern void exit_irq_thread(void); - #else - - extern int __must_check -@@ -177,8 +175,6 @@ request_percpu_irq(unsigned int irq, irq_handler_t handler, - { - return request_irq(irq, handler, 0, devname, percpu_dev_id); - } -- --static inline void exit_irq_thread(void) { } - #endif - - extern void free_irq(unsigned int, void *); -diff --git a/include/linux/sched.h b/include/linux/sched.h -index d62c928..3ea394c 100644 ---- a/include/linux/sched.h -+++ b/include/linux/sched.h -@@ -1348,11 +1348,6 @@ struct task_struct { - unsigned sched_reset_on_fork:1; - unsigned sched_contributes_to_load:1; - --#ifdef CONFIG_GENERIC_HARDIRQS -- /* IRQ handler threads */ -- unsigned irq_thread:1; --#endif -- - pid_t pid; - pid_t tgid; - -@@ -1360,10 +1355,9 @@ struct task_struct { - /* Canary value for the -fstack-protector gcc feature */ - unsigned long stack_canary; - #endif -- -- /* -+ /* - * pointers to (original) parent process, youngest child, younger sibling, -- * older sibling, respectively. (p->father can be replaced with -+ * older sibling, respectively. (p->father can be replaced with - * p->real_parent->pid) - */ - struct task_struct __rcu *real_parent; /* real parent process */ -diff --git a/kernel/exit.c b/kernel/exit.c -index 36516fc..275013c 100644 ---- a/kernel/exit.c -+++ b/kernel/exit.c -@@ -955,8 +955,6 @@ void do_exit(long code) - - exit_task_work(tsk); - -- exit_irq_thread(); -- - if (unlikely(in_atomic())) - printk(KERN_INFO "note: %s[%d] exited with preempt_count %d\n", - current->comm, task_pid_nr(current), -diff --git a/kernel/irq/manage.c b/kernel/irq/manage.c -index 89a3ea8..ac4dab7 100644 ---- a/kernel/irq/manage.c -+++ b/kernel/irq/manage.c -@@ -14,6 +14,7 @@ - #include <linux/interrupt.h> - #include <linux/slab.h> - #include <linux/sched.h> -+#include <linux/task_work.h> - - #include "internals.h" - -@@ -773,11 +774,39 @@ static void wake_threads_waitq(struct irq_desc *desc) - wake_up(&desc->wait_for_threads); - } - -+static void irq_thread_dtor(struct task_work *unused) -+{ -+ struct task_struct *tsk = current; -+ struct irq_desc *desc; -+ struct irqaction *action; -+ -+ if (WARN_ON_ONCE(!(current->flags & PF_EXITING))) -+ return; -+ -+ action = kthread_data(tsk); -+ -+ pr_err("genirq: exiting task \"%s\" (%d) is an active IRQ thread (irq %d)\n", -+ tsk->comm ? tsk->comm : "", tsk->pid, action->irq); -+ -+ -+ desc = irq_to_desc(action->irq); -+ /* -+ * If IRQTF_RUNTHREAD is set, we need to decrement -+ * desc->threads_active and wake possible waiters. -+ */ -+ if (test_and_clear_bit(IRQTF_RUNTHREAD, &action->thread_flags)) -+ wake_threads_waitq(desc); -+ -+ /* Prevent a stale desc->threads_oneshot */ -+ irq_finalize_oneshot(desc, action); -+} -+ - /* - * Interrupt handler thread - */ - static int irq_thread(void *data) - { -+ struct task_work on_exit_work; - static const struct sched_param param = { - .sched_priority = MAX_USER_RT_PRIO/2, - }; -@@ -793,7 +822,9 @@ static int irq_thread(void *data) - handler_fn = irq_thread_fn; - - sched_setscheduler(current, SCHED_FIFO, ¶m); -- current->irq_thread = 1; -+ -+ init_task_work(&on_exit_work, irq_thread_dtor, NULL); -+ task_work_add(current, &on_exit_work, false); - - while (!irq_wait_for_interrupt(action)) { - irqreturn_t action_ret; -@@ -815,45 +846,11 @@ static int irq_thread(void *data) - * cannot touch the oneshot mask at this point anymore as - * __setup_irq() might have given out currents thread_mask - * again. -- * -- * Clear irq_thread. Otherwise exit_irq_thread() would make -- * fuzz about an active irq thread going into nirvana. - */ -- current->irq_thread = 0; -+ task_work_cancel(current, irq_thread_dtor); - return 0; - } - --/* -- * Called from do_exit() -- */ --void exit_irq_thread(void) --{ -- struct task_struct *tsk = current; -- struct irq_desc *desc; -- struct irqaction *action; -- -- if (!tsk->irq_thread) -- return; -- -- action = kthread_data(tsk); -- -- printk(KERN_ERR -- "exiting task \"%s\" (%d) is an active IRQ thread (irq %d)\n", -- tsk->comm ? tsk->comm : "", tsk->pid, action->irq); -- -- desc = irq_to_desc(action->irq); -- -- /* -- * If IRQTF_RUNTHREAD is set, we need to decrement -- * desc->threads_active and wake possible waiters. -- */ -- if (test_and_clear_bit(IRQTF_RUNTHREAD, &action->thread_flags)) -- wake_threads_waitq(desc); -- -- /* Prevent a stale desc->threads_oneshot */ -- irq_finalize_oneshot(desc, action); --} -- - static void irq_setup_forced_threading(struct irqaction *new) - { - if (!force_irqthreads) --- -1.7.5.4 - diff --git a/features/uprobe/keys-change-keyctl_session_to_parent-to-use-task_wor.patch b/features/uprobe/keys-change-keyctl_session_to_parent-to-use-task_wor.patch deleted file mode 100644 index a32e83855a883d6b4343e4edf1bc026f59b87218..0000000000000000000000000000000000000000 --- a/features/uprobe/keys-change-keyctl_session_to_parent-to-use-task_wor.patch +++ /dev/null @@ -1,264 +0,0 @@ -From 090ca453c4d5b4e1300c46daf1ac4f2a5f086ec1 Mon Sep 17 00:00:00 2001 -From: Oleg Nesterov <oleg@redhat.com> -Date: Fri, 11 May 2012 10:59:08 +1000 -Subject: [PATCH 4/6] keys: change keyctl_session_to_parent() to use - task_work_add() - -commit 413cd3d9abeaef590e5ce00564f7a443165db238 upstream. - -Change keyctl_session_to_parent() to use task_work_add() and move -key_replace_session_keyring() logic into task_work->func(). - -Note that we do task_work_cancel() before task_work_add() to ensure that -only one work can be pending at any time. This is important, we must not -allow user-space to abuse the parent's ->task_works list. - -The callback, replace_session_keyring(), checks PF_EXITING. I guess this -is not really needed but looks better. - -As a side effect, this fixes the (unlikely) race. The callers of -key_replace_session_keyring() and keyctl_session_to_parent() lack the -necessary barriers, the parent can miss the request. - -Now we can remove task_struct->replacement_session_keyring and related -code. - -Signed-off-by: Oleg Nesterov <oleg@redhat.com> -Acked-by: David Howells <dhowells@redhat.com> -Cc: Thomas Gleixner <tglx@linutronix.de> -Cc: Richard Kuo <rkuo@codeaurora.org> -Cc: Linus Torvalds <torvalds@linux-foundation.org> -Cc: Alexander Gordeev <agordeev@redhat.com> -Cc: Chris Zankel <chris@zankel.net> -Cc: David Smith <dsmith@redhat.com> -Cc: "Frank Ch. Eigler" <fche@redhat.com> -Cc: Geert Uytterhoeven <geert@linux-m68k.org> -Cc: Larry Woodman <lwoodman@redhat.com> -Cc: Peter Zijlstra <peterz@infradead.org> -Cc: Tejun Heo <tj@kernel.org> -Cc: Ingo Molnar <mingo@elte.hu> -Signed-off-by: Andrew Morton <akpm@linux-foundation.org> -Signed-off-by: Al Viro <viro@zeniv.linux.org.uk> -Signed-off-by: Paul Barrette <paul.barrette@windriver.com> ---- - include/linux/key.h | 6 +-- - security/keys/internal.h | 2 + - security/keys/keyctl.c | 63 +++++++++++++++++++++++------------------ - security/keys/process_keys.c | 20 ++++-------- - 4 files changed, 46 insertions(+), 45 deletions(-) - -diff --git a/include/linux/key.h b/include/linux/key.h -index 96933b1..0c263d6 100644 ---- a/include/linux/key.h -+++ b/include/linux/key.h -@@ -33,6 +33,8 @@ typedef uint32_t key_perm_t; - - struct key; - -+#define key_replace_session_keyring() do { } while (0) -+ - #ifdef CONFIG_KEYS - - #undef KEY_DEBUGGING -@@ -302,9 +304,6 @@ static inline bool key_is_instantiated(const struct key *key) - #ifdef CONFIG_SYSCTL - extern ctl_table key_sysctls[]; - #endif -- --extern void key_replace_session_keyring(void); -- - /* - * the userspace interface - */ -@@ -327,7 +326,6 @@ extern void key_init(void); - #define key_fsuid_changed(t) do { } while(0) - #define key_fsgid_changed(t) do { } while(0) - #define key_init() do { } while(0) --#define key_replace_session_keyring() do { } while(0) - - #endif /* CONFIG_KEYS */ - #endif /* __KERNEL__ */ -diff --git a/security/keys/internal.h b/security/keys/internal.h -index 65647f8..c2986da 100644 ---- a/security/keys/internal.h -+++ b/security/keys/internal.h -@@ -14,6 +14,7 @@ - - #include <linux/sched.h> - #include <linux/key-type.h> -+#include <linux/task_work.h> - - #ifdef __KDEBUG - #define kenter(FMT, ...) \ -@@ -148,6 +149,7 @@ extern key_ref_t lookup_user_key(key_serial_t id, unsigned long flags, - #define KEY_LOOKUP_FOR_UNLINK 0x04 - - extern long join_session_keyring(const char *name); -+extern void key_change_session_keyring(struct task_work *twork); - - extern struct work_struct key_gc_work; - extern unsigned key_gc_delay; -diff --git a/security/keys/keyctl.c b/security/keys/keyctl.c -index fb767c6..a237e03 100644 ---- a/security/keys/keyctl.c -+++ b/security/keys/keyctl.c -@@ -1426,47 +1426,55 @@ long keyctl_session_to_parent(void) - #ifdef TIF_NOTIFY_RESUME - struct task_struct *me, *parent; - const struct cred *mycred, *pcred; -- struct cred *cred, *oldcred; -+ struct task_work *newwork, *oldwork; - key_ref_t keyring_r; -+ struct cred *cred; - int ret; - - keyring_r = lookup_user_key(KEY_SPEC_SESSION_KEYRING, 0, KEY_LINK); - if (IS_ERR(keyring_r)) - return PTR_ERR(keyring_r); - -+ ret = -ENOMEM; -+ newwork = kmalloc(sizeof(struct task_work), GFP_KERNEL); -+ if (!newwork) -+ goto error_keyring; -+ - /* our parent is going to need a new cred struct, a new tgcred struct - * and new security data, so we allocate them here to prevent ENOMEM in - * our parent */ -- ret = -ENOMEM; - cred = cred_alloc_blank(); - if (!cred) -- goto error_keyring; -+ goto error_newwork; - - cred->tgcred->session_keyring = key_ref_to_ptr(keyring_r); -- keyring_r = NULL; -+ init_task_work(newwork, key_change_session_keyring, cred); - - me = current; - rcu_read_lock(); - write_lock_irq(&tasklist_lock); - -- parent = me->real_parent; - ret = -EPERM; -+ oldwork = NULL; -+ parent = me->real_parent; - - /* the parent mustn't be init and mustn't be a kernel thread */ - if (parent->pid <= 1 || !parent->mm) -- goto not_permitted; -+ goto unlock; - - /* the parent must be single threaded */ - if (!thread_group_empty(parent)) -- goto not_permitted; -+ goto unlock; - - /* the parent and the child must have different session keyrings or - * there's no point */ - mycred = current_cred(); - pcred = __task_cred(parent); - if (mycred == pcred || -- mycred->tgcred->session_keyring == pcred->tgcred->session_keyring) -- goto already_same; -+ mycred->tgcred->session_keyring == pcred->tgcred->session_keyring) { -+ ret = 0; -+ goto unlock; -+ } - - /* the parent must have the same effective ownership and mustn't be - * SUID/SGID */ -@@ -1476,38 +1484,37 @@ long keyctl_session_to_parent(void) - pcred->gid != mycred->egid || - pcred->egid != mycred->egid || - pcred->sgid != mycred->egid) -- goto not_permitted; -+ goto unlock; - - /* the keyrings must have the same UID */ - if ((pcred->tgcred->session_keyring && - pcred->tgcred->session_keyring->uid != mycred->euid) || - mycred->tgcred->session_keyring->uid != mycred->euid) -- goto not_permitted; -+ goto unlock; - -- /* if there's an already pending keyring replacement, then we replace -- * that */ -- oldcred = parent->replacement_session_keyring; -+ /* cancel an already pending keyring replacement */ -+ oldwork = task_work_cancel(parent, key_change_session_keyring); - - /* the replacement session keyring is applied just prior to userspace - * restarting */ -- parent->replacement_session_keyring = cred; -- cred = NULL; -- set_ti_thread_flag(task_thread_info(parent), TIF_NOTIFY_RESUME); -- -- write_unlock_irq(&tasklist_lock); -- rcu_read_unlock(); -- if (oldcred) -- put_cred(oldcred); -- return 0; -- --already_same: -- ret = 0; --not_permitted: -+ ret = task_work_add(parent, newwork, true); -+ if (!ret) -+ newwork = NULL; -+unlock: - write_unlock_irq(&tasklist_lock); - rcu_read_unlock(); -- put_cred(cred); -+ if (oldwork) { -+ put_cred(oldwork->data); -+ kfree(oldwork); -+ } -+ if (newwork) { -+ put_cred(newwork->data); -+ kfree(newwork); -+ } - return ret; - -+error_newwork: -+ kfree(newwork); - error_keyring: - key_ref_put(keyring_r); - return ret; -diff --git a/security/keys/process_keys.c b/security/keys/process_keys.c -index be7ecb2..7ab0d8b 100644 ---- a/security/keys/process_keys.c -+++ b/security/keys/process_keys.c -@@ -832,23 +832,17 @@ error: - * Replace a process's session keyring on behalf of one of its children when - * the target process is about to resume userspace execution. - */ --void key_replace_session_keyring(void) -+void key_change_session_keyring(struct task_work *twork) - { -- const struct cred *old; -- struct cred *new; -- -- if (!current->replacement_session_keyring) -- return; -+ const struct cred *old = current_cred(); -+ struct cred *new = twork->data; - -- write_lock_irq(&tasklist_lock); -- new = current->replacement_session_keyring; -- current->replacement_session_keyring = NULL; -- write_unlock_irq(&tasklist_lock); -- -- if (!new) -+ kfree(twork); -+ if (unlikely(current->flags & PF_EXITING)) { -+ put_cred(new); - return; -+ } - -- old = current_cred(); - new-> uid = old-> uid; - new-> euid = old-> euid; - new-> suid = old-> suid; --- -1.7.5.4 - diff --git a/features/uprobe/keys-kill-task_struct-replacement_session_keyring.patch b/features/uprobe/keys-kill-task_struct-replacement_session_keyring.patch deleted file mode 100644 index 215ff3b4f1bcd225f0d023afeaa7dbc93c879951..0000000000000000000000000000000000000000 --- a/features/uprobe/keys-kill-task_struct-replacement_session_keyring.patch +++ /dev/null @@ -1,75 +0,0 @@ -From d4ef82f00c0b2e2abe0934f0808b390d469a44f9 Mon Sep 17 00:00:00 2001 -From: Oleg Nesterov <oleg@redhat.com> -Date: Fri, 11 May 2012 10:59:09 +1000 -Subject: [PATCH 6/6] keys: kill task_struct->replacement_session_keyring - -commit f23ca335462e3c84f13270b9e65f83936068ec2c upstream. - -Kill the no longer used task_struct->replacement_session_keyring, update -copy_creds() and exit_creds(). - -Signed-off-by: Oleg Nesterov <oleg@redhat.com> -Acked-by: David Howells <dhowells@redhat.com> -Cc: Thomas Gleixner <tglx@linutronix.de> -Cc: Richard Kuo <rkuo@codeaurora.org> -Cc: Linus Torvalds <torvalds@linux-foundation.org> -Cc: Alexander Gordeev <agordeev@redhat.com> -Cc: Chris Zankel <chris@zankel.net> -Cc: David Smith <dsmith@redhat.com> -Cc: "Frank Ch. Eigler" <fche@redhat.com> -Cc: Geert Uytterhoeven <geert@linux-m68k.org> -Cc: Larry Woodman <lwoodman@redhat.com> -Cc: Peter Zijlstra <peterz@infradead.org> -Cc: Tejun Heo <tj@kernel.org> -Cc: Ingo Molnar <mingo@elte.hu> -Signed-off-by: Andrew Morton <akpm@linux-foundation.org> -Signed-off-by: Al Viro <viro@zeniv.linux.org.uk> -Signed-off-by: Paul Barrette <paul.barrette@windriver.com> ---- - include/linux/sched.h | 2 -- - kernel/cred.c | 9 --------- - 2 files changed, 0 insertions(+), 11 deletions(-) - -diff --git a/include/linux/sched.h b/include/linux/sched.h -index 3ea394c..3dd6575 100644 ---- a/include/linux/sched.h -+++ b/include/linux/sched.h -@@ -1404,8 +1404,6 @@ struct task_struct { - * credentials (COW) */ - const struct cred __rcu *cred; /* effective (overridable) subjective task - * credentials (COW) */ -- struct cred *replacement_session_keyring; /* for KEYCTL_SESSION_TO_PARENT */ -- - char comm[TASK_COMM_LEN]; /* executable name excluding path - - access with [gs]et_task_comm (which lock - it with task_lock()) -diff --git a/kernel/cred.c b/kernel/cred.c -index e70683d..9570736 100644 ---- a/kernel/cred.c -+++ b/kernel/cred.c -@@ -198,13 +198,6 @@ void exit_creds(struct task_struct *tsk) - validate_creds(cred); - alter_cred_subscribers(cred, -1); - put_cred(cred); -- -- cred = (struct cred *) tsk->replacement_session_keyring; -- if (cred) { -- tsk->replacement_session_keyring = NULL; -- validate_creds(cred); -- put_cred(cred); -- } - } - - /** -@@ -386,8 +379,6 @@ int copy_creds(struct task_struct *p, unsigned long clone_flags) - struct cred *new; - int ret; - -- p->replacement_session_keyring = NULL; -- - if ( - #ifdef CONFIG_KEYS - !p->cred->thread_keyring && --- -1.7.5.4 - diff --git a/features/uprobe/keys-kill-the-dummy-key_replace_session_keyring.patch b/features/uprobe/keys-kill-the-dummy-key_replace_session_keyring.patch deleted file mode 100644 index 89dd5db575385c3bee63645d088804ff27b72d9d..0000000000000000000000000000000000000000 --- a/features/uprobe/keys-kill-the-dummy-key_replace_session_keyring.patch +++ /dev/null @@ -1,62 +0,0 @@ -From 1cc141e62623a487e42a6af977549c628bb8a4f7 Mon Sep 17 00:00:00 2001 -From: Oleg Nesterov <oleg@redhat.com> -Date: Fri, 11 May 2012 10:59:09 +1000 -Subject: [PATCH 5/6] keys: kill the dummy key_replace_session_keyring() - -commit dea649b8ac1861107c5d91e1a71121434fc64193 upstream. - -After the previouse change key_replace_session_keyring() becomes a nop. -Remove the dummy definition in key.h and update the callers in -arch/*/kernel/signal.c. - -Signed-off-by: Oleg Nesterov <oleg@redhat.com> -Acked-by: David Howells <dhowells@redhat.com> -Cc: Thomas Gleixner <tglx@linutronix.de> -Cc: Richard Kuo <rkuo@codeaurora.org> -Cc: Linus Torvalds <torvalds@linux-foundation.org> -Cc: Alexander Gordeev <agordeev@redhat.com> -Cc: Chris Zankel <chris@zankel.net> -Cc: David Smith <dsmith@redhat.com> -Cc: "Frank Ch. Eigler" <fche@redhat.com> -Cc: Geert Uytterhoeven <geert@linux-m68k.org> -Cc: Larry Woodman <lwoodman@redhat.com> -Cc: Peter Zijlstra <peterz@infradead.org> -Cc: Tejun Heo <tj@kernel.org> -Cc: Ingo Molnar <mingo@elte.hu> -Signed-off-by: Andrew Morton <akpm@linux-foundation.org> -Signed-off-by: Al Viro <viro@zeniv.linux.org.uk> -Signed-off-by: Paul Barrette <paul.barrette@windriver.com> ---- - include/linux/key.h | 2 -- - include/linux/tracehook.h | 2 -- - 2 files changed, 0 insertions(+), 4 deletions(-) - -diff --git a/include/linux/key.h b/include/linux/key.h -index 0c263d6..16cbdb0 100644 ---- a/include/linux/key.h -+++ b/include/linux/key.h -@@ -33,8 +33,6 @@ typedef uint32_t key_perm_t; - - struct key; - --#define key_replace_session_keyring() do { } while (0) -- - #ifdef CONFIG_KEYS - - #undef KEY_DEBUGGING -diff --git a/include/linux/tracehook.h b/include/linux/tracehook.h -index ea9558f..48c597d 100644 ---- a/include/linux/tracehook.h -+++ b/include/linux/tracehook.h -@@ -187,8 +187,6 @@ static inline void set_notify_resume(struct task_struct *task) - */ - static inline void tracehook_notify_resume(struct pt_regs *regs) - { -- if (current->replacement_session_keyring) -- key_replace_session_keyring(); - /* - * The caller just cleared TIF_NOTIFY_RESUME. This barrier - * pairs with task_work_add()->set_notify_resume() after --- -1.7.5.4 - diff --git a/features/uprobe/move-key_repace_session_keyring-into-tracehook_notif.patch b/features/uprobe/move-key_repace_session_keyring-into-tracehook_notif.patch deleted file mode 100644 index ae51e06e875e0a2937182f980458be0de677eb45..0000000000000000000000000000000000000000 --- a/features/uprobe/move-key_repace_session_keyring-into-tracehook_notif.patch +++ /dev/null @@ -1,359 +0,0 @@ -From 70754ded9575da5dafcf389d827d8dbfbf596240 Mon Sep 17 00:00:00 2001 -From: Al Viro <viro@zeniv.linux.org.uk> -Date: Wed, 23 May 2012 14:44:37 -0400 -Subject: [PATCH 1/6] move key_repace_session_keyring() into - tracehook_notify_resume() - -commit a42c6ded827dbd396d2efde7530620be029a72d1 upstream. - -Signed-off-by: Al Viro <viro@zeniv.linux.org.uk> -[Pb: dropped changes to archs lacking TIF_NOTIFY_RESUME: microblaze, -m68k, um, xtensa, score] -Signed-off-by: Paul Barrette <paul.barrette@windriver.com> ---- - arch/alpha/kernel/signal.c | 2 -- - arch/arm/kernel/signal.c | 2 -- - arch/avr32/kernel/signal.c | 2 -- - arch/blackfin/kernel/signal.c | 2 -- - arch/c6x/kernel/signal.c | 2 -- - arch/cris/kernel/ptrace.c | 2 -- - arch/frv/kernel/signal.c | 2 -- - arch/h8300/kernel/signal.c | 2 -- - arch/hexagon/kernel/signal.c | 5 +---- - arch/ia64/kernel/process.c | 2 -- - arch/m32r/kernel/signal.c | 2 -- - arch/mips/kernel/signal.c | 2 -- - arch/mn10300/kernel/signal.c | 2 -- - arch/openrisc/kernel/signal.c | 2 -- - arch/parisc/kernel/signal.c | 2 -- - arch/powerpc/kernel/signal.c | 2 -- - arch/s390/kernel/signal.c | 2 -- - arch/sh/kernel/signal_32.c | 2 -- - arch/sh/kernel/signal_64.c | 2 -- - arch/sparc/kernel/signal_32.c | 2 -- - arch/sparc/kernel/signal_64.c | 2 -- - arch/tile/kernel/process.c | 2 -- - arch/unicore32/kernel/signal.c | 2 -- - arch/x86/kernel/signal.c | 2 -- - include/linux/tracehook.h | 2 ++ - 25 files changed, 3 insertions(+), 50 deletions(-) - -diff --git a/arch/alpha/kernel/signal.c b/arch/alpha/kernel/signal.c -index 35f2ef4..bb61c58 100644 ---- a/arch/alpha/kernel/signal.c -+++ b/arch/alpha/kernel/signal.c -@@ -616,7 +616,5 @@ do_notify_resume(struct pt_regs *regs, struct switch_stack *sw, - if (thread_info_flags & _TIF_NOTIFY_RESUME) { - clear_thread_flag(TIF_NOTIFY_RESUME); - tracehook_notify_resume(regs); -- if (current->replacement_session_keyring) -- key_replace_session_keyring(); - } - } -diff --git a/arch/arm/kernel/signal.c b/arch/arm/kernel/signal.c -index d68d1b6..b2abc46 100644 ---- a/arch/arm/kernel/signal.c -+++ b/arch/arm/kernel/signal.c -@@ -735,7 +735,5 @@ do_notify_resume(struct pt_regs *regs, unsigned int thread_flags, int syscall) - if (thread_flags & _TIF_NOTIFY_RESUME) { - clear_thread_flag(TIF_NOTIFY_RESUME); - tracehook_notify_resume(regs); -- if (current->replacement_session_keyring) -- key_replace_session_keyring(); - } - } -diff --git a/arch/avr32/kernel/signal.c b/arch/avr32/kernel/signal.c -index 64f886f..0d512c5 100644 ---- a/arch/avr32/kernel/signal.c -+++ b/arch/avr32/kernel/signal.c -@@ -327,7 +327,5 @@ asmlinkage void do_notify_resume(struct pt_regs *regs, struct thread_info *ti) - if (ti->flags & _TIF_NOTIFY_RESUME) { - clear_thread_flag(TIF_NOTIFY_RESUME); - tracehook_notify_resume(regs); -- if (current->replacement_session_keyring) -- key_replace_session_keyring(); - } - } -diff --git a/arch/blackfin/kernel/signal.c b/arch/blackfin/kernel/signal.c -index d536f35..0af1a1b 100644 ---- a/arch/blackfin/kernel/signal.c -+++ b/arch/blackfin/kernel/signal.c -@@ -347,8 +347,6 @@ asmlinkage void do_notify_resume(struct pt_regs *regs) - if (test_thread_flag(TIF_NOTIFY_RESUME)) { - clear_thread_flag(TIF_NOTIFY_RESUME); - tracehook_notify_resume(regs); -- if (current->replacement_session_keyring) -- key_replace_session_keyring(); - } - } - -diff --git a/arch/c6x/kernel/signal.c b/arch/c6x/kernel/signal.c -index 3b5a050..ee7beae 100644 ---- a/arch/c6x/kernel/signal.c -+++ b/arch/c6x/kernel/signal.c -@@ -361,7 +361,5 @@ asmlinkage void do_notify_resume(struct pt_regs *regs, u32 thread_info_flags, - if (thread_info_flags & (1 << TIF_NOTIFY_RESUME)) { - clear_thread_flag(TIF_NOTIFY_RESUME); - tracehook_notify_resume(regs); -- if (current->replacement_session_keyring) -- key_replace_session_keyring(); - } - } -diff --git a/arch/cris/kernel/ptrace.c b/arch/cris/kernel/ptrace.c -index d114ad3..58d44ee 100644 ---- a/arch/cris/kernel/ptrace.c -+++ b/arch/cris/kernel/ptrace.c -@@ -40,7 +40,5 @@ void do_notify_resume(int canrestart, struct pt_regs *regs, - if (thread_info_flags & _TIF_NOTIFY_RESUME) { - clear_thread_flag(TIF_NOTIFY_RESUME); - tracehook_notify_resume(regs); -- if (current->replacement_session_keyring) -- key_replace_session_keyring(); - } - } -diff --git a/arch/frv/kernel/signal.c b/arch/frv/kernel/signal.c -index bab0129..151a3fd 100644 ---- a/arch/frv/kernel/signal.c -+++ b/arch/frv/kernel/signal.c -@@ -583,8 +583,6 @@ asmlinkage void do_notify_resume(__u32 thread_info_flags) - if (thread_info_flags & _TIF_NOTIFY_RESUME) { - clear_thread_flag(TIF_NOTIFY_RESUME); - tracehook_notify_resume(__frame); -- if (current->replacement_session_keyring) -- key_replace_session_keyring(); - } - - } /* end do_notify_resume() */ -diff --git a/arch/h8300/kernel/signal.c b/arch/h8300/kernel/signal.c -index af842c3..14c46e8 100644 ---- a/arch/h8300/kernel/signal.c -+++ b/arch/h8300/kernel/signal.c -@@ -557,7 +557,5 @@ asmlinkage void do_notify_resume(struct pt_regs *regs, u32 thread_info_flags) - if (thread_info_flags & _TIF_NOTIFY_RESUME) { - clear_thread_flag(TIF_NOTIFY_RESUME); - tracehook_notify_resume(regs); -- if (current->replacement_session_keyring) -- key_replace_session_keyring(); - } - } -diff --git a/arch/hexagon/kernel/signal.c b/arch/hexagon/kernel/signal.c -index ecbab34..6274022 100644 ---- a/arch/hexagon/kernel/signal.c -+++ b/arch/hexagon/kernel/signal.c -@@ -270,11 +270,8 @@ void do_notify_resume(struct pt_regs *regs, unsigned long thread_info_flags) - if (thread_info_flags & _TIF_SIGPENDING) - do_signal(regs); - -- if (thread_info_flags & _TIF_NOTIFY_RESUME) { -+ if (thread_info_flags & _TIF_NOTIFY_RESUME) - clear_thread_flag(TIF_NOTIFY_RESUME); -- if (current->replacement_session_keyring) -- key_replace_session_keyring(); -- } - } - - /* -diff --git a/arch/ia64/kernel/process.c b/arch/ia64/kernel/process.c -index ce74e14..99f34a8 100644 ---- a/arch/ia64/kernel/process.c -+++ b/arch/ia64/kernel/process.c -@@ -199,8 +199,6 @@ do_notify_resume_user(sigset_t *unused, struct sigscratch *scr, long in_syscall) - if (test_thread_flag(TIF_NOTIFY_RESUME)) { - clear_thread_flag(TIF_NOTIFY_RESUME); - tracehook_notify_resume(&scr->pt); -- if (current->replacement_session_keyring) -- key_replace_session_keyring(); - } - - /* copy user rbs to kernel rbs */ -diff --git a/arch/m32r/kernel/signal.c b/arch/m32r/kernel/signal.c -index a08697f..d0a24f4 100644 ---- a/arch/m32r/kernel/signal.c -+++ b/arch/m32r/kernel/signal.c -@@ -391,8 +391,6 @@ void do_notify_resume(struct pt_regs *regs, __u32 thread_info_flags) - if (thread_info_flags & _TIF_NOTIFY_RESUME) { - clear_thread_flag(TIF_NOTIFY_RESUME); - tracehook_notify_resume(regs); -- if (current->replacement_session_keyring) -- key_replace_session_keyring(); - } - - clear_thread_flag(TIF_IRET); -diff --git a/arch/mips/kernel/signal.c b/arch/mips/kernel/signal.c -index d5a338a..3f0fe74 100644 ---- a/arch/mips/kernel/signal.c -+++ b/arch/mips/kernel/signal.c -@@ -652,8 +652,6 @@ asmlinkage void do_notify_resume(struct pt_regs *regs, void *unused, - if (thread_info_flags & _TIF_NOTIFY_RESUME) { - clear_thread_flag(TIF_NOTIFY_RESUME); - tracehook_notify_resume(regs); -- if (current->replacement_session_keyring) -- key_replace_session_keyring(); - } - } - -diff --git a/arch/mn10300/kernel/signal.c b/arch/mn10300/kernel/signal.c -index 690f4e9..909059e 100644 ---- a/arch/mn10300/kernel/signal.c -+++ b/arch/mn10300/kernel/signal.c -@@ -575,7 +575,5 @@ asmlinkage void do_notify_resume(struct pt_regs *regs, u32 thread_info_flags) - if (thread_info_flags & _TIF_NOTIFY_RESUME) { - clear_thread_flag(TIF_NOTIFY_RESUME); - tracehook_notify_resume(current_frame()); -- if (current->replacement_session_keyring) -- key_replace_session_keyring(); - } - } -diff --git a/arch/openrisc/kernel/signal.c b/arch/openrisc/kernel/signal.c -index e970743..9ae6115 100644 ---- a/arch/openrisc/kernel/signal.c -+++ b/arch/openrisc/kernel/signal.c -@@ -376,7 +376,5 @@ asmlinkage void do_notify_resume(struct pt_regs *regs) - if (current_thread_info()->flags & _TIF_NOTIFY_RESUME) { - clear_thread_flag(TIF_NOTIFY_RESUME); - tracehook_notify_resume(regs); -- if (current->replacement_session_keyring) -- key_replace_session_keyring(); - } - } -diff --git a/arch/parisc/kernel/signal.c b/arch/parisc/kernel/signal.c -index 12c1ed3..c3102c4 100644 ---- a/arch/parisc/kernel/signal.c -+++ b/arch/parisc/kernel/signal.c -@@ -647,7 +647,5 @@ void do_notify_resume(struct pt_regs *regs, long in_syscall) - if (test_thread_flag(TIF_NOTIFY_RESUME)) { - clear_thread_flag(TIF_NOTIFY_RESUME); - tracehook_notify_resume(regs); -- if (current->replacement_session_keyring) -- key_replace_session_keyring(); - } - } -diff --git a/arch/powerpc/kernel/signal.c b/arch/powerpc/kernel/signal.c -index f1d61f0..e72fb65 100644 ---- a/arch/powerpc/kernel/signal.c -+++ b/arch/powerpc/kernel/signal.c -@@ -199,8 +199,6 @@ void do_notify_resume(struct pt_regs *regs, unsigned long thread_info_flags) - if (thread_info_flags & _TIF_NOTIFY_RESUME) { - clear_thread_flag(TIF_NOTIFY_RESUME); - tracehook_notify_resume(regs); -- if (current->replacement_session_keyring) -- key_replace_session_keyring(); - } - } - -diff --git a/arch/s390/kernel/signal.c b/arch/s390/kernel/signal.c -index f7582b2..fbf2495 100644 ---- a/arch/s390/kernel/signal.c -+++ b/arch/s390/kernel/signal.c -@@ -517,6 +517,4 @@ void do_notify_resume(struct pt_regs *regs) - { - clear_thread_flag(TIF_NOTIFY_RESUME); - tracehook_notify_resume(regs); -- if (current->replacement_session_keyring) -- key_replace_session_keyring(); - } -diff --git a/arch/sh/kernel/signal_32.c b/arch/sh/kernel/signal_32.c -index 5901fba..a6b74c3 100644 ---- a/arch/sh/kernel/signal_32.c -+++ b/arch/sh/kernel/signal_32.c -@@ -633,7 +633,5 @@ asmlinkage void do_notify_resume(struct pt_regs *regs, unsigned int save_r0, - if (thread_info_flags & _TIF_NOTIFY_RESUME) { - clear_thread_flag(TIF_NOTIFY_RESUME); - tracehook_notify_resume(regs); -- if (current->replacement_session_keyring) -- key_replace_session_keyring(); - } - } -diff --git a/arch/sh/kernel/signal_64.c b/arch/sh/kernel/signal_64.c -index 3c9a6f7..52bdfb0 100644 ---- a/arch/sh/kernel/signal_64.c -+++ b/arch/sh/kernel/signal_64.c -@@ -737,7 +737,5 @@ asmlinkage void do_notify_resume(struct pt_regs *regs, unsigned long thread_info - if (thread_info_flags & _TIF_NOTIFY_RESUME) { - clear_thread_flag(TIF_NOTIFY_RESUME); - tracehook_notify_resume(regs); -- if (current->replacement_session_keyring) -- key_replace_session_keyring(); - } - } -diff --git a/arch/sparc/kernel/signal_32.c b/arch/sparc/kernel/signal_32.c -index 1e750e41..72bd0f7 100644 ---- a/arch/sparc/kernel/signal_32.c -+++ b/arch/sparc/kernel/signal_32.c -@@ -603,8 +603,6 @@ void do_notify_resume(struct pt_regs *regs, unsigned long orig_i0, - if (thread_info_flags & _TIF_NOTIFY_RESUME) { - clear_thread_flag(TIF_NOTIFY_RESUME); - tracehook_notify_resume(regs); -- if (current->replacement_session_keyring) -- key_replace_session_keyring(); - } - } - -diff --git a/arch/sparc/kernel/signal_64.c b/arch/sparc/kernel/signal_64.c -index 48b0f57..f2dcaab 100644 ---- a/arch/sparc/kernel/signal_64.c -+++ b/arch/sparc/kernel/signal_64.c -@@ -618,8 +618,6 @@ void do_notify_resume(struct pt_regs *regs, unsigned long orig_i0, unsigned long - if (thread_info_flags & _TIF_NOTIFY_RESUME) { - clear_thread_flag(TIF_NOTIFY_RESUME); - tracehook_notify_resume(regs); -- if (current->replacement_session_keyring) -- key_replace_session_keyring(); - } - } - -diff --git a/arch/tile/kernel/process.c b/arch/tile/kernel/process.c -index 54e6c64..4515c92 100644 ---- a/arch/tile/kernel/process.c -+++ b/arch/tile/kernel/process.c -@@ -588,8 +588,6 @@ int do_work_pending(struct pt_regs *regs, u32 thread_info_flags) - if (thread_info_flags & _TIF_NOTIFY_RESUME) { - clear_thread_flag(TIF_NOTIFY_RESUME); - tracehook_notify_resume(regs); -- if (current->replacement_session_keyring) -- key_replace_session_keyring(); - return 1; - } - if (thread_info_flags & _TIF_SINGLESTEP) { -diff --git a/arch/unicore32/kernel/signal.c b/arch/unicore32/kernel/signal.c -index 911b549..b1e5cd5 100644 ---- a/arch/unicore32/kernel/signal.c -+++ b/arch/unicore32/kernel/signal.c -@@ -470,8 +470,6 @@ asmlinkage void do_notify_resume(struct pt_regs *regs, - if (thread_flags & _TIF_NOTIFY_RESUME) { - clear_thread_flag(TIF_NOTIFY_RESUME); - tracehook_notify_resume(regs); -- if (current->replacement_session_keyring) -- key_replace_session_keyring(); - } - } - -diff --git a/arch/x86/kernel/signal.c b/arch/x86/kernel/signal.c -index 041af2f..a0679ff 100644 ---- a/arch/x86/kernel/signal.c -+++ b/arch/x86/kernel/signal.c -@@ -837,8 +837,6 @@ do_notify_resume(struct pt_regs *regs, void *unused, __u32 thread_info_flags) - if (thread_info_flags & _TIF_NOTIFY_RESUME) { - clear_thread_flag(TIF_NOTIFY_RESUME); - tracehook_notify_resume(regs); -- if (current->replacement_session_keyring) -- key_replace_session_keyring(); - } - if (thread_info_flags & _TIF_USER_RETURN_NOTIFY) - fire_user_return_notifiers(); -diff --git a/include/linux/tracehook.h b/include/linux/tracehook.h -index 51bd91d..d28ceaf 100644 ---- a/include/linux/tracehook.h -+++ b/include/linux/tracehook.h -@@ -184,6 +184,8 @@ static inline void set_notify_resume(struct task_struct *task) - */ - static inline void tracehook_notify_resume(struct pt_regs *regs) - { -+ if (current->replacement_session_keyring) -+ key_replace_session_keyring(); - } - #endif /* TIF_NOTIFY_RESUME */ - --- -1.7.5.4 - diff --git a/features/uprobe/perf-probe-Detect-probe-target-when-m-x-options-are-.patch b/features/uprobe/perf-probe-Detect-probe-target-when-m-x-options-are-.patch deleted file mode 100644 index 98a2f0c0cb90ae8ce1e066df902b2679dd64e55d..0000000000000000000000000000000000000000 --- a/features/uprobe/perf-probe-Detect-probe-target-when-m-x-options-are-.patch +++ /dev/null @@ -1,136 +0,0 @@ -From 8893371eedcf3baa234184e9156fdfe0ea69260d Mon Sep 17 00:00:00 2001 -From: Srikar Dronamraju <srikar@linux.vnet.ibm.com> -Date: Mon, 16 Apr 2012 17:39:25 +0530 -Subject: [PATCH 21/24] perf probe: Detect probe target when m/x options are - absent - -Options -m and -x explicitly allow tracing of modules / user space -binaries. In absense of these options, check if the first argument can -be used as a target. - -perf probe /bin/zsh zfree is equivalent to perf probe -x /bin/zsh zfree. - -commit 73eff9f56e15598c8399c0b86899fd889b97f085 upstream - -Suggested-by: Arnaldo Carvalho de Melo <acme@redhat.com> -Cc: Ananth N Mavinakayanahalli <ananth@in.ibm.com> -Cc: Andi Kleen <andi@firstfloor.org> -Cc: Andrew Morton <akpm@linux-foundation.org> -Cc: Anton Arapov <anton@redhat.com> -Cc: Christoph Hellwig <hch@infradead.org> -Cc: Ingo Molnar <mingo@elte.hu> -Cc: Jim Keniston <jkenisto@linux.vnet.ibm.com> -Cc: Linus Torvalds <torvalds@linux-foundation.org> -Cc: Linux-mm <linux-mm@kvack.org> -Cc: Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com> -Cc: Oleg Nesterov <oleg@redhat.com> -Cc: Peter Zijlstra <peterz@infradead.org> -Cc: Steven Rostedt <rostedt@goodmis.org> -Cc: Thomas Gleixner <tglx@linutronix.de> -Link: http://lkml.kernel.org/r/20120416120925.30661.40409.sendpatchset@srdronam.in.ibm.com -Signed-off-by: Srikar Dronamraju <srikar@linux.vnet.ibm.com> -Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com> -Signed-off-by: Paul Barrette <paul.barrette@windriver.com> ---- - tools/perf/Documentation/perf-probe.txt | 8 ++++- - tools/perf/builtin-probe.c | 43 ++++++++++++++++++++++++++++-- - 2 files changed, 46 insertions(+), 5 deletions(-) - -diff --git a/tools/perf/Documentation/perf-probe.txt b/tools/perf/Documentation/perf-probe.txt -index fb673be..b715cb7 100644 ---- a/tools/perf/Documentation/perf-probe.txt -+++ b/tools/perf/Documentation/perf-probe.txt -@@ -104,6 +104,10 @@ OPTIONS - Specify path to the executable or shared library file for user - space tracing. Can also be used with --funcs option. - -+In absence of -m/-x options, perf probe checks if the first argument after -+the options is an absolute path name. If its an absolute path, perf probe -+uses it as a target module/target user space binary to probe. -+ - PROBE SYNTAX - ------------ - Probe points are defined by following syntax. -@@ -190,11 +194,11 @@ Delete all probes on schedule(). - - Add probes at zfree() function on /bin/zsh - -- ./perf probe -x /bin/zsh zfree -+ ./perf probe -x /bin/zsh zfree or ./perf probe /bin/zsh zfree - - Add probes at malloc() function on libc - -- ./perf probe -x /lib/libc.so.6 malloc -+ ./perf probe -x /lib/libc.so.6 malloc or ./perf probe /lib/libc.so.6 malloc - - SEE ALSO - -------- -diff --git a/tools/perf/builtin-probe.c b/tools/perf/builtin-probe.c -index ee3d84a..e215ae6 100644 ---- a/tools/perf/builtin-probe.c -+++ b/tools/perf/builtin-probe.c -@@ -85,21 +85,58 @@ static int parse_probe_event(const char *str) - return ret; - } - -+static int set_target(const char *ptr) -+{ -+ int found = 0; -+ const char *buf; -+ -+ /* -+ * The first argument after options can be an absolute path -+ * to an executable / library or kernel module. -+ * -+ * TODO: Support relative path, and $PATH, $LD_LIBRARY_PATH, -+ * short module name. -+ */ -+ if (!params.target && ptr && *ptr == '/') { -+ params.target = ptr; -+ found = 1; -+ buf = ptr + (strlen(ptr) - 3); -+ -+ if (strcmp(buf, ".ko")) -+ params.uprobes = true; -+ -+ } -+ -+ return found; -+} -+ - static int parse_probe_event_argv(int argc, const char **argv) - { -- int i, len, ret; -+ int i, len, ret, found_target; - char *buf; - -+ found_target = set_target(argv[0]); -+ if (found_target && argc == 1) -+ return 0; -+ - /* Bind up rest arguments */ - len = 0; -- for (i = 0; i < argc; i++) -+ for (i = 0; i < argc; i++) { -+ if (i == 0 && found_target) -+ continue; -+ - len += strlen(argv[i]) + 1; -+ } - buf = zalloc(len + 1); - if (buf == NULL) - return -ENOMEM; - len = 0; -- for (i = 0; i < argc; i++) -+ for (i = 0; i < argc; i++) { -+ if (i == 0 && found_target) -+ continue; -+ - len += sprintf(&buf[len], "%s ", argv[i]); -+ } - params.mod_events = true; - ret = parse_probe_event(buf); - free(buf); --- -1.7.5.4 - diff --git a/features/uprobe/perf-probe-Provide-perf-interface-for-uprobes.patch b/features/uprobe/perf-probe-Provide-perf-interface-for-uprobes.patch deleted file mode 100644 index 0d2503d5f6437835de88282ebec03f670217c3e8..0000000000000000000000000000000000000000 --- a/features/uprobe/perf-probe-Provide-perf-interface-for-uprobes.patch +++ /dev/null @@ -1,944 +0,0 @@ -From 544d531a337d560bd89f44ec45b0f6f2658c8e7c Mon Sep 17 00:00:00 2001 -From: Srikar Dronamraju <srikar@linux.vnet.ibm.com> -Date: Mon, 16 Apr 2012 17:39:09 +0530 -Subject: [PATCH 20/24] perf probe: Provide perf interface for uprobes - -- Enhances perf to probe user space executables and libraries. -- Enhances -F/--funcs option of "perf probe" to list possible probe points in - an executable file or library. -- Documents userspace probing support in perf. - -[ Probing a function in the executable using function name ] -perf probe -x /bin/zsh zfree - -[ Probing a library function using function name ] -perf probe -x /lib64/libc.so.6 malloc - -[ list probe-able functions in an executable ] -perf probe -F -x /bin/zsh - -[ list probe-able functions in an library] -perf probe -F -x /lib/libc.so.6 - -commit 225466f1c2d816c33b4341008f45dfdc83a9f0cb upstream - -Signed-off-by: Srikar Dronamraju <srikar@linux.vnet.ibm.com> -Cc: Ananth N Mavinakayanahalli <ananth@in.ibm.com> -Cc: Andi Kleen <andi@firstfloor.org> -Cc: Andrew Morton <akpm@linux-foundation.org> -Cc: Anton Arapov <anton@redhat.com> -Cc: Christoph Hellwig <hch@infradead.org> -Cc: Ingo Molnar <mingo@elte.hu> -Cc: Jim Keniston <jkenisto@linux.vnet.ibm.com> -Cc: Linus Torvalds <torvalds@linux-foundation.org> -Cc: Linux-mm <linux-mm@kvack.org> -Cc: Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com> -Cc: Oleg Nesterov <oleg@redhat.com> -Cc: Peter Zijlstra <peterz@infradead.org> -Cc: Steven Rostedt <rostedt@goodmis.org> -Cc: Thomas Gleixner <tglx@linutronix.de> -Link: http://lkml.kernel.org/r/20120416120909.30661.99781.sendpatchset@srdronam.in.ibm.com -Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com> -Signed-off-by: Paul Barrette <paul.barrette@windriver.com> ---- - tools/perf/Documentation/perf-probe.txt | 15 +- - tools/perf/builtin-probe.c | 43 +++- - tools/perf/util/probe-event.c | 422 ++++++++++++++++++++++++------- - tools/perf/util/probe-event.h | 12 +- - tools/perf/util/symbol.c | 8 + - tools/perf/util/symbol.h | 1 + - 6 files changed, 403 insertions(+), 98 deletions(-) - -diff --git a/tools/perf/Documentation/perf-probe.txt b/tools/perf/Documentation/perf-probe.txt -index 2780d9c..fb673be 100644 ---- a/tools/perf/Documentation/perf-probe.txt -+++ b/tools/perf/Documentation/perf-probe.txt -@@ -77,7 +77,8 @@ OPTIONS - - -F:: - --funcs:: -- Show available functions in given module or kernel. -+ Show available functions in given module or kernel. With -x/--exec, -+ can also list functions in a user space executable / shared library. - - --filter=FILTER:: - (Only for --vars and --funcs) Set filter. FILTER is a combination of glob -@@ -98,6 +99,11 @@ OPTIONS - --max-probes:: - Set the maximum number of probe points for an event. Default is 128. - -+-x:: -+--exec=PATH:: -+ Specify path to the executable or shared library file for user -+ space tracing. Can also be used with --funcs option. -+ - PROBE SYNTAX - ------------ - Probe points are defined by following syntax. -@@ -182,6 +188,13 @@ Delete all probes on schedule(). - - ./perf probe --del='schedule*' - -+Add probes at zfree() function on /bin/zsh -+ -+ ./perf probe -x /bin/zsh zfree -+ -+Add probes at malloc() function on libc -+ -+ ./perf probe -x /lib/libc.so.6 malloc - - SEE ALSO - -------- -diff --git a/tools/perf/builtin-probe.c b/tools/perf/builtin-probe.c -index 4935c09..ee3d84a 100644 ---- a/tools/perf/builtin-probe.c -+++ b/tools/perf/builtin-probe.c -@@ -54,6 +54,7 @@ static struct { - bool show_ext_vars; - bool show_funcs; - bool mod_events; -+ bool uprobes; - int nevents; - struct perf_probe_event events[MAX_PROBES]; - struct strlist *dellist; -@@ -75,6 +76,8 @@ static int parse_probe_event(const char *str) - return -1; - } - -+ pev->uprobes = params.uprobes; -+ - /* Parse a perf-probe command into event */ - ret = parse_perf_probe_command(str, pev); - pr_debug("%d arguments\n", pev->nargs); -@@ -125,6 +128,28 @@ static int opt_del_probe_event(const struct option *opt __used, - return 0; - } - -+static int opt_set_target(const struct option *opt, const char *str, -+ int unset __used) -+{ -+ int ret = -ENOENT; -+ -+ if (str && !params.target) { -+ if (!strcmp(opt->long_name, "exec")) -+ params.uprobes = true; -+#ifdef DWARF_SUPPORT -+ else if (!strcmp(opt->long_name, "module")) -+ params.uprobes = false; -+#endif -+ else -+ return ret; -+ -+ params.target = str; -+ ret = 0; -+ } -+ -+ return ret; -+} -+ - #ifdef DWARF_SUPPORT - static int opt_show_lines(const struct option *opt __used, - const char *str, int unset __used) -@@ -246,9 +271,9 @@ static const struct option options[] = { - "file", "vmlinux pathname"), - OPT_STRING('s', "source", &symbol_conf.source_prefix, - "directory", "path to kernel source"), -- OPT_STRING('m', "module", ¶ms.target, -- "modname|path", -- "target module name (for online) or path (for offline)"), -+ OPT_CALLBACK('m', "module", NULL, "modname|path", -+ "target module name (for online) or path (for offline)", -+ opt_set_target), - #endif - OPT__DRY_RUN(&probe_event_dry_run), - OPT_INTEGER('\0', "max-probes", ¶ms.max_probe_points, -@@ -260,6 +285,8 @@ static const struct option options[] = { - "\t\t\t(default: \"" DEFAULT_VAR_FILTER "\" for --vars,\n" - "\t\t\t \"" DEFAULT_FUNC_FILTER "\" for --funcs)", - opt_set_filter), -+ OPT_CALLBACK('x', "exec", NULL, "executable|path", -+ "target executable name or path", opt_set_target), - OPT_END() - }; - -@@ -310,6 +337,10 @@ int cmd_probe(int argc, const char **argv, const char *prefix __used) - pr_err(" Error: Don't use --list with --funcs.\n"); - usage_with_options(probe_usage, options); - } -+ if (params.uprobes) { -+ pr_warning(" Error: Don't use --list with --exec.\n"); -+ usage_with_options(probe_usage, options); -+ } - ret = show_perf_probe_events(); - if (ret < 0) - pr_err(" Error: Failed to show event list. (%d)\n", -@@ -333,8 +364,8 @@ int cmd_probe(int argc, const char **argv, const char *prefix __used) - if (!params.filter) - params.filter = strfilter__new(DEFAULT_FUNC_FILTER, - NULL); -- ret = show_available_funcs(params.target, -- params.filter); -+ ret = show_available_funcs(params.target, params.filter, -+ params.uprobes); - strfilter__delete(params.filter); - if (ret < 0) - pr_err(" Error: Failed to show functions." -@@ -343,7 +374,7 @@ int cmd_probe(int argc, const char **argv, const char *prefix __used) - } - - #ifdef DWARF_SUPPORT -- if (params.show_lines) { -+ if (params.show_lines && !params.uprobes) { - if (params.mod_events) { - pr_err(" Error: Don't use --line with" - " --add/--del.\n"); -diff --git a/tools/perf/util/probe-event.c b/tools/perf/util/probe-event.c -index 8a8ee64..59dccc9 100644 ---- a/tools/perf/util/probe-event.c -+++ b/tools/perf/util/probe-event.c -@@ -44,6 +44,7 @@ - #include "trace-event.h" /* For __unused */ - #include "probe-event.h" - #include "probe-finder.h" -+#include "session.h" - - #define MAX_CMDLEN 256 - #define MAX_PROBE_ARGS 128 -@@ -70,6 +71,8 @@ static int e_snprintf(char *str, size_t size, const char *format, ...) - } - - static char *synthesize_perf_probe_point(struct perf_probe_point *pp); -+static int convert_name_to_addr(struct perf_probe_event *pev, -+ const char *exec); - static struct machine machine; - - /* Initialize symbol maps and path of vmlinux/modules */ -@@ -170,6 +173,34 @@ const char *kernel_get_module_path(const char *module) - return (dso) ? dso->long_name : NULL; - } - -+static int init_user_exec(void) -+{ -+ int ret = 0; -+ -+ symbol_conf.try_vmlinux_path = false; -+ symbol_conf.sort_by_name = true; -+ ret = symbol__init(); -+ -+ if (ret < 0) -+ pr_debug("Failed to init symbol map.\n"); -+ -+ return ret; -+} -+ -+static int convert_to_perf_probe_point(struct probe_trace_point *tp, -+ struct perf_probe_point *pp) -+{ -+ pp->function = strdup(tp->symbol); -+ -+ if (pp->function == NULL) -+ return -ENOMEM; -+ -+ pp->offset = tp->offset; -+ pp->retprobe = tp->retprobe; -+ -+ return 0; -+} -+ - #ifdef DWARF_SUPPORT - /* Open new debuginfo of given module */ - static struct debuginfo *open_debuginfo(const char *module) -@@ -224,10 +255,7 @@ static int kprobe_convert_to_perf_probe(struct probe_trace_point *tp, - if (ret <= 0) { - pr_debug("Failed to find corresponding probes from " - "debuginfo. Use kprobe event information.\n"); -- pp->function = strdup(tp->symbol); -- if (pp->function == NULL) -- return -ENOMEM; -- pp->offset = tp->offset; -+ return convert_to_perf_probe_point(tp, pp); - } - pp->retprobe = tp->retprobe; - -@@ -275,9 +303,20 @@ static int try_to_find_probe_trace_events(struct perf_probe_event *pev, - int max_tevs, const char *target) - { - bool need_dwarf = perf_probe_event_need_dwarf(pev); -- struct debuginfo *dinfo = open_debuginfo(target); -+ struct debuginfo *dinfo; - int ntevs, ret = 0; - -+ if (pev->uprobes) { -+ if (need_dwarf) { -+ pr_warning("Debuginfo-analysis is not yet supported" -+ " with -x/--exec option.\n"); -+ return -ENOSYS; -+ } -+ return convert_name_to_addr(pev, target); -+ } -+ -+ dinfo = open_debuginfo(target); -+ - if (!dinfo) { - if (need_dwarf) { - pr_warning("Failed to open debuginfo file.\n"); -@@ -603,23 +642,22 @@ static int kprobe_convert_to_perf_probe(struct probe_trace_point *tp, - pr_err("Failed to find symbol %s in kernel.\n", tp->symbol); - return -ENOENT; - } -- pp->function = strdup(tp->symbol); -- if (pp->function == NULL) -- return -ENOMEM; -- pp->offset = tp->offset; -- pp->retprobe = tp->retprobe; - -- return 0; -+ return convert_to_perf_probe_point(tp, pp); - } - - static int try_to_find_probe_trace_events(struct perf_probe_event *pev, - struct probe_trace_event **tevs __unused, -- int max_tevs __unused, const char *mod __unused) -+ int max_tevs __unused, const char *target) - { - if (perf_probe_event_need_dwarf(pev)) { - pr_warning("Debuginfo-analysis is not supported.\n"); - return -ENOSYS; - } -+ -+ if (pev->uprobes) -+ return convert_name_to_addr(pev, target); -+ - return 0; - } - -@@ -1341,11 +1379,18 @@ char *synthesize_probe_trace_command(struct probe_trace_event *tev) - if (buf == NULL) - return NULL; - -- len = e_snprintf(buf, MAX_CMDLEN, "%c:%s/%s %s%s%s+%lu", -- tp->retprobe ? 'r' : 'p', -- tev->group, tev->event, -- tp->module ?: "", tp->module ? ":" : "", -- tp->symbol, tp->offset); -+ if (tev->uprobes) -+ len = e_snprintf(buf, MAX_CMDLEN, "%c:%s/%s %s:%s", -+ tp->retprobe ? 'r' : 'p', -+ tev->group, tev->event, -+ tp->module, tp->symbol); -+ else -+ len = e_snprintf(buf, MAX_CMDLEN, "%c:%s/%s %s%s%s+%lu", -+ tp->retprobe ? 'r' : 'p', -+ tev->group, tev->event, -+ tp->module ?: "", tp->module ? ":" : "", -+ tp->symbol, tp->offset); -+ - if (len <= 0) - goto error; - -@@ -1364,7 +1409,7 @@ error: - } - - static int convert_to_perf_probe_event(struct probe_trace_event *tev, -- struct perf_probe_event *pev) -+ struct perf_probe_event *pev, bool is_kprobe) - { - char buf[64] = ""; - int i, ret; -@@ -1376,7 +1421,11 @@ static int convert_to_perf_probe_event(struct probe_trace_event *tev, - return -ENOMEM; - - /* Convert trace_point to probe_point */ -- ret = kprobe_convert_to_perf_probe(&tev->point, &pev->point); -+ if (is_kprobe) -+ ret = kprobe_convert_to_perf_probe(&tev->point, &pev->point); -+ else -+ ret = convert_to_perf_probe_point(&tev->point, &pev->point); -+ - if (ret < 0) - return ret; - -@@ -1472,7 +1521,26 @@ static void clear_probe_trace_event(struct probe_trace_event *tev) - memset(tev, 0, sizeof(*tev)); - } - --static int open_kprobe_events(bool readwrite) -+static void print_warn_msg(const char *file, bool is_kprobe) -+{ -+ -+ if (errno == ENOENT) { -+ const char *config; -+ -+ if (!is_kprobe) -+ config = "CONFIG_UPROBE_EVENTS"; -+ else -+ config = "CONFIG_KPROBE_EVENTS"; -+ -+ pr_warning("%s file does not exist - please rebuild kernel" -+ " with %s.\n", file, config); -+ } else -+ pr_warning("Failed to open %s file: %s\n", file, -+ strerror(errno)); -+} -+ -+static int open_probe_events(const char *trace_file, bool readwrite, -+ bool is_kprobe) - { - char buf[PATH_MAX]; - const char *__debugfs; -@@ -1484,27 +1552,31 @@ static int open_kprobe_events(bool readwrite) - return -ENOENT; - } - -- ret = e_snprintf(buf, PATH_MAX, "%stracing/kprobe_events", __debugfs); -+ ret = e_snprintf(buf, PATH_MAX, "%s/%s", __debugfs, trace_file); - if (ret >= 0) { - pr_debug("Opening %s write=%d\n", buf, readwrite); - if (readwrite && !probe_event_dry_run) - ret = open(buf, O_RDWR, O_APPEND); - else - ret = open(buf, O_RDONLY, 0); -- } - -- if (ret < 0) { -- if (errno == ENOENT) -- pr_warning("kprobe_events file does not exist - please" -- " rebuild kernel with CONFIG_KPROBE_EVENT.\n"); -- else -- pr_warning("Failed to open kprobe_events file: %s\n", -- strerror(errno)); -+ if (ret < 0) -+ print_warn_msg(buf, is_kprobe); - } - return ret; - } - --/* Get raw string list of current kprobe_events */ -+static int open_kprobe_events(bool readwrite) -+{ -+ return open_probe_events("tracing/kprobe_events", readwrite, true); -+} -+ -+static int open_uprobe_events(bool readwrite) -+{ -+ return open_probe_events("tracing/uprobe_events", readwrite, false); -+} -+ -+/* Get raw string list of current kprobe_events or uprobe_events */ - static struct strlist *get_probe_trace_command_rawlist(int fd) - { - int ret, idx; -@@ -1569,36 +1641,26 @@ static int show_perf_probe_event(struct perf_probe_event *pev) - return ret; - } - --/* List up current perf-probe events */ --int show_perf_probe_events(void) -+static int __show_perf_probe_events(int fd, bool is_kprobe) - { -- int fd, ret; -+ int ret = 0; - struct probe_trace_event tev; - struct perf_probe_event pev; - struct strlist *rawlist; - struct str_node *ent; - -- setup_pager(); -- ret = init_vmlinux(); -- if (ret < 0) -- return ret; -- - memset(&tev, 0, sizeof(tev)); - memset(&pev, 0, sizeof(pev)); - -- fd = open_kprobe_events(false); -- if (fd < 0) -- return fd; -- - rawlist = get_probe_trace_command_rawlist(fd); -- close(fd); - if (!rawlist) - return -ENOENT; - - strlist__for_each(ent, rawlist) { - ret = parse_probe_trace_command(ent->s, &tev); - if (ret >= 0) { -- ret = convert_to_perf_probe_event(&tev, &pev); -+ ret = convert_to_perf_probe_event(&tev, &pev, -+ is_kprobe); - if (ret >= 0) - ret = show_perf_probe_event(&pev); - } -@@ -1612,6 +1674,33 @@ int show_perf_probe_events(void) - return ret; - } - -+/* List up current perf-probe events */ -+int show_perf_probe_events(void) -+{ -+ int fd, ret; -+ -+ setup_pager(); -+ fd = open_kprobe_events(false); -+ -+ if (fd < 0) -+ return fd; -+ -+ ret = init_vmlinux(); -+ if (ret < 0) -+ return ret; -+ -+ ret = __show_perf_probe_events(fd, true); -+ close(fd); -+ -+ fd = open_uprobe_events(false); -+ if (fd >= 0) { -+ ret = __show_perf_probe_events(fd, false); -+ close(fd); -+ } -+ -+ return ret; -+} -+ - /* Get current perf-probe event names */ - static struct strlist *get_probe_trace_event_names(int fd, bool include_group) - { -@@ -1717,7 +1806,11 @@ static int __add_probe_trace_events(struct perf_probe_event *pev, - const char *event, *group; - struct strlist *namelist; - -- fd = open_kprobe_events(true); -+ if (pev->uprobes) -+ fd = open_uprobe_events(true); -+ else -+ fd = open_kprobe_events(true); -+ - if (fd < 0) - return fd; - /* Get current event names */ -@@ -1829,6 +1922,8 @@ static int convert_to_probe_trace_events(struct perf_probe_event *pev, - tev->point.offset = pev->point.offset; - tev->point.retprobe = pev->point.retprobe; - tev->nargs = pev->nargs; -+ tev->uprobes = pev->uprobes; -+ - if (tev->nargs) { - tev->args = zalloc(sizeof(struct probe_trace_arg) - * tev->nargs); -@@ -1859,6 +1954,9 @@ static int convert_to_probe_trace_events(struct perf_probe_event *pev, - } - } - -+ if (pev->uprobes) -+ return 1; -+ - /* Currently just checking function name from symbol map */ - sym = __find_kernel_function_by_name(tev->point.symbol, NULL); - if (!sym) { -@@ -1894,12 +1992,18 @@ int add_perf_probe_events(struct perf_probe_event *pevs, int npevs, - int i, j, ret; - struct __event_package *pkgs; - -+ ret = 0; - pkgs = zalloc(sizeof(struct __event_package) * npevs); -+ - if (pkgs == NULL) - return -ENOMEM; - -- /* Init vmlinux path */ -- ret = init_vmlinux(); -+ if (!pevs->uprobes) -+ /* Init vmlinux path */ -+ ret = init_vmlinux(); -+ else -+ ret = init_user_exec(); -+ - if (ret < 0) { - free(pkgs); - return ret; -@@ -1971,23 +2075,15 @@ error: - return ret; - } - --static int del_trace_probe_event(int fd, const char *group, -- const char *event, struct strlist *namelist) -+static int del_trace_probe_event(int fd, const char *buf, -+ struct strlist *namelist) - { -- char buf[128]; - struct str_node *ent, *n; -- int found = 0, ret = 0; -- -- ret = e_snprintf(buf, 128, "%s:%s", group, event); -- if (ret < 0) { -- pr_err("Failed to copy event.\n"); -- return ret; -- } -+ int ret = -1; - - if (strpbrk(buf, "*?")) { /* Glob-exp */ - strlist__for_each_safe(ent, n, namelist) - if (strglobmatch(ent->s, buf)) { -- found++; - ret = __del_trace_probe_event(fd, ent); - if (ret < 0) - break; -@@ -1996,40 +2092,43 @@ static int del_trace_probe_event(int fd, const char *group, - } else { - ent = strlist__find(namelist, buf); - if (ent) { -- found++; - ret = __del_trace_probe_event(fd, ent); - if (ret >= 0) - strlist__remove(namelist, ent); - } - } -- if (found == 0 && ret >= 0) -- pr_info("Info: Event \"%s\" does not exist.\n", buf); - - return ret; - } - - int del_perf_probe_events(struct strlist *dellist) - { -- int fd, ret = 0; -+ int ret = -1, ufd = -1, kfd = -1; -+ char buf[128]; - const char *group, *event; - char *p, *str; - struct str_node *ent; -- struct strlist *namelist; -- -- fd = open_kprobe_events(true); -- if (fd < 0) -- return fd; -+ struct strlist *namelist = NULL, *unamelist = NULL; - - /* Get current event names */ -- namelist = get_probe_trace_event_names(fd, true); -- if (namelist == NULL) -- return -EINVAL; -+ kfd = open_kprobe_events(true); -+ if (kfd < 0) -+ return kfd; -+ -+ namelist = get_probe_trace_event_names(kfd, true); -+ ufd = open_uprobe_events(true); -+ -+ if (ufd >= 0) -+ unamelist = get_probe_trace_event_names(ufd, true); -+ -+ if (namelist == NULL && unamelist == NULL) -+ goto error; - - strlist__for_each(ent, dellist) { - str = strdup(ent->s); - if (str == NULL) { - ret = -ENOMEM; -- break; -+ goto error; - } - pr_debug("Parsing: %s\n", str); - p = strchr(str, ':'); -@@ -2041,17 +2140,46 @@ int del_perf_probe_events(struct strlist *dellist) - group = "*"; - event = str; - } -+ -+ ret = e_snprintf(buf, 128, "%s:%s", group, event); -+ if (ret < 0) { -+ pr_err("Failed to copy event."); -+ free(str); -+ goto error; -+ } -+ - pr_debug("Group: %s, Event: %s\n", group, event); -- ret = del_trace_probe_event(fd, group, event, namelist); -+ -+ if (namelist) -+ ret = del_trace_probe_event(kfd, buf, namelist); -+ -+ if (unamelist && ret != 0) -+ ret = del_trace_probe_event(ufd, buf, unamelist); -+ -+ if (ret != 0) -+ pr_info("Info: Event \"%s\" does not exist.\n", buf); -+ - free(str); -- if (ret < 0) -- break; - } -- strlist__delete(namelist); -- close(fd); -+ -+error: -+ if (kfd >= 0) { -+ if (namelist) -+ strlist__delete(namelist); -+ -+ close(kfd); -+ } -+ -+ if (ufd >= 0) { -+ if (unamelist) -+ strlist__delete(unamelist); -+ -+ close(ufd); -+ } - - return ret; - } -+ - /* TODO: don't use a global variable for filter ... */ - static struct strfilter *available_func_filter; - -@@ -2068,30 +2196,152 @@ static int filter_available_functions(struct map *map __unused, - return 1; - } - --int show_available_funcs(const char *target, struct strfilter *_filter) -+static int __show_available_funcs(struct map *map) -+{ -+ if (map__load(map, filter_available_functions)) { -+ pr_err("Failed to load map.\n"); -+ return -EINVAL; -+ } -+ if (!dso__sorted_by_name(map->dso, map->type)) -+ dso__sort_by_name(map->dso, map->type); -+ -+ dso__fprintf_symbols_by_name(map->dso, map->type, stdout); -+ return 0; -+} -+ -+static int available_kernel_funcs(const char *module) - { - struct map *map; - int ret; - -- setup_pager(); -- - ret = init_vmlinux(); - if (ret < 0) - return ret; - -- map = kernel_get_module_map(target); -+ map = kernel_get_module_map(module); - if (!map) { -- pr_err("Failed to find %s map.\n", (target) ? : "kernel"); -+ pr_err("Failed to find %s map.\n", (module) ? : "kernel"); - return -EINVAL; - } -+ return __show_available_funcs(map); -+} -+ -+static int available_user_funcs(const char *target) -+{ -+ struct map *map; -+ int ret; -+ -+ ret = init_user_exec(); -+ if (ret < 0) -+ return ret; -+ -+ map = dso__new_map(target); -+ ret = __show_available_funcs(map); -+ dso__delete(map->dso); -+ map__delete(map); -+ return ret; -+} -+ -+int show_available_funcs(const char *target, struct strfilter *_filter, -+ bool user) -+{ -+ setup_pager(); - available_func_filter = _filter; -+ -+ if (!user) -+ return available_kernel_funcs(target); -+ -+ return available_user_funcs(target); -+} -+ -+/* -+ * uprobe_events only accepts address: -+ * Convert function and any offset to address -+ */ -+static int convert_name_to_addr(struct perf_probe_event *pev, const char *exec) -+{ -+ struct perf_probe_point *pp = &pev->point; -+ struct symbol *sym; -+ struct map *map = NULL; -+ char *function = NULL, *name = NULL; -+ int ret = -EINVAL; -+ unsigned long long vaddr = 0; -+ -+ if (!pp->function) { -+ pr_warning("No function specified for uprobes"); -+ goto out; -+ } -+ -+ function = strdup(pp->function); -+ if (!function) { -+ pr_warning("Failed to allocate memory by strdup.\n"); -+ ret = -ENOMEM; -+ goto out; -+ } -+ -+ name = realpath(exec, NULL); -+ if (!name) { -+ pr_warning("Cannot find realpath for %s.\n", exec); -+ goto out; -+ } -+ map = dso__new_map(name); -+ if (!map) { -+ pr_warning("Cannot find appropriate DSO for %s.\n", exec); -+ goto out; -+ } -+ available_func_filter = strfilter__new(function, NULL); - if (map__load(map, filter_available_functions)) { - pr_err("Failed to load map.\n"); -- return -EINVAL; -+ goto out; - } -- if (!dso__sorted_by_name(map->dso, map->type)) -- dso__sort_by_name(map->dso, map->type); - -- dso__fprintf_symbols_by_name(map->dso, map->type, stdout); -- return 0; -+ sym = map__find_symbol_by_name(map, function, NULL); -+ if (!sym) { -+ pr_warning("Cannot find %s in DSO %s\n", function, exec); -+ goto out; -+ } -+ -+ if (map->start > sym->start) -+ vaddr = map->start; -+ vaddr += sym->start + pp->offset + map->pgoff; -+ pp->offset = 0; -+ -+ if (!pev->event) { -+ pev->event = function; -+ function = NULL; -+ } -+ if (!pev->group) { -+ char *ptr1, *ptr2; -+ -+ pev->group = zalloc(sizeof(char *) * 64); -+ ptr1 = strdup(basename(exec)); -+ if (ptr1) { -+ ptr2 = strpbrk(ptr1, "-._"); -+ if (ptr2) -+ *ptr2 = '\0'; -+ e_snprintf(pev->group, 64, "%s_%s", PERFPROBE_GROUP, -+ ptr1); -+ free(ptr1); -+ } -+ } -+ free(pp->function); -+ pp->function = zalloc(sizeof(char *) * MAX_PROBE_ARGS); -+ if (!pp->function) { -+ ret = -ENOMEM; -+ pr_warning("Failed to allocate memory by zalloc.\n"); -+ goto out; -+ } -+ e_snprintf(pp->function, MAX_PROBE_ARGS, "0x%llx", vaddr); -+ ret = 0; -+ -+out: -+ if (map) { -+ dso__delete(map->dso); -+ map__delete(map); -+ } -+ if (function) -+ free(function); -+ if (name) -+ free(name); -+ return ret; - } -diff --git a/tools/perf/util/probe-event.h b/tools/perf/util/probe-event.h -index a7dee83..f9f3de8 100644 ---- a/tools/perf/util/probe-event.h -+++ b/tools/perf/util/probe-event.h -@@ -7,7 +7,7 @@ - - extern bool probe_event_dry_run; - --/* kprobe-tracer tracing point */ -+/* kprobe-tracer and uprobe-tracer tracing point */ - struct probe_trace_point { - char *symbol; /* Base symbol */ - char *module; /* Module name */ -@@ -21,7 +21,7 @@ struct probe_trace_arg_ref { - long offset; /* Offset value */ - }; - --/* kprobe-tracer tracing argument */ -+/* kprobe-tracer and uprobe-tracer tracing argument */ - struct probe_trace_arg { - char *name; /* Argument name */ - char *value; /* Base value */ -@@ -29,12 +29,13 @@ struct probe_trace_arg { - struct probe_trace_arg_ref *ref; /* Referencing offset */ - }; - --/* kprobe-tracer tracing event (point + arg) */ -+/* kprobe-tracer and uprobe-tracer tracing event (point + arg) */ - struct probe_trace_event { - char *event; /* Event name */ - char *group; /* Group name */ - struct probe_trace_point point; /* Trace point */ - int nargs; /* Number of args */ -+ bool uprobes; /* uprobes only */ - struct probe_trace_arg *args; /* Arguments */ - }; - -@@ -70,6 +71,7 @@ struct perf_probe_event { - char *group; /* Group name */ - struct perf_probe_point point; /* Probe point */ - int nargs; /* Number of arguments */ -+ bool uprobes; - struct perf_probe_arg *args; /* Arguments */ - }; - -@@ -129,8 +131,8 @@ extern int show_line_range(struct line_range *lr, const char *module); - extern int show_available_vars(struct perf_probe_event *pevs, int npevs, - int max_probe_points, const char *module, - struct strfilter *filter, bool externs); --extern int show_available_funcs(const char *module, struct strfilter *filter); -- -+extern int show_available_funcs(const char *module, struct strfilter *filter, -+ bool user); - - /* Maximum index number of event-name postfix */ - #define MAX_EVENT_INDEX 1024 -diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c -index ab9867b..e2ba885 100644 ---- a/tools/perf/util/symbol.c -+++ b/tools/perf/util/symbol.c -@@ -2783,3 +2783,11 @@ int machine__load_vmlinux_path(struct machine *machine, enum map_type type, - - return ret; - } -+ -+struct map *dso__new_map(const char *name) -+{ -+ struct dso *dso = dso__new(name); -+ struct map *map = map__new2(0, dso, MAP__FUNCTION); -+ -+ return map; -+} -diff --git a/tools/perf/util/symbol.h b/tools/perf/util/symbol.h -index ac49ef2..9e7742c 100644 ---- a/tools/perf/util/symbol.h -+++ b/tools/perf/util/symbol.h -@@ -237,6 +237,7 @@ void dso__set_long_name(struct dso *dso, char *name); - void dso__set_build_id(struct dso *dso, void *build_id); - void dso__read_running_kernel_build_id(struct dso *dso, - struct machine *machine); -+struct map *dso__new_map(const char *name); - struct symbol *dso__find_symbol(struct dso *dso, enum map_type type, - u64 addr); - struct symbol *dso__find_symbol_by_name(struct dso *dso, enum map_type type, --- -1.7.5.4 - diff --git a/features/uprobe/powerpc-Add-trap_nr-to-thread_struct.patch b/features/uprobe/powerpc-Add-trap_nr-to-thread_struct.patch deleted file mode 100644 index e9cbc45d229f8bc99639fd2fff4be3801b85a186..0000000000000000000000000000000000000000 --- a/features/uprobe/powerpc-Add-trap_nr-to-thread_struct.patch +++ /dev/null @@ -1,84 +0,0 @@ -From d40e73dea840d9e6e7617b45fd98638615ab2c45 Mon Sep 17 00:00:00 2001 -From: Ananth N Mavinakayanahalli <ananth@in.ibm.com> -Date: Wed, 25 Jul 2012 19:19:02 +0000 -Subject: [PATCH 1/2] powerpc: Add trap_nr to thread_struct - -http://patchwork.ozlabs.org/patch/173338/ - -Add thread_struct.trap_nr and use it to store the last exception -the thread experienced. In this patch, we populate the field at -various places where we force_sig_info() to the process. - -This is also used in uprobes to determine if the probed instruction -caused an exception. - -Patch applies on the current master branch of Linus' tree (bdc0077af) - -Signed-off-by: Ananth N Mavinakayanahalli <ananth@in.ibm.com> -Signed-off-by: Paul Barrette <paul.barrette@windriver.com> ---- - arch/powerpc/include/asm/processor.h | 1 + - arch/powerpc/kernel/process.c | 2 ++ - arch/powerpc/kernel/traps.c | 1 + - arch/powerpc/mm/fault.c | 1 + - 4 files changed, 5 insertions(+), 0 deletions(-) - -diff --git a/arch/powerpc/include/asm/processor.h b/arch/powerpc/include/asm/processor.h -index 8e2d037..88ceb27 100644 ---- a/arch/powerpc/include/asm/processor.h -+++ b/arch/powerpc/include/asm/processor.h -@@ -222,6 +222,7 @@ struct thread_struct { - #endif /* CONFIG_HAVE_HW_BREAKPOINT */ - #endif - unsigned long dabr; /* Data address breakpoint register */ -+ unsigned long trap_nr; /* last trap # on this thread */ - #ifdef CONFIG_ALTIVEC - /* Complete AltiVec register set */ - vector128 vr[32] __attribute__((aligned(16))); -diff --git a/arch/powerpc/kernel/process.c b/arch/powerpc/kernel/process.c -index 4937c96..e2a4be7 100644 ---- a/arch/powerpc/kernel/process.c -+++ b/arch/powerpc/kernel/process.c -@@ -258,6 +258,7 @@ void do_send_trap(struct pt_regs *regs, unsigned long address, - { - siginfo_t info; - -+ current->thread.trap_nr = signal_code; - if (notify_die(DIE_DABR_MATCH, "dabr_match", regs, error_code, - 11, SIGSEGV) == NOTIFY_STOP) - return; -@@ -275,6 +276,7 @@ void do_dabr(struct pt_regs *regs, unsigned long address, - { - siginfo_t info; - -+ current->thread.trap_nr = TRAP_HWBKPT; - if (notify_die(DIE_DABR_MATCH, "dabr_match", regs, error_code, - 11, SIGSEGV) == NOTIFY_STOP) - return; -diff --git a/arch/powerpc/kernel/traps.c b/arch/powerpc/kernel/traps.c -index 1589723..8831322 100644 ---- a/arch/powerpc/kernel/traps.c -+++ b/arch/powerpc/kernel/traps.c -@@ -251,6 +251,7 @@ void _exception(int signr, struct pt_regs *regs, int code, unsigned long addr) - if (arch_irqs_disabled() && !arch_irq_disabled_regs(regs)) - local_irq_enable(); - -+ current->thread.trap_nr = code; - memset(&info, 0, sizeof(info)); - info.si_signo = signr; - info.si_code = code; -diff --git a/arch/powerpc/mm/fault.c b/arch/powerpc/mm/fault.c -index 08ffcf5..995f924 100644 ---- a/arch/powerpc/mm/fault.c -+++ b/arch/powerpc/mm/fault.c -@@ -133,6 +133,7 @@ static int do_sigbus(struct pt_regs *regs, unsigned long address) - up_read(¤t->mm->mmap_sem); - - if (user_mode(regs)) { -+ current->thread.trap_nr = BUS_ADRERR; - info.si_signo = SIGBUS; - info.si_errno = 0; - info.si_code = BUS_ADRERR; --- -1.7.5.4 - diff --git a/features/uprobe/powerpc-Uprobes-port-to-powerpc.patch b/features/uprobe/powerpc-Uprobes-port-to-powerpc.patch deleted file mode 100644 index 31df9904ba7d4ef6ee969085beba56f6bcb6d670..0000000000000000000000000000000000000000 --- a/features/uprobe/powerpc-Uprobes-port-to-powerpc.patch +++ /dev/null @@ -1,372 +0,0 @@ -From c262f3eed4690512f702fec529eda094ad29f5d6 Mon Sep 17 00:00:00 2001 -From: Ananth N Mavinakayanahalli <ananth@in.ibm.com> -Date: Wed, 25 Jul 2012 19:20:29 +0000 -Subject: [PATCH 2/2] powerpc: Uprobes port to powerpc - -http://patchwork.ozlabs.org/patch/173343/ - -This is the port of uprobes to powerpc. Usage is similar to x86. - -[root@xxxx ~]# ./bin/perf probe -x /lib64/libc.so.6 malloc -Added new event: - probe_libc:malloc (on 0xb4860) - -You can now use it in all perf tools, such as: - - perf record -e probe_libc:malloc -aR sleep 1 - -[root@xxxx ~]# ./bin/perf record -e probe_libc:malloc -aR sleep 20 -[ perf record: Woken up 22 times to write data ] -[ perf record: Captured and wrote 5.843 MB perf.data (~255302 samples) ] -[root@xxxx ~]# ./bin/perf report --stdio -... - -# Samples: 83K of event 'probe_libc:malloc' -# Event count (approx.): 83484 -# -# Overhead Command Shared Object Symbol -# ........ ............ ............. .......... -# - 69.05% tar libc-2.12.so [.] malloc - 28.57% rm libc-2.12.so [.] malloc - 1.32% avahi-daemon libc-2.12.so [.] malloc - 0.58% bash libc-2.12.so [.] malloc - 0.28% sshd libc-2.12.so [.] malloc - 0.08% irqbalance libc-2.12.so [.] malloc - 0.05% bzip2 libc-2.12.so [.] malloc - 0.04% sleep libc-2.12.so [.] malloc - 0.03% multipathd libc-2.12.so [.] malloc - 0.01% sendmail libc-2.12.so [.] malloc - 0.01% automount libc-2.12.so [.] malloc - -Signed-off-by: Ananth N Mavinakayanahalli <ananth@in.ibm.com> -Acked-by: Srikar Dronamraju <srikar@linux.vnet.ibm.com> -Signed-off-by: Paul Barrette <paul.barrette@windriver.com> ---- - arch/powerpc/Kconfig | 3 + - arch/powerpc/include/asm/thread_info.h | 4 +- - arch/powerpc/include/asm/uprobes.h | 50 +++++++++ - arch/powerpc/kernel/Makefile | 1 + - arch/powerpc/kernel/signal.c | 6 + - arch/powerpc/kernel/uprobes.c | 174 ++++++++++++++++++++++++++++++++ - 6 files changed, 237 insertions(+), 1 deletions(-) - create mode 100644 arch/powerpc/include/asm/uprobes.h - create mode 100644 arch/powerpc/kernel/uprobes.c - -diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig -index feab3ba..b2a13ca 100644 ---- a/arch/powerpc/Kconfig -+++ b/arch/powerpc/Kconfig -@@ -244,6 +244,9 @@ config PPC_OF_PLATFORM_PCI - config ARCH_SUPPORTS_DEBUG_PAGEALLOC - def_bool y - -+config ARCH_SUPPORTS_UPROBES -+ def_bool y -+ - config PPC_ADV_DEBUG_REGS - bool - depends on 40x || BOOKE -diff --git a/arch/powerpc/include/asm/thread_info.h b/arch/powerpc/include/asm/thread_info.h -index 4a741c7..9a30809 100644 ---- a/arch/powerpc/include/asm/thread_info.h -+++ b/arch/powerpc/include/asm/thread_info.h -@@ -109,6 +109,7 @@ static inline struct thread_info *current_thread_info(void) - #define TIF_RESTOREALL 11 /* Restore all regs (implies NOERROR) */ - #define TIF_NOERROR 12 /* Force successful syscall return */ - #define TIF_NOTIFY_RESUME 13 /* callback before returning to user */ -+#define TIF_UPROBE 14 /* breakpointed or single-stepping */ - #define TIF_SYSCALL_TRACEPOINT 15 /* syscall tracepoint instrumentation */ - - /* as above, but as bit values */ -@@ -125,13 +126,14 @@ static inline struct thread_info *current_thread_info(void) - #define _TIF_RESTOREALL (1<<TIF_RESTOREALL) - #define _TIF_NOERROR (1<<TIF_NOERROR) - #define _TIF_NOTIFY_RESUME (1<<TIF_NOTIFY_RESUME) -+#define _TIF_UPROBE (1<<TIF_UPROBE) - #define _TIF_SYSCALL_TRACEPOINT (1<<TIF_SYSCALL_TRACEPOINT) - #define _TIF_RUNLATCH (1<<TIF_RUNLATCH) - #define _TIF_SYSCALL_T_OR_A (_TIF_SYSCALL_TRACE | _TIF_SYSCALL_AUDIT | \ - _TIF_SECCOMP | _TIF_SYSCALL_TRACEPOINT) - - #define _TIF_USER_WORK_MASK (_TIF_SIGPENDING | _TIF_NEED_RESCHED | \ -- _TIF_NOTIFY_RESUME) -+ _TIF_NOTIFY_RESUME | _TIF_UPROBE) - #define _TIF_PERSYSCALL_MASK (_TIF_RESTOREALL|_TIF_NOERROR) - - /* Bits in local_flags */ -diff --git a/arch/powerpc/include/asm/uprobes.h b/arch/powerpc/include/asm/uprobes.h -new file mode 100644 -index 0000000..a7f5950 ---- /dev/null -+++ b/arch/powerpc/include/asm/uprobes.h -@@ -0,0 +1,50 @@ -+#ifndef _ASM_UPROBES_H -+#define _ASM_UPROBES_H -+/* -+ * User-space Probes (UProbes) for powerpc -+ * -+ * 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. -+ * -+ * 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. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -+ * -+ * Copyright (C) IBM Corporation, 2007-2012 -+ * -+ * Adapted from the x86 port by Ananth N Mavinakayanahalli <ananth@in.ibm.com> -+ */ -+ -+#include <linux/notifier.h> -+ -+typedef unsigned int uprobe_opcode_t; -+ -+#define MAX_UINSN_BYTES 4 -+#define UPROBE_XOL_SLOT_BYTES (MAX_UINSN_BYTES) -+ -+#define UPROBE_SWBP_INSN 0x7fe00008 -+#define UPROBE_SWBP_INSN_SIZE 4 /* swbp insn size in bytes */ -+ -+struct arch_uprobe { -+ u8 insn[MAX_UINSN_BYTES]; -+}; -+ -+struct arch_uprobe_task { -+ unsigned long saved_trap_nr; -+}; -+ -+extern int arch_uprobe_analyze_insn(struct arch_uprobe *aup, struct mm_struct *mm, unsigned long addr); -+extern unsigned long uprobe_get_swbp_addr(struct pt_regs *regs); -+extern int arch_uprobe_pre_xol(struct arch_uprobe *aup, struct pt_regs *regs); -+extern int arch_uprobe_post_xol(struct arch_uprobe *aup, struct pt_regs *regs); -+extern bool arch_uprobe_xol_was_trapped(struct task_struct *tsk); -+extern int arch_uprobe_exception_notify(struct notifier_block *self, unsigned long val, void *data); -+extern void arch_uprobe_abort_xol(struct arch_uprobe *aup, struct pt_regs *regs); -+#endif /* _ASM_UPROBES_H */ -diff --git a/arch/powerpc/kernel/Makefile b/arch/powerpc/kernel/Makefile -index f5808a3..1cedb0e 100644 ---- a/arch/powerpc/kernel/Makefile -+++ b/arch/powerpc/kernel/Makefile -@@ -96,6 +96,7 @@ obj-$(CONFIG_MODULES) += ppc_ksyms.o - obj-$(CONFIG_BOOTX_TEXT) += btext.o - obj-$(CONFIG_SMP) += smp.o - obj-$(CONFIG_KPROBES) += kprobes.o -+obj-$(CONFIG_UPROBES) += uprobes.o - obj-$(CONFIG_PPC_UDBG_16550) += legacy_serial.o udbg_16550.o - obj-$(CONFIG_STACKTRACE) += stacktrace.o - obj-$(CONFIG_SWIOTLB) += dma-swiotlb.o -diff --git a/arch/powerpc/kernel/signal.c b/arch/powerpc/kernel/signal.c -index bfc3ec1..e72fb65 100644 ---- a/arch/powerpc/kernel/signal.c -+++ b/arch/powerpc/kernel/signal.c -@@ -11,6 +11,7 @@ - - #include <linux/tracehook.h> - #include <linux/signal.h> -+#include <linux/uprobes.h> - #include <linux/key.h> - #include <asm/hw_breakpoint.h> - #include <asm/uaccess.h> -@@ -187,6 +188,11 @@ static int do_signal(struct pt_regs *regs) - - void do_notify_resume(struct pt_regs *regs, unsigned long thread_info_flags) - { -+ if (thread_info_flags & _TIF_UPROBE) { -+ clear_thread_flag(TIF_UPROBE); -+ uprobe_notify_resume(regs); -+ } -+ - if (thread_info_flags & _TIF_SIGPENDING) - do_signal(regs); - -diff --git a/arch/powerpc/kernel/uprobes.c b/arch/powerpc/kernel/uprobes.c -new file mode 100644 -index 0000000..a193611 ---- /dev/null -+++ b/arch/powerpc/kernel/uprobes.c -@@ -0,0 +1,174 @@ -+/* -+ * User-space Probes (UProbes) for powerpc -+ * -+ * 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. -+ * -+ * 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. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -+ * -+ * Copyright (C) IBM Corporation, 2007-2012 -+ * -+ * Adapted from the x86 port by Ananth N Mavinakayanahalli <ananth@in.ibm.com> -+ */ -+#include <linux/kernel.h> -+#include <linux/sched.h> -+#include <linux/ptrace.h> -+#include <linux/uprobes.h> -+#include <linux/uaccess.h> -+#include <linux/kdebug.h> -+ -+#include <asm/sstep.h> -+ -+#define UPROBE_TRAP_NR UINT_MAX -+ -+/** -+ * arch_uprobe_analyze_insn -+ * @mm: the probed address space. -+ * @arch_uprobe: the probepoint information. -+ * @addr: vaddr to probe. -+ * Return 0 on success or a -ve number on error. -+ */ -+int arch_uprobe_analyze_insn(struct arch_uprobe *auprobe, struct mm_struct *mm, unsigned long addr) -+{ -+ if (addr & 0x03) -+ return -EINVAL; -+ return 0; -+} -+ -+/* -+ * arch_uprobe_pre_xol - prepare to execute out of line. -+ * @auprobe: the probepoint information. -+ * @regs: reflects the saved user state of current task. -+ */ -+int arch_uprobe_pre_xol(struct arch_uprobe *auprobe, struct pt_regs *regs) -+{ -+ struct arch_uprobe_task *autask = ¤t->utask->autask; -+ -+ autask->saved_trap_nr = current->thread.trap_nr; -+ current->thread.trap_nr = UPROBE_TRAP_NR; -+ regs->nip = current->utask->xol_vaddr; -+ return 0; -+} -+ -+/** -+ * uprobe_get_swbp_addr - compute address of swbp given post-swbp regs -+ * @regs: Reflects the saved state of the task after it has hit a breakpoint -+ * instruction. -+ * Return the address of the breakpoint instruction. -+ */ -+unsigned long uprobe_get_swbp_addr(struct pt_regs *regs) -+{ -+ return instruction_pointer(regs); -+} -+ -+/* -+ * If xol insn itself traps and generates a signal (SIGILL/SIGSEGV/etc), -+ * then detect the case where a singlestepped instruction jumps back to its -+ * own address. It is assumed that anything like do_page_fault/do_trap/etc -+ * sets thread.trap_nr != -1. -+ * -+ * arch_uprobe_pre_xol/arch_uprobe_post_xol save/restore thread.trap_nr, -+ * arch_uprobe_xol_was_trapped() simply checks that ->trap_nr is not equal to -+ * UPROBE_TRAP_NR == -1 set by arch_uprobe_pre_xol(). -+ */ -+bool arch_uprobe_xol_was_trapped(struct task_struct *t) -+{ -+ if (t->thread.trap_nr != UPROBE_TRAP_NR) -+ return true; -+ -+ return false; -+} -+ -+/* -+ * Called after single-stepping. To avoid the SMP problems that can -+ * occur when we temporarily put back the original opcode to -+ * single-step, we single-stepped a copy of the instruction. -+ * -+ * This function prepares to resume execution after the single-step. -+ */ -+int arch_uprobe_post_xol(struct arch_uprobe *auprobe, struct pt_regs *regs) -+{ -+ struct uprobe_task *utask = current->utask; -+ -+ WARN_ON_ONCE(current->thread.trap_nr != UPROBE_TRAP_NR); -+ -+ current->thread.trap_nr = utask->autask.saved_trap_nr; -+ -+ /* -+ * On powerpc, except for loads and stores, most instructions -+ * including ones that alter code flow (branches, calls, returns) -+ * are emulated in the kernel. We get here only if the emulation -+ * support doesn't exist and have to fix-up the next instruction -+ * to be executed. -+ */ -+ regs->nip = utask->vaddr + MAX_UINSN_BYTES; -+ return 0; -+} -+ -+/* callback routine for handling exceptions. */ -+int arch_uprobe_exception_notify(struct notifier_block *self, unsigned long val, void *data) -+{ -+ struct die_args *args = data; -+ struct pt_regs *regs = args->regs; -+ -+ /* We are only interested in userspace traps */ -+ if (regs && !user_mode(regs)) -+ return NOTIFY_DONE; -+ -+ switch (val) { -+ case DIE_BPT: -+ if (uprobe_pre_sstep_notifier(regs)) -+ return NOTIFY_STOP; -+ break; -+ case DIE_SSTEP: -+ if (uprobe_post_sstep_notifier(regs)) -+ return NOTIFY_STOP; -+ default: -+ break; -+ } -+ return NOTIFY_DONE; -+} -+ -+/* -+ * This function gets called when XOL instruction either gets trapped or -+ * the thread has a fatal signal, so reset the instruction pointer to its -+ * probed address. -+ */ -+void arch_uprobe_abort_xol(struct arch_uprobe *auprobe, struct pt_regs *regs) -+{ -+ struct uprobe_task *utask = current->utask; -+ -+ current->thread.trap_nr = utask->autask.saved_trap_nr; -+ instruction_pointer_set(regs, utask->vaddr); -+} -+ -+/* -+ * See if the instruction can be emulated. -+ * Returns true if instruction was emulated, false otherwise. -+ */ -+bool arch_uprobe_skip_sstep(struct arch_uprobe *auprobe, struct pt_regs *regs) -+{ -+ int ret; -+ unsigned int insn; -+ -+ memcpy(&insn, auprobe->insn, MAX_UINSN_BYTES); -+ -+ /* -+ * emulate_step() returns 1 if the insn was successfully emulated. -+ * For all other cases, we need to single-step in hardware. -+ */ -+ ret = emulate_step(regs, insn); -+ if (ret > 0) -+ return true; -+ -+ return false; -+} --- -1.7.5.4 - diff --git a/features/uprobe/powerpc-uprobes-removed-external-declaration-of-upro.patch b/features/uprobe/powerpc-uprobes-removed-external-declaration-of-upro.patch deleted file mode 100644 index 478d448bf0709dc2a53fa896d2e81e5bf5800aee..0000000000000000000000000000000000000000 --- a/features/uprobe/powerpc-uprobes-removed-external-declaration-of-upro.patch +++ /dev/null @@ -1,29 +0,0 @@ -From 6f70bc1d54887ad3a97dd9c9ae52f86302274932 Mon Sep 17 00:00:00 2001 -From: Paul Barrette <paul.barrette@windriver.com> -Date: Tue, 12 Jun 2012 14:24:12 -0400 -Subject: [PATCH 24/24] powerpc: uprobes: removed external declaration of - uprobe_get_swbp_addr. - -uprobe_get_swbp_addr is declared as static inline in linux/uprobes.h. -Redeclaring it differently breaks compilation. - -Signed-off-by: Paul Barrette <paul.barrette@windriver.com> ---- - arch/powerpc/include/asm/uprobes.h | 1 - - 1 files changed, 0 insertions(+), 1 deletions(-) - -diff --git a/arch/powerpc/include/asm/uprobes.h b/arch/powerpc/include/asm/uprobes.h -index bd9e8412..ed6197b 100644 ---- a/arch/powerpc/include/asm/uprobes.h -+++ b/arch/powerpc/include/asm/uprobes.h -@@ -40,7 +40,6 @@ struct arch_uprobe_task { - }; - - extern int arch_uprobe_analyze_insn(struct arch_uprobe *aup, struct mm_struct *mm, unsigned long addr); --extern unsigned long uprobe_get_swbp_addr(struct pt_regs *regs); - extern int arch_uprobe_pre_xol(struct arch_uprobe *aup, struct pt_regs *regs); - extern int arch_uprobe_post_xol(struct arch_uprobe *aup, struct pt_regs *regs); - extern bool arch_uprobe_xol_was_trapped(struct task_struct *tsk); --- -1.7.5.4 - diff --git a/features/uprobe/task_work_add-generic-process-context-callbacks.patch b/features/uprobe/task_work_add-generic-process-context-callbacks.patch deleted file mode 100644 index 4bd791ff146ddf72f38d76b8dc5ebf3b297ef1c2..0000000000000000000000000000000000000000 --- a/features/uprobe/task_work_add-generic-process-context-callbacks.patch +++ /dev/null @@ -1,287 +0,0 @@ -From 5ee34dd5dffe2d2a971ee208de419be114ecf77e Mon Sep 17 00:00:00 2001 -From: Oleg Nesterov <oleg@redhat.com> -Date: Fri, 11 May 2012 10:59:07 +1000 -Subject: [PATCH 2/6] task_work_add: generic process-context callbacks - -commit e73f8959af0439d114847eab5a8a5ce48f1217c4 upstream. - -Provide a simple mechanism that allows running code in the (nonatomic) -context of the arbitrary task. - -The caller does task_work_add(task, task_work) and this task executes -task_work->func() either from do_notify_resume() or from do_exit(). The -callback can rely on PF_EXITING to detect the latter case. - -"struct task_work" can be embedded in another struct, still it has "void -*data" to handle the most common/simple case. - -This allows us to kill the ->replacement_session_keyring hack, and -potentially this can have more users. - -Performance-wise, this adds 2 "unlikely(!hlist_empty())" checks into -tracehook_notify_resume() and do_exit(). But at the same time we can -remove the "replacement_session_keyring != NULL" checks from -arch/*/signal.c and exit_creds(). - -Note: task_work_add/task_work_run abuses ->pi_lock. This is only because -this lock is already used by lookup_pi_state() to synchronize with -do_exit() setting PF_EXITING. Fortunately the scope of this lock in -task_work.c is really tiny, and the code is unlikely anyway. - -Signed-off-by: Oleg Nesterov <oleg@redhat.com> -Acked-by: David Howells <dhowells@redhat.com> -Cc: Thomas Gleixner <tglx@linutronix.de> -Cc: Richard Kuo <rkuo@codeaurora.org> -Cc: Linus Torvalds <torvalds@linux-foundation.org> -Cc: Alexander Gordeev <agordeev@redhat.com> -Cc: Chris Zankel <chris@zankel.net> -Cc: David Smith <dsmith@redhat.com> -Cc: "Frank Ch. Eigler" <fche@redhat.com> -Cc: Geert Uytterhoeven <geert@linux-m68k.org> -Cc: Larry Woodman <lwoodman@redhat.com> -Cc: Peter Zijlstra <peterz@infradead.org> -Cc: Tejun Heo <tj@kernel.org> -Cc: Ingo Molnar <mingo@elte.hu> -Signed-off-by: Andrew Morton <akpm@linux-foundation.org> -Signed-off-by: Al Viro <viro@zeniv.linux.org.uk> -Signed-off-by: Paul Barrette <paul.barrette@windriver.com> ---- - include/linux/sched.h | 2 + - include/linux/task_work.h | 33 +++++++++++++++++ - include/linux/tracehook.h | 11 ++++++ - kernel/Makefile | 2 +- - kernel/exit.c | 5 ++- - kernel/fork.c | 1 + - kernel/task_work.c | 84 +++++++++++++++++++++++++++++++++++++++++++++ - 7 files changed, 136 insertions(+), 2 deletions(-) - create mode 100644 include/linux/task_work.h - create mode 100644 kernel/task_work.c - -diff --git a/include/linux/sched.h b/include/linux/sched.h -index 7bcc634..d62c928 100644 ---- a/include/linux/sched.h -+++ b/include/linux/sched.h -@@ -1447,6 +1447,8 @@ struct task_struct { - int (*notifier)(void *priv); - void *notifier_data; - sigset_t *notifier_mask; -+ struct hlist_head task_works; -+ - struct audit_context *audit_context; - #ifdef CONFIG_AUDITSYSCALL - uid_t loginuid; -diff --git a/include/linux/task_work.h b/include/linux/task_work.h -new file mode 100644 -index 0000000..294d5d5 ---- /dev/null -+++ b/include/linux/task_work.h -@@ -0,0 +1,33 @@ -+#ifndef _LINUX_TASK_WORK_H -+#define _LINUX_TASK_WORK_H -+ -+#include <linux/list.h> -+#include <linux/sched.h> -+ -+struct task_work; -+typedef void (*task_work_func_t)(struct task_work *); -+ -+struct task_work { -+ struct hlist_node hlist; -+ task_work_func_t func; -+ void *data; -+}; -+ -+static inline void -+init_task_work(struct task_work *twork, task_work_func_t func, void *data) -+{ -+ twork->func = func; -+ twork->data = data; -+} -+ -+int task_work_add(struct task_struct *task, struct task_work *twork, bool); -+struct task_work *task_work_cancel(struct task_struct *, task_work_func_t); -+void task_work_run(void); -+ -+static inline void exit_task_work(struct task_struct *task) -+{ -+ if (unlikely(!hlist_empty(&task->task_works))) -+ task_work_run(); -+} -+ -+#endif /* _LINUX_TASK_WORK_H */ -diff --git a/include/linux/tracehook.h b/include/linux/tracehook.h -index d28ceaf..ea9558f 100644 ---- a/include/linux/tracehook.h -+++ b/include/linux/tracehook.h -@@ -49,6 +49,7 @@ - #include <linux/sched.h> - #include <linux/ptrace.h> - #include <linux/security.h> -+#include <linux/task_work.h> - struct linux_binprm; - - /* -@@ -165,8 +166,10 @@ static inline void tracehook_signal_handler(int sig, siginfo_t *info, - */ - static inline void set_notify_resume(struct task_struct *task) - { -+#ifdef TIF_NOTIFY_RESUME - if (!test_and_set_tsk_thread_flag(task, TIF_NOTIFY_RESUME)) - kick_process(task); -+#endif - } - - /** -@@ -186,6 +189,14 @@ static inline void tracehook_notify_resume(struct pt_regs *regs) - { - if (current->replacement_session_keyring) - key_replace_session_keyring(); -+ /* -+ * The caller just cleared TIF_NOTIFY_RESUME. This barrier -+ * pairs with task_work_add()->set_notify_resume() after -+ * hlist_add_head(task->task_works); -+ */ -+ smp_mb__after_clear_bit(); -+ if (unlikely(!hlist_empty(¤t->task_works))) -+ task_work_run(); - } - #endif /* TIF_NOTIFY_RESUME */ - -diff --git a/kernel/Makefile b/kernel/Makefile -index 633b548..d06c109 100644 ---- a/kernel/Makefile -+++ b/kernel/Makefile -@@ -5,7 +5,7 @@ - obj-y = fork.o exec_domain.o panic.o printk.o \ - cpu.o exit.o itimer.o time.o softirq.o resource.o \ - sysctl.o sysctl_binary.o capability.o ptrace.o timer.o user.o \ -- signal.o sys.o kmod.o workqueue.o pid.o \ -+ signal.o sys.o kmod.o workqueue.o pid.o task_work.o \ - rcupdate.o extable.o params.o posix-timers.o \ - kthread.o wait.o kfifo.o sys_ni.o posix-cpu-timers.o mutex.o \ - hrtimer.o rwsem.o nsproxy.o srcu.o semaphore.o \ -diff --git a/kernel/exit.c b/kernel/exit.c -index 9d81012..36516fc 100644 ---- a/kernel/exit.c -+++ b/kernel/exit.c -@@ -947,11 +947,14 @@ void do_exit(long code) - exit_signals(tsk); /* sets PF_EXITING */ - /* - * tsk->flags are checked in the futex code to protect against -- * an exiting task cleaning up the robust pi futexes. -+ * an exiting task cleaning up the robust pi futexes, and in -+ * task_work_add() to avoid the race with exit_task_work(). - */ - smp_mb(); - raw_spin_unlock_wait(&tsk->pi_lock); - -+ exit_task_work(tsk); -+ - exit_irq_thread(); - - if (unlikely(in_atomic())) -diff --git a/kernel/fork.c b/kernel/fork.c -index 764efe3..6c77a93 100644 ---- a/kernel/fork.c -+++ b/kernel/fork.c -@@ -1394,6 +1394,7 @@ static struct task_struct *copy_process(unsigned long clone_flags, - */ - p->group_leader = p; - INIT_LIST_HEAD(&p->thread_group); -+ INIT_HLIST_HEAD(&p->task_works); - - /* Now that the task is set up, run cgroup callbacks if - * necessary. We need to run them before the task is visible -diff --git a/kernel/task_work.c b/kernel/task_work.c -new file mode 100644 -index 0000000..82d1c79 ---- /dev/null -+++ b/kernel/task_work.c -@@ -0,0 +1,84 @@ -+#include <linux/spinlock.h> -+#include <linux/task_work.h> -+#include <linux/tracehook.h> -+ -+int -+task_work_add(struct task_struct *task, struct task_work *twork, bool notify) -+{ -+ unsigned long flags; -+ int err = -ESRCH; -+ -+#ifndef TIF_NOTIFY_RESUME -+ if (notify) -+ return -ENOTSUPP; -+#endif -+ /* -+ * We must not insert the new work if the task has already passed -+ * exit_task_work(). We rely on do_exit()->raw_spin_unlock_wait() -+ * and check PF_EXITING under pi_lock. -+ */ -+ raw_spin_lock_irqsave(&task->pi_lock, flags); -+ if (likely(!(task->flags & PF_EXITING))) { -+ hlist_add_head(&twork->hlist, &task->task_works); -+ err = 0; -+ } -+ raw_spin_unlock_irqrestore(&task->pi_lock, flags); -+ -+ /* test_and_set_bit() implies mb(), see tracehook_notify_resume(). */ -+ if (likely(!err) && notify) -+ set_notify_resume(task); -+ return err; -+} -+ -+struct task_work * -+task_work_cancel(struct task_struct *task, task_work_func_t func) -+{ -+ unsigned long flags; -+ struct task_work *twork; -+ struct hlist_node *pos; -+ -+ raw_spin_lock_irqsave(&task->pi_lock, flags); -+ hlist_for_each_entry(twork, pos, &task->task_works, hlist) { -+ if (twork->func == func) { -+ hlist_del(&twork->hlist); -+ goto found; -+ } -+ } -+ twork = NULL; -+ found: -+ raw_spin_unlock_irqrestore(&task->pi_lock, flags); -+ -+ return twork; -+} -+ -+void task_work_run(void) -+{ -+ struct task_struct *task = current; -+ struct hlist_head task_works; -+ struct hlist_node *pos; -+ -+ raw_spin_lock_irq(&task->pi_lock); -+ hlist_move_list(&task->task_works, &task_works); -+ raw_spin_unlock_irq(&task->pi_lock); -+ -+ if (unlikely(hlist_empty(&task_works))) -+ return; -+ /* -+ * We use hlist to save the space in task_struct, but we want fifo. -+ * Find the last entry, the list should be short, then process them -+ * in reverse order. -+ */ -+ for (pos = task_works.first; pos->next; pos = pos->next) -+ ; -+ -+ for (;;) { -+ struct hlist_node **pprev = pos->pprev; -+ struct task_work *twork = container_of(pos, struct task_work, -+ hlist); -+ twork->func(twork); -+ -+ if (pprev == &task_works.first) -+ break; -+ pos = container_of(pprev, struct hlist_node, next); -+ } -+} --- -1.7.5.4 - diff --git a/features/uprobe/tracing-Extract-out-common-code-for-kprobes-uprobes-.patch b/features/uprobe/tracing-Extract-out-common-code-for-kprobes-uprobes-.patch deleted file mode 100644 index 6a11c0d270c7288a968d0b2486156529a21f6a1c..0000000000000000000000000000000000000000 --- a/features/uprobe/tracing-Extract-out-common-code-for-kprobes-uprobes-.patch +++ /dev/null @@ -1,2083 +0,0 @@ -From b9b7281e08e0f3c38a5f9e333d9c5481615d8211 Mon Sep 17 00:00:00 2001 -From: Srikar Dronamraju <srikar@linux.vnet.ibm.com> -Date: Mon, 9 Apr 2012 14:41:44 +0530 -Subject: [PATCH 17/24] tracing: Extract out common code for kprobes/uprobes - trace events - -Move parts of trace_kprobe.c that can be shared with upcoming -trace_uprobe.c. Common code to kernel/trace/trace_probe.h and -kernel/trace/trace_probe.c. There are no functional changes. - -commit 8ab83f56475ec9151645a888dfe1941f4a92091d upstream - -Signed-off-by: Srikar Dronamraju <srikar@linux.vnet.ibm.com> -Acked-by: Steven Rostedt <rostedt@goodmis.org> -Acked-by: Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com> -Cc: Linus Torvalds <torvalds@linux-foundation.org> -Cc: Ananth N Mavinakayanahalli <ananth@in.ibm.com> -Cc: Jim Keniston <jkenisto@linux.vnet.ibm.com> -Cc: Linux-mm <linux-mm@kvack.org> -Cc: Oleg Nesterov <oleg@redhat.com> -Cc: Andi Kleen <andi@firstfloor.org> -Cc: Christoph Hellwig <hch@infradead.org> -Cc: Arnaldo Carvalho de Melo <acme@infradead.org> -Cc: Anton Arapov <anton@redhat.com> -Cc: Peter Zijlstra <peterz@infradead.org> -Link: http://lkml.kernel.org/r/20120409091144.8343.76218.sendpatchset@srdronam.in.ibm.com -Signed-off-by: Ingo Molnar <mingo@kernel.org> -Signed-off-by: Paul Barrette <paul.barrette@windriver.com> ---- - kernel/trace/Kconfig | 4 + - kernel/trace/Makefile | 1 + - kernel/trace/trace_kprobe.c | 889 +------------------------------------------ - kernel/trace/trace_probe.c | 833 ++++++++++++++++++++++++++++++++++++++++ - kernel/trace/trace_probe.h | 160 ++++++++ - 5 files changed, 1016 insertions(+), 871 deletions(-) - create mode 100644 kernel/trace/trace_probe.c - create mode 100644 kernel/trace/trace_probe.h - -diff --git a/kernel/trace/Kconfig b/kernel/trace/Kconfig -index a1d2849..ce5a5c5 100644 ---- a/kernel/trace/Kconfig -+++ b/kernel/trace/Kconfig -@@ -373,6 +373,7 @@ config KPROBE_EVENT - depends on HAVE_REGS_AND_STACK_ACCESS_API - bool "Enable kprobes-based dynamic events" - select TRACING -+ select PROBE_EVENTS - default y - help - This allows the user to add tracing events (similar to tracepoints) -@@ -385,6 +386,9 @@ config KPROBE_EVENT - This option is also required by perf-probe subcommand of perf tools. - If you want to use perf tools, this option is strongly recommended. - -+config PROBE_EVENTS -+ def_bool n -+ - config DYNAMIC_FTRACE - bool "enable/disable ftrace tracepoints dynamically" - depends on FUNCTION_TRACER -diff --git a/kernel/trace/Makefile b/kernel/trace/Makefile -index 5f39a07..fa10d5c 100644 ---- a/kernel/trace/Makefile -+++ b/kernel/trace/Makefile -@@ -61,5 +61,6 @@ endif - ifeq ($(CONFIG_TRACING),y) - obj-$(CONFIG_KGDB_KDB) += trace_kdb.o - endif -+obj-$(CONFIG_PROBE_EVENTS) += trace_probe.o - - libftrace-y := ftrace.o -diff --git a/kernel/trace/trace_kprobe.c b/kernel/trace/trace_kprobe.c -index 4f935f8..f8b7773 100644 ---- a/kernel/trace/trace_kprobe.c -+++ b/kernel/trace/trace_kprobe.c -@@ -19,547 +19,15 @@ - - #include <linux/module.h> - #include <linux/uaccess.h> --#include <linux/kprobes.h> --#include <linux/seq_file.h> --#include <linux/slab.h> --#include <linux/smp.h> --#include <linux/debugfs.h> --#include <linux/types.h> --#include <linux/string.h> --#include <linux/ctype.h> --#include <linux/ptrace.h> --#include <linux/perf_event.h> --#include <linux/stringify.h> --#include <linux/limits.h> --#include <asm/bitsperlong.h> -- --#include "trace.h" --#include "trace_output.h" -- --#define MAX_TRACE_ARGS 128 --#define MAX_ARGSTR_LEN 63 --#define MAX_EVENT_NAME_LEN 64 --#define MAX_STRING_SIZE PATH_MAX --#define KPROBE_EVENT_SYSTEM "kprobes" -- --/* Reserved field names */ --#define FIELD_STRING_IP "__probe_ip" --#define FIELD_STRING_RETIP "__probe_ret_ip" --#define FIELD_STRING_FUNC "__probe_func" -- --const char *reserved_field_names[] = { -- "common_type", -- "common_flags", -- "common_preempt_count", -- "common_pid", -- "common_tgid", -- FIELD_STRING_IP, -- FIELD_STRING_RETIP, -- FIELD_STRING_FUNC, --}; -- --/* Printing function type */ --typedef int (*print_type_func_t)(struct trace_seq *, const char *, void *, -- void *); --#define PRINT_TYPE_FUNC_NAME(type) print_type_##type --#define PRINT_TYPE_FMT_NAME(type) print_type_format_##type -- --/* Printing in basic type function template */ --#define DEFINE_BASIC_PRINT_TYPE_FUNC(type, fmt, cast) \ --static __kprobes int PRINT_TYPE_FUNC_NAME(type)(struct trace_seq *s, \ -- const char *name, \ -- void *data, void *ent)\ --{ \ -- return trace_seq_printf(s, " %s=" fmt, name, (cast)*(type *)data);\ --} \ --static const char PRINT_TYPE_FMT_NAME(type)[] = fmt; -- --DEFINE_BASIC_PRINT_TYPE_FUNC(u8, "%x", unsigned int) --DEFINE_BASIC_PRINT_TYPE_FUNC(u16, "%x", unsigned int) --DEFINE_BASIC_PRINT_TYPE_FUNC(u32, "%lx", unsigned long) --DEFINE_BASIC_PRINT_TYPE_FUNC(u64, "%llx", unsigned long long) --DEFINE_BASIC_PRINT_TYPE_FUNC(s8, "%d", int) --DEFINE_BASIC_PRINT_TYPE_FUNC(s16, "%d", int) --DEFINE_BASIC_PRINT_TYPE_FUNC(s32, "%ld", long) --DEFINE_BASIC_PRINT_TYPE_FUNC(s64, "%lld", long long) -- --/* data_rloc: data relative location, compatible with u32 */ --#define make_data_rloc(len, roffs) \ -- (((u32)(len) << 16) | ((u32)(roffs) & 0xffff)) --#define get_rloc_len(dl) ((u32)(dl) >> 16) --#define get_rloc_offs(dl) ((u32)(dl) & 0xffff) -- --static inline void *get_rloc_data(u32 *dl) --{ -- return (u8 *)dl + get_rloc_offs(*dl); --} -- --/* For data_loc conversion */ --static inline void *get_loc_data(u32 *dl, void *ent) --{ -- return (u8 *)ent + get_rloc_offs(*dl); --} -- --/* -- * Convert data_rloc to data_loc: -- * data_rloc stores the offset from data_rloc itself, but data_loc -- * stores the offset from event entry. -- */ --#define convert_rloc_to_loc(dl, offs) ((u32)(dl) + (offs)) -- --/* For defining macros, define string/string_size types */ --typedef u32 string; --typedef u32 string_size; -- --/* Print type function for string type */ --static __kprobes int PRINT_TYPE_FUNC_NAME(string)(struct trace_seq *s, -- const char *name, -- void *data, void *ent) --{ -- int len = *(u32 *)data >> 16; -- -- if (!len) -- return trace_seq_printf(s, " %s=(fault)", name); -- else -- return trace_seq_printf(s, " %s=\"%s\"", name, -- (const char *)get_loc_data(data, ent)); --} --static const char PRINT_TYPE_FMT_NAME(string)[] = "\\\"%s\\\""; -- --/* Data fetch function type */ --typedef void (*fetch_func_t)(struct pt_regs *, void *, void *); -- --struct fetch_param { -- fetch_func_t fn; -- void *data; --}; -- --static __kprobes void call_fetch(struct fetch_param *fprm, -- struct pt_regs *regs, void *dest) --{ -- return fprm->fn(regs, fprm->data, dest); --} -- --#define FETCH_FUNC_NAME(method, type) fetch_##method##_##type --/* -- * Define macro for basic types - we don't need to define s* types, because -- * we have to care only about bitwidth at recording time. -- */ --#define DEFINE_BASIC_FETCH_FUNCS(method) \ --DEFINE_FETCH_##method(u8) \ --DEFINE_FETCH_##method(u16) \ --DEFINE_FETCH_##method(u32) \ --DEFINE_FETCH_##method(u64) -- --#define CHECK_FETCH_FUNCS(method, fn) \ -- (((FETCH_FUNC_NAME(method, u8) == fn) || \ -- (FETCH_FUNC_NAME(method, u16) == fn) || \ -- (FETCH_FUNC_NAME(method, u32) == fn) || \ -- (FETCH_FUNC_NAME(method, u64) == fn) || \ -- (FETCH_FUNC_NAME(method, string) == fn) || \ -- (FETCH_FUNC_NAME(method, string_size) == fn)) \ -- && (fn != NULL)) -- --/* Data fetch function templates */ --#define DEFINE_FETCH_reg(type) \ --static __kprobes void FETCH_FUNC_NAME(reg, type)(struct pt_regs *regs, \ -- void *offset, void *dest) \ --{ \ -- *(type *)dest = (type)regs_get_register(regs, \ -- (unsigned int)((unsigned long)offset)); \ --} --DEFINE_BASIC_FETCH_FUNCS(reg) --/* No string on the register */ --#define fetch_reg_string NULL --#define fetch_reg_string_size NULL -- --#define DEFINE_FETCH_stack(type) \ --static __kprobes void FETCH_FUNC_NAME(stack, type)(struct pt_regs *regs,\ -- void *offset, void *dest) \ --{ \ -- *(type *)dest = (type)regs_get_kernel_stack_nth(regs, \ -- (unsigned int)((unsigned long)offset)); \ --} --DEFINE_BASIC_FETCH_FUNCS(stack) --/* No string on the stack entry */ --#define fetch_stack_string NULL --#define fetch_stack_string_size NULL -- --#define DEFINE_FETCH_retval(type) \ --static __kprobes void FETCH_FUNC_NAME(retval, type)(struct pt_regs *regs,\ -- void *dummy, void *dest) \ --{ \ -- *(type *)dest = (type)regs_return_value(regs); \ --} --DEFINE_BASIC_FETCH_FUNCS(retval) --/* No string on the retval */ --#define fetch_retval_string NULL --#define fetch_retval_string_size NULL -- --#define DEFINE_FETCH_memory(type) \ --static __kprobes void FETCH_FUNC_NAME(memory, type)(struct pt_regs *regs,\ -- void *addr, void *dest) \ --{ \ -- type retval; \ -- if (probe_kernel_address(addr, retval)) \ -- *(type *)dest = 0; \ -- else \ -- *(type *)dest = retval; \ --} --DEFINE_BASIC_FETCH_FUNCS(memory) --/* -- * Fetch a null-terminated string. Caller MUST set *(u32 *)dest with max -- * length and relative data location. -- */ --static __kprobes void FETCH_FUNC_NAME(memory, string)(struct pt_regs *regs, -- void *addr, void *dest) --{ -- long ret; -- int maxlen = get_rloc_len(*(u32 *)dest); -- u8 *dst = get_rloc_data(dest); -- u8 *src = addr; -- mm_segment_t old_fs = get_fs(); -- if (!maxlen) -- return; -- /* -- * Try to get string again, since the string can be changed while -- * probing. -- */ -- set_fs(KERNEL_DS); -- pagefault_disable(); -- do -- ret = __copy_from_user_inatomic(dst++, src++, 1); -- while (dst[-1] && ret == 0 && src - (u8 *)addr < maxlen); -- dst[-1] = '\0'; -- pagefault_enable(); -- set_fs(old_fs); -- -- if (ret < 0) { /* Failed to fetch string */ -- ((u8 *)get_rloc_data(dest))[0] = '\0'; -- *(u32 *)dest = make_data_rloc(0, get_rloc_offs(*(u32 *)dest)); -- } else -- *(u32 *)dest = make_data_rloc(src - (u8 *)addr, -- get_rloc_offs(*(u32 *)dest)); --} --/* Return the length of string -- including null terminal byte */ --static __kprobes void FETCH_FUNC_NAME(memory, string_size)(struct pt_regs *regs, -- void *addr, void *dest) --{ -- int ret, len = 0; -- u8 c; -- mm_segment_t old_fs = get_fs(); -- -- set_fs(KERNEL_DS); -- pagefault_disable(); -- do { -- ret = __copy_from_user_inatomic(&c, (u8 *)addr + len, 1); -- len++; -- } while (c && ret == 0 && len < MAX_STRING_SIZE); -- pagefault_enable(); -- set_fs(old_fs); -- -- if (ret < 0) /* Failed to check the length */ -- *(u32 *)dest = 0; -- else -- *(u32 *)dest = len; --} -- --/* Memory fetching by symbol */ --struct symbol_cache { -- char *symbol; -- long offset; -- unsigned long addr; --}; -- --static unsigned long update_symbol_cache(struct symbol_cache *sc) --{ -- sc->addr = (unsigned long)kallsyms_lookup_name(sc->symbol); -- if (sc->addr) -- sc->addr += sc->offset; -- return sc->addr; --} -- --static void free_symbol_cache(struct symbol_cache *sc) --{ -- kfree(sc->symbol); -- kfree(sc); --} -- --static struct symbol_cache *alloc_symbol_cache(const char *sym, long offset) --{ -- struct symbol_cache *sc; -- -- if (!sym || strlen(sym) == 0) -- return NULL; -- sc = kzalloc(sizeof(struct symbol_cache), GFP_KERNEL); -- if (!sc) -- return NULL; -- -- sc->symbol = kstrdup(sym, GFP_KERNEL); -- if (!sc->symbol) { -- kfree(sc); -- return NULL; -- } -- sc->offset = offset; - -- update_symbol_cache(sc); -- return sc; --} -- --#define DEFINE_FETCH_symbol(type) \ --static __kprobes void FETCH_FUNC_NAME(symbol, type)(struct pt_regs *regs,\ -- void *data, void *dest) \ --{ \ -- struct symbol_cache *sc = data; \ -- if (sc->addr) \ -- fetch_memory_##type(regs, (void *)sc->addr, dest); \ -- else \ -- *(type *)dest = 0; \ --} --DEFINE_BASIC_FETCH_FUNCS(symbol) --DEFINE_FETCH_symbol(string) --DEFINE_FETCH_symbol(string_size) -- --/* Dereference memory access function */ --struct deref_fetch_param { -- struct fetch_param orig; -- long offset; --}; -- --#define DEFINE_FETCH_deref(type) \ --static __kprobes void FETCH_FUNC_NAME(deref, type)(struct pt_regs *regs,\ -- void *data, void *dest) \ --{ \ -- struct deref_fetch_param *dprm = data; \ -- unsigned long addr; \ -- call_fetch(&dprm->orig, regs, &addr); \ -- if (addr) { \ -- addr += dprm->offset; \ -- fetch_memory_##type(regs, (void *)addr, dest); \ -- } else \ -- *(type *)dest = 0; \ --} --DEFINE_BASIC_FETCH_FUNCS(deref) --DEFINE_FETCH_deref(string) --DEFINE_FETCH_deref(string_size) -- --static __kprobes void update_deref_fetch_param(struct deref_fetch_param *data) --{ -- if (CHECK_FETCH_FUNCS(deref, data->orig.fn)) -- update_deref_fetch_param(data->orig.data); -- else if (CHECK_FETCH_FUNCS(symbol, data->orig.fn)) -- update_symbol_cache(data->orig.data); --} -- --static __kprobes void free_deref_fetch_param(struct deref_fetch_param *data) --{ -- if (CHECK_FETCH_FUNCS(deref, data->orig.fn)) -- free_deref_fetch_param(data->orig.data); -- else if (CHECK_FETCH_FUNCS(symbol, data->orig.fn)) -- free_symbol_cache(data->orig.data); -- kfree(data); --} -- --/* Bitfield fetch function */ --struct bitfield_fetch_param { -- struct fetch_param orig; -- unsigned char hi_shift; -- unsigned char low_shift; --}; -+#include "trace_probe.h" - --#define DEFINE_FETCH_bitfield(type) \ --static __kprobes void FETCH_FUNC_NAME(bitfield, type)(struct pt_regs *regs,\ -- void *data, void *dest) \ --{ \ -- struct bitfield_fetch_param *bprm = data; \ -- type buf = 0; \ -- call_fetch(&bprm->orig, regs, &buf); \ -- if (buf) { \ -- buf <<= bprm->hi_shift; \ -- buf >>= bprm->low_shift; \ -- } \ -- *(type *)dest = buf; \ --} --DEFINE_BASIC_FETCH_FUNCS(bitfield) --#define fetch_bitfield_string NULL --#define fetch_bitfield_string_size NULL -- --static __kprobes void --update_bitfield_fetch_param(struct bitfield_fetch_param *data) --{ -- /* -- * Don't check the bitfield itself, because this must be the -- * last fetch function. -- */ -- if (CHECK_FETCH_FUNCS(deref, data->orig.fn)) -- update_deref_fetch_param(data->orig.data); -- else if (CHECK_FETCH_FUNCS(symbol, data->orig.fn)) -- update_symbol_cache(data->orig.data); --} -- --static __kprobes void --free_bitfield_fetch_param(struct bitfield_fetch_param *data) --{ -- /* -- * Don't check the bitfield itself, because this must be the -- * last fetch function. -- */ -- if (CHECK_FETCH_FUNCS(deref, data->orig.fn)) -- free_deref_fetch_param(data->orig.data); -- else if (CHECK_FETCH_FUNCS(symbol, data->orig.fn)) -- free_symbol_cache(data->orig.data); -- kfree(data); --} -- --/* Default (unsigned long) fetch type */ --#define __DEFAULT_FETCH_TYPE(t) u##t --#define _DEFAULT_FETCH_TYPE(t) __DEFAULT_FETCH_TYPE(t) --#define DEFAULT_FETCH_TYPE _DEFAULT_FETCH_TYPE(BITS_PER_LONG) --#define DEFAULT_FETCH_TYPE_STR __stringify(DEFAULT_FETCH_TYPE) -- --/* Fetch types */ --enum { -- FETCH_MTD_reg = 0, -- FETCH_MTD_stack, -- FETCH_MTD_retval, -- FETCH_MTD_memory, -- FETCH_MTD_symbol, -- FETCH_MTD_deref, -- FETCH_MTD_bitfield, -- FETCH_MTD_END, --}; -- --#define ASSIGN_FETCH_FUNC(method, type) \ -- [FETCH_MTD_##method] = FETCH_FUNC_NAME(method, type) -- --#define __ASSIGN_FETCH_TYPE(_name, ptype, ftype, _size, sign, _fmttype) \ -- {.name = _name, \ -- .size = _size, \ -- .is_signed = sign, \ -- .print = PRINT_TYPE_FUNC_NAME(ptype), \ -- .fmt = PRINT_TYPE_FMT_NAME(ptype), \ -- .fmttype = _fmttype, \ -- .fetch = { \ --ASSIGN_FETCH_FUNC(reg, ftype), \ --ASSIGN_FETCH_FUNC(stack, ftype), \ --ASSIGN_FETCH_FUNC(retval, ftype), \ --ASSIGN_FETCH_FUNC(memory, ftype), \ --ASSIGN_FETCH_FUNC(symbol, ftype), \ --ASSIGN_FETCH_FUNC(deref, ftype), \ --ASSIGN_FETCH_FUNC(bitfield, ftype), \ -- } \ -- } -- --#define ASSIGN_FETCH_TYPE(ptype, ftype, sign) \ -- __ASSIGN_FETCH_TYPE(#ptype, ptype, ftype, sizeof(ftype), sign, #ptype) -- --#define FETCH_TYPE_STRING 0 --#define FETCH_TYPE_STRSIZE 1 -- --/* Fetch type information table */ --static const struct fetch_type { -- const char *name; /* Name of type */ -- size_t size; /* Byte size of type */ -- int is_signed; /* Signed flag */ -- print_type_func_t print; /* Print functions */ -- const char *fmt; /* Fromat string */ -- const char *fmttype; /* Name in format file */ -- /* Fetch functions */ -- fetch_func_t fetch[FETCH_MTD_END]; --} fetch_type_table[] = { -- /* Special types */ -- [FETCH_TYPE_STRING] = __ASSIGN_FETCH_TYPE("string", string, string, -- sizeof(u32), 1, "__data_loc char[]"), -- [FETCH_TYPE_STRSIZE] = __ASSIGN_FETCH_TYPE("string_size", u32, -- string_size, sizeof(u32), 0, "u32"), -- /* Basic types */ -- ASSIGN_FETCH_TYPE(u8, u8, 0), -- ASSIGN_FETCH_TYPE(u16, u16, 0), -- ASSIGN_FETCH_TYPE(u32, u32, 0), -- ASSIGN_FETCH_TYPE(u64, u64, 0), -- ASSIGN_FETCH_TYPE(s8, u8, 1), -- ASSIGN_FETCH_TYPE(s16, u16, 1), -- ASSIGN_FETCH_TYPE(s32, u32, 1), -- ASSIGN_FETCH_TYPE(s64, u64, 1), --}; -- --static const struct fetch_type *find_fetch_type(const char *type) --{ -- int i; -- -- if (!type) -- type = DEFAULT_FETCH_TYPE_STR; -- -- /* Special case: bitfield */ -- if (*type == 'b') { -- unsigned long bs; -- type = strchr(type, '/'); -- if (!type) -- goto fail; -- type++; -- if (strict_strtoul(type, 0, &bs)) -- goto fail; -- switch (bs) { -- case 8: -- return find_fetch_type("u8"); -- case 16: -- return find_fetch_type("u16"); -- case 32: -- return find_fetch_type("u32"); -- case 64: -- return find_fetch_type("u64"); -- default: -- goto fail; -- } -- } -- -- for (i = 0; i < ARRAY_SIZE(fetch_type_table); i++) -- if (strcmp(type, fetch_type_table[i].name) == 0) -- return &fetch_type_table[i]; --fail: -- return NULL; --} -- --/* Special function : only accept unsigned long */ --static __kprobes void fetch_stack_address(struct pt_regs *regs, -- void *dummy, void *dest) --{ -- *(unsigned long *)dest = kernel_stack_pointer(regs); --} -- --static fetch_func_t get_fetch_size_function(const struct fetch_type *type, -- fetch_func_t orig_fn) --{ -- int i; -- -- if (type != &fetch_type_table[FETCH_TYPE_STRING]) -- return NULL; /* Only string type needs size function */ -- for (i = 0; i < FETCH_MTD_END; i++) -- if (type->fetch[i] == orig_fn) -- return fetch_type_table[FETCH_TYPE_STRSIZE].fetch[i]; -- -- WARN_ON(1); /* This should not happen */ -- return NULL; --} -+#define KPROBE_EVENT_SYSTEM "kprobes" - - /** - * Kprobe event core functions - */ - --struct probe_arg { -- struct fetch_param fetch; -- struct fetch_param fetch_size; -- unsigned int offset; /* Offset from argument entry */ -- const char *name; /* Name of this argument */ -- const char *comm; /* Command of this argument */ -- const struct fetch_type *type; /* Type of this argument */ --}; -- --/* Flags for trace_probe */ --#define TP_FLAG_TRACE 1 --#define TP_FLAG_PROFILE 2 --#define TP_FLAG_REGISTERED 4 -- - struct trace_probe { - struct list_head list; - struct kretprobe rp; /* Use rp.kp for kprobe use */ -@@ -631,18 +99,6 @@ static int kprobe_dispatcher(struct kprobe *kp, struct pt_regs *regs); - static int kretprobe_dispatcher(struct kretprobe_instance *ri, - struct pt_regs *regs); - --/* Check the name is good for event/group/fields */ --static int is_good_name(const char *name) --{ -- if (!isalpha(*name) && *name != '_') -- return 0; -- while (*++name != '\0') { -- if (!isalpha(*name) && !isdigit(*name) && *name != '_') -- return 0; -- } -- return 1; --} -- - /* - * Allocate new trace_probe and initialize it (including kprobes). - */ -@@ -702,34 +158,12 @@ error: - return ERR_PTR(ret); - } - --static void update_probe_arg(struct probe_arg *arg) --{ -- if (CHECK_FETCH_FUNCS(bitfield, arg->fetch.fn)) -- update_bitfield_fetch_param(arg->fetch.data); -- else if (CHECK_FETCH_FUNCS(deref, arg->fetch.fn)) -- update_deref_fetch_param(arg->fetch.data); -- else if (CHECK_FETCH_FUNCS(symbol, arg->fetch.fn)) -- update_symbol_cache(arg->fetch.data); --} -- --static void free_probe_arg(struct probe_arg *arg) --{ -- if (CHECK_FETCH_FUNCS(bitfield, arg->fetch.fn)) -- free_bitfield_fetch_param(arg->fetch.data); -- else if (CHECK_FETCH_FUNCS(deref, arg->fetch.fn)) -- free_deref_fetch_param(arg->fetch.data); -- else if (CHECK_FETCH_FUNCS(symbol, arg->fetch.fn)) -- free_symbol_cache(arg->fetch.data); -- kfree(arg->name); -- kfree(arg->comm); --} -- - static void free_trace_probe(struct trace_probe *tp) - { - int i; - - for (i = 0; i < tp->nr_args; i++) -- free_probe_arg(&tp->args[i]); -+ traceprobe_free_probe_arg(&tp->args[i]); - - kfree(tp->call.class->system); - kfree(tp->call.name); -@@ -787,7 +221,7 @@ static int __register_trace_probe(struct trace_probe *tp) - return -EINVAL; - - for (i = 0; i < tp->nr_args; i++) -- update_probe_arg(&tp->args[i]); -+ traceprobe_update_arg(&tp->args[i]); - - /* Set/clear disabled flag according to tp->flag */ - if (trace_probe_is_enabled(tp)) -@@ -919,227 +353,6 @@ static struct notifier_block trace_probe_module_nb = { - .priority = 1 /* Invoked after kprobe module callback */ - }; - --/* Split symbol and offset. */ --static int split_symbol_offset(char *symbol, unsigned long *offset) --{ -- char *tmp; -- int ret; -- -- if (!offset) -- return -EINVAL; -- -- tmp = strchr(symbol, '+'); -- if (tmp) { -- /* skip sign because strict_strtol doesn't accept '+' */ -- ret = strict_strtoul(tmp + 1, 0, offset); -- if (ret) -- return ret; -- *tmp = '\0'; -- } else -- *offset = 0; -- return 0; --} -- --#define PARAM_MAX_ARGS 16 --#define PARAM_MAX_STACK (THREAD_SIZE / sizeof(unsigned long)) -- --static int parse_probe_vars(char *arg, const struct fetch_type *t, -- struct fetch_param *f, bool is_return) --{ -- int ret = 0; -- unsigned long param; -- -- if (strcmp(arg, "retval") == 0) { -- if (is_return) -- f->fn = t->fetch[FETCH_MTD_retval]; -- else -- ret = -EINVAL; -- } else if (strncmp(arg, "stack", 5) == 0) { -- if (arg[5] == '\0') { -- if (strcmp(t->name, DEFAULT_FETCH_TYPE_STR) == 0) -- f->fn = fetch_stack_address; -- else -- ret = -EINVAL; -- } else if (isdigit(arg[5])) { -- ret = strict_strtoul(arg + 5, 10, ¶m); -- if (ret || param > PARAM_MAX_STACK) -- ret = -EINVAL; -- else { -- f->fn = t->fetch[FETCH_MTD_stack]; -- f->data = (void *)param; -- } -- } else -- ret = -EINVAL; -- } else -- ret = -EINVAL; -- return ret; --} -- --/* Recursive argument parser */ --static int __parse_probe_arg(char *arg, const struct fetch_type *t, -- struct fetch_param *f, bool is_return) --{ -- int ret = 0; -- unsigned long param; -- long offset; -- char *tmp; -- -- switch (arg[0]) { -- case '$': -- ret = parse_probe_vars(arg + 1, t, f, is_return); -- break; -- case '%': /* named register */ -- ret = regs_query_register_offset(arg + 1); -- if (ret >= 0) { -- f->fn = t->fetch[FETCH_MTD_reg]; -- f->data = (void *)(unsigned long)ret; -- ret = 0; -- } -- break; -- case '@': /* memory or symbol */ -- if (isdigit(arg[1])) { -- ret = strict_strtoul(arg + 1, 0, ¶m); -- if (ret) -- break; -- f->fn = t->fetch[FETCH_MTD_memory]; -- f->data = (void *)param; -- } else { -- ret = split_symbol_offset(arg + 1, &offset); -- if (ret) -- break; -- f->data = alloc_symbol_cache(arg + 1, offset); -- if (f->data) -- f->fn = t->fetch[FETCH_MTD_symbol]; -- } -- break; -- case '+': /* deref memory */ -- arg++; /* Skip '+', because strict_strtol() rejects it. */ -- case '-': -- tmp = strchr(arg, '('); -- if (!tmp) -- break; -- *tmp = '\0'; -- ret = strict_strtol(arg, 0, &offset); -- if (ret) -- break; -- arg = tmp + 1; -- tmp = strrchr(arg, ')'); -- if (tmp) { -- struct deref_fetch_param *dprm; -- const struct fetch_type *t2 = find_fetch_type(NULL); -- *tmp = '\0'; -- dprm = kzalloc(sizeof(struct deref_fetch_param), -- GFP_KERNEL); -- if (!dprm) -- return -ENOMEM; -- dprm->offset = offset; -- ret = __parse_probe_arg(arg, t2, &dprm->orig, -- is_return); -- if (ret) -- kfree(dprm); -- else { -- f->fn = t->fetch[FETCH_MTD_deref]; -- f->data = (void *)dprm; -- } -- } -- break; -- } -- if (!ret && !f->fn) { /* Parsed, but do not find fetch method */ -- pr_info("%s type has no corresponding fetch method.\n", -- t->name); -- ret = -EINVAL; -- } -- return ret; --} -- --#define BYTES_TO_BITS(nb) ((BITS_PER_LONG * (nb)) / sizeof(long)) -- --/* Bitfield type needs to be parsed into a fetch function */ --static int __parse_bitfield_probe_arg(const char *bf, -- const struct fetch_type *t, -- struct fetch_param *f) --{ -- struct bitfield_fetch_param *bprm; -- unsigned long bw, bo; -- char *tail; -- -- if (*bf != 'b') -- return 0; -- -- bprm = kzalloc(sizeof(*bprm), GFP_KERNEL); -- if (!bprm) -- return -ENOMEM; -- bprm->orig = *f; -- f->fn = t->fetch[FETCH_MTD_bitfield]; -- f->data = (void *)bprm; -- -- bw = simple_strtoul(bf + 1, &tail, 0); /* Use simple one */ -- if (bw == 0 || *tail != '@') -- return -EINVAL; -- -- bf = tail + 1; -- bo = simple_strtoul(bf, &tail, 0); -- if (tail == bf || *tail != '/') -- return -EINVAL; -- -- bprm->hi_shift = BYTES_TO_BITS(t->size) - (bw + bo); -- bprm->low_shift = bprm->hi_shift + bo; -- return (BYTES_TO_BITS(t->size) < (bw + bo)) ? -EINVAL : 0; --} -- --/* String length checking wrapper */ --static int parse_probe_arg(char *arg, struct trace_probe *tp, -- struct probe_arg *parg, bool is_return) --{ -- const char *t; -- int ret; -- -- if (strlen(arg) > MAX_ARGSTR_LEN) { -- pr_info("Argument is too long.: %s\n", arg); -- return -ENOSPC; -- } -- parg->comm = kstrdup(arg, GFP_KERNEL); -- if (!parg->comm) { -- pr_info("Failed to allocate memory for command '%s'.\n", arg); -- return -ENOMEM; -- } -- t = strchr(parg->comm, ':'); -- if (t) { -- arg[t - parg->comm] = '\0'; -- t++; -- } -- parg->type = find_fetch_type(t); -- if (!parg->type) { -- pr_info("Unsupported type: %s\n", t); -- return -EINVAL; -- } -- parg->offset = tp->size; -- tp->size += parg->type->size; -- ret = __parse_probe_arg(arg, parg->type, &parg->fetch, is_return); -- if (ret >= 0 && t != NULL) -- ret = __parse_bitfield_probe_arg(t, parg->type, &parg->fetch); -- if (ret >= 0) { -- parg->fetch_size.fn = get_fetch_size_function(parg->type, -- parg->fetch.fn); -- parg->fetch_size.data = parg->fetch.data; -- } -- return ret; --} -- --/* Return 1 if name is reserved or already used by another argument */ --static int conflict_field_name(const char *name, -- struct probe_arg *args, int narg) --{ -- int i; -- for (i = 0; i < ARRAY_SIZE(reserved_field_names); i++) -- if (strcmp(reserved_field_names[i], name) == 0) -- return 1; -- for (i = 0; i < narg; i++) -- if (strcmp(args[i].name, name) == 0) -- return 1; -- return 0; --} -- - static int create_trace_probe(int argc, char **argv) - { - /* -@@ -1240,7 +453,7 @@ static int create_trace_probe(int argc, char **argv) - /* a symbol specified */ - symbol = argv[1]; - /* TODO: support .init module functions */ -- ret = split_symbol_offset(symbol, &offset); -+ ret = traceprobe_split_symbol_offset(symbol, &offset); - if (ret) { - pr_info("Failed to parse symbol.\n"); - return ret; -@@ -1302,7 +515,8 @@ static int create_trace_probe(int argc, char **argv) - goto error; - } - -- if (conflict_field_name(tp->args[i].name, tp->args, i)) { -+ if (traceprobe_conflict_field_name(tp->args[i].name, -+ tp->args, i)) { - pr_info("Argument[%d] name '%s' conflicts with " - "another field.\n", i, argv[i]); - ret = -EINVAL; -@@ -1310,7 +524,8 @@ static int create_trace_probe(int argc, char **argv) - } - - /* Parse fetch argument */ -- ret = parse_probe_arg(arg, tp, &tp->args[i], is_return); -+ ret = traceprobe_parse_probe_arg(arg, &tp->size, &tp->args[i], -+ is_return); - if (ret) { - pr_info("Parse error at argument[%d]. (%d)\n", i, ret); - goto error; -@@ -1412,70 +627,11 @@ static int probes_open(struct inode *inode, struct file *file) - return seq_open(file, &probes_seq_op); - } - --static int command_trace_probe(const char *buf) --{ -- char **argv; -- int argc = 0, ret = 0; -- -- argv = argv_split(GFP_KERNEL, buf, &argc); -- if (!argv) -- return -ENOMEM; -- -- if (argc) -- ret = create_trace_probe(argc, argv); -- -- argv_free(argv); -- return ret; --} -- --#define WRITE_BUFSIZE 4096 -- - static ssize_t probes_write(struct file *file, const char __user *buffer, - size_t count, loff_t *ppos) - { -- char *kbuf, *tmp; -- int ret; -- size_t done; -- size_t size; -- -- kbuf = kmalloc(WRITE_BUFSIZE, GFP_KERNEL); -- if (!kbuf) -- return -ENOMEM; -- -- ret = done = 0; -- while (done < count) { -- size = count - done; -- if (size >= WRITE_BUFSIZE) -- size = WRITE_BUFSIZE - 1; -- if (copy_from_user(kbuf, buffer + done, size)) { -- ret = -EFAULT; -- goto out; -- } -- kbuf[size] = '\0'; -- tmp = strchr(kbuf, '\n'); -- if (tmp) { -- *tmp = '\0'; -- size = tmp - kbuf + 1; -- } else if (done + size < count) { -- pr_warning("Line length is too long: " -- "Should be less than %d.", WRITE_BUFSIZE); -- ret = -EINVAL; -- goto out; -- } -- done += size; -- /* Remove comments */ -- tmp = strchr(kbuf, '#'); -- if (tmp) -- *tmp = '\0'; -- -- ret = command_trace_probe(kbuf); -- if (ret) -- goto out; -- } -- ret = done; --out: -- kfree(kbuf); -- return ret; -+ return traceprobe_probes_write(file, buffer, count, ppos, -+ create_trace_probe); - } - - static const struct file_operations kprobe_events_ops = { -@@ -1711,16 +867,6 @@ partial: - return TRACE_TYPE_PARTIAL_LINE; - } - --#undef DEFINE_FIELD --#define DEFINE_FIELD(type, item, name, is_signed) \ -- do { \ -- ret = trace_define_field(event_call, #type, name, \ -- offsetof(typeof(field), item), \ -- sizeof(field.item), is_signed, \ -- FILTER_OTHER); \ -- if (ret) \ -- return ret; \ -- } while (0) - - static int kprobe_event_define_fields(struct ftrace_event_call *event_call) - { -@@ -2051,8 +1197,9 @@ static __init int kprobe_trace_self_tests_init(void) - - pr_info("Testing kprobe tracing: "); - -- ret = command_trace_probe("p:testprobe kprobe_trace_selftest_target " -- "$stack $stack0 +0($stack)"); -+ ret = traceprobe_command("p:testprobe kprobe_trace_selftest_target " -+ "$stack $stack0 +0($stack)", -+ create_trace_probe); - if (WARN_ON_ONCE(ret)) { - pr_warning("error on probing function entry.\n"); - warn++; -@@ -2066,8 +1213,8 @@ static __init int kprobe_trace_self_tests_init(void) - enable_trace_probe(tp, TP_FLAG_TRACE); - } - -- ret = command_trace_probe("r:testprobe2 kprobe_trace_selftest_target " -- "$retval"); -+ ret = traceprobe_command("r:testprobe2 kprobe_trace_selftest_target " -+ "$retval", create_trace_probe); - if (WARN_ON_ONCE(ret)) { - pr_warning("error on probing function return.\n"); - warn++; -@@ -2101,13 +1248,13 @@ static __init int kprobe_trace_self_tests_init(void) - } else - disable_trace_probe(tp, TP_FLAG_TRACE); - -- ret = command_trace_probe("-:testprobe"); -+ ret = traceprobe_command("-:testprobe", create_trace_probe); - if (WARN_ON_ONCE(ret)) { - pr_warning("error on deleting a probe.\n"); - warn++; - } - -- ret = command_trace_probe("-:testprobe2"); -+ ret = traceprobe_command("-:testprobe2", create_trace_probe); - if (WARN_ON_ONCE(ret)) { - pr_warning("error on deleting a probe.\n"); - warn++; -diff --git a/kernel/trace/trace_probe.c b/kernel/trace/trace_probe.c -new file mode 100644 -index 0000000..8e526b9 ---- /dev/null -+++ b/kernel/trace/trace_probe.c -@@ -0,0 +1,833 @@ -+/* -+ * Common code for probe-based Dynamic events. -+ * -+ * 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. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -+ * -+ * This code was copied from kernel/trace/trace_kprobe.c written by -+ * Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com> -+ * -+ * Updates to make this generic: -+ * Copyright (C) IBM Corporation, 2010-2011 -+ * Author: Srikar Dronamraju -+ */ -+ -+#include "trace_probe.h" -+ -+const char *reserved_field_names[] = { -+ "common_type", -+ "common_flags", -+ "common_preempt_count", -+ "common_pid", -+ "common_tgid", -+ FIELD_STRING_IP, -+ FIELD_STRING_RETIP, -+ FIELD_STRING_FUNC, -+}; -+ -+/* Printing function type */ -+#define PRINT_TYPE_FUNC_NAME(type) print_type_##type -+#define PRINT_TYPE_FMT_NAME(type) print_type_format_##type -+ -+/* Printing in basic type function template */ -+#define DEFINE_BASIC_PRINT_TYPE_FUNC(type, fmt, cast) \ -+static __kprobes int PRINT_TYPE_FUNC_NAME(type)(struct trace_seq *s, \ -+ const char *name, \ -+ void *data, void *ent)\ -+{ \ -+ return trace_seq_printf(s, " %s=" fmt, name, (cast)*(type *)data);\ -+} \ -+static const char PRINT_TYPE_FMT_NAME(type)[] = fmt; -+ -+DEFINE_BASIC_PRINT_TYPE_FUNC(u8, "%x", unsigned int) -+DEFINE_BASIC_PRINT_TYPE_FUNC(u16, "%x", unsigned int) -+DEFINE_BASIC_PRINT_TYPE_FUNC(u32, "%lx", unsigned long) -+DEFINE_BASIC_PRINT_TYPE_FUNC(u64, "%llx", unsigned long long) -+DEFINE_BASIC_PRINT_TYPE_FUNC(s8, "%d", int) -+DEFINE_BASIC_PRINT_TYPE_FUNC(s16, "%d", int) -+DEFINE_BASIC_PRINT_TYPE_FUNC(s32, "%ld", long) -+DEFINE_BASIC_PRINT_TYPE_FUNC(s64, "%lld", long long) -+ -+static inline void *get_rloc_data(u32 *dl) -+{ -+ return (u8 *)dl + get_rloc_offs(*dl); -+} -+ -+/* For data_loc conversion */ -+static inline void *get_loc_data(u32 *dl, void *ent) -+{ -+ return (u8 *)ent + get_rloc_offs(*dl); -+} -+ -+/* For defining macros, define string/string_size types */ -+typedef u32 string; -+typedef u32 string_size; -+ -+/* Print type function for string type */ -+static __kprobes int PRINT_TYPE_FUNC_NAME(string)(struct trace_seq *s, -+ const char *name, -+ void *data, void *ent) -+{ -+ int len = *(u32 *)data >> 16; -+ -+ if (!len) -+ return trace_seq_printf(s, " %s=(fault)", name); -+ else -+ return trace_seq_printf(s, " %s=\"%s\"", name, -+ (const char *)get_loc_data(data, ent)); -+} -+ -+static const char PRINT_TYPE_FMT_NAME(string)[] = "\\\"%s\\\""; -+ -+#define FETCH_FUNC_NAME(method, type) fetch_##method##_##type -+/* -+ * Define macro for basic types - we don't need to define s* types, because -+ * we have to care only about bitwidth at recording time. -+ */ -+#define DEFINE_BASIC_FETCH_FUNCS(method) \ -+DEFINE_FETCH_##method(u8) \ -+DEFINE_FETCH_##method(u16) \ -+DEFINE_FETCH_##method(u32) \ -+DEFINE_FETCH_##method(u64) -+ -+#define CHECK_FETCH_FUNCS(method, fn) \ -+ (((FETCH_FUNC_NAME(method, u8) == fn) || \ -+ (FETCH_FUNC_NAME(method, u16) == fn) || \ -+ (FETCH_FUNC_NAME(method, u32) == fn) || \ -+ (FETCH_FUNC_NAME(method, u64) == fn) || \ -+ (FETCH_FUNC_NAME(method, string) == fn) || \ -+ (FETCH_FUNC_NAME(method, string_size) == fn)) \ -+ && (fn != NULL)) -+ -+/* Data fetch function templates */ -+#define DEFINE_FETCH_reg(type) \ -+static __kprobes void FETCH_FUNC_NAME(reg, type)(struct pt_regs *regs, \ -+ void *offset, void *dest) \ -+{ \ -+ *(type *)dest = (type)regs_get_register(regs, \ -+ (unsigned int)((unsigned long)offset)); \ -+} -+DEFINE_BASIC_FETCH_FUNCS(reg) -+/* No string on the register */ -+#define fetch_reg_string NULL -+#define fetch_reg_string_size NULL -+ -+#define DEFINE_FETCH_stack(type) \ -+static __kprobes void FETCH_FUNC_NAME(stack, type)(struct pt_regs *regs,\ -+ void *offset, void *dest) \ -+{ \ -+ *(type *)dest = (type)regs_get_kernel_stack_nth(regs, \ -+ (unsigned int)((unsigned long)offset)); \ -+} -+DEFINE_BASIC_FETCH_FUNCS(stack) -+/* No string on the stack entry */ -+#define fetch_stack_string NULL -+#define fetch_stack_string_size NULL -+ -+#define DEFINE_FETCH_retval(type) \ -+static __kprobes void FETCH_FUNC_NAME(retval, type)(struct pt_regs *regs,\ -+ void *dummy, void *dest) \ -+{ \ -+ *(type *)dest = (type)regs_return_value(regs); \ -+} -+DEFINE_BASIC_FETCH_FUNCS(retval) -+/* No string on the retval */ -+#define fetch_retval_string NULL -+#define fetch_retval_string_size NULL -+ -+#define DEFINE_FETCH_memory(type) \ -+static __kprobes void FETCH_FUNC_NAME(memory, type)(struct pt_regs *regs,\ -+ void *addr, void *dest) \ -+{ \ -+ type retval; \ -+ if (probe_kernel_address(addr, retval)) \ -+ *(type *)dest = 0; \ -+ else \ -+ *(type *)dest = retval; \ -+} -+DEFINE_BASIC_FETCH_FUNCS(memory) -+/* -+ * Fetch a null-terminated string. Caller MUST set *(u32 *)dest with max -+ * length and relative data location. -+ */ -+static __kprobes void FETCH_FUNC_NAME(memory, string)(struct pt_regs *regs, -+ void *addr, void *dest) -+{ -+ long ret; -+ int maxlen = get_rloc_len(*(u32 *)dest); -+ u8 *dst = get_rloc_data(dest); -+ u8 *src = addr; -+ mm_segment_t old_fs = get_fs(); -+ -+ if (!maxlen) -+ return; -+ -+ /* -+ * Try to get string again, since the string can be changed while -+ * probing. -+ */ -+ set_fs(KERNEL_DS); -+ pagefault_disable(); -+ -+ do -+ ret = __copy_from_user_inatomic(dst++, src++, 1); -+ while (dst[-1] && ret == 0 && src - (u8 *)addr < maxlen); -+ -+ dst[-1] = '\0'; -+ pagefault_enable(); -+ set_fs(old_fs); -+ -+ if (ret < 0) { /* Failed to fetch string */ -+ ((u8 *)get_rloc_data(dest))[0] = '\0'; -+ *(u32 *)dest = make_data_rloc(0, get_rloc_offs(*(u32 *)dest)); -+ } else { -+ *(u32 *)dest = make_data_rloc(src - (u8 *)addr, -+ get_rloc_offs(*(u32 *)dest)); -+ } -+} -+ -+/* Return the length of string -- including null terminal byte */ -+static __kprobes void FETCH_FUNC_NAME(memory, string_size)(struct pt_regs *regs, -+ void *addr, void *dest) -+{ -+ mm_segment_t old_fs; -+ int ret, len = 0; -+ u8 c; -+ -+ old_fs = get_fs(); -+ set_fs(KERNEL_DS); -+ pagefault_disable(); -+ -+ do { -+ ret = __copy_from_user_inatomic(&c, (u8 *)addr + len, 1); -+ len++; -+ } while (c && ret == 0 && len < MAX_STRING_SIZE); -+ -+ pagefault_enable(); -+ set_fs(old_fs); -+ -+ if (ret < 0) /* Failed to check the length */ -+ *(u32 *)dest = 0; -+ else -+ *(u32 *)dest = len; -+} -+ -+/* Memory fetching by symbol */ -+struct symbol_cache { -+ char *symbol; -+ long offset; -+ unsigned long addr; -+}; -+ -+static unsigned long update_symbol_cache(struct symbol_cache *sc) -+{ -+ sc->addr = (unsigned long)kallsyms_lookup_name(sc->symbol); -+ -+ if (sc->addr) -+ sc->addr += sc->offset; -+ -+ return sc->addr; -+} -+ -+static void free_symbol_cache(struct symbol_cache *sc) -+{ -+ kfree(sc->symbol); -+ kfree(sc); -+} -+ -+static struct symbol_cache *alloc_symbol_cache(const char *sym, long offset) -+{ -+ struct symbol_cache *sc; -+ -+ if (!sym || strlen(sym) == 0) -+ return NULL; -+ -+ sc = kzalloc(sizeof(struct symbol_cache), GFP_KERNEL); -+ if (!sc) -+ return NULL; -+ -+ sc->symbol = kstrdup(sym, GFP_KERNEL); -+ if (!sc->symbol) { -+ kfree(sc); -+ return NULL; -+ } -+ sc->offset = offset; -+ update_symbol_cache(sc); -+ -+ return sc; -+} -+ -+#define DEFINE_FETCH_symbol(type) \ -+static __kprobes void FETCH_FUNC_NAME(symbol, type)(struct pt_regs *regs,\ -+ void *data, void *dest) \ -+{ \ -+ struct symbol_cache *sc = data; \ -+ if (sc->addr) \ -+ fetch_memory_##type(regs, (void *)sc->addr, dest); \ -+ else \ -+ *(type *)dest = 0; \ -+} -+DEFINE_BASIC_FETCH_FUNCS(symbol) -+DEFINE_FETCH_symbol(string) -+DEFINE_FETCH_symbol(string_size) -+ -+/* Dereference memory access function */ -+struct deref_fetch_param { -+ struct fetch_param orig; -+ long offset; -+}; -+ -+#define DEFINE_FETCH_deref(type) \ -+static __kprobes void FETCH_FUNC_NAME(deref, type)(struct pt_regs *regs,\ -+ void *data, void *dest) \ -+{ \ -+ struct deref_fetch_param *dprm = data; \ -+ unsigned long addr; \ -+ call_fetch(&dprm->orig, regs, &addr); \ -+ if (addr) { \ -+ addr += dprm->offset; \ -+ fetch_memory_##type(regs, (void *)addr, dest); \ -+ } else \ -+ *(type *)dest = 0; \ -+} -+DEFINE_BASIC_FETCH_FUNCS(deref) -+DEFINE_FETCH_deref(string) -+DEFINE_FETCH_deref(string_size) -+ -+static __kprobes void update_deref_fetch_param(struct deref_fetch_param *data) -+{ -+ if (CHECK_FETCH_FUNCS(deref, data->orig.fn)) -+ update_deref_fetch_param(data->orig.data); -+ else if (CHECK_FETCH_FUNCS(symbol, data->orig.fn)) -+ update_symbol_cache(data->orig.data); -+} -+ -+static __kprobes void free_deref_fetch_param(struct deref_fetch_param *data) -+{ -+ if (CHECK_FETCH_FUNCS(deref, data->orig.fn)) -+ free_deref_fetch_param(data->orig.data); -+ else if (CHECK_FETCH_FUNCS(symbol, data->orig.fn)) -+ free_symbol_cache(data->orig.data); -+ kfree(data); -+} -+ -+/* Bitfield fetch function */ -+struct bitfield_fetch_param { -+ struct fetch_param orig; -+ unsigned char hi_shift; -+ unsigned char low_shift; -+}; -+ -+#define DEFINE_FETCH_bitfield(type) \ -+static __kprobes void FETCH_FUNC_NAME(bitfield, type)(struct pt_regs *regs,\ -+ void *data, void *dest) \ -+{ \ -+ struct bitfield_fetch_param *bprm = data; \ -+ type buf = 0; \ -+ call_fetch(&bprm->orig, regs, &buf); \ -+ if (buf) { \ -+ buf <<= bprm->hi_shift; \ -+ buf >>= bprm->low_shift; \ -+ } \ -+ *(type *)dest = buf; \ -+} -+ -+DEFINE_BASIC_FETCH_FUNCS(bitfield) -+#define fetch_bitfield_string NULL -+#define fetch_bitfield_string_size NULL -+ -+static __kprobes void -+update_bitfield_fetch_param(struct bitfield_fetch_param *data) -+{ -+ /* -+ * Don't check the bitfield itself, because this must be the -+ * last fetch function. -+ */ -+ if (CHECK_FETCH_FUNCS(deref, data->orig.fn)) -+ update_deref_fetch_param(data->orig.data); -+ else if (CHECK_FETCH_FUNCS(symbol, data->orig.fn)) -+ update_symbol_cache(data->orig.data); -+} -+ -+static __kprobes void -+free_bitfield_fetch_param(struct bitfield_fetch_param *data) -+{ -+ /* -+ * Don't check the bitfield itself, because this must be the -+ * last fetch function. -+ */ -+ if (CHECK_FETCH_FUNCS(deref, data->orig.fn)) -+ free_deref_fetch_param(data->orig.data); -+ else if (CHECK_FETCH_FUNCS(symbol, data->orig.fn)) -+ free_symbol_cache(data->orig.data); -+ -+ kfree(data); -+} -+ -+/* Default (unsigned long) fetch type */ -+#define __DEFAULT_FETCH_TYPE(t) u##t -+#define _DEFAULT_FETCH_TYPE(t) __DEFAULT_FETCH_TYPE(t) -+#define DEFAULT_FETCH_TYPE _DEFAULT_FETCH_TYPE(BITS_PER_LONG) -+#define DEFAULT_FETCH_TYPE_STR __stringify(DEFAULT_FETCH_TYPE) -+ -+#define ASSIGN_FETCH_FUNC(method, type) \ -+ [FETCH_MTD_##method] = FETCH_FUNC_NAME(method, type) -+ -+#define __ASSIGN_FETCH_TYPE(_name, ptype, ftype, _size, sign, _fmttype) \ -+ {.name = _name, \ -+ .size = _size, \ -+ .is_signed = sign, \ -+ .print = PRINT_TYPE_FUNC_NAME(ptype), \ -+ .fmt = PRINT_TYPE_FMT_NAME(ptype), \ -+ .fmttype = _fmttype, \ -+ .fetch = { \ -+ASSIGN_FETCH_FUNC(reg, ftype), \ -+ASSIGN_FETCH_FUNC(stack, ftype), \ -+ASSIGN_FETCH_FUNC(retval, ftype), \ -+ASSIGN_FETCH_FUNC(memory, ftype), \ -+ASSIGN_FETCH_FUNC(symbol, ftype), \ -+ASSIGN_FETCH_FUNC(deref, ftype), \ -+ASSIGN_FETCH_FUNC(bitfield, ftype), \ -+ } \ -+ } -+ -+#define ASSIGN_FETCH_TYPE(ptype, ftype, sign) \ -+ __ASSIGN_FETCH_TYPE(#ptype, ptype, ftype, sizeof(ftype), sign, #ptype) -+ -+#define FETCH_TYPE_STRING 0 -+#define FETCH_TYPE_STRSIZE 1 -+ -+/* Fetch type information table */ -+static const struct fetch_type fetch_type_table[] = { -+ /* Special types */ -+ [FETCH_TYPE_STRING] = __ASSIGN_FETCH_TYPE("string", string, string, -+ sizeof(u32), 1, "__data_loc char[]"), -+ [FETCH_TYPE_STRSIZE] = __ASSIGN_FETCH_TYPE("string_size", u32, -+ string_size, sizeof(u32), 0, "u32"), -+ /* Basic types */ -+ ASSIGN_FETCH_TYPE(u8, u8, 0), -+ ASSIGN_FETCH_TYPE(u16, u16, 0), -+ ASSIGN_FETCH_TYPE(u32, u32, 0), -+ ASSIGN_FETCH_TYPE(u64, u64, 0), -+ ASSIGN_FETCH_TYPE(s8, u8, 1), -+ ASSIGN_FETCH_TYPE(s16, u16, 1), -+ ASSIGN_FETCH_TYPE(s32, u32, 1), -+ ASSIGN_FETCH_TYPE(s64, u64, 1), -+}; -+ -+static const struct fetch_type *find_fetch_type(const char *type) -+{ -+ int i; -+ -+ if (!type) -+ type = DEFAULT_FETCH_TYPE_STR; -+ -+ /* Special case: bitfield */ -+ if (*type == 'b') { -+ unsigned long bs; -+ -+ type = strchr(type, '/'); -+ if (!type) -+ goto fail; -+ -+ type++; -+ if (strict_strtoul(type, 0, &bs)) -+ goto fail; -+ -+ switch (bs) { -+ case 8: -+ return find_fetch_type("u8"); -+ case 16: -+ return find_fetch_type("u16"); -+ case 32: -+ return find_fetch_type("u32"); -+ case 64: -+ return find_fetch_type("u64"); -+ default: -+ goto fail; -+ } -+ } -+ -+ for (i = 0; i < ARRAY_SIZE(fetch_type_table); i++) -+ if (strcmp(type, fetch_type_table[i].name) == 0) -+ return &fetch_type_table[i]; -+ -+fail: -+ return NULL; -+} -+ -+/* Special function : only accept unsigned long */ -+static __kprobes void fetch_stack_address(struct pt_regs *regs, -+ void *dummy, void *dest) -+{ -+ *(unsigned long *)dest = kernel_stack_pointer(regs); -+} -+ -+static fetch_func_t get_fetch_size_function(const struct fetch_type *type, -+ fetch_func_t orig_fn) -+{ -+ int i; -+ -+ if (type != &fetch_type_table[FETCH_TYPE_STRING]) -+ return NULL; /* Only string type needs size function */ -+ -+ for (i = 0; i < FETCH_MTD_END; i++) -+ if (type->fetch[i] == orig_fn) -+ return fetch_type_table[FETCH_TYPE_STRSIZE].fetch[i]; -+ -+ WARN_ON(1); /* This should not happen */ -+ -+ return NULL; -+} -+ -+/* Split symbol and offset. */ -+int traceprobe_split_symbol_offset(char *symbol, unsigned long *offset) -+{ -+ char *tmp; -+ int ret; -+ -+ if (!offset) -+ return -EINVAL; -+ -+ tmp = strchr(symbol, '+'); -+ if (tmp) { -+ /* skip sign because strict_strtol doesn't accept '+' */ -+ ret = strict_strtoul(tmp + 1, 0, offset); -+ if (ret) -+ return ret; -+ -+ *tmp = '\0'; -+ } else -+ *offset = 0; -+ -+ return 0; -+} -+ -+#define PARAM_MAX_STACK (THREAD_SIZE / sizeof(unsigned long)) -+ -+static int parse_probe_vars(char *arg, const struct fetch_type *t, -+ struct fetch_param *f, bool is_return) -+{ -+ int ret = 0; -+ unsigned long param; -+ -+ if (strcmp(arg, "retval") == 0) { -+ if (is_return) -+ f->fn = t->fetch[FETCH_MTD_retval]; -+ else -+ ret = -EINVAL; -+ } else if (strncmp(arg, "stack", 5) == 0) { -+ if (arg[5] == '\0') { -+ if (strcmp(t->name, DEFAULT_FETCH_TYPE_STR) == 0) -+ f->fn = fetch_stack_address; -+ else -+ ret = -EINVAL; -+ } else if (isdigit(arg[5])) { -+ ret = strict_strtoul(arg + 5, 10, ¶m); -+ if (ret || param > PARAM_MAX_STACK) -+ ret = -EINVAL; -+ else { -+ f->fn = t->fetch[FETCH_MTD_stack]; -+ f->data = (void *)param; -+ } -+ } else -+ ret = -EINVAL; -+ } else -+ ret = -EINVAL; -+ -+ return ret; -+} -+ -+/* Recursive argument parser */ -+static int parse_probe_arg(char *arg, const struct fetch_type *t, -+ struct fetch_param *f, bool is_return) -+{ -+ unsigned long param; -+ long offset; -+ char *tmp; -+ int ret; -+ -+ ret = 0; -+ switch (arg[0]) { -+ case '$': -+ ret = parse_probe_vars(arg + 1, t, f, is_return); -+ break; -+ -+ case '%': /* named register */ -+ ret = regs_query_register_offset(arg + 1); -+ if (ret >= 0) { -+ f->fn = t->fetch[FETCH_MTD_reg]; -+ f->data = (void *)(unsigned long)ret; -+ ret = 0; -+ } -+ break; -+ -+ case '@': /* memory or symbol */ -+ if (isdigit(arg[1])) { -+ ret = strict_strtoul(arg + 1, 0, ¶m); -+ if (ret) -+ break; -+ -+ f->fn = t->fetch[FETCH_MTD_memory]; -+ f->data = (void *)param; -+ } else { -+ ret = traceprobe_split_symbol_offset(arg + 1, &offset); -+ if (ret) -+ break; -+ -+ f->data = alloc_symbol_cache(arg + 1, offset); -+ if (f->data) -+ f->fn = t->fetch[FETCH_MTD_symbol]; -+ } -+ break; -+ -+ case '+': /* deref memory */ -+ arg++; /* Skip '+', because strict_strtol() rejects it. */ -+ case '-': -+ tmp = strchr(arg, '('); -+ if (!tmp) -+ break; -+ -+ *tmp = '\0'; -+ ret = strict_strtol(arg, 0, &offset); -+ -+ if (ret) -+ break; -+ -+ arg = tmp + 1; -+ tmp = strrchr(arg, ')'); -+ -+ if (tmp) { -+ struct deref_fetch_param *dprm; -+ const struct fetch_type *t2; -+ -+ t2 = find_fetch_type(NULL); -+ *tmp = '\0'; -+ dprm = kzalloc(sizeof(struct deref_fetch_param), GFP_KERNEL); -+ -+ if (!dprm) -+ return -ENOMEM; -+ -+ dprm->offset = offset; -+ ret = parse_probe_arg(arg, t2, &dprm->orig, is_return); -+ if (ret) -+ kfree(dprm); -+ else { -+ f->fn = t->fetch[FETCH_MTD_deref]; -+ f->data = (void *)dprm; -+ } -+ } -+ break; -+ } -+ if (!ret && !f->fn) { /* Parsed, but do not find fetch method */ -+ pr_info("%s type has no corresponding fetch method.\n", t->name); -+ ret = -EINVAL; -+ } -+ -+ return ret; -+} -+ -+#define BYTES_TO_BITS(nb) ((BITS_PER_LONG * (nb)) / sizeof(long)) -+ -+/* Bitfield type needs to be parsed into a fetch function */ -+static int __parse_bitfield_probe_arg(const char *bf, -+ const struct fetch_type *t, -+ struct fetch_param *f) -+{ -+ struct bitfield_fetch_param *bprm; -+ unsigned long bw, bo; -+ char *tail; -+ -+ if (*bf != 'b') -+ return 0; -+ -+ bprm = kzalloc(sizeof(*bprm), GFP_KERNEL); -+ if (!bprm) -+ return -ENOMEM; -+ -+ bprm->orig = *f; -+ f->fn = t->fetch[FETCH_MTD_bitfield]; -+ f->data = (void *)bprm; -+ bw = simple_strtoul(bf + 1, &tail, 0); /* Use simple one */ -+ -+ if (bw == 0 || *tail != '@') -+ return -EINVAL; -+ -+ bf = tail + 1; -+ bo = simple_strtoul(bf, &tail, 0); -+ -+ if (tail == bf || *tail != '/') -+ return -EINVAL; -+ -+ bprm->hi_shift = BYTES_TO_BITS(t->size) - (bw + bo); -+ bprm->low_shift = bprm->hi_shift + bo; -+ -+ return (BYTES_TO_BITS(t->size) < (bw + bo)) ? -EINVAL : 0; -+} -+ -+/* String length checking wrapper */ -+int traceprobe_parse_probe_arg(char *arg, ssize_t *size, -+ struct probe_arg *parg, bool is_return) -+{ -+ const char *t; -+ int ret; -+ -+ if (strlen(arg) > MAX_ARGSTR_LEN) { -+ pr_info("Argument is too long.: %s\n", arg); -+ return -ENOSPC; -+ } -+ parg->comm = kstrdup(arg, GFP_KERNEL); -+ if (!parg->comm) { -+ pr_info("Failed to allocate memory for command '%s'.\n", arg); -+ return -ENOMEM; -+ } -+ t = strchr(parg->comm, ':'); -+ if (t) { -+ arg[t - parg->comm] = '\0'; -+ t++; -+ } -+ parg->type = find_fetch_type(t); -+ if (!parg->type) { -+ pr_info("Unsupported type: %s\n", t); -+ return -EINVAL; -+ } -+ parg->offset = *size; -+ *size += parg->type->size; -+ ret = parse_probe_arg(arg, parg->type, &parg->fetch, is_return); -+ -+ if (ret >= 0 && t != NULL) -+ ret = __parse_bitfield_probe_arg(t, parg->type, &parg->fetch); -+ -+ if (ret >= 0) { -+ parg->fetch_size.fn = get_fetch_size_function(parg->type, -+ parg->fetch.fn); -+ parg->fetch_size.data = parg->fetch.data; -+ } -+ -+ return ret; -+} -+ -+/* Return 1 if name is reserved or already used by another argument */ -+int traceprobe_conflict_field_name(const char *name, -+ struct probe_arg *args, int narg) -+{ -+ int i; -+ -+ for (i = 0; i < ARRAY_SIZE(reserved_field_names); i++) -+ if (strcmp(reserved_field_names[i], name) == 0) -+ return 1; -+ -+ for (i = 0; i < narg; i++) -+ if (strcmp(args[i].name, name) == 0) -+ return 1; -+ -+ return 0; -+} -+ -+void traceprobe_update_arg(struct probe_arg *arg) -+{ -+ if (CHECK_FETCH_FUNCS(bitfield, arg->fetch.fn)) -+ update_bitfield_fetch_param(arg->fetch.data); -+ else if (CHECK_FETCH_FUNCS(deref, arg->fetch.fn)) -+ update_deref_fetch_param(arg->fetch.data); -+ else if (CHECK_FETCH_FUNCS(symbol, arg->fetch.fn)) -+ update_symbol_cache(arg->fetch.data); -+} -+ -+void traceprobe_free_probe_arg(struct probe_arg *arg) -+{ -+ if (CHECK_FETCH_FUNCS(bitfield, arg->fetch.fn)) -+ free_bitfield_fetch_param(arg->fetch.data); -+ else if (CHECK_FETCH_FUNCS(deref, arg->fetch.fn)) -+ free_deref_fetch_param(arg->fetch.data); -+ else if (CHECK_FETCH_FUNCS(symbol, arg->fetch.fn)) -+ free_symbol_cache(arg->fetch.data); -+ -+ kfree(arg->name); -+ kfree(arg->comm); -+} -+ -+int traceprobe_command(const char *buf, int (*createfn)(int, char **)) -+{ -+ char **argv; -+ int argc, ret; -+ -+ argc = 0; -+ ret = 0; -+ argv = argv_split(GFP_KERNEL, buf, &argc); -+ if (!argv) -+ return -ENOMEM; -+ -+ if (argc) -+ ret = createfn(argc, argv); -+ -+ argv_free(argv); -+ -+ return ret; -+} -+ -+#define WRITE_BUFSIZE 4096 -+ -+ssize_t traceprobe_probes_write(struct file *file, const char __user *buffer, -+ size_t count, loff_t *ppos, -+ int (*createfn)(int, char **)) -+{ -+ char *kbuf, *tmp; -+ int ret = 0; -+ size_t done = 0; -+ size_t size; -+ -+ kbuf = kmalloc(WRITE_BUFSIZE, GFP_KERNEL); -+ if (!kbuf) -+ return -ENOMEM; -+ -+ while (done < count) { -+ size = count - done; -+ -+ if (size >= WRITE_BUFSIZE) -+ size = WRITE_BUFSIZE - 1; -+ -+ if (copy_from_user(kbuf, buffer + done, size)) { -+ ret = -EFAULT; -+ goto out; -+ } -+ kbuf[size] = '\0'; -+ tmp = strchr(kbuf, '\n'); -+ -+ if (tmp) { -+ *tmp = '\0'; -+ size = tmp - kbuf + 1; -+ } else if (done + size < count) { -+ pr_warning("Line length is too long: " -+ "Should be less than %d.", WRITE_BUFSIZE); -+ ret = -EINVAL; -+ goto out; -+ } -+ done += size; -+ /* Remove comments */ -+ tmp = strchr(kbuf, '#'); -+ -+ if (tmp) -+ *tmp = '\0'; -+ -+ ret = traceprobe_command(kbuf, createfn); -+ if (ret) -+ goto out; -+ } -+ ret = done; -+ -+out: -+ kfree(kbuf); -+ -+ return ret; -+} -diff --git a/kernel/trace/trace_probe.h b/kernel/trace/trace_probe.h -new file mode 100644 -index 0000000..2df9a18 ---- /dev/null -+++ b/kernel/trace/trace_probe.h -@@ -0,0 +1,160 @@ -+/* -+ * Common header file for probe-based Dynamic events. -+ * -+ * 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. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -+ * -+ * This code was copied from kernel/trace/trace_kprobe.h written by -+ * Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com> -+ * -+ * Updates to make this generic: -+ * Copyright (C) IBM Corporation, 2010-2011 -+ * Author: Srikar Dronamraju -+ */ -+ -+#include <linux/seq_file.h> -+#include <linux/slab.h> -+#include <linux/smp.h> -+#include <linux/debugfs.h> -+#include <linux/types.h> -+#include <linux/string.h> -+#include <linux/ctype.h> -+#include <linux/ptrace.h> -+#include <linux/perf_event.h> -+#include <linux/kprobes.h> -+#include <linux/stringify.h> -+#include <linux/limits.h> -+#include <linux/uaccess.h> -+#include <asm/bitsperlong.h> -+ -+#include "trace.h" -+#include "trace_output.h" -+ -+#define MAX_TRACE_ARGS 128 -+#define MAX_ARGSTR_LEN 63 -+#define MAX_EVENT_NAME_LEN 64 -+#define MAX_STRING_SIZE PATH_MAX -+ -+/* Reserved field names */ -+#define FIELD_STRING_IP "__probe_ip" -+#define FIELD_STRING_RETIP "__probe_ret_ip" -+#define FIELD_STRING_FUNC "__probe_func" -+ -+#undef DEFINE_FIELD -+#define DEFINE_FIELD(type, item, name, is_signed) \ -+ do { \ -+ ret = trace_define_field(event_call, #type, name, \ -+ offsetof(typeof(field), item), \ -+ sizeof(field.item), is_signed, \ -+ FILTER_OTHER); \ -+ if (ret) \ -+ return ret; \ -+ } while (0) -+ -+ -+/* Flags for trace_probe */ -+#define TP_FLAG_TRACE 1 -+#define TP_FLAG_PROFILE 2 -+#define TP_FLAG_REGISTERED 4 -+ -+ -+/* data_rloc: data relative location, compatible with u32 */ -+#define make_data_rloc(len, roffs) \ -+ (((u32)(len) << 16) | ((u32)(roffs) & 0xffff)) -+#define get_rloc_len(dl) ((u32)(dl) >> 16) -+#define get_rloc_offs(dl) ((u32)(dl) & 0xffff) -+ -+/* -+ * Convert data_rloc to data_loc: -+ * data_rloc stores the offset from data_rloc itself, but data_loc -+ * stores the offset from event entry. -+ */ -+#define convert_rloc_to_loc(dl, offs) ((u32)(dl) + (offs)) -+ -+/* Data fetch function type */ -+typedef void (*fetch_func_t)(struct pt_regs *, void *, void *); -+/* Printing function type */ -+typedef int (*print_type_func_t)(struct trace_seq *, const char *, void *, void *); -+ -+/* Fetch types */ -+enum { -+ FETCH_MTD_reg = 0, -+ FETCH_MTD_stack, -+ FETCH_MTD_retval, -+ FETCH_MTD_memory, -+ FETCH_MTD_symbol, -+ FETCH_MTD_deref, -+ FETCH_MTD_bitfield, -+ FETCH_MTD_END, -+}; -+ -+/* Fetch type information table */ -+struct fetch_type { -+ const char *name; /* Name of type */ -+ size_t size; /* Byte size of type */ -+ int is_signed; /* Signed flag */ -+ print_type_func_t print; /* Print functions */ -+ const char *fmt; /* Fromat string */ -+ const char *fmttype; /* Name in format file */ -+ /* Fetch functions */ -+ fetch_func_t fetch[FETCH_MTD_END]; -+}; -+ -+struct fetch_param { -+ fetch_func_t fn; -+ void *data; -+}; -+ -+struct probe_arg { -+ struct fetch_param fetch; -+ struct fetch_param fetch_size; -+ unsigned int offset; /* Offset from argument entry */ -+ const char *name; /* Name of this argument */ -+ const char *comm; /* Command of this argument */ -+ const struct fetch_type *type; /* Type of this argument */ -+}; -+ -+static inline __kprobes void call_fetch(struct fetch_param *fprm, -+ struct pt_regs *regs, void *dest) -+{ -+ return fprm->fn(regs, fprm->data, dest); -+} -+ -+/* Check the name is good for event/group/fields */ -+static inline int is_good_name(const char *name) -+{ -+ if (!isalpha(*name) && *name != '_') -+ return 0; -+ while (*++name != '\0') { -+ if (!isalpha(*name) && !isdigit(*name) && *name != '_') -+ return 0; -+ } -+ return 1; -+} -+ -+extern int traceprobe_parse_probe_arg(char *arg, ssize_t *size, -+ struct probe_arg *parg, bool is_return); -+ -+extern int traceprobe_conflict_field_name(const char *name, -+ struct probe_arg *args, int narg); -+ -+extern void traceprobe_update_arg(struct probe_arg *arg); -+extern void traceprobe_free_probe_arg(struct probe_arg *arg); -+ -+extern int traceprobe_split_symbol_offset(char *symbol, unsigned long *offset); -+ -+extern ssize_t traceprobe_probes_write(struct file *file, -+ const char __user *buffer, size_t count, loff_t *ppos, -+ int (*createfn)(int, char**)); -+ -+extern int traceprobe_command(const char *buf, int (*createfn)(int, char**)); --- -1.7.5.4 - diff --git a/features/uprobe/tracing-Fix-kconfig-warning-due-to-a-typo.patch b/features/uprobe/tracing-Fix-kconfig-warning-due-to-a-typo.patch deleted file mode 100644 index e0d0ebf1141fc8aa168632fb68cf0bb813051d61..0000000000000000000000000000000000000000 --- a/features/uprobe/tracing-Fix-kconfig-warning-due-to-a-typo.patch +++ /dev/null @@ -1,95 +0,0 @@ -From 103b503daaff2328d12b1ba2bd8d27e95a1474bb Mon Sep 17 00:00:00 2001 -From: Srikar Dronamraju <srikar@linux.vnet.ibm.com> -Date: Tue, 8 May 2012 16:41:26 +0530 -Subject: [PATCH 19/24] tracing: Fix kconfig warning due to a typo - -Commit f3f096cfe ("tracing: Provide trace events interface for -uprobes") throws a warning about unmet dependencies. - -The exact warning message is: - warning: (UPROBE_EVENT) selects UPROBES which has unmet direct dependencies (UPROBE_EVENTS && PERF_EVENTS) - -This is due to a typo in arch/Kconfig file. Fix similar typos in -the uprobetracer documentation. - -Also add sample format of a uprobe event in the uprobetracer -documentation as suggested by Masami Hiramatsu. - -commit ec83db0f78cd44c3b586ec1c3a348d1a8a389797 upstream - -Reported-by: Stephen Boyd <sboyd@codeaurora.org> -Reported-by: Ingo Molnar <mingo@kernel.org> -Signed-off-by: Srikar Dronamraju <srikar@linux.vnet.ibm.com> -Cc: Linus Torvalds <torvalds@linux-foundation.org> -Cc: Ananth N Mavinakayanahalli <ananth@in.ibm.com> -Cc: Oleg Nesterov <oleg@redhat.com> -Cc: Christoph Hellwig <hch@infradead.org> -Cc: Steven Rostedt <rostedt@goodmis.org> -Cc: Arnaldo Carvalho de Melo <acme@infradead.org> -Cc: Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com> -Cc: Anton Arapov <anton@redhat.com> -Cc: Peter Zijlstra <peterz@infradead.org> -Link: http://lkml.kernel.org/r/20120508111126.21004.38285.sendpatchset@srdronam.in.ibm.com -Signed-off-by: Ingo Molnar <mingo@kernel.org> -Signed-off-by: Paul Barrette <paul.barrette@windriver.com> ---- - Documentation/trace/uprobetracer.txt | 22 ++++++++++++++++++++-- - arch/Kconfig | 2 +- - 2 files changed, 21 insertions(+), 3 deletions(-) - -diff --git a/Documentation/trace/uprobetracer.txt b/Documentation/trace/uprobetracer.txt -index eae40a0..24ce682 100644 ---- a/Documentation/trace/uprobetracer.txt -+++ b/Documentation/trace/uprobetracer.txt -@@ -5,7 +5,7 @@ - Overview - -------- - Uprobe based trace events are similar to kprobe based trace events. --To enable this feature, build your kernel with CONFIG_UPROBE_EVENTS=y. -+To enable this feature, build your kernel with CONFIG_UPROBE_EVENT=y. - - Similar to the kprobe-event tracer, this doesn't need to be activated via - current_tracer. Instead of that, add probe points via -@@ -68,7 +68,25 @@ in the object. We can see the events that are registered by looking at the - uprobe_events file. - - # cat uprobe_events -- p:uprobes/p_zsh_0x46420 /bin/zsh:0x0000000000046420 -+ p:uprobes/p_zsh_0x46420 /bin/zsh:0x00046420 arg1=%ip arg2=%ax -+ -+The format of events can be seen by viewing the file events/uprobes/p_zsh_0x46420/format -+ -+ # cat events/uprobes/p_zsh_0x46420/format -+ name: p_zsh_0x46420 -+ ID: 922 -+ format: -+ field:unsigned short common_type; offset:0; size:2; signed:0; -+ field:unsigned char common_flags; offset:2; size:1; signed:0; -+ field:unsigned char common_preempt_count; offset:3; size:1; signed:0; -+ field:int common_pid; offset:4; size:4; signed:1; -+ field:int common_padding; offset:8; size:4; signed:1; -+ -+ field:unsigned long __probe_ip; offset:12; size:4; signed:0; -+ field:u32 arg1; offset:16; size:4; signed:0; -+ field:u32 arg2; offset:20; size:4; signed:0; -+ -+ print fmt: "(%lx) arg1=%lx arg2=%lx", REC->__probe_ip, REC->arg1, REC->arg2 - - Right after definition, each event is disabled by default. For tracing these - events, you need to enable it by: -diff --git a/arch/Kconfig b/arch/Kconfig -index 5e4ab5c..dd939a9 100644 ---- a/arch/Kconfig -+++ b/arch/Kconfig -@@ -78,7 +78,7 @@ config OPTPROBES - - config UPROBES - bool "Transparent user-space probes (EXPERIMENTAL)" -- depends on UPROBE_EVENTS && PERF_EVENTS -+ depends on UPROBE_EVENT && PERF_EVENTS - default n - help - Uprobes is the user-space counterpart to kprobes: they --- -1.7.5.4 - diff --git a/features/uprobe/tracing-Modify-is_delete-is_return-from-int-to-bool.patch b/features/uprobe/tracing-Modify-is_delete-is_return-from-int-to-bool.patch deleted file mode 100644 index 36d06e2d3047b3836cca73a8684399c5ab71d793..0000000000000000000000000000000000000000 --- a/features/uprobe/tracing-Modify-is_delete-is_return-from-int-to-bool.patch +++ /dev/null @@ -1,97 +0,0 @@ -From 91f0360db35261ddffbc89ee68e9d7b2dddb0cf6 Mon Sep 17 00:00:00 2001 -From: Srikar Dronamraju <srikar@linux.vnet.ibm.com> -Date: Mon, 9 Apr 2012 14:41:33 +0530 -Subject: [PATCH 16/24] tracing: Modify is_delete, is_return from int to bool - -is_delete and is_return can take utmost 2 values and are better -of being a boolean than a int. There are no functional changes. - -commit 3a6b76661da8e92124a813b43607f5bec1a618de upstream - -Signed-off-by: Srikar Dronamraju <srikar@linux.vnet.ibm.com> -Acked-by: Steven Rostedt <rostedt@goodmis.org> -Acked-by: Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com> -Cc: Linus Torvalds <torvalds@linux-foundation.org> -Cc: Ananth N Mavinakayanahalli <ananth@in.ibm.com> -Cc: Jim Keniston <jkenisto@linux.vnet.ibm.com> -Cc: Linux-mm <linux-mm@kvack.org> -Cc: Oleg Nesterov <oleg@redhat.com> -Cc: Andi Kleen <andi@firstfloor.org> -Cc: Christoph Hellwig <hch@infradead.org> -Cc: Arnaldo Carvalho de Melo <acme@infradead.org> -Cc: Anton Arapov <anton@redhat.com> -Cc: Peter Zijlstra <peterz@infradead.org> -Link: http://lkml.kernel.org/r/20120409091133.8343.65289.sendpatchset@srdronam.in.ibm.com -Signed-off-by: Ingo Molnar <mingo@kernel.org> -Signed-off-by: Paul Barrette <paul.barrette@windriver.com> ---- - kernel/trace/trace_kprobe.c | 16 ++++++++-------- - 1 files changed, 8 insertions(+), 8 deletions(-) - -diff --git a/kernel/trace/trace_kprobe.c b/kernel/trace/trace_kprobe.c -index 580a05e..4f935f8 100644 ---- a/kernel/trace/trace_kprobe.c -+++ b/kernel/trace/trace_kprobe.c -@@ -651,7 +651,7 @@ static struct trace_probe *alloc_trace_probe(const char *group, - void *addr, - const char *symbol, - unsigned long offs, -- int nargs, int is_return) -+ int nargs, bool is_return) - { - struct trace_probe *tp; - int ret = -ENOMEM; -@@ -944,7 +944,7 @@ static int split_symbol_offset(char *symbol, unsigned long *offset) - #define PARAM_MAX_STACK (THREAD_SIZE / sizeof(unsigned long)) - - static int parse_probe_vars(char *arg, const struct fetch_type *t, -- struct fetch_param *f, int is_return) -+ struct fetch_param *f, bool is_return) - { - int ret = 0; - unsigned long param; -@@ -977,7 +977,7 @@ static int parse_probe_vars(char *arg, const struct fetch_type *t, - - /* Recursive argument parser */ - static int __parse_probe_arg(char *arg, const struct fetch_type *t, -- struct fetch_param *f, int is_return) -+ struct fetch_param *f, bool is_return) - { - int ret = 0; - unsigned long param; -@@ -1089,7 +1089,7 @@ static int __parse_bitfield_probe_arg(const char *bf, - - /* String length checking wrapper */ - static int parse_probe_arg(char *arg, struct trace_probe *tp, -- struct probe_arg *parg, int is_return) -+ struct probe_arg *parg, bool is_return) - { - const char *t; - int ret; -@@ -1162,7 +1162,7 @@ static int create_trace_probe(int argc, char **argv) - */ - struct trace_probe *tp; - int i, ret = 0; -- int is_return = 0, is_delete = 0; -+ bool is_return = false, is_delete = false; - char *symbol = NULL, *event = NULL, *group = NULL; - char *arg; - unsigned long offset = 0; -@@ -1171,11 +1171,11 @@ static int create_trace_probe(int argc, char **argv) - - /* argc must be >= 1 */ - if (argv[0][0] == 'p') -- is_return = 0; -+ is_return = false; - else if (argv[0][0] == 'r') -- is_return = 1; -+ is_return = true; - else if (argv[0][0] == '-') -- is_delete = 1; -+ is_delete = true; - else { - pr_info("Probe definition must be started with 'p', 'r' or" - " '-'.\n"); --- -1.7.5.4 - diff --git a/features/uprobe/tracing-Provide-trace-events-interface-for-uprobes.patch b/features/uprobe/tracing-Provide-trace-events-interface-for-uprobes.patch deleted file mode 100644 index 747797458b60c2eb0ec97dfdc4f5c7e56e7fffe6..0000000000000000000000000000000000000000 --- a/features/uprobe/tracing-Provide-trace-events-interface-for-uprobes.patch +++ /dev/null @@ -1,1119 +0,0 @@ -From 9bb012e0faf6b1ea887a4c42cbfdf468285ce93a Mon Sep 17 00:00:00 2001 -From: Srikar Dronamraju <srikar@linux.vnet.ibm.com> -Date: Wed, 11 Apr 2012 16:00:43 +0530 -Subject: [PATCH 18/24] tracing: Provide trace events interface for uprobes - -Implements trace_event support for uprobes. In its current form -it can be used to put probes at a specified offset in a file and -dump the required registers when the code flow reaches the -probed address. - -The following example shows how to dump the instruction pointer -and %ax a register at the probed text address. Here we are -trying to probe zfree in /bin/zsh: - - # cd /sys/kernel/debug/tracing/ - # cat /proc/`pgrep zsh`/maps | grep /bin/zsh | grep r-xp - 00400000-0048a000 r-xp 00000000 08:03 130904 /bin/zsh - # objdump -T /bin/zsh | grep -w zfree - 0000000000446420 g DF .text 0000000000000012 Base - zfree # echo 'p /bin/zsh:0x46420 %ip %ax' > uprobe_events - # cat uprobe_events - p:uprobes/p_zsh_0x46420 /bin/zsh:0x0000000000046420 - # echo 1 > events/uprobes/enable - # sleep 20 - # echo 0 > events/uprobes/enable - # cat trace - # tracer: nop - # - # TASK-PID CPU# TIMESTAMP FUNCTION - # | | | | | - zsh-24842 [006] 258544.995456: p_zsh_0x46420: (0x446420) arg1=446421 arg2=79 - zsh-24842 [007] 258545.000270: p_zsh_0x46420: (0x446420) arg1=446421 arg2=79 - zsh-24842 [002] 258545.043929: p_zsh_0x46420: (0x446420) arg1=446421 arg2=79 - zsh-24842 [004] 258547.046129: p_zsh_0x46420: (0x446420) arg1=446421 arg2=79 - -commit f3f096cfedf8113380c56fc855275cc75cd8cf55 upstream - -Signed-off-by: Srikar Dronamraju <srikar@linux.vnet.ibm.com> -Acked-by: Steven Rostedt <rostedt@goodmis.org> -Acked-by: Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com> -Cc: Linus Torvalds <torvalds@linux-foundation.org> -Cc: Ananth N Mavinakayanahalli <ananth@in.ibm.com> -Cc: Jim Keniston <jkenisto@linux.vnet.ibm.com> -Cc: Linux-mm <linux-mm@kvack.org> -Cc: Oleg Nesterov <oleg@redhat.com> -Cc: Andi Kleen <andi@firstfloor.org> -Cc: Christoph Hellwig <hch@infradead.org> -Cc: Arnaldo Carvalho de Melo <acme@infradead.org> -Cc: Anton Arapov <anton@redhat.com> -Cc: Peter Zijlstra <peterz@infradead.org> -Link: http://lkml.kernel.org/r/20120411103043.GB29437@linux.vnet.ibm.com -Signed-off-by: Ingo Molnar <mingo@kernel.org> -Signed-off-by: Paul Barrette <paul.barrette@windriver.com> ---- - Documentation/trace/uprobetracer.txt | 95 ++++ - arch/Kconfig | 2 +- - kernel/trace/Kconfig | 16 + - kernel/trace/Makefile | 1 + - kernel/trace/trace.h | 5 + - kernel/trace/trace_kprobe.c | 2 +- - kernel/trace/trace_probe.c | 14 +- - kernel/trace/trace_probe.h | 3 +- - kernel/trace/trace_uprobe.c | 788 ++++++++++++++++++++++++++++++++++ - 9 files changed, 919 insertions(+), 7 deletions(-) - create mode 100644 Documentation/trace/uprobetracer.txt - create mode 100644 kernel/trace/trace_uprobe.c - -diff --git a/Documentation/trace/uprobetracer.txt b/Documentation/trace/uprobetracer.txt -new file mode 100644 -index 0000000..eae40a0 ---- /dev/null -+++ b/Documentation/trace/uprobetracer.txt -@@ -0,0 +1,95 @@ -+ Uprobe-tracer: Uprobe-based Event Tracing -+ ========================================= -+ Documentation written by Srikar Dronamraju -+ -+Overview -+-------- -+Uprobe based trace events are similar to kprobe based trace events. -+To enable this feature, build your kernel with CONFIG_UPROBE_EVENTS=y. -+ -+Similar to the kprobe-event tracer, this doesn't need to be activated via -+current_tracer. Instead of that, add probe points via -+/sys/kernel/debug/tracing/uprobe_events, and enable it via -+/sys/kernel/debug/tracing/events/uprobes/<EVENT>/enabled. -+ -+However unlike kprobe-event tracer, the uprobe event interface expects the -+user to calculate the offset of the probepoint in the object -+ -+Synopsis of uprobe_tracer -+------------------------- -+ p[:[GRP/]EVENT] PATH:SYMBOL[+offs] [FETCHARGS] : Set a probe -+ -+ GRP : Group name. If omitted, use "uprobes" for it. -+ EVENT : Event name. If omitted, the event name is generated -+ based on SYMBOL+offs. -+ PATH : path to an executable or a library. -+ SYMBOL[+offs] : Symbol+offset where the probe is inserted. -+ -+ FETCHARGS : Arguments. Each probe can have up to 128 args. -+ %REG : Fetch register REG -+ -+Event Profiling -+--------------- -+ You can check the total number of probe hits and probe miss-hits via -+/sys/kernel/debug/tracing/uprobe_profile. -+ The first column is event name, the second is the number of probe hits, -+the third is the number of probe miss-hits. -+ -+Usage examples -+-------------- -+To add a probe as a new event, write a new definition to uprobe_events -+as below. -+ -+ echo 'p: /bin/bash:0x4245c0' > /sys/kernel/debug/tracing/uprobe_events -+ -+ This sets a uprobe at an offset of 0x4245c0 in the executable /bin/bash -+ -+ echo > /sys/kernel/debug/tracing/uprobe_events -+ -+ This clears all probe points. -+ -+The following example shows how to dump the instruction pointer and %ax -+a register at the probed text address. Here we are trying to probe -+function zfree in /bin/zsh -+ -+ # cd /sys/kernel/debug/tracing/ -+ # cat /proc/`pgrep zsh`/maps | grep /bin/zsh | grep r-xp -+ 00400000-0048a000 r-xp 00000000 08:03 130904 /bin/zsh -+ # objdump -T /bin/zsh | grep -w zfree -+ 0000000000446420 g DF .text 0000000000000012 Base zfree -+ -+0x46420 is the offset of zfree in object /bin/zsh that is loaded at -+0x00400000. Hence the command to probe would be : -+ -+ # echo 'p /bin/zsh:0x46420 %ip %ax' > uprobe_events -+ -+Please note: User has to explicitly calculate the offset of the probepoint -+in the object. We can see the events that are registered by looking at the -+uprobe_events file. -+ -+ # cat uprobe_events -+ p:uprobes/p_zsh_0x46420 /bin/zsh:0x0000000000046420 -+ -+Right after definition, each event is disabled by default. For tracing these -+events, you need to enable it by: -+ -+ # echo 1 > events/uprobes/enable -+ -+Lets disable the event after sleeping for some time. -+ # sleep 20 -+ # echo 0 > events/uprobes/enable -+ -+And you can see the traced information via /sys/kernel/debug/tracing/trace. -+ -+ # cat trace -+ # tracer: nop -+ # -+ # TASK-PID CPU# TIMESTAMP FUNCTION -+ # | | | | | -+ zsh-24842 [006] 258544.995456: p_zsh_0x46420: (0x446420) arg1=446421 arg2=79 -+ zsh-24842 [007] 258545.000270: p_zsh_0x46420: (0x446420) arg1=446421 arg2=79 -+ zsh-24842 [002] 258545.043929: p_zsh_0x46420: (0x446420) arg1=446421 arg2=79 -+ zsh-24842 [004] 258547.046129: p_zsh_0x46420: (0x446420) arg1=446421 arg2=79 -+ -+Each line shows us probes were triggered for a pid 24842 with ip being -+0x446421 and contents of ax register being 79. -diff --git a/arch/Kconfig b/arch/Kconfig -index 88b9183..5e4ab5c 100644 ---- a/arch/Kconfig -+++ b/arch/Kconfig -@@ -78,7 +78,7 @@ config OPTPROBES - - config UPROBES - bool "Transparent user-space probes (EXPERIMENTAL)" -- depends on ARCH_SUPPORTS_UPROBES && PERF_EVENTS -+ depends on UPROBE_EVENTS && PERF_EVENTS - default n - help - Uprobes is the user-space counterpart to kprobes: they -diff --git a/kernel/trace/Kconfig b/kernel/trace/Kconfig -index ce5a5c5..ea4bff6 100644 ---- a/kernel/trace/Kconfig -+++ b/kernel/trace/Kconfig -@@ -386,6 +386,22 @@ config KPROBE_EVENT - This option is also required by perf-probe subcommand of perf tools. - If you want to use perf tools, this option is strongly recommended. - -+config UPROBE_EVENT -+ bool "Enable uprobes-based dynamic events" -+ depends on ARCH_SUPPORTS_UPROBES -+ depends on MMU -+ select UPROBES -+ select PROBE_EVENTS -+ select TRACING -+ default n -+ help -+ This allows the user to add tracing events on top of userspace -+ dynamic events (similar to tracepoints) on the fly via the trace -+ events interface. Those events can be inserted wherever uprobes -+ can probe, and record various registers. -+ This option is required if you plan to use perf-probe subcommand -+ of perf tools on user space applications. -+ - config PROBE_EVENTS - def_bool n - -diff --git a/kernel/trace/Makefile b/kernel/trace/Makefile -index fa10d5c..1734c03 100644 ---- a/kernel/trace/Makefile -+++ b/kernel/trace/Makefile -@@ -62,5 +62,6 @@ ifeq ($(CONFIG_TRACING),y) - obj-$(CONFIG_KGDB_KDB) += trace_kdb.o - endif - obj-$(CONFIG_PROBE_EVENTS) += trace_probe.o -+obj-$(CONFIG_UPROBE_EVENT) += trace_uprobe.o - - libftrace-y := ftrace.o -diff --git a/kernel/trace/trace.h b/kernel/trace/trace.h -index f95d65d..a6bf705 100644 ---- a/kernel/trace/trace.h -+++ b/kernel/trace/trace.h -@@ -103,6 +103,11 @@ struct kretprobe_trace_entry_head { - unsigned long ret_ip; - }; - -+struct uprobe_trace_entry_head { -+ struct trace_entry ent; -+ unsigned long ip; -+}; -+ - /* - * trace_flag_type is an enumeration that holds different - * states when a trace occurs. These are: -diff --git a/kernel/trace/trace_kprobe.c b/kernel/trace/trace_kprobe.c -index f8b7773..b31d3d5 100644 ---- a/kernel/trace/trace_kprobe.c -+++ b/kernel/trace/trace_kprobe.c -@@ -525,7 +525,7 @@ static int create_trace_probe(int argc, char **argv) - - /* Parse fetch argument */ - ret = traceprobe_parse_probe_arg(arg, &tp->size, &tp->args[i], -- is_return); -+ is_return, true); - if (ret) { - pr_info("Parse error at argument[%d]. (%d)\n", i, ret); - goto error; -diff --git a/kernel/trace/trace_probe.c b/kernel/trace/trace_probe.c -index 8e526b9..daa9980 100644 ---- a/kernel/trace/trace_probe.c -+++ b/kernel/trace/trace_probe.c -@@ -550,7 +550,7 @@ static int parse_probe_vars(char *arg, const struct fetch_type *t, - - /* Recursive argument parser */ - static int parse_probe_arg(char *arg, const struct fetch_type *t, -- struct fetch_param *f, bool is_return) -+ struct fetch_param *f, bool is_return, bool is_kprobe) - { - unsigned long param; - long offset; -@@ -558,6 +558,11 @@ static int parse_probe_arg(char *arg, const struct fetch_type *t, - int ret; - - ret = 0; -+ -+ /* Until uprobe_events supports only reg arguments */ -+ if (!is_kprobe && arg[0] != '%') -+ return -EINVAL; -+ - switch (arg[0]) { - case '$': - ret = parse_probe_vars(arg + 1, t, f, is_return); -@@ -619,7 +624,8 @@ static int parse_probe_arg(char *arg, const struct fetch_type *t, - return -ENOMEM; - - dprm->offset = offset; -- ret = parse_probe_arg(arg, t2, &dprm->orig, is_return); -+ ret = parse_probe_arg(arg, t2, &dprm->orig, is_return, -+ is_kprobe); - if (ret) - kfree(dprm); - else { -@@ -677,7 +683,7 @@ static int __parse_bitfield_probe_arg(const char *bf, - - /* String length checking wrapper */ - int traceprobe_parse_probe_arg(char *arg, ssize_t *size, -- struct probe_arg *parg, bool is_return) -+ struct probe_arg *parg, bool is_return, bool is_kprobe) - { - const char *t; - int ret; -@@ -703,7 +709,7 @@ int traceprobe_parse_probe_arg(char *arg, ssize_t *size, - } - parg->offset = *size; - *size += parg->type->size; -- ret = parse_probe_arg(arg, parg->type, &parg->fetch, is_return); -+ ret = parse_probe_arg(arg, parg->type, &parg->fetch, is_return, is_kprobe); - - if (ret >= 0 && t != NULL) - ret = __parse_bitfield_probe_arg(t, parg->type, &parg->fetch); -diff --git a/kernel/trace/trace_probe.h b/kernel/trace/trace_probe.h -index 2df9a18..9337086 100644 ---- a/kernel/trace/trace_probe.h -+++ b/kernel/trace/trace_probe.h -@@ -66,6 +66,7 @@ - #define TP_FLAG_TRACE 1 - #define TP_FLAG_PROFILE 2 - #define TP_FLAG_REGISTERED 4 -+#define TP_FLAG_UPROBE 8 - - - /* data_rloc: data relative location, compatible with u32 */ -@@ -143,7 +144,7 @@ static inline int is_good_name(const char *name) - } - - extern int traceprobe_parse_probe_arg(char *arg, ssize_t *size, -- struct probe_arg *parg, bool is_return); -+ struct probe_arg *parg, bool is_return, bool is_kprobe); - - extern int traceprobe_conflict_field_name(const char *name, - struct probe_arg *args, int narg); -diff --git a/kernel/trace/trace_uprobe.c b/kernel/trace/trace_uprobe.c -new file mode 100644 -index 0000000..2b36ac6 ---- /dev/null -+++ b/kernel/trace/trace_uprobe.c -@@ -0,0 +1,788 @@ -+/* -+ * uprobes-based tracing events -+ * -+ * 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. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -+ * -+ * Copyright (C) IBM Corporation, 2010-2012 -+ * Author: Srikar Dronamraju <srikar@linux.vnet.ibm.com> -+ */ -+ -+#include <linux/module.h> -+#include <linux/uaccess.h> -+#include <linux/uprobes.h> -+#include <linux/namei.h> -+ -+#include "trace_probe.h" -+ -+#define UPROBE_EVENT_SYSTEM "uprobes" -+ -+/* -+ * uprobe event core functions -+ */ -+struct trace_uprobe; -+struct uprobe_trace_consumer { -+ struct uprobe_consumer cons; -+ struct trace_uprobe *tu; -+}; -+ -+struct trace_uprobe { -+ struct list_head list; -+ struct ftrace_event_class class; -+ struct ftrace_event_call call; -+ struct uprobe_trace_consumer *consumer; -+ struct inode *inode; -+ char *filename; -+ unsigned long offset; -+ unsigned long nhit; -+ unsigned int flags; /* For TP_FLAG_* */ -+ ssize_t size; /* trace entry size */ -+ unsigned int nr_args; -+ struct probe_arg args[]; -+}; -+ -+#define SIZEOF_TRACE_UPROBE(n) \ -+ (offsetof(struct trace_uprobe, args) + \ -+ (sizeof(struct probe_arg) * (n))) -+ -+static int register_uprobe_event(struct trace_uprobe *tu); -+static void unregister_uprobe_event(struct trace_uprobe *tu); -+ -+static DEFINE_MUTEX(uprobe_lock); -+static LIST_HEAD(uprobe_list); -+ -+static int uprobe_dispatcher(struct uprobe_consumer *con, struct pt_regs *regs); -+ -+/* -+ * Allocate new trace_uprobe and initialize it (including uprobes). -+ */ -+static struct trace_uprobe * -+alloc_trace_uprobe(const char *group, const char *event, int nargs) -+{ -+ struct trace_uprobe *tu; -+ -+ if (!event || !is_good_name(event)) -+ return ERR_PTR(-EINVAL); -+ -+ if (!group || !is_good_name(group)) -+ return ERR_PTR(-EINVAL); -+ -+ tu = kzalloc(SIZEOF_TRACE_UPROBE(nargs), GFP_KERNEL); -+ if (!tu) -+ return ERR_PTR(-ENOMEM); -+ -+ tu->call.class = &tu->class; -+ tu->call.name = kstrdup(event, GFP_KERNEL); -+ if (!tu->call.name) -+ goto error; -+ -+ tu->class.system = kstrdup(group, GFP_KERNEL); -+ if (!tu->class.system) -+ goto error; -+ -+ INIT_LIST_HEAD(&tu->list); -+ return tu; -+ -+error: -+ kfree(tu->call.name); -+ kfree(tu); -+ -+ return ERR_PTR(-ENOMEM); -+} -+ -+static void free_trace_uprobe(struct trace_uprobe *tu) -+{ -+ int i; -+ -+ for (i = 0; i < tu->nr_args; i++) -+ traceprobe_free_probe_arg(&tu->args[i]); -+ -+ iput(tu->inode); -+ kfree(tu->call.class->system); -+ kfree(tu->call.name); -+ kfree(tu->filename); -+ kfree(tu); -+} -+ -+static struct trace_uprobe *find_probe_event(const char *event, const char *group) -+{ -+ struct trace_uprobe *tu; -+ -+ list_for_each_entry(tu, &uprobe_list, list) -+ if (strcmp(tu->call.name, event) == 0 && -+ strcmp(tu->call.class->system, group) == 0) -+ return tu; -+ -+ return NULL; -+} -+ -+/* Unregister a trace_uprobe and probe_event: call with locking uprobe_lock */ -+static void unregister_trace_uprobe(struct trace_uprobe *tu) -+{ -+ list_del(&tu->list); -+ unregister_uprobe_event(tu); -+ free_trace_uprobe(tu); -+} -+ -+/* Register a trace_uprobe and probe_event */ -+static int register_trace_uprobe(struct trace_uprobe *tu) -+{ -+ struct trace_uprobe *old_tp; -+ int ret; -+ -+ mutex_lock(&uprobe_lock); -+ -+ /* register as an event */ -+ old_tp = find_probe_event(tu->call.name, tu->call.class->system); -+ if (old_tp) -+ /* delete old event */ -+ unregister_trace_uprobe(old_tp); -+ -+ ret = register_uprobe_event(tu); -+ if (ret) { -+ pr_warning("Failed to register probe event(%d)\n", ret); -+ goto end; -+ } -+ -+ list_add_tail(&tu->list, &uprobe_list); -+ -+end: -+ mutex_unlock(&uprobe_lock); -+ -+ return ret; -+} -+ -+/* -+ * Argument syntax: -+ * - Add uprobe: p[:[GRP/]EVENT] PATH:SYMBOL[+offs] [FETCHARGS] -+ * -+ * - Remove uprobe: -:[GRP/]EVENT -+ */ -+static int create_trace_uprobe(int argc, char **argv) -+{ -+ struct trace_uprobe *tu; -+ struct inode *inode; -+ char *arg, *event, *group, *filename; -+ char buf[MAX_EVENT_NAME_LEN]; -+ struct path path; -+ unsigned long offset; -+ bool is_delete; -+ int i, ret; -+ -+ inode = NULL; -+ ret = 0; -+ is_delete = false; -+ event = NULL; -+ group = NULL; -+ -+ /* argc must be >= 1 */ -+ if (argv[0][0] == '-') -+ is_delete = true; -+ else if (argv[0][0] != 'p') { -+ pr_info("Probe definition must be started with 'p', 'r' or" " '-'.\n"); -+ return -EINVAL; -+ } -+ -+ if (argv[0][1] == ':') { -+ event = &argv[0][2]; -+ arg = strchr(event, '/'); -+ -+ if (arg) { -+ group = event; -+ event = arg + 1; -+ event[-1] = '\0'; -+ -+ if (strlen(group) == 0) { -+ pr_info("Group name is not specified\n"); -+ return -EINVAL; -+ } -+ } -+ if (strlen(event) == 0) { -+ pr_info("Event name is not specified\n"); -+ return -EINVAL; -+ } -+ } -+ if (!group) -+ group = UPROBE_EVENT_SYSTEM; -+ -+ if (is_delete) { -+ if (!event) { -+ pr_info("Delete command needs an event name.\n"); -+ return -EINVAL; -+ } -+ mutex_lock(&uprobe_lock); -+ tu = find_probe_event(event, group); -+ -+ if (!tu) { -+ mutex_unlock(&uprobe_lock); -+ pr_info("Event %s/%s doesn't exist.\n", group, event); -+ return -ENOENT; -+ } -+ /* delete an event */ -+ unregister_trace_uprobe(tu); -+ mutex_unlock(&uprobe_lock); -+ return 0; -+ } -+ -+ if (argc < 2) { -+ pr_info("Probe point is not specified.\n"); -+ return -EINVAL; -+ } -+ if (isdigit(argv[1][0])) { -+ pr_info("probe point must be have a filename.\n"); -+ return -EINVAL; -+ } -+ arg = strchr(argv[1], ':'); -+ if (!arg) -+ goto fail_address_parse; -+ -+ *arg++ = '\0'; -+ filename = argv[1]; -+ ret = kern_path(filename, LOOKUP_FOLLOW, &path); -+ if (ret) -+ goto fail_address_parse; -+ -+ ret = strict_strtoul(arg, 0, &offset); -+ if (ret) -+ goto fail_address_parse; -+ -+ inode = igrab(path.dentry->d_inode); -+ -+ argc -= 2; -+ argv += 2; -+ -+ /* setup a probe */ -+ if (!event) { -+ char *tail = strrchr(filename, '/'); -+ char *ptr; -+ -+ ptr = kstrdup((tail ? tail + 1 : filename), GFP_KERNEL); -+ if (!ptr) { -+ ret = -ENOMEM; -+ goto fail_address_parse; -+ } -+ -+ tail = ptr; -+ ptr = strpbrk(tail, ".-_"); -+ if (ptr) -+ *ptr = '\0'; -+ -+ snprintf(buf, MAX_EVENT_NAME_LEN, "%c_%s_0x%lx", 'p', tail, offset); -+ event = buf; -+ kfree(tail); -+ } -+ -+ tu = alloc_trace_uprobe(group, event, argc); -+ if (IS_ERR(tu)) { -+ pr_info("Failed to allocate trace_uprobe.(%d)\n", (int)PTR_ERR(tu)); -+ ret = PTR_ERR(tu); -+ goto fail_address_parse; -+ } -+ tu->offset = offset; -+ tu->inode = inode; -+ tu->filename = kstrdup(filename, GFP_KERNEL); -+ -+ if (!tu->filename) { -+ pr_info("Failed to allocate filename.\n"); -+ ret = -ENOMEM; -+ goto error; -+ } -+ -+ /* parse arguments */ -+ ret = 0; -+ for (i = 0; i < argc && i < MAX_TRACE_ARGS; i++) { -+ /* Increment count for freeing args in error case */ -+ tu->nr_args++; -+ -+ /* Parse argument name */ -+ arg = strchr(argv[i], '='); -+ if (arg) { -+ *arg++ = '\0'; -+ tu->args[i].name = kstrdup(argv[i], GFP_KERNEL); -+ } else { -+ arg = argv[i]; -+ /* If argument name is omitted, set "argN" */ -+ snprintf(buf, MAX_EVENT_NAME_LEN, "arg%d", i + 1); -+ tu->args[i].name = kstrdup(buf, GFP_KERNEL); -+ } -+ -+ if (!tu->args[i].name) { -+ pr_info("Failed to allocate argument[%d] name.\n", i); -+ ret = -ENOMEM; -+ goto error; -+ } -+ -+ if (!is_good_name(tu->args[i].name)) { -+ pr_info("Invalid argument[%d] name: %s\n", i, tu->args[i].name); -+ ret = -EINVAL; -+ goto error; -+ } -+ -+ if (traceprobe_conflict_field_name(tu->args[i].name, tu->args, i)) { -+ pr_info("Argument[%d] name '%s' conflicts with " -+ "another field.\n", i, argv[i]); -+ ret = -EINVAL; -+ goto error; -+ } -+ -+ /* Parse fetch argument */ -+ ret = traceprobe_parse_probe_arg(arg, &tu->size, &tu->args[i], false, false); -+ if (ret) { -+ pr_info("Parse error at argument[%d]. (%d)\n", i, ret); -+ goto error; -+ } -+ } -+ -+ ret = register_trace_uprobe(tu); -+ if (ret) -+ goto error; -+ return 0; -+ -+error: -+ free_trace_uprobe(tu); -+ return ret; -+ -+fail_address_parse: -+ if (inode) -+ iput(inode); -+ -+ pr_info("Failed to parse address.\n"); -+ -+ return ret; -+} -+ -+static void cleanup_all_probes(void) -+{ -+ struct trace_uprobe *tu; -+ -+ mutex_lock(&uprobe_lock); -+ while (!list_empty(&uprobe_list)) { -+ tu = list_entry(uprobe_list.next, struct trace_uprobe, list); -+ unregister_trace_uprobe(tu); -+ } -+ mutex_unlock(&uprobe_lock); -+} -+ -+/* Probes listing interfaces */ -+static void *probes_seq_start(struct seq_file *m, loff_t *pos) -+{ -+ mutex_lock(&uprobe_lock); -+ return seq_list_start(&uprobe_list, *pos); -+} -+ -+static void *probes_seq_next(struct seq_file *m, void *v, loff_t *pos) -+{ -+ return seq_list_next(v, &uprobe_list, pos); -+} -+ -+static void probes_seq_stop(struct seq_file *m, void *v) -+{ -+ mutex_unlock(&uprobe_lock); -+} -+ -+static int probes_seq_show(struct seq_file *m, void *v) -+{ -+ struct trace_uprobe *tu = v; -+ int i; -+ -+ seq_printf(m, "p:%s/%s", tu->call.class->system, tu->call.name); -+ seq_printf(m, " %s:0x%p", tu->filename, (void *)tu->offset); -+ -+ for (i = 0; i < tu->nr_args; i++) -+ seq_printf(m, " %s=%s", tu->args[i].name, tu->args[i].comm); -+ -+ seq_printf(m, "\n"); -+ return 0; -+} -+ -+static const struct seq_operations probes_seq_op = { -+ .start = probes_seq_start, -+ .next = probes_seq_next, -+ .stop = probes_seq_stop, -+ .show = probes_seq_show -+}; -+ -+static int probes_open(struct inode *inode, struct file *file) -+{ -+ if ((file->f_mode & FMODE_WRITE) && (file->f_flags & O_TRUNC)) -+ cleanup_all_probes(); -+ -+ return seq_open(file, &probes_seq_op); -+} -+ -+static ssize_t probes_write(struct file *file, const char __user *buffer, -+ size_t count, loff_t *ppos) -+{ -+ return traceprobe_probes_write(file, buffer, count, ppos, create_trace_uprobe); -+} -+ -+static const struct file_operations uprobe_events_ops = { -+ .owner = THIS_MODULE, -+ .open = probes_open, -+ .read = seq_read, -+ .llseek = seq_lseek, -+ .release = seq_release, -+ .write = probes_write, -+}; -+ -+/* Probes profiling interfaces */ -+static int probes_profile_seq_show(struct seq_file *m, void *v) -+{ -+ struct trace_uprobe *tu = v; -+ -+ seq_printf(m, " %s %-44s %15lu\n", tu->filename, tu->call.name, tu->nhit); -+ return 0; -+} -+ -+static const struct seq_operations profile_seq_op = { -+ .start = probes_seq_start, -+ .next = probes_seq_next, -+ .stop = probes_seq_stop, -+ .show = probes_profile_seq_show -+}; -+ -+static int profile_open(struct inode *inode, struct file *file) -+{ -+ return seq_open(file, &profile_seq_op); -+} -+ -+static const struct file_operations uprobe_profile_ops = { -+ .owner = THIS_MODULE, -+ .open = profile_open, -+ .read = seq_read, -+ .llseek = seq_lseek, -+ .release = seq_release, -+}; -+ -+/* uprobe handler */ -+static void uprobe_trace_func(struct trace_uprobe *tu, struct pt_regs *regs) -+{ -+ struct uprobe_trace_entry_head *entry; -+ struct ring_buffer_event *event; -+ struct ring_buffer *buffer; -+ u8 *data; -+ int size, i, pc; -+ unsigned long irq_flags; -+ struct ftrace_event_call *call = &tu->call; -+ -+ tu->nhit++; -+ -+ local_save_flags(irq_flags); -+ pc = preempt_count(); -+ -+ size = sizeof(*entry) + tu->size; -+ -+ event = trace_current_buffer_lock_reserve(&buffer, call->event.type, -+ size, irq_flags, pc); -+ if (!event) -+ return; -+ -+ entry = ring_buffer_event_data(event); -+ entry->ip = uprobe_get_swbp_addr(task_pt_regs(current)); -+ data = (u8 *)&entry[1]; -+ for (i = 0; i < tu->nr_args; i++) -+ call_fetch(&tu->args[i].fetch, regs, data + tu->args[i].offset); -+ -+ if (!filter_current_check_discard(buffer, call, entry, event)) -+ trace_buffer_unlock_commit(buffer, event, irq_flags, pc); -+} -+ -+/* Event entry printers */ -+static enum print_line_t -+print_uprobe_event(struct trace_iterator *iter, int flags, struct trace_event *event) -+{ -+ struct uprobe_trace_entry_head *field; -+ struct trace_seq *s = &iter->seq; -+ struct trace_uprobe *tu; -+ u8 *data; -+ int i; -+ -+ field = (struct uprobe_trace_entry_head *)iter->ent; -+ tu = container_of(event, struct trace_uprobe, call.event); -+ -+ if (!trace_seq_printf(s, "%s: (", tu->call.name)) -+ goto partial; -+ -+ if (!seq_print_ip_sym(s, field->ip, flags | TRACE_ITER_SYM_OFFSET)) -+ goto partial; -+ -+ if (!trace_seq_puts(s, ")")) -+ goto partial; -+ -+ data = (u8 *)&field[1]; -+ for (i = 0; i < tu->nr_args; i++) { -+ if (!tu->args[i].type->print(s, tu->args[i].name, -+ data + tu->args[i].offset, field)) -+ goto partial; -+ } -+ -+ if (trace_seq_puts(s, "\n")) -+ return TRACE_TYPE_HANDLED; -+ -+partial: -+ return TRACE_TYPE_PARTIAL_LINE; -+} -+ -+static int probe_event_enable(struct trace_uprobe *tu, int flag) -+{ -+ struct uprobe_trace_consumer *utc; -+ int ret = 0; -+ -+ if (!tu->inode || tu->consumer) -+ return -EINTR; -+ -+ utc = kzalloc(sizeof(struct uprobe_trace_consumer), GFP_KERNEL); -+ if (!utc) -+ return -EINTR; -+ -+ utc->cons.handler = uprobe_dispatcher; -+ utc->cons.filter = NULL; -+ ret = uprobe_register(tu->inode, tu->offset, &utc->cons); -+ if (ret) { -+ kfree(utc); -+ return ret; -+ } -+ -+ tu->flags |= flag; -+ utc->tu = tu; -+ tu->consumer = utc; -+ -+ return 0; -+} -+ -+static void probe_event_disable(struct trace_uprobe *tu, int flag) -+{ -+ if (!tu->inode || !tu->consumer) -+ return; -+ -+ uprobe_unregister(tu->inode, tu->offset, &tu->consumer->cons); -+ tu->flags &= ~flag; -+ kfree(tu->consumer); -+ tu->consumer = NULL; -+} -+ -+static int uprobe_event_define_fields(struct ftrace_event_call *event_call) -+{ -+ int ret, i; -+ struct uprobe_trace_entry_head field; -+ struct trace_uprobe *tu = (struct trace_uprobe *)event_call->data; -+ -+ DEFINE_FIELD(unsigned long, ip, FIELD_STRING_IP, 0); -+ /* Set argument names as fields */ -+ for (i = 0; i < tu->nr_args; i++) { -+ ret = trace_define_field(event_call, tu->args[i].type->fmttype, -+ tu->args[i].name, -+ sizeof(field) + tu->args[i].offset, -+ tu->args[i].type->size, -+ tu->args[i].type->is_signed, -+ FILTER_OTHER); -+ -+ if (ret) -+ return ret; -+ } -+ return 0; -+} -+ -+#define LEN_OR_ZERO (len ? len - pos : 0) -+static int __set_print_fmt(struct trace_uprobe *tu, char *buf, int len) -+{ -+ const char *fmt, *arg; -+ int i; -+ int pos = 0; -+ -+ fmt = "(%lx)"; -+ arg = "REC->" FIELD_STRING_IP; -+ -+ /* When len=0, we just calculate the needed length */ -+ -+ pos += snprintf(buf + pos, LEN_OR_ZERO, "\"%s", fmt); -+ -+ for (i = 0; i < tu->nr_args; i++) { -+ pos += snprintf(buf + pos, LEN_OR_ZERO, " %s=%s", -+ tu->args[i].name, tu->args[i].type->fmt); -+ } -+ -+ pos += snprintf(buf + pos, LEN_OR_ZERO, "\", %s", arg); -+ -+ for (i = 0; i < tu->nr_args; i++) { -+ pos += snprintf(buf + pos, LEN_OR_ZERO, ", REC->%s", -+ tu->args[i].name); -+ } -+ -+ return pos; /* return the length of print_fmt */ -+} -+#undef LEN_OR_ZERO -+ -+static int set_print_fmt(struct trace_uprobe *tu) -+{ -+ char *print_fmt; -+ int len; -+ -+ /* First: called with 0 length to calculate the needed length */ -+ len = __set_print_fmt(tu, NULL, 0); -+ print_fmt = kmalloc(len + 1, GFP_KERNEL); -+ if (!print_fmt) -+ return -ENOMEM; -+ -+ /* Second: actually write the @print_fmt */ -+ __set_print_fmt(tu, print_fmt, len + 1); -+ tu->call.print_fmt = print_fmt; -+ -+ return 0; -+} -+ -+#ifdef CONFIG_PERF_EVENTS -+/* uprobe profile handler */ -+static void uprobe_perf_func(struct trace_uprobe *tu, struct pt_regs *regs) -+{ -+ struct ftrace_event_call *call = &tu->call; -+ struct uprobe_trace_entry_head *entry; -+ struct hlist_head *head; -+ u8 *data; -+ int size, __size, i; -+ int rctx; -+ -+ __size = sizeof(*entry) + tu->size; -+ size = ALIGN(__size + sizeof(u32), sizeof(u64)); -+ size -= sizeof(u32); -+ if (WARN_ONCE(size > PERF_MAX_TRACE_SIZE, "profile buffer not large enough")) -+ return; -+ -+ preempt_disable(); -+ -+ entry = perf_trace_buf_prepare(size, call->event.type, regs, &rctx); -+ if (!entry) -+ goto out; -+ -+ entry->ip = uprobe_get_swbp_addr(task_pt_regs(current)); -+ data = (u8 *)&entry[1]; -+ for (i = 0; i < tu->nr_args; i++) -+ call_fetch(&tu->args[i].fetch, regs, data + tu->args[i].offset); -+ -+ head = this_cpu_ptr(call->perf_events); -+ perf_trace_buf_submit(entry, size, rctx, entry->ip, 1, regs, head); -+ -+ out: -+ preempt_enable(); -+} -+#endif /* CONFIG_PERF_EVENTS */ -+ -+static -+int trace_uprobe_register(struct ftrace_event_call *event, enum trace_reg type, void *data) -+{ -+ struct trace_uprobe *tu = (struct trace_uprobe *)event->data; -+ -+ switch (type) { -+ case TRACE_REG_REGISTER: -+ return probe_event_enable(tu, TP_FLAG_TRACE); -+ -+ case TRACE_REG_UNREGISTER: -+ probe_event_disable(tu, TP_FLAG_TRACE); -+ return 0; -+ -+#ifdef CONFIG_PERF_EVENTS -+ case TRACE_REG_PERF_REGISTER: -+ return probe_event_enable(tu, TP_FLAG_PROFILE); -+ -+ case TRACE_REG_PERF_UNREGISTER: -+ probe_event_disable(tu, TP_FLAG_PROFILE); -+ return 0; -+#endif -+ default: -+ return 0; -+ } -+ return 0; -+} -+ -+static int uprobe_dispatcher(struct uprobe_consumer *con, struct pt_regs *regs) -+{ -+ struct uprobe_trace_consumer *utc; -+ struct trace_uprobe *tu; -+ -+ utc = container_of(con, struct uprobe_trace_consumer, cons); -+ tu = utc->tu; -+ if (!tu || tu->consumer != utc) -+ return 0; -+ -+ if (tu->flags & TP_FLAG_TRACE) -+ uprobe_trace_func(tu, regs); -+ -+#ifdef CONFIG_PERF_EVENTS -+ if (tu->flags & TP_FLAG_PROFILE) -+ uprobe_perf_func(tu, regs); -+#endif -+ return 0; -+} -+ -+static struct trace_event_functions uprobe_funcs = { -+ .trace = print_uprobe_event -+}; -+ -+static int register_uprobe_event(struct trace_uprobe *tu) -+{ -+ struct ftrace_event_call *call = &tu->call; -+ int ret; -+ -+ /* Initialize ftrace_event_call */ -+ INIT_LIST_HEAD(&call->class->fields); -+ call->event.funcs = &uprobe_funcs; -+ call->class->define_fields = uprobe_event_define_fields; -+ -+ if (set_print_fmt(tu) < 0) -+ return -ENOMEM; -+ -+ ret = register_ftrace_event(&call->event); -+ if (!ret) { -+ kfree(call->print_fmt); -+ return -ENODEV; -+ } -+ call->flags = 0; -+ call->class->reg = trace_uprobe_register; -+ call->data = tu; -+ ret = trace_add_event_call(call); -+ -+ if (ret) { -+ pr_info("Failed to register uprobe event: %s\n", call->name); -+ kfree(call->print_fmt); -+ unregister_ftrace_event(&call->event); -+ } -+ -+ return ret; -+} -+ -+static void unregister_uprobe_event(struct trace_uprobe *tu) -+{ -+ /* tu->event is unregistered in trace_remove_event_call() */ -+ trace_remove_event_call(&tu->call); -+ kfree(tu->call.print_fmt); -+ tu->call.print_fmt = NULL; -+} -+ -+/* Make a trace interface for controling probe points */ -+static __init int init_uprobe_trace(void) -+{ -+ struct dentry *d_tracer; -+ -+ d_tracer = tracing_init_dentry(); -+ if (!d_tracer) -+ return 0; -+ -+ trace_create_file("uprobe_events", 0644, d_tracer, -+ NULL, &uprobe_events_ops); -+ /* Profile interface */ -+ trace_create_file("uprobe_profile", 0444, d_tracer, -+ NULL, &uprobe_profile_ops); -+ return 0; -+} -+ -+fs_initcall(init_uprobe_trace); --- -1.7.5.4 - diff --git a/features/uprobe/uprobe.scc b/features/uprobe/uprobe.scc index 15e519c3fca5ec426e529526c14125a8478a224d..39391a51a07d0459466371568222c925888a962e 100644 --- a/features/uprobe/uprobe.scc +++ b/features/uprobe/uprobe.scc @@ -1,32 +1 @@ # place holder for uprobe -patch uprobes-mm-x86-Add-the-ability-to-install-and-remove.patch -patch uprobes-core-Clean-up-refactor-and-improve-the-code.patch -patch uprobes-Move-to-kernel-events.patch -patch uprobes-core-Make-instruction-tables-volatile.patch -patch uprobes-core-Remove-uprobe_opcode_sz.patch -patch uprobes-core-Move-insn-to-arch-specific-structure.patch -patch uprobes-Update-copyright-notices.patch -patch uprobes-core-Make-macro-names-consistent.patch -patch uprobes-core-Make-order-of-function-parameters-consi.patch -patch uprobes-core-Rename-bkpt-to-swbp.patch -patch uprobes-core-Handle-breakpoint-and-singlestep-except.patch -patch uprobes-core-Allocate-XOL-slots-for-uprobes-use.patch -patch uprobes-core-Optimize-probe-hits-with-the-help-of-a-.patch -patch uprobes-core-Make-background-page-replacement-logic-.patch -patch uprobes-core-Decrement-uprobe-count-before-the-pages.patch -patch tracing-Modify-is_delete-is_return-from-int-to-bool.patch -patch tracing-Extract-out-common-code-for-kprobes-uprobes-.patch -patch tracing-Provide-trace-events-interface-for-uprobes.patch -patch tracing-Fix-kconfig-warning-due-to-a-typo.patch -patch perf-probe-Provide-perf-interface-for-uprobes.patch -patch perf-probe-Detect-probe-target-when-m-x-options-are-.patch -patch On-RISC-architectures-like-powerpc-instructions-are-.patch -patch powerpc-Add-trap_nr-to-thread_struct.patch -patch powerpc-Uprobes-port-to-powerpc.patch -patch powerpc-uprobes-removed-external-declaration-of-upro.patch -patch move-key_repace_session_keyring-into-tracehook_notif.patch -patch task_work_add-generic-process-context-callbacks.patch -patch genirq-reimplement-exit_irq_thread-hook-via-task_wor.patch -patch keys-change-keyctl_session_to_parent-to-use-task_wor.patch -patch keys-kill-the-dummy-key_replace_session_keyring.patch -patch keys-kill-task_struct-replacement_session_keyring.patch diff --git a/features/uprobe/uprobes-Move-to-kernel-events.patch b/features/uprobe/uprobes-Move-to-kernel-events.patch deleted file mode 100644 index f4872403b3da61c98fca45fbedcd6e14e1241c5e..0000000000000000000000000000000000000000 --- a/features/uprobe/uprobes-Move-to-kernel-events.patch +++ /dev/null @@ -1,2105 +0,0 @@ -From 56c1e99bdd34661e774e055d6748685310284306 Mon Sep 17 00:00:00 2001 -From: Ingo Molnar <mingo@elte.hu> -Date: Wed, 22 Feb 2012 11:01:49 +0100 -Subject: [PATCH 03/24] uprobes: Move to kernel/events/ - -Consolidate the uprobes code under kernel/events/, where the various -core kernel event handling routines live. - -commit a5f4374a9610fd7286c2164d4e680436727eff71 upstream - -Acked-by: Peter Zijlstra <a.p.zijlstra@chello.nl> -Cc: Srikar Dronamraju <srikar@linux.vnet.ibm.com> -Cc: Jim Keniston <jkenisto@us.ibm.com> -Cc: Oleg Nesterov <oleg@redhat.com> -Cc: Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com> -Cc: Arnaldo Carvalho de Melo <acme@infradead.org> -Cc: Anton Arapov <anton@redhat.com> -Cc: Ananth N Mavinakayanahalli <ananth@in.ibm.com> -Link: http://lkml.kernel.org/n/tip-biuyhhwohxgbp2vzbap5yr8o@git.kernel.org -Signed-off-by: Ingo Molnar <mingo@elte.hu> -Signed-off-by: Paul Barrette <paul.barrette@windriver.com> ---- - arch/Kconfig | 2 +- - kernel/Makefile | 1 - - kernel/events/Makefile | 3 + - kernel/events/uprobes.c | 1011 +++++++++++++++++++++++++++++++++++++++++++++++ - kernel/uprobes.c | 1011 ----------------------------------------------- - 5 files changed, 1015 insertions(+), 1013 deletions(-) - create mode 100644 kernel/events/uprobes.c - delete mode 100644 kernel/uprobes.c - -diff --git a/arch/Kconfig b/arch/Kconfig -index b78bf33..88b9183 100644 ---- a/arch/Kconfig -+++ b/arch/Kconfig -@@ -78,7 +78,7 @@ config OPTPROBES - - config UPROBES - bool "Transparent user-space probes (EXPERIMENTAL)" -- depends on ARCH_SUPPORTS_UPROBES -+ depends on ARCH_SUPPORTS_UPROBES && PERF_EVENTS - default n - help - Uprobes is the user-space counterpart to kprobes: they -diff --git a/kernel/Makefile b/kernel/Makefile -index 72ea789..633b548 100644 ---- a/kernel/Makefile -+++ b/kernel/Makefile -@@ -107,7 +107,6 @@ obj-$(CONFIG_USER_RETURN_NOTIFIER) += user-return-notifier.o - obj-$(CONFIG_PADATA) += padata.o - obj-$(CONFIG_CRASH_DUMP) += crash_dump.o - obj-$(CONFIG_JUMP_LABEL) += jump_label.o --obj-$(CONFIG_UPROBES) += uprobes.o - - $(obj)/configs.o: $(obj)/config_data.h - -diff --git a/kernel/events/Makefile b/kernel/events/Makefile -index 22d901f..103f5d1 100644 ---- a/kernel/events/Makefile -+++ b/kernel/events/Makefile -@@ -3,4 +3,7 @@ CFLAGS_REMOVE_core.o = -pg - endif - - obj-y := core.o ring_buffer.o callchain.o -+ - obj-$(CONFIG_HAVE_HW_BREAKPOINT) += hw_breakpoint.o -+obj-$(CONFIG_UPROBES) += uprobes.o -+ -diff --git a/kernel/events/uprobes.c b/kernel/events/uprobes.c -new file mode 100644 -index 0000000..884817f ---- /dev/null -+++ b/kernel/events/uprobes.c -@@ -0,0 +1,1011 @@ -+/* -+ * User-space Probes (UProbes) -+ * -+ * 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. -+ * -+ * 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. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -+ * -+ * Copyright (C) IBM Corporation, 2008-2011 -+ * Authors: -+ * Srikar Dronamraju -+ * Jim Keniston -+ */ -+ -+#include <linux/kernel.h> -+#include <linux/highmem.h> -+#include <linux/pagemap.h> /* read_mapping_page */ -+#include <linux/slab.h> -+#include <linux/sched.h> -+#include <linux/rmap.h> /* anon_vma_prepare */ -+#include <linux/mmu_notifier.h> /* set_pte_at_notify */ -+#include <linux/swap.h> /* try_to_free_swap */ -+ -+#include <linux/uprobes.h> -+ -+static struct rb_root uprobes_tree = RB_ROOT; -+ -+static DEFINE_SPINLOCK(uprobes_treelock); /* serialize rbtree access */ -+ -+#define UPROBES_HASH_SZ 13 -+ -+/* serialize (un)register */ -+static struct mutex uprobes_mutex[UPROBES_HASH_SZ]; -+ -+#define uprobes_hash(v) (&uprobes_mutex[((unsigned long)(v)) % UPROBES_HASH_SZ]) -+ -+/* serialize uprobe->pending_list */ -+static struct mutex uprobes_mmap_mutex[UPROBES_HASH_SZ]; -+#define uprobes_mmap_hash(v) (&uprobes_mmap_mutex[((unsigned long)(v)) % UPROBES_HASH_SZ]) -+ -+/* -+ * uprobe_events allows us to skip the uprobe_mmap if there are no uprobe -+ * events active at this time. Probably a fine grained per inode count is -+ * better? -+ */ -+static atomic_t uprobe_events = ATOMIC_INIT(0); -+ -+/* -+ * Maintain a temporary per vma info that can be used to search if a vma -+ * has already been handled. This structure is introduced since extending -+ * vm_area_struct wasnt recommended. -+ */ -+struct vma_info { -+ struct list_head probe_list; -+ struct mm_struct *mm; -+ loff_t vaddr; -+}; -+ -+/* -+ * valid_vma: Verify if the specified vma is an executable vma -+ * Relax restrictions while unregistering: vm_flags might have -+ * changed after breakpoint was inserted. -+ * - is_register: indicates if we are in register context. -+ * - Return 1 if the specified virtual address is in an -+ * executable vma. -+ */ -+static bool valid_vma(struct vm_area_struct *vma, bool is_register) -+{ -+ if (!vma->vm_file) -+ return false; -+ -+ if (!is_register) -+ return true; -+ -+ if ((vma->vm_flags & (VM_READ|VM_WRITE|VM_EXEC|VM_SHARED)) == (VM_READ|VM_EXEC)) -+ return true; -+ -+ return false; -+} -+ -+static loff_t vma_address(struct vm_area_struct *vma, loff_t offset) -+{ -+ loff_t vaddr; -+ -+ vaddr = vma->vm_start + offset; -+ vaddr -= vma->vm_pgoff << PAGE_SHIFT; -+ -+ return vaddr; -+} -+ -+/** -+ * __replace_page - replace page in vma by new page. -+ * based on replace_page in mm/ksm.c -+ * -+ * @vma: vma that holds the pte pointing to page -+ * @page: the cowed page we are replacing by kpage -+ * @kpage: the modified page we replace page by -+ * -+ * Returns 0 on success, -EFAULT on failure. -+ */ -+static int __replace_page(struct vm_area_struct *vma, struct page *page, struct page *kpage) -+{ -+ struct mm_struct *mm = vma->vm_mm; -+ pgd_t *pgd; -+ pud_t *pud; -+ pmd_t *pmd; -+ pte_t *ptep; -+ spinlock_t *ptl; -+ unsigned long addr; -+ int err = -EFAULT; -+ -+ addr = page_address_in_vma(page, vma); -+ if (addr == -EFAULT) -+ goto out; -+ -+ pgd = pgd_offset(mm, addr); -+ if (!pgd_present(*pgd)) -+ goto out; -+ -+ pud = pud_offset(pgd, addr); -+ if (!pud_present(*pud)) -+ goto out; -+ -+ pmd = pmd_offset(pud, addr); -+ if (!pmd_present(*pmd)) -+ goto out; -+ -+ ptep = pte_offset_map_lock(mm, pmd, addr, &ptl); -+ if (!ptep) -+ goto out; -+ -+ get_page(kpage); -+ page_add_new_anon_rmap(kpage, vma, addr); -+ -+ flush_cache_page(vma, addr, pte_pfn(*ptep)); -+ ptep_clear_flush(vma, addr, ptep); -+ set_pte_at_notify(mm, addr, ptep, mk_pte(kpage, vma->vm_page_prot)); -+ -+ page_remove_rmap(page); -+ if (!page_mapped(page)) -+ try_to_free_swap(page); -+ put_page(page); -+ pte_unmap_unlock(ptep, ptl); -+ err = 0; -+ -+out: -+ return err; -+} -+ -+/** -+ * is_bkpt_insn - check if instruction is breakpoint instruction. -+ * @insn: instruction to be checked. -+ * Default implementation of is_bkpt_insn -+ * Returns true if @insn is a breakpoint instruction. -+ */ -+bool __weak is_bkpt_insn(uprobe_opcode_t *insn) -+{ -+ return *insn == UPROBES_BKPT_INSN; -+} -+ -+/* -+ * NOTE: -+ * Expect the breakpoint instruction to be the smallest size instruction for -+ * the architecture. If an arch has variable length instruction and the -+ * breakpoint instruction is not of the smallest length instruction -+ * supported by that architecture then we need to modify read_opcode / -+ * write_opcode accordingly. This would never be a problem for archs that -+ * have fixed length instructions. -+ */ -+ -+/* -+ * write_opcode - write the opcode at a given virtual address. -+ * @mm: the probed process address space. -+ * @uprobe: the breakpointing information. -+ * @vaddr: the virtual address to store the opcode. -+ * @opcode: opcode to be written at @vaddr. -+ * -+ * Called with mm->mmap_sem held (for read and with a reference to -+ * mm). -+ * -+ * For mm @mm, write the opcode at @vaddr. -+ * Return 0 (success) or a negative errno. -+ */ -+static int write_opcode(struct mm_struct *mm, struct uprobe *uprobe, -+ unsigned long vaddr, uprobe_opcode_t opcode) -+{ -+ struct page *old_page, *new_page; -+ struct address_space *mapping; -+ void *vaddr_old, *vaddr_new; -+ struct vm_area_struct *vma; -+ loff_t addr; -+ int ret; -+ -+ /* Read the page with vaddr into memory */ -+ ret = get_user_pages(NULL, mm, vaddr, 1, 0, 0, &old_page, &vma); -+ if (ret <= 0) -+ return ret; -+ -+ ret = -EINVAL; -+ -+ /* -+ * We are interested in text pages only. Our pages of interest -+ * should be mapped for read and execute only. We desist from -+ * adding probes in write mapped pages since the breakpoints -+ * might end up in the file copy. -+ */ -+ if (!valid_vma(vma, is_bkpt_insn(&opcode))) -+ goto put_out; -+ -+ mapping = uprobe->inode->i_mapping; -+ if (mapping != vma->vm_file->f_mapping) -+ goto put_out; -+ -+ addr = vma_address(vma, uprobe->offset); -+ if (vaddr != (unsigned long)addr) -+ goto put_out; -+ -+ ret = -ENOMEM; -+ new_page = alloc_page_vma(GFP_HIGHUSER_MOVABLE, vma, vaddr); -+ if (!new_page) -+ goto put_out; -+ -+ __SetPageUptodate(new_page); -+ -+ /* -+ * lock page will serialize against do_wp_page()'s -+ * PageAnon() handling -+ */ -+ lock_page(old_page); -+ /* copy the page now that we've got it stable */ -+ vaddr_old = kmap_atomic(old_page); -+ vaddr_new = kmap_atomic(new_page); -+ -+ memcpy(vaddr_new, vaddr_old, PAGE_SIZE); -+ -+ /* poke the new insn in, ASSUMES we don't cross page boundary */ -+ vaddr &= ~PAGE_MASK; -+ BUG_ON(vaddr + uprobe_opcode_sz > PAGE_SIZE); -+ memcpy(vaddr_new + vaddr, &opcode, uprobe_opcode_sz); -+ -+ kunmap_atomic(vaddr_new); -+ kunmap_atomic(vaddr_old); -+ -+ ret = anon_vma_prepare(vma); -+ if (ret) -+ goto unlock_out; -+ -+ lock_page(new_page); -+ ret = __replace_page(vma, old_page, new_page); -+ unlock_page(new_page); -+ -+unlock_out: -+ unlock_page(old_page); -+ page_cache_release(new_page); -+ -+put_out: -+ put_page(old_page); -+ -+ return ret; -+} -+ -+/** -+ * read_opcode - read the opcode at a given virtual address. -+ * @mm: the probed process address space. -+ * @vaddr: the virtual address to read the opcode. -+ * @opcode: location to store the read opcode. -+ * -+ * Called with mm->mmap_sem held (for read and with a reference to -+ * mm. -+ * -+ * For mm @mm, read the opcode at @vaddr and store it in @opcode. -+ * Return 0 (success) or a negative errno. -+ */ -+static int read_opcode(struct mm_struct *mm, unsigned long vaddr, uprobe_opcode_t *opcode) -+{ -+ struct page *page; -+ void *vaddr_new; -+ int ret; -+ -+ ret = get_user_pages(NULL, mm, vaddr, 1, 0, 0, &page, NULL); -+ if (ret <= 0) -+ return ret; -+ -+ lock_page(page); -+ vaddr_new = kmap_atomic(page); -+ vaddr &= ~PAGE_MASK; -+ memcpy(opcode, vaddr_new + vaddr, uprobe_opcode_sz); -+ kunmap_atomic(vaddr_new); -+ unlock_page(page); -+ -+ put_page(page); -+ -+ return 0; -+} -+ -+static int is_bkpt_at_addr(struct mm_struct *mm, unsigned long vaddr) -+{ -+ uprobe_opcode_t opcode; -+ int result; -+ -+ result = read_opcode(mm, vaddr, &opcode); -+ if (result) -+ return result; -+ -+ if (is_bkpt_insn(&opcode)) -+ return 1; -+ -+ return 0; -+} -+ -+/** -+ * set_bkpt - store breakpoint at a given address. -+ * @mm: the probed process address space. -+ * @uprobe: the probepoint information. -+ * @vaddr: the virtual address to insert the opcode. -+ * -+ * For mm @mm, store the breakpoint instruction at @vaddr. -+ * Return 0 (success) or a negative errno. -+ */ -+int __weak set_bkpt(struct mm_struct *mm, struct uprobe *uprobe, unsigned long vaddr) -+{ -+ int result; -+ -+ result = is_bkpt_at_addr(mm, vaddr); -+ if (result == 1) -+ return -EEXIST; -+ -+ if (result) -+ return result; -+ -+ return write_opcode(mm, uprobe, vaddr, UPROBES_BKPT_INSN); -+} -+ -+/** -+ * set_orig_insn - Restore the original instruction. -+ * @mm: the probed process address space. -+ * @uprobe: the probepoint information. -+ * @vaddr: the virtual address to insert the opcode. -+ * @verify: if true, verify existance of breakpoint instruction. -+ * -+ * For mm @mm, restore the original opcode (opcode) at @vaddr. -+ * Return 0 (success) or a negative errno. -+ */ -+int __weak -+set_orig_insn(struct mm_struct *mm, struct uprobe *uprobe, unsigned long vaddr, bool verify) -+{ -+ if (verify) { -+ int result; -+ -+ result = is_bkpt_at_addr(mm, vaddr); -+ if (!result) -+ return -EINVAL; -+ -+ if (result != 1) -+ return result; -+ } -+ return write_opcode(mm, uprobe, vaddr, *(uprobe_opcode_t *)uprobe->insn); -+} -+ -+static int match_uprobe(struct uprobe *l, struct uprobe *r) -+{ -+ if (l->inode < r->inode) -+ return -1; -+ -+ if (l->inode > r->inode) -+ return 1; -+ -+ if (l->offset < r->offset) -+ return -1; -+ -+ if (l->offset > r->offset) -+ return 1; -+ -+ return 0; -+} -+ -+static struct uprobe *__find_uprobe(struct inode *inode, loff_t offset) -+{ -+ struct uprobe u = { .inode = inode, .offset = offset }; -+ struct rb_node *n = uprobes_tree.rb_node; -+ struct uprobe *uprobe; -+ int match; -+ -+ while (n) { -+ uprobe = rb_entry(n, struct uprobe, rb_node); -+ match = match_uprobe(&u, uprobe); -+ if (!match) { -+ atomic_inc(&uprobe->ref); -+ return uprobe; -+ } -+ -+ if (match < 0) -+ n = n->rb_left; -+ else -+ n = n->rb_right; -+ } -+ return NULL; -+} -+ -+/* -+ * Find a uprobe corresponding to a given inode:offset -+ * Acquires uprobes_treelock -+ */ -+static struct uprobe *find_uprobe(struct inode *inode, loff_t offset) -+{ -+ struct uprobe *uprobe; -+ unsigned long flags; -+ -+ spin_lock_irqsave(&uprobes_treelock, flags); -+ uprobe = __find_uprobe(inode, offset); -+ spin_unlock_irqrestore(&uprobes_treelock, flags); -+ -+ return uprobe; -+} -+ -+static struct uprobe *__insert_uprobe(struct uprobe *uprobe) -+{ -+ struct rb_node **p = &uprobes_tree.rb_node; -+ struct rb_node *parent = NULL; -+ struct uprobe *u; -+ int match; -+ -+ while (*p) { -+ parent = *p; -+ u = rb_entry(parent, struct uprobe, rb_node); -+ match = match_uprobe(uprobe, u); -+ if (!match) { -+ atomic_inc(&u->ref); -+ return u; -+ } -+ -+ if (match < 0) -+ p = &parent->rb_left; -+ else -+ p = &parent->rb_right; -+ -+ } -+ -+ u = NULL; -+ rb_link_node(&uprobe->rb_node, parent, p); -+ rb_insert_color(&uprobe->rb_node, &uprobes_tree); -+ /* get access + creation ref */ -+ atomic_set(&uprobe->ref, 2); -+ -+ return u; -+} -+ -+/* -+ * Acquire uprobes_treelock. -+ * Matching uprobe already exists in rbtree; -+ * increment (access refcount) and return the matching uprobe. -+ * -+ * No matching uprobe; insert the uprobe in rb_tree; -+ * get a double refcount (access + creation) and return NULL. -+ */ -+static struct uprobe *insert_uprobe(struct uprobe *uprobe) -+{ -+ unsigned long flags; -+ struct uprobe *u; -+ -+ spin_lock_irqsave(&uprobes_treelock, flags); -+ u = __insert_uprobe(uprobe); -+ spin_unlock_irqrestore(&uprobes_treelock, flags); -+ -+ return u; -+} -+ -+static void put_uprobe(struct uprobe *uprobe) -+{ -+ if (atomic_dec_and_test(&uprobe->ref)) -+ kfree(uprobe); -+} -+ -+static struct uprobe *alloc_uprobe(struct inode *inode, loff_t offset) -+{ -+ struct uprobe *uprobe, *cur_uprobe; -+ -+ uprobe = kzalloc(sizeof(struct uprobe), GFP_KERNEL); -+ if (!uprobe) -+ return NULL; -+ -+ uprobe->inode = igrab(inode); -+ uprobe->offset = offset; -+ init_rwsem(&uprobe->consumer_rwsem); -+ INIT_LIST_HEAD(&uprobe->pending_list); -+ -+ /* add to uprobes_tree, sorted on inode:offset */ -+ cur_uprobe = insert_uprobe(uprobe); -+ -+ /* a uprobe exists for this inode:offset combination */ -+ if (cur_uprobe) { -+ kfree(uprobe); -+ uprobe = cur_uprobe; -+ iput(inode); -+ } else { -+ atomic_inc(&uprobe_events); -+ } -+ -+ return uprobe; -+} -+ -+/* Returns the previous consumer */ -+static struct uprobe_consumer * -+consumer_add(struct uprobe *uprobe, struct uprobe_consumer *consumer) -+{ -+ down_write(&uprobe->consumer_rwsem); -+ consumer->next = uprobe->consumers; -+ uprobe->consumers = consumer; -+ up_write(&uprobe->consumer_rwsem); -+ -+ return consumer->next; -+} -+ -+/* -+ * For uprobe @uprobe, delete the consumer @consumer. -+ * Return true if the @consumer is deleted successfully -+ * or return false. -+ */ -+static bool consumer_del(struct uprobe *uprobe, struct uprobe_consumer *consumer) -+{ -+ struct uprobe_consumer **con; -+ bool ret = false; -+ -+ down_write(&uprobe->consumer_rwsem); -+ for (con = &uprobe->consumers; *con; con = &(*con)->next) { -+ if (*con == consumer) { -+ *con = consumer->next; -+ ret = true; -+ break; -+ } -+ } -+ up_write(&uprobe->consumer_rwsem); -+ -+ return ret; -+} -+ -+static int __copy_insn(struct address_space *mapping, -+ struct vm_area_struct *vma, char *insn, -+ unsigned long nbytes, unsigned long offset) -+{ -+ struct file *filp = vma->vm_file; -+ struct page *page; -+ void *vaddr; -+ unsigned long off1; -+ unsigned long idx; -+ -+ if (!filp) -+ return -EINVAL; -+ -+ idx = (unsigned long)(offset >> PAGE_CACHE_SHIFT); -+ off1 = offset &= ~PAGE_MASK; -+ -+ /* -+ * Ensure that the page that has the original instruction is -+ * populated and in page-cache. -+ */ -+ page = read_mapping_page(mapping, idx, filp); -+ if (IS_ERR(page)) -+ return PTR_ERR(page); -+ -+ vaddr = kmap_atomic(page); -+ memcpy(insn, vaddr + off1, nbytes); -+ kunmap_atomic(vaddr); -+ page_cache_release(page); -+ -+ return 0; -+} -+ -+static int copy_insn(struct uprobe *uprobe, struct vm_area_struct *vma, unsigned long addr) -+{ -+ struct address_space *mapping; -+ unsigned long nbytes; -+ int bytes; -+ -+ addr &= ~PAGE_MASK; -+ nbytes = PAGE_SIZE - addr; -+ mapping = uprobe->inode->i_mapping; -+ -+ /* Instruction at end of binary; copy only available bytes */ -+ if (uprobe->offset + MAX_UINSN_BYTES > uprobe->inode->i_size) -+ bytes = uprobe->inode->i_size - uprobe->offset; -+ else -+ bytes = MAX_UINSN_BYTES; -+ -+ /* Instruction at the page-boundary; copy bytes in second page */ -+ if (nbytes < bytes) { -+ if (__copy_insn(mapping, vma, uprobe->insn + nbytes, -+ bytes - nbytes, uprobe->offset + nbytes)) -+ return -ENOMEM; -+ -+ bytes = nbytes; -+ } -+ return __copy_insn(mapping, vma, uprobe->insn, bytes, uprobe->offset); -+} -+ -+static int install_breakpoint(struct mm_struct *mm, struct uprobe *uprobe, -+ struct vm_area_struct *vma, loff_t vaddr) -+{ -+ unsigned long addr; -+ int ret; -+ -+ /* -+ * If probe is being deleted, unregister thread could be done with -+ * the vma-rmap-walk through. Adding a probe now can be fatal since -+ * nobody will be able to cleanup. Also we could be from fork or -+ * mremap path, where the probe might have already been inserted. -+ * Hence behave as if probe already existed. -+ */ -+ if (!uprobe->consumers) -+ return -EEXIST; -+ -+ addr = (unsigned long)vaddr; -+ -+ if (!(uprobe->flags & UPROBES_COPY_INSN)) { -+ ret = copy_insn(uprobe, vma, addr); -+ if (ret) -+ return ret; -+ -+ if (is_bkpt_insn((uprobe_opcode_t *)uprobe->insn)) -+ return -EEXIST; -+ -+ ret = arch_uprobes_analyze_insn(mm, uprobe); -+ if (ret) -+ return ret; -+ -+ uprobe->flags |= UPROBES_COPY_INSN; -+ } -+ ret = set_bkpt(mm, uprobe, addr); -+ -+ return ret; -+} -+ -+static void remove_breakpoint(struct mm_struct *mm, struct uprobe *uprobe, loff_t vaddr) -+{ -+ set_orig_insn(mm, uprobe, (unsigned long)vaddr, true); -+} -+ -+static void delete_uprobe(struct uprobe *uprobe) -+{ -+ unsigned long flags; -+ -+ spin_lock_irqsave(&uprobes_treelock, flags); -+ rb_erase(&uprobe->rb_node, &uprobes_tree); -+ spin_unlock_irqrestore(&uprobes_treelock, flags); -+ iput(uprobe->inode); -+ put_uprobe(uprobe); -+ atomic_dec(&uprobe_events); -+} -+ -+static struct vma_info *__find_next_vma_info(struct list_head *head, -+ loff_t offset, struct address_space *mapping, -+ struct vma_info *vi, bool is_register) -+{ -+ struct prio_tree_iter iter; -+ struct vm_area_struct *vma; -+ struct vma_info *tmpvi; -+ unsigned long pgoff; -+ int existing_vma; -+ loff_t vaddr; -+ -+ pgoff = offset >> PAGE_SHIFT; -+ -+ vma_prio_tree_foreach(vma, &iter, &mapping->i_mmap, pgoff, pgoff) { -+ if (!valid_vma(vma, is_register)) -+ continue; -+ -+ existing_vma = 0; -+ vaddr = vma_address(vma, offset); -+ -+ list_for_each_entry(tmpvi, head, probe_list) { -+ if (tmpvi->mm == vma->vm_mm && tmpvi->vaddr == vaddr) { -+ existing_vma = 1; -+ break; -+ } -+ } -+ -+ /* -+ * Another vma needs a probe to be installed. However skip -+ * installing the probe if the vma is about to be unlinked. -+ */ -+ if (!existing_vma && atomic_inc_not_zero(&vma->vm_mm->mm_users)) { -+ vi->mm = vma->vm_mm; -+ vi->vaddr = vaddr; -+ list_add(&vi->probe_list, head); -+ -+ return vi; -+ } -+ } -+ -+ return NULL; -+} -+ -+/* -+ * Iterate in the rmap prio tree and find a vma where a probe has not -+ * yet been inserted. -+ */ -+static struct vma_info * -+find_next_vma_info(struct list_head *head, loff_t offset, struct address_space *mapping, -+ bool is_register) -+{ -+ struct vma_info *vi, *retvi; -+ -+ vi = kzalloc(sizeof(struct vma_info), GFP_KERNEL); -+ if (!vi) -+ return ERR_PTR(-ENOMEM); -+ -+ mutex_lock(&mapping->i_mmap_mutex); -+ retvi = __find_next_vma_info(head, offset, mapping, vi, is_register); -+ mutex_unlock(&mapping->i_mmap_mutex); -+ -+ if (!retvi) -+ kfree(vi); -+ -+ return retvi; -+} -+ -+static int register_for_each_vma(struct uprobe *uprobe, bool is_register) -+{ -+ struct list_head try_list; -+ struct vm_area_struct *vma; -+ struct address_space *mapping; -+ struct vma_info *vi, *tmpvi; -+ struct mm_struct *mm; -+ loff_t vaddr; -+ int ret; -+ -+ mapping = uprobe->inode->i_mapping; -+ INIT_LIST_HEAD(&try_list); -+ -+ ret = 0; -+ -+ for (;;) { -+ vi = find_next_vma_info(&try_list, uprobe->offset, mapping, is_register); -+ if (!vi) -+ break; -+ -+ if (IS_ERR(vi)) { -+ ret = PTR_ERR(vi); -+ break; -+ } -+ -+ mm = vi->mm; -+ down_read(&mm->mmap_sem); -+ vma = find_vma(mm, (unsigned long)vi->vaddr); -+ if (!vma || !valid_vma(vma, is_register)) { -+ list_del(&vi->probe_list); -+ kfree(vi); -+ up_read(&mm->mmap_sem); -+ mmput(mm); -+ continue; -+ } -+ vaddr = vma_address(vma, uprobe->offset); -+ if (vma->vm_file->f_mapping->host != uprobe->inode || -+ vaddr != vi->vaddr) { -+ list_del(&vi->probe_list); -+ kfree(vi); -+ up_read(&mm->mmap_sem); -+ mmput(mm); -+ continue; -+ } -+ -+ if (is_register) -+ ret = install_breakpoint(mm, uprobe, vma, vi->vaddr); -+ else -+ remove_breakpoint(mm, uprobe, vi->vaddr); -+ -+ up_read(&mm->mmap_sem); -+ mmput(mm); -+ if (is_register) { -+ if (ret && ret == -EEXIST) -+ ret = 0; -+ if (ret) -+ break; -+ } -+ } -+ -+ list_for_each_entry_safe(vi, tmpvi, &try_list, probe_list) { -+ list_del(&vi->probe_list); -+ kfree(vi); -+ } -+ -+ return ret; -+} -+ -+static int __uprobe_register(struct uprobe *uprobe) -+{ -+ return register_for_each_vma(uprobe, true); -+} -+ -+static void __uprobe_unregister(struct uprobe *uprobe) -+{ -+ if (!register_for_each_vma(uprobe, false)) -+ delete_uprobe(uprobe); -+ -+ /* TODO : cant unregister? schedule a worker thread */ -+} -+ -+/* -+ * uprobe_register - register a probe -+ * @inode: the file in which the probe has to be placed. -+ * @offset: offset from the start of the file. -+ * @consumer: information on howto handle the probe.. -+ * -+ * Apart from the access refcount, uprobe_register() takes a creation -+ * refcount (thro alloc_uprobe) if and only if this @uprobe is getting -+ * inserted into the rbtree (i.e first consumer for a @inode:@offset -+ * tuple). Creation refcount stops uprobe_unregister from freeing the -+ * @uprobe even before the register operation is complete. Creation -+ * refcount is released when the last @consumer for the @uprobe -+ * unregisters. -+ * -+ * Return errno if it cannot successully install probes -+ * else return 0 (success) -+ */ -+int uprobe_register(struct inode *inode, loff_t offset, struct uprobe_consumer *consumer) -+{ -+ struct uprobe *uprobe; -+ int ret; -+ -+ if (!inode || !consumer || consumer->next) -+ return -EINVAL; -+ -+ if (offset > i_size_read(inode)) -+ return -EINVAL; -+ -+ ret = 0; -+ mutex_lock(uprobes_hash(inode)); -+ uprobe = alloc_uprobe(inode, offset); -+ -+ if (uprobe && !consumer_add(uprobe, consumer)) { -+ ret = __uprobe_register(uprobe); -+ if (ret) { -+ uprobe->consumers = NULL; -+ __uprobe_unregister(uprobe); -+ } else { -+ uprobe->flags |= UPROBES_RUN_HANDLER; -+ } -+ } -+ -+ mutex_unlock(uprobes_hash(inode)); -+ put_uprobe(uprobe); -+ -+ return ret; -+} -+ -+/* -+ * uprobe_unregister - unregister a already registered probe. -+ * @inode: the file in which the probe has to be removed. -+ * @offset: offset from the start of the file. -+ * @consumer: identify which probe if multiple probes are colocated. -+ */ -+void uprobe_unregister(struct inode *inode, loff_t offset, struct uprobe_consumer *consumer) -+{ -+ struct uprobe *uprobe; -+ -+ if (!inode || !consumer) -+ return; -+ -+ uprobe = find_uprobe(inode, offset); -+ if (!uprobe) -+ return; -+ -+ mutex_lock(uprobes_hash(inode)); -+ -+ if (consumer_del(uprobe, consumer)) { -+ if (!uprobe->consumers) { -+ __uprobe_unregister(uprobe); -+ uprobe->flags &= ~UPROBES_RUN_HANDLER; -+ } -+ } -+ -+ mutex_unlock(uprobes_hash(inode)); -+ if (uprobe) -+ put_uprobe(uprobe); -+} -+ -+/* -+ * Of all the nodes that correspond to the given inode, return the node -+ * with the least offset. -+ */ -+static struct rb_node *find_least_offset_node(struct inode *inode) -+{ -+ struct uprobe u = { .inode = inode, .offset = 0}; -+ struct rb_node *n = uprobes_tree.rb_node; -+ struct rb_node *close_node = NULL; -+ struct uprobe *uprobe; -+ int match; -+ -+ while (n) { -+ uprobe = rb_entry(n, struct uprobe, rb_node); -+ match = match_uprobe(&u, uprobe); -+ -+ if (uprobe->inode == inode) -+ close_node = n; -+ -+ if (!match) -+ return close_node; -+ -+ if (match < 0) -+ n = n->rb_left; -+ else -+ n = n->rb_right; -+ } -+ -+ return close_node; -+} -+ -+/* -+ * For a given inode, build a list of probes that need to be inserted. -+ */ -+static void build_probe_list(struct inode *inode, struct list_head *head) -+{ -+ struct uprobe *uprobe; -+ unsigned long flags; -+ struct rb_node *n; -+ -+ spin_lock_irqsave(&uprobes_treelock, flags); -+ -+ n = find_least_offset_node(inode); -+ -+ for (; n; n = rb_next(n)) { -+ uprobe = rb_entry(n, struct uprobe, rb_node); -+ if (uprobe->inode != inode) -+ break; -+ -+ list_add(&uprobe->pending_list, head); -+ atomic_inc(&uprobe->ref); -+ } -+ -+ spin_unlock_irqrestore(&uprobes_treelock, flags); -+} -+ -+/* -+ * Called from mmap_region. -+ * called with mm->mmap_sem acquired. -+ * -+ * Return -ve no if we fail to insert probes and we cannot -+ * bail-out. -+ * Return 0 otherwise. i.e: -+ * -+ * - successful insertion of probes -+ * - (or) no possible probes to be inserted. -+ * - (or) insertion of probes failed but we can bail-out. -+ */ -+int uprobe_mmap(struct vm_area_struct *vma) -+{ -+ struct list_head tmp_list; -+ struct uprobe *uprobe, *u; -+ struct inode *inode; -+ int ret; -+ -+ if (!atomic_read(&uprobe_events) || !valid_vma(vma, true)) -+ return 0; -+ -+ inode = vma->vm_file->f_mapping->host; -+ if (!inode) -+ return 0; -+ -+ INIT_LIST_HEAD(&tmp_list); -+ mutex_lock(uprobes_mmap_hash(inode)); -+ build_probe_list(inode, &tmp_list); -+ -+ ret = 0; -+ -+ list_for_each_entry_safe(uprobe, u, &tmp_list, pending_list) { -+ loff_t vaddr; -+ -+ list_del(&uprobe->pending_list); -+ if (!ret) { -+ vaddr = vma_address(vma, uprobe->offset); -+ if (vaddr >= vma->vm_start && vaddr < vma->vm_end) { -+ ret = install_breakpoint(vma->vm_mm, uprobe, vma, vaddr); -+ /* Ignore double add: */ -+ if (ret == -EEXIST) -+ ret = 0; -+ } -+ } -+ put_uprobe(uprobe); -+ } -+ -+ mutex_unlock(uprobes_mmap_hash(inode)); -+ -+ return ret; -+} -+ -+static int __init init_uprobes(void) -+{ -+ int i; -+ -+ for (i = 0; i < UPROBES_HASH_SZ; i++) { -+ mutex_init(&uprobes_mutex[i]); -+ mutex_init(&uprobes_mmap_mutex[i]); -+ } -+ return 0; -+} -+ -+static void __exit exit_uprobes(void) -+{ -+} -+ -+module_init(init_uprobes); -+module_exit(exit_uprobes); -diff --git a/kernel/uprobes.c b/kernel/uprobes.c -deleted file mode 100644 -index 884817f..0000000 ---- a/kernel/uprobes.c -+++ /dev/null -@@ -1,1011 +0,0 @@ --/* -- * User-space Probes (UProbes) -- * -- * 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. -- * -- * 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. -- * -- * You should have received a copy of the GNU General Public License -- * along with this program; if not, write to the Free Software -- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -- * -- * Copyright (C) IBM Corporation, 2008-2011 -- * Authors: -- * Srikar Dronamraju -- * Jim Keniston -- */ -- --#include <linux/kernel.h> --#include <linux/highmem.h> --#include <linux/pagemap.h> /* read_mapping_page */ --#include <linux/slab.h> --#include <linux/sched.h> --#include <linux/rmap.h> /* anon_vma_prepare */ --#include <linux/mmu_notifier.h> /* set_pte_at_notify */ --#include <linux/swap.h> /* try_to_free_swap */ -- --#include <linux/uprobes.h> -- --static struct rb_root uprobes_tree = RB_ROOT; -- --static DEFINE_SPINLOCK(uprobes_treelock); /* serialize rbtree access */ -- --#define UPROBES_HASH_SZ 13 -- --/* serialize (un)register */ --static struct mutex uprobes_mutex[UPROBES_HASH_SZ]; -- --#define uprobes_hash(v) (&uprobes_mutex[((unsigned long)(v)) % UPROBES_HASH_SZ]) -- --/* serialize uprobe->pending_list */ --static struct mutex uprobes_mmap_mutex[UPROBES_HASH_SZ]; --#define uprobes_mmap_hash(v) (&uprobes_mmap_mutex[((unsigned long)(v)) % UPROBES_HASH_SZ]) -- --/* -- * uprobe_events allows us to skip the uprobe_mmap if there are no uprobe -- * events active at this time. Probably a fine grained per inode count is -- * better? -- */ --static atomic_t uprobe_events = ATOMIC_INIT(0); -- --/* -- * Maintain a temporary per vma info that can be used to search if a vma -- * has already been handled. This structure is introduced since extending -- * vm_area_struct wasnt recommended. -- */ --struct vma_info { -- struct list_head probe_list; -- struct mm_struct *mm; -- loff_t vaddr; --}; -- --/* -- * valid_vma: Verify if the specified vma is an executable vma -- * Relax restrictions while unregistering: vm_flags might have -- * changed after breakpoint was inserted. -- * - is_register: indicates if we are in register context. -- * - Return 1 if the specified virtual address is in an -- * executable vma. -- */ --static bool valid_vma(struct vm_area_struct *vma, bool is_register) --{ -- if (!vma->vm_file) -- return false; -- -- if (!is_register) -- return true; -- -- if ((vma->vm_flags & (VM_READ|VM_WRITE|VM_EXEC|VM_SHARED)) == (VM_READ|VM_EXEC)) -- return true; -- -- return false; --} -- --static loff_t vma_address(struct vm_area_struct *vma, loff_t offset) --{ -- loff_t vaddr; -- -- vaddr = vma->vm_start + offset; -- vaddr -= vma->vm_pgoff << PAGE_SHIFT; -- -- return vaddr; --} -- --/** -- * __replace_page - replace page in vma by new page. -- * based on replace_page in mm/ksm.c -- * -- * @vma: vma that holds the pte pointing to page -- * @page: the cowed page we are replacing by kpage -- * @kpage: the modified page we replace page by -- * -- * Returns 0 on success, -EFAULT on failure. -- */ --static int __replace_page(struct vm_area_struct *vma, struct page *page, struct page *kpage) --{ -- struct mm_struct *mm = vma->vm_mm; -- pgd_t *pgd; -- pud_t *pud; -- pmd_t *pmd; -- pte_t *ptep; -- spinlock_t *ptl; -- unsigned long addr; -- int err = -EFAULT; -- -- addr = page_address_in_vma(page, vma); -- if (addr == -EFAULT) -- goto out; -- -- pgd = pgd_offset(mm, addr); -- if (!pgd_present(*pgd)) -- goto out; -- -- pud = pud_offset(pgd, addr); -- if (!pud_present(*pud)) -- goto out; -- -- pmd = pmd_offset(pud, addr); -- if (!pmd_present(*pmd)) -- goto out; -- -- ptep = pte_offset_map_lock(mm, pmd, addr, &ptl); -- if (!ptep) -- goto out; -- -- get_page(kpage); -- page_add_new_anon_rmap(kpage, vma, addr); -- -- flush_cache_page(vma, addr, pte_pfn(*ptep)); -- ptep_clear_flush(vma, addr, ptep); -- set_pte_at_notify(mm, addr, ptep, mk_pte(kpage, vma->vm_page_prot)); -- -- page_remove_rmap(page); -- if (!page_mapped(page)) -- try_to_free_swap(page); -- put_page(page); -- pte_unmap_unlock(ptep, ptl); -- err = 0; -- --out: -- return err; --} -- --/** -- * is_bkpt_insn - check if instruction is breakpoint instruction. -- * @insn: instruction to be checked. -- * Default implementation of is_bkpt_insn -- * Returns true if @insn is a breakpoint instruction. -- */ --bool __weak is_bkpt_insn(uprobe_opcode_t *insn) --{ -- return *insn == UPROBES_BKPT_INSN; --} -- --/* -- * NOTE: -- * Expect the breakpoint instruction to be the smallest size instruction for -- * the architecture. If an arch has variable length instruction and the -- * breakpoint instruction is not of the smallest length instruction -- * supported by that architecture then we need to modify read_opcode / -- * write_opcode accordingly. This would never be a problem for archs that -- * have fixed length instructions. -- */ -- --/* -- * write_opcode - write the opcode at a given virtual address. -- * @mm: the probed process address space. -- * @uprobe: the breakpointing information. -- * @vaddr: the virtual address to store the opcode. -- * @opcode: opcode to be written at @vaddr. -- * -- * Called with mm->mmap_sem held (for read and with a reference to -- * mm). -- * -- * For mm @mm, write the opcode at @vaddr. -- * Return 0 (success) or a negative errno. -- */ --static int write_opcode(struct mm_struct *mm, struct uprobe *uprobe, -- unsigned long vaddr, uprobe_opcode_t opcode) --{ -- struct page *old_page, *new_page; -- struct address_space *mapping; -- void *vaddr_old, *vaddr_new; -- struct vm_area_struct *vma; -- loff_t addr; -- int ret; -- -- /* Read the page with vaddr into memory */ -- ret = get_user_pages(NULL, mm, vaddr, 1, 0, 0, &old_page, &vma); -- if (ret <= 0) -- return ret; -- -- ret = -EINVAL; -- -- /* -- * We are interested in text pages only. Our pages of interest -- * should be mapped for read and execute only. We desist from -- * adding probes in write mapped pages since the breakpoints -- * might end up in the file copy. -- */ -- if (!valid_vma(vma, is_bkpt_insn(&opcode))) -- goto put_out; -- -- mapping = uprobe->inode->i_mapping; -- if (mapping != vma->vm_file->f_mapping) -- goto put_out; -- -- addr = vma_address(vma, uprobe->offset); -- if (vaddr != (unsigned long)addr) -- goto put_out; -- -- ret = -ENOMEM; -- new_page = alloc_page_vma(GFP_HIGHUSER_MOVABLE, vma, vaddr); -- if (!new_page) -- goto put_out; -- -- __SetPageUptodate(new_page); -- -- /* -- * lock page will serialize against do_wp_page()'s -- * PageAnon() handling -- */ -- lock_page(old_page); -- /* copy the page now that we've got it stable */ -- vaddr_old = kmap_atomic(old_page); -- vaddr_new = kmap_atomic(new_page); -- -- memcpy(vaddr_new, vaddr_old, PAGE_SIZE); -- -- /* poke the new insn in, ASSUMES we don't cross page boundary */ -- vaddr &= ~PAGE_MASK; -- BUG_ON(vaddr + uprobe_opcode_sz > PAGE_SIZE); -- memcpy(vaddr_new + vaddr, &opcode, uprobe_opcode_sz); -- -- kunmap_atomic(vaddr_new); -- kunmap_atomic(vaddr_old); -- -- ret = anon_vma_prepare(vma); -- if (ret) -- goto unlock_out; -- -- lock_page(new_page); -- ret = __replace_page(vma, old_page, new_page); -- unlock_page(new_page); -- --unlock_out: -- unlock_page(old_page); -- page_cache_release(new_page); -- --put_out: -- put_page(old_page); -- -- return ret; --} -- --/** -- * read_opcode - read the opcode at a given virtual address. -- * @mm: the probed process address space. -- * @vaddr: the virtual address to read the opcode. -- * @opcode: location to store the read opcode. -- * -- * Called with mm->mmap_sem held (for read and with a reference to -- * mm. -- * -- * For mm @mm, read the opcode at @vaddr and store it in @opcode. -- * Return 0 (success) or a negative errno. -- */ --static int read_opcode(struct mm_struct *mm, unsigned long vaddr, uprobe_opcode_t *opcode) --{ -- struct page *page; -- void *vaddr_new; -- int ret; -- -- ret = get_user_pages(NULL, mm, vaddr, 1, 0, 0, &page, NULL); -- if (ret <= 0) -- return ret; -- -- lock_page(page); -- vaddr_new = kmap_atomic(page); -- vaddr &= ~PAGE_MASK; -- memcpy(opcode, vaddr_new + vaddr, uprobe_opcode_sz); -- kunmap_atomic(vaddr_new); -- unlock_page(page); -- -- put_page(page); -- -- return 0; --} -- --static int is_bkpt_at_addr(struct mm_struct *mm, unsigned long vaddr) --{ -- uprobe_opcode_t opcode; -- int result; -- -- result = read_opcode(mm, vaddr, &opcode); -- if (result) -- return result; -- -- if (is_bkpt_insn(&opcode)) -- return 1; -- -- return 0; --} -- --/** -- * set_bkpt - store breakpoint at a given address. -- * @mm: the probed process address space. -- * @uprobe: the probepoint information. -- * @vaddr: the virtual address to insert the opcode. -- * -- * For mm @mm, store the breakpoint instruction at @vaddr. -- * Return 0 (success) or a negative errno. -- */ --int __weak set_bkpt(struct mm_struct *mm, struct uprobe *uprobe, unsigned long vaddr) --{ -- int result; -- -- result = is_bkpt_at_addr(mm, vaddr); -- if (result == 1) -- return -EEXIST; -- -- if (result) -- return result; -- -- return write_opcode(mm, uprobe, vaddr, UPROBES_BKPT_INSN); --} -- --/** -- * set_orig_insn - Restore the original instruction. -- * @mm: the probed process address space. -- * @uprobe: the probepoint information. -- * @vaddr: the virtual address to insert the opcode. -- * @verify: if true, verify existance of breakpoint instruction. -- * -- * For mm @mm, restore the original opcode (opcode) at @vaddr. -- * Return 0 (success) or a negative errno. -- */ --int __weak --set_orig_insn(struct mm_struct *mm, struct uprobe *uprobe, unsigned long vaddr, bool verify) --{ -- if (verify) { -- int result; -- -- result = is_bkpt_at_addr(mm, vaddr); -- if (!result) -- return -EINVAL; -- -- if (result != 1) -- return result; -- } -- return write_opcode(mm, uprobe, vaddr, *(uprobe_opcode_t *)uprobe->insn); --} -- --static int match_uprobe(struct uprobe *l, struct uprobe *r) --{ -- if (l->inode < r->inode) -- return -1; -- -- if (l->inode > r->inode) -- return 1; -- -- if (l->offset < r->offset) -- return -1; -- -- if (l->offset > r->offset) -- return 1; -- -- return 0; --} -- --static struct uprobe *__find_uprobe(struct inode *inode, loff_t offset) --{ -- struct uprobe u = { .inode = inode, .offset = offset }; -- struct rb_node *n = uprobes_tree.rb_node; -- struct uprobe *uprobe; -- int match; -- -- while (n) { -- uprobe = rb_entry(n, struct uprobe, rb_node); -- match = match_uprobe(&u, uprobe); -- if (!match) { -- atomic_inc(&uprobe->ref); -- return uprobe; -- } -- -- if (match < 0) -- n = n->rb_left; -- else -- n = n->rb_right; -- } -- return NULL; --} -- --/* -- * Find a uprobe corresponding to a given inode:offset -- * Acquires uprobes_treelock -- */ --static struct uprobe *find_uprobe(struct inode *inode, loff_t offset) --{ -- struct uprobe *uprobe; -- unsigned long flags; -- -- spin_lock_irqsave(&uprobes_treelock, flags); -- uprobe = __find_uprobe(inode, offset); -- spin_unlock_irqrestore(&uprobes_treelock, flags); -- -- return uprobe; --} -- --static struct uprobe *__insert_uprobe(struct uprobe *uprobe) --{ -- struct rb_node **p = &uprobes_tree.rb_node; -- struct rb_node *parent = NULL; -- struct uprobe *u; -- int match; -- -- while (*p) { -- parent = *p; -- u = rb_entry(parent, struct uprobe, rb_node); -- match = match_uprobe(uprobe, u); -- if (!match) { -- atomic_inc(&u->ref); -- return u; -- } -- -- if (match < 0) -- p = &parent->rb_left; -- else -- p = &parent->rb_right; -- -- } -- -- u = NULL; -- rb_link_node(&uprobe->rb_node, parent, p); -- rb_insert_color(&uprobe->rb_node, &uprobes_tree); -- /* get access + creation ref */ -- atomic_set(&uprobe->ref, 2); -- -- return u; --} -- --/* -- * Acquire uprobes_treelock. -- * Matching uprobe already exists in rbtree; -- * increment (access refcount) and return the matching uprobe. -- * -- * No matching uprobe; insert the uprobe in rb_tree; -- * get a double refcount (access + creation) and return NULL. -- */ --static struct uprobe *insert_uprobe(struct uprobe *uprobe) --{ -- unsigned long flags; -- struct uprobe *u; -- -- spin_lock_irqsave(&uprobes_treelock, flags); -- u = __insert_uprobe(uprobe); -- spin_unlock_irqrestore(&uprobes_treelock, flags); -- -- return u; --} -- --static void put_uprobe(struct uprobe *uprobe) --{ -- if (atomic_dec_and_test(&uprobe->ref)) -- kfree(uprobe); --} -- --static struct uprobe *alloc_uprobe(struct inode *inode, loff_t offset) --{ -- struct uprobe *uprobe, *cur_uprobe; -- -- uprobe = kzalloc(sizeof(struct uprobe), GFP_KERNEL); -- if (!uprobe) -- return NULL; -- -- uprobe->inode = igrab(inode); -- uprobe->offset = offset; -- init_rwsem(&uprobe->consumer_rwsem); -- INIT_LIST_HEAD(&uprobe->pending_list); -- -- /* add to uprobes_tree, sorted on inode:offset */ -- cur_uprobe = insert_uprobe(uprobe); -- -- /* a uprobe exists for this inode:offset combination */ -- if (cur_uprobe) { -- kfree(uprobe); -- uprobe = cur_uprobe; -- iput(inode); -- } else { -- atomic_inc(&uprobe_events); -- } -- -- return uprobe; --} -- --/* Returns the previous consumer */ --static struct uprobe_consumer * --consumer_add(struct uprobe *uprobe, struct uprobe_consumer *consumer) --{ -- down_write(&uprobe->consumer_rwsem); -- consumer->next = uprobe->consumers; -- uprobe->consumers = consumer; -- up_write(&uprobe->consumer_rwsem); -- -- return consumer->next; --} -- --/* -- * For uprobe @uprobe, delete the consumer @consumer. -- * Return true if the @consumer is deleted successfully -- * or return false. -- */ --static bool consumer_del(struct uprobe *uprobe, struct uprobe_consumer *consumer) --{ -- struct uprobe_consumer **con; -- bool ret = false; -- -- down_write(&uprobe->consumer_rwsem); -- for (con = &uprobe->consumers; *con; con = &(*con)->next) { -- if (*con == consumer) { -- *con = consumer->next; -- ret = true; -- break; -- } -- } -- up_write(&uprobe->consumer_rwsem); -- -- return ret; --} -- --static int __copy_insn(struct address_space *mapping, -- struct vm_area_struct *vma, char *insn, -- unsigned long nbytes, unsigned long offset) --{ -- struct file *filp = vma->vm_file; -- struct page *page; -- void *vaddr; -- unsigned long off1; -- unsigned long idx; -- -- if (!filp) -- return -EINVAL; -- -- idx = (unsigned long)(offset >> PAGE_CACHE_SHIFT); -- off1 = offset &= ~PAGE_MASK; -- -- /* -- * Ensure that the page that has the original instruction is -- * populated and in page-cache. -- */ -- page = read_mapping_page(mapping, idx, filp); -- if (IS_ERR(page)) -- return PTR_ERR(page); -- -- vaddr = kmap_atomic(page); -- memcpy(insn, vaddr + off1, nbytes); -- kunmap_atomic(vaddr); -- page_cache_release(page); -- -- return 0; --} -- --static int copy_insn(struct uprobe *uprobe, struct vm_area_struct *vma, unsigned long addr) --{ -- struct address_space *mapping; -- unsigned long nbytes; -- int bytes; -- -- addr &= ~PAGE_MASK; -- nbytes = PAGE_SIZE - addr; -- mapping = uprobe->inode->i_mapping; -- -- /* Instruction at end of binary; copy only available bytes */ -- if (uprobe->offset + MAX_UINSN_BYTES > uprobe->inode->i_size) -- bytes = uprobe->inode->i_size - uprobe->offset; -- else -- bytes = MAX_UINSN_BYTES; -- -- /* Instruction at the page-boundary; copy bytes in second page */ -- if (nbytes < bytes) { -- if (__copy_insn(mapping, vma, uprobe->insn + nbytes, -- bytes - nbytes, uprobe->offset + nbytes)) -- return -ENOMEM; -- -- bytes = nbytes; -- } -- return __copy_insn(mapping, vma, uprobe->insn, bytes, uprobe->offset); --} -- --static int install_breakpoint(struct mm_struct *mm, struct uprobe *uprobe, -- struct vm_area_struct *vma, loff_t vaddr) --{ -- unsigned long addr; -- int ret; -- -- /* -- * If probe is being deleted, unregister thread could be done with -- * the vma-rmap-walk through. Adding a probe now can be fatal since -- * nobody will be able to cleanup. Also we could be from fork or -- * mremap path, where the probe might have already been inserted. -- * Hence behave as if probe already existed. -- */ -- if (!uprobe->consumers) -- return -EEXIST; -- -- addr = (unsigned long)vaddr; -- -- if (!(uprobe->flags & UPROBES_COPY_INSN)) { -- ret = copy_insn(uprobe, vma, addr); -- if (ret) -- return ret; -- -- if (is_bkpt_insn((uprobe_opcode_t *)uprobe->insn)) -- return -EEXIST; -- -- ret = arch_uprobes_analyze_insn(mm, uprobe); -- if (ret) -- return ret; -- -- uprobe->flags |= UPROBES_COPY_INSN; -- } -- ret = set_bkpt(mm, uprobe, addr); -- -- return ret; --} -- --static void remove_breakpoint(struct mm_struct *mm, struct uprobe *uprobe, loff_t vaddr) --{ -- set_orig_insn(mm, uprobe, (unsigned long)vaddr, true); --} -- --static void delete_uprobe(struct uprobe *uprobe) --{ -- unsigned long flags; -- -- spin_lock_irqsave(&uprobes_treelock, flags); -- rb_erase(&uprobe->rb_node, &uprobes_tree); -- spin_unlock_irqrestore(&uprobes_treelock, flags); -- iput(uprobe->inode); -- put_uprobe(uprobe); -- atomic_dec(&uprobe_events); --} -- --static struct vma_info *__find_next_vma_info(struct list_head *head, -- loff_t offset, struct address_space *mapping, -- struct vma_info *vi, bool is_register) --{ -- struct prio_tree_iter iter; -- struct vm_area_struct *vma; -- struct vma_info *tmpvi; -- unsigned long pgoff; -- int existing_vma; -- loff_t vaddr; -- -- pgoff = offset >> PAGE_SHIFT; -- -- vma_prio_tree_foreach(vma, &iter, &mapping->i_mmap, pgoff, pgoff) { -- if (!valid_vma(vma, is_register)) -- continue; -- -- existing_vma = 0; -- vaddr = vma_address(vma, offset); -- -- list_for_each_entry(tmpvi, head, probe_list) { -- if (tmpvi->mm == vma->vm_mm && tmpvi->vaddr == vaddr) { -- existing_vma = 1; -- break; -- } -- } -- -- /* -- * Another vma needs a probe to be installed. However skip -- * installing the probe if the vma is about to be unlinked. -- */ -- if (!existing_vma && atomic_inc_not_zero(&vma->vm_mm->mm_users)) { -- vi->mm = vma->vm_mm; -- vi->vaddr = vaddr; -- list_add(&vi->probe_list, head); -- -- return vi; -- } -- } -- -- return NULL; --} -- --/* -- * Iterate in the rmap prio tree and find a vma where a probe has not -- * yet been inserted. -- */ --static struct vma_info * --find_next_vma_info(struct list_head *head, loff_t offset, struct address_space *mapping, -- bool is_register) --{ -- struct vma_info *vi, *retvi; -- -- vi = kzalloc(sizeof(struct vma_info), GFP_KERNEL); -- if (!vi) -- return ERR_PTR(-ENOMEM); -- -- mutex_lock(&mapping->i_mmap_mutex); -- retvi = __find_next_vma_info(head, offset, mapping, vi, is_register); -- mutex_unlock(&mapping->i_mmap_mutex); -- -- if (!retvi) -- kfree(vi); -- -- return retvi; --} -- --static int register_for_each_vma(struct uprobe *uprobe, bool is_register) --{ -- struct list_head try_list; -- struct vm_area_struct *vma; -- struct address_space *mapping; -- struct vma_info *vi, *tmpvi; -- struct mm_struct *mm; -- loff_t vaddr; -- int ret; -- -- mapping = uprobe->inode->i_mapping; -- INIT_LIST_HEAD(&try_list); -- -- ret = 0; -- -- for (;;) { -- vi = find_next_vma_info(&try_list, uprobe->offset, mapping, is_register); -- if (!vi) -- break; -- -- if (IS_ERR(vi)) { -- ret = PTR_ERR(vi); -- break; -- } -- -- mm = vi->mm; -- down_read(&mm->mmap_sem); -- vma = find_vma(mm, (unsigned long)vi->vaddr); -- if (!vma || !valid_vma(vma, is_register)) { -- list_del(&vi->probe_list); -- kfree(vi); -- up_read(&mm->mmap_sem); -- mmput(mm); -- continue; -- } -- vaddr = vma_address(vma, uprobe->offset); -- if (vma->vm_file->f_mapping->host != uprobe->inode || -- vaddr != vi->vaddr) { -- list_del(&vi->probe_list); -- kfree(vi); -- up_read(&mm->mmap_sem); -- mmput(mm); -- continue; -- } -- -- if (is_register) -- ret = install_breakpoint(mm, uprobe, vma, vi->vaddr); -- else -- remove_breakpoint(mm, uprobe, vi->vaddr); -- -- up_read(&mm->mmap_sem); -- mmput(mm); -- if (is_register) { -- if (ret && ret == -EEXIST) -- ret = 0; -- if (ret) -- break; -- } -- } -- -- list_for_each_entry_safe(vi, tmpvi, &try_list, probe_list) { -- list_del(&vi->probe_list); -- kfree(vi); -- } -- -- return ret; --} -- --static int __uprobe_register(struct uprobe *uprobe) --{ -- return register_for_each_vma(uprobe, true); --} -- --static void __uprobe_unregister(struct uprobe *uprobe) --{ -- if (!register_for_each_vma(uprobe, false)) -- delete_uprobe(uprobe); -- -- /* TODO : cant unregister? schedule a worker thread */ --} -- --/* -- * uprobe_register - register a probe -- * @inode: the file in which the probe has to be placed. -- * @offset: offset from the start of the file. -- * @consumer: information on howto handle the probe.. -- * -- * Apart from the access refcount, uprobe_register() takes a creation -- * refcount (thro alloc_uprobe) if and only if this @uprobe is getting -- * inserted into the rbtree (i.e first consumer for a @inode:@offset -- * tuple). Creation refcount stops uprobe_unregister from freeing the -- * @uprobe even before the register operation is complete. Creation -- * refcount is released when the last @consumer for the @uprobe -- * unregisters. -- * -- * Return errno if it cannot successully install probes -- * else return 0 (success) -- */ --int uprobe_register(struct inode *inode, loff_t offset, struct uprobe_consumer *consumer) --{ -- struct uprobe *uprobe; -- int ret; -- -- if (!inode || !consumer || consumer->next) -- return -EINVAL; -- -- if (offset > i_size_read(inode)) -- return -EINVAL; -- -- ret = 0; -- mutex_lock(uprobes_hash(inode)); -- uprobe = alloc_uprobe(inode, offset); -- -- if (uprobe && !consumer_add(uprobe, consumer)) { -- ret = __uprobe_register(uprobe); -- if (ret) { -- uprobe->consumers = NULL; -- __uprobe_unregister(uprobe); -- } else { -- uprobe->flags |= UPROBES_RUN_HANDLER; -- } -- } -- -- mutex_unlock(uprobes_hash(inode)); -- put_uprobe(uprobe); -- -- return ret; --} -- --/* -- * uprobe_unregister - unregister a already registered probe. -- * @inode: the file in which the probe has to be removed. -- * @offset: offset from the start of the file. -- * @consumer: identify which probe if multiple probes are colocated. -- */ --void uprobe_unregister(struct inode *inode, loff_t offset, struct uprobe_consumer *consumer) --{ -- struct uprobe *uprobe; -- -- if (!inode || !consumer) -- return; -- -- uprobe = find_uprobe(inode, offset); -- if (!uprobe) -- return; -- -- mutex_lock(uprobes_hash(inode)); -- -- if (consumer_del(uprobe, consumer)) { -- if (!uprobe->consumers) { -- __uprobe_unregister(uprobe); -- uprobe->flags &= ~UPROBES_RUN_HANDLER; -- } -- } -- -- mutex_unlock(uprobes_hash(inode)); -- if (uprobe) -- put_uprobe(uprobe); --} -- --/* -- * Of all the nodes that correspond to the given inode, return the node -- * with the least offset. -- */ --static struct rb_node *find_least_offset_node(struct inode *inode) --{ -- struct uprobe u = { .inode = inode, .offset = 0}; -- struct rb_node *n = uprobes_tree.rb_node; -- struct rb_node *close_node = NULL; -- struct uprobe *uprobe; -- int match; -- -- while (n) { -- uprobe = rb_entry(n, struct uprobe, rb_node); -- match = match_uprobe(&u, uprobe); -- -- if (uprobe->inode == inode) -- close_node = n; -- -- if (!match) -- return close_node; -- -- if (match < 0) -- n = n->rb_left; -- else -- n = n->rb_right; -- } -- -- return close_node; --} -- --/* -- * For a given inode, build a list of probes that need to be inserted. -- */ --static void build_probe_list(struct inode *inode, struct list_head *head) --{ -- struct uprobe *uprobe; -- unsigned long flags; -- struct rb_node *n; -- -- spin_lock_irqsave(&uprobes_treelock, flags); -- -- n = find_least_offset_node(inode); -- -- for (; n; n = rb_next(n)) { -- uprobe = rb_entry(n, struct uprobe, rb_node); -- if (uprobe->inode != inode) -- break; -- -- list_add(&uprobe->pending_list, head); -- atomic_inc(&uprobe->ref); -- } -- -- spin_unlock_irqrestore(&uprobes_treelock, flags); --} -- --/* -- * Called from mmap_region. -- * called with mm->mmap_sem acquired. -- * -- * Return -ve no if we fail to insert probes and we cannot -- * bail-out. -- * Return 0 otherwise. i.e: -- * -- * - successful insertion of probes -- * - (or) no possible probes to be inserted. -- * - (or) insertion of probes failed but we can bail-out. -- */ --int uprobe_mmap(struct vm_area_struct *vma) --{ -- struct list_head tmp_list; -- struct uprobe *uprobe, *u; -- struct inode *inode; -- int ret; -- -- if (!atomic_read(&uprobe_events) || !valid_vma(vma, true)) -- return 0; -- -- inode = vma->vm_file->f_mapping->host; -- if (!inode) -- return 0; -- -- INIT_LIST_HEAD(&tmp_list); -- mutex_lock(uprobes_mmap_hash(inode)); -- build_probe_list(inode, &tmp_list); -- -- ret = 0; -- -- list_for_each_entry_safe(uprobe, u, &tmp_list, pending_list) { -- loff_t vaddr; -- -- list_del(&uprobe->pending_list); -- if (!ret) { -- vaddr = vma_address(vma, uprobe->offset); -- if (vaddr >= vma->vm_start && vaddr < vma->vm_end) { -- ret = install_breakpoint(vma->vm_mm, uprobe, vma, vaddr); -- /* Ignore double add: */ -- if (ret == -EEXIST) -- ret = 0; -- } -- } -- put_uprobe(uprobe); -- } -- -- mutex_unlock(uprobes_mmap_hash(inode)); -- -- return ret; --} -- --static int __init init_uprobes(void) --{ -- int i; -- -- for (i = 0; i < UPROBES_HASH_SZ; i++) { -- mutex_init(&uprobes_mutex[i]); -- mutex_init(&uprobes_mmap_mutex[i]); -- } -- return 0; --} -- --static void __exit exit_uprobes(void) --{ --} -- --module_init(init_uprobes); --module_exit(exit_uprobes); --- -1.7.5.4 - diff --git a/features/uprobe/uprobes-Update-copyright-notices.patch b/features/uprobe/uprobes-Update-copyright-notices.patch deleted file mode 100644 index 046b94def26a9200865d6be79694de752da75981..0000000000000000000000000000000000000000 --- a/features/uprobe/uprobes-Update-copyright-notices.patch +++ /dev/null @@ -1,62 +0,0 @@ -From c4247f2d15fa6250ae4397687807396ff1246955 Mon Sep 17 00:00:00 2001 -From: Ingo Molnar <mingo@elte.hu> -Date: Wed, 22 Feb 2012 11:37:29 +0100 -Subject: [PATCH 07/24] uprobes: Update copyright notices - -Add Peter Zijlstra's copyright to the uprobes code, whose -contributions to the uprobes code are not visible in the Git -history, because they were backmerged. - -Also update existing copyright notices to the year 2012. - -commit 35aa621b5ab9d08767f7bc8d209b696df281d715 upstream - -Acked-by: Srikar Dronamraju <srikar@linux.vnet.ibm.com> -Cc: Peter Zijlstra <a.p.zijlstra@chello.nl> -Cc: Ananth N Mavinakayanahalli <ananth@in.ibm.com> -Cc: Jim Keniston <jkenisto@linux.vnet.ibm.com> -Link: http://lkml.kernel.org/n/tip-vjqxst502pc1efz7ah8cyht4@git.kernel.org -Signed-off-by: Ingo Molnar <mingo@elte.hu> -Signed-off-by: Paul Barrette <paul.barrette@windriver.com> ---- - include/linux/uprobes.h | 3 ++- - kernel/events/uprobes.c | 3 ++- - 2 files changed, 4 insertions(+), 2 deletions(-) - -diff --git a/include/linux/uprobes.h b/include/linux/uprobes.h -index 9c6be62..f85797e 100644 ---- a/include/linux/uprobes.h -+++ b/include/linux/uprobes.h -@@ -17,10 +17,11 @@ - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - * -- * Copyright (C) IBM Corporation, 2008-2011 -+ * Copyright (C) IBM Corporation, 2008-2012 - * Authors: - * Srikar Dronamraju - * Jim Keniston -+ * Copyright (C) 2011-2012 Red Hat, Inc., Peter Zijlstra <pzijlstr@redhat.com> - */ - - #include <linux/errno.h> -diff --git a/kernel/events/uprobes.c b/kernel/events/uprobes.c -index 13f1b59..5ce32e3 100644 ---- a/kernel/events/uprobes.c -+++ b/kernel/events/uprobes.c -@@ -15,10 +15,11 @@ - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - * -- * Copyright (C) IBM Corporation, 2008-2011 -+ * Copyright (C) IBM Corporation, 2008-2012 - * Authors: - * Srikar Dronamraju - * Jim Keniston -+ * Copyright (C) 2011-2012 Red Hat, Inc., Peter Zijlstra <pzijlstr@redhat.com> - */ - - #include <linux/kernel.h> --- -1.7.5.4 - diff --git a/features/uprobe/uprobes-core-Allocate-XOL-slots-for-uprobes-use.patch b/features/uprobe/uprobes-core-Allocate-XOL-slots-for-uprobes-use.patch deleted file mode 100644 index 41a6da421ed8380fecb00c1c804d41d679bb1adb..0000000000000000000000000000000000000000 --- a/features/uprobe/uprobes-core-Allocate-XOL-slots-for-uprobes-use.patch +++ /dev/null @@ -1,414 +0,0 @@ -From 20f3d76f4cb4bca02796181c4eedb2406fd1c2b7 Mon Sep 17 00:00:00 2001 -From: Srikar Dronamraju <srikar@linux.vnet.ibm.com> -Date: Fri, 30 Mar 2012 23:56:31 +0530 -Subject: [PATCH 12/24] uprobes/core: Allocate XOL slots for uprobes use - -Uprobes executes the original instruction at a probed location -out of line. For this, we allocate a page (per mm) upon the -first uprobe hit, in the process user address space, divide it -into slots that are used to store the actual instructions to be -singlestepped. These slots are known as xol (execution out of -line) slots. - -Care is taken to ensure that the allocation is in an unmapped -area as close to the top of the user address space as possible, -with appropriate permission settings to keep selinux like -frameworks happy. - -Upon a uprobe hit, a free slot is acquired, and is released -after the singlestep completes. - -Lots of improvements courtesy suggestions/inputs from Peter and -Oleg. - -[ Folded a fix for build issue on powerpc fixed and reported by - Stephen Rothwell. ] - -commit d4b3b6384f98f8692ad0209891ccdbc7e78bbefe upstream - -Signed-off-by: Srikar Dronamraju <srikar@linux.vnet.ibm.com> -Cc: Linus Torvalds <torvalds@linux-foundation.org> -Cc: Ananth N Mavinakayanahalli <ananth@in.ibm.com> -Cc: Jim Keniston <jkenisto@linux.vnet.ibm.com> -Cc: Linux-mm <linux-mm@kvack.org> -Cc: Oleg Nesterov <oleg@redhat.com> -Cc: Andi Kleen <andi@firstfloor.org> -Cc: Christoph Hellwig <hch@infradead.org> -Cc: Steven Rostedt <rostedt@goodmis.org> -Cc: Arnaldo Carvalho de Melo <acme@infradead.org> -Cc: Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com> -Cc: Anton Arapov <anton@redhat.com> -Cc: Peter Zijlstra <peterz@infradead.org> -Link: http://lkml.kernel.org/r/20120330182631.10018.48175.sendpatchset@srdronam.in.ibm.com -Signed-off-by: Ingo Molnar <mingo@kernel.org> -Signed-off-by: Paul Barrette <paul.barrette@windriver.com> ---- - include/linux/mm_types.h | 2 + - include/linux/uprobes.h | 34 +++++++ - kernel/events/uprobes.c | 215 ++++++++++++++++++++++++++++++++++++++++++++++ - kernel/fork.c | 2 + - 4 files changed, 253 insertions(+), 0 deletions(-) - -diff --git a/include/linux/mm_types.h b/include/linux/mm_types.h -index b35752f..f773215 100644 ---- a/include/linux/mm_types.h -+++ b/include/linux/mm_types.h -@@ -12,6 +12,7 @@ - #include <linux/completion.h> - #include <linux/cpumask.h> - #include <linux/page-debug-flags.h> -+#include <linux/uprobes.h> - #include <asm/page.h> - #include <asm/mmu.h> - -@@ -398,6 +399,7 @@ struct mm_struct { - #ifdef CONFIG_CPUMASK_OFFSTACK - struct cpumask cpumask_allocation; - #endif -+ struct uprobes_state uprobes_state; - }; - - static inline void mm_init_cpumask(struct mm_struct *mm) -diff --git a/include/linux/uprobes.h b/include/linux/uprobes.h -index 5ec778f..a111460 100644 ---- a/include/linux/uprobes.h -+++ b/include/linux/uprobes.h -@@ -28,6 +28,8 @@ - #include <linux/rbtree.h> - - struct vm_area_struct; -+struct mm_struct; -+struct inode; - - #ifdef CONFIG_ARCH_SUPPORTS_UPROBES - # include <asm/uprobes.h> -@@ -76,6 +78,28 @@ struct uprobe_task { - unsigned long vaddr; - }; - -+/* -+ * On a breakpoint hit, thread contests for a slot. It frees the -+ * slot after singlestep. Currently a fixed number of slots are -+ * allocated. -+ */ -+struct xol_area { -+ wait_queue_head_t wq; /* if all slots are busy */ -+ atomic_t slot_count; /* number of in-use slots */ -+ unsigned long *bitmap; /* 0 = free slot */ -+ struct page *page; -+ -+ /* -+ * We keep the vma's vm_start rather than a pointer to the vma -+ * itself. The probed process or a naughty kernel module could make -+ * the vma go away, and we must handle that reasonably gracefully. -+ */ -+ unsigned long vaddr; /* Page(s) of instruction slots */ -+}; -+ -+struct uprobes_state { -+ struct xol_area *xol_area; -+}; - extern int __weak set_swbp(struct arch_uprobe *aup, struct mm_struct *mm, unsigned long vaddr); - extern int __weak set_orig_insn(struct arch_uprobe *aup, struct mm_struct *mm, unsigned long vaddr, bool verify); - extern bool __weak is_swbp_insn(uprobe_opcode_t *insn); -@@ -90,7 +114,11 @@ extern int uprobe_pre_sstep_notifier(struct pt_regs *regs); - extern void uprobe_notify_resume(struct pt_regs *regs); - extern bool uprobe_deny_signal(void); - extern bool __weak arch_uprobe_skip_sstep(struct arch_uprobe *aup, struct pt_regs *regs); -+extern void uprobe_clear_state(struct mm_struct *mm); -+extern void uprobe_reset_state(struct mm_struct *mm); - #else /* !CONFIG_UPROBES */ -+struct uprobes_state { -+}; - static inline int - uprobe_register(struct inode *inode, loff_t offset, struct uprobe_consumer *uc) - { -@@ -121,5 +149,11 @@ static inline void uprobe_free_utask(struct task_struct *t) - static inline void uprobe_copy_process(struct task_struct *t) - { - } -+static inline void uprobe_clear_state(struct mm_struct *mm) -+{ -+} -+static inline void uprobe_reset_state(struct mm_struct *mm) -+{ -+} - #endif /* !CONFIG_UPROBES */ - #endif /* _LINUX_UPROBES_H */ -diff --git a/kernel/events/uprobes.c b/kernel/events/uprobes.c -index b807d15..b395edb 100644 ---- a/kernel/events/uprobes.c -+++ b/kernel/events/uprobes.c -@@ -35,6 +35,9 @@ - - #include <linux/uprobes.h> - -+#define UINSNS_PER_PAGE (PAGE_SIZE/UPROBE_XOL_SLOT_BYTES) -+#define MAX_UPROBE_XOL_SLOTS UINSNS_PER_PAGE -+ - static struct srcu_struct uprobes_srcu; - static struct rb_root uprobes_tree = RB_ROOT; - -@@ -1042,6 +1045,213 @@ int uprobe_mmap(struct vm_area_struct *vma) - return ret; - } - -+/* Slot allocation for XOL */ -+static int xol_add_vma(struct xol_area *area) -+{ -+ struct mm_struct *mm; -+ int ret; -+ -+ area->page = alloc_page(GFP_HIGHUSER); -+ if (!area->page) -+ return -ENOMEM; -+ -+ ret = -EALREADY; -+ mm = current->mm; -+ -+ down_write(&mm->mmap_sem); -+ if (mm->uprobes_state.xol_area) -+ goto fail; -+ -+ ret = -ENOMEM; -+ -+ /* Try to map as high as possible, this is only a hint. */ -+ area->vaddr = get_unmapped_area(NULL, TASK_SIZE - PAGE_SIZE, PAGE_SIZE, 0, 0); -+ if (area->vaddr & ~PAGE_MASK) { -+ ret = area->vaddr; -+ goto fail; -+ } -+ -+ ret = install_special_mapping(mm, area->vaddr, PAGE_SIZE, -+ VM_EXEC|VM_MAYEXEC|VM_DONTCOPY|VM_IO, &area->page); -+ if (ret) -+ goto fail; -+ -+ smp_wmb(); /* pairs with get_xol_area() */ -+ mm->uprobes_state.xol_area = area; -+ ret = 0; -+ -+fail: -+ up_write(&mm->mmap_sem); -+ if (ret) -+ __free_page(area->page); -+ -+ return ret; -+} -+ -+static struct xol_area *get_xol_area(struct mm_struct *mm) -+{ -+ struct xol_area *area; -+ -+ area = mm->uprobes_state.xol_area; -+ smp_read_barrier_depends(); /* pairs with wmb in xol_add_vma() */ -+ -+ return area; -+} -+ -+/* -+ * xol_alloc_area - Allocate process's xol_area. -+ * This area will be used for storing instructions for execution out of -+ * line. -+ * -+ * Returns the allocated area or NULL. -+ */ -+static struct xol_area *xol_alloc_area(void) -+{ -+ struct xol_area *area; -+ -+ area = kzalloc(sizeof(*area), GFP_KERNEL); -+ if (unlikely(!area)) -+ return NULL; -+ -+ area->bitmap = kzalloc(BITS_TO_LONGS(UINSNS_PER_PAGE) * sizeof(long), GFP_KERNEL); -+ -+ if (!area->bitmap) -+ goto fail; -+ -+ init_waitqueue_head(&area->wq); -+ if (!xol_add_vma(area)) -+ return area; -+ -+fail: -+ kfree(area->bitmap); -+ kfree(area); -+ -+ return get_xol_area(current->mm); -+} -+ -+/* -+ * uprobe_clear_state - Free the area allocated for slots. -+ */ -+void uprobe_clear_state(struct mm_struct *mm) -+{ -+ struct xol_area *area = mm->uprobes_state.xol_area; -+ -+ if (!area) -+ return; -+ -+ put_page(area->page); -+ kfree(area->bitmap); -+ kfree(area); -+} -+ -+/* -+ * uprobe_reset_state - Free the area allocated for slots. -+ */ -+void uprobe_reset_state(struct mm_struct *mm) -+{ -+ mm->uprobes_state.xol_area = NULL; -+} -+ -+/* -+ * - search for a free slot. -+ */ -+static unsigned long xol_take_insn_slot(struct xol_area *area) -+{ -+ unsigned long slot_addr; -+ int slot_nr; -+ -+ do { -+ slot_nr = find_first_zero_bit(area->bitmap, UINSNS_PER_PAGE); -+ if (slot_nr < UINSNS_PER_PAGE) { -+ if (!test_and_set_bit(slot_nr, area->bitmap)) -+ break; -+ -+ slot_nr = UINSNS_PER_PAGE; -+ continue; -+ } -+ wait_event(area->wq, (atomic_read(&area->slot_count) < UINSNS_PER_PAGE)); -+ } while (slot_nr >= UINSNS_PER_PAGE); -+ -+ slot_addr = area->vaddr + (slot_nr * UPROBE_XOL_SLOT_BYTES); -+ atomic_inc(&area->slot_count); -+ -+ return slot_addr; -+} -+ -+/* -+ * xol_get_insn_slot - If was not allocated a slot, then -+ * allocate a slot. -+ * Returns the allocated slot address or 0. -+ */ -+static unsigned long xol_get_insn_slot(struct uprobe *uprobe, unsigned long slot_addr) -+{ -+ struct xol_area *area; -+ unsigned long offset; -+ void *vaddr; -+ -+ area = get_xol_area(current->mm); -+ if (!area) { -+ area = xol_alloc_area(); -+ if (!area) -+ return 0; -+ } -+ current->utask->xol_vaddr = xol_take_insn_slot(area); -+ -+ /* -+ * Initialize the slot if xol_vaddr points to valid -+ * instruction slot. -+ */ -+ if (unlikely(!current->utask->xol_vaddr)) -+ return 0; -+ -+ current->utask->vaddr = slot_addr; -+ offset = current->utask->xol_vaddr & ~PAGE_MASK; -+ vaddr = kmap_atomic(area->page); -+ memcpy(vaddr + offset, uprobe->arch.insn, MAX_UINSN_BYTES); -+ kunmap_atomic(vaddr); -+ -+ return current->utask->xol_vaddr; -+} -+ -+/* -+ * xol_free_insn_slot - If slot was earlier allocated by -+ * @xol_get_insn_slot(), make the slot available for -+ * subsequent requests. -+ */ -+static void xol_free_insn_slot(struct task_struct *tsk) -+{ -+ struct xol_area *area; -+ unsigned long vma_end; -+ unsigned long slot_addr; -+ -+ if (!tsk->mm || !tsk->mm->uprobes_state.xol_area || !tsk->utask) -+ return; -+ -+ slot_addr = tsk->utask->xol_vaddr; -+ -+ if (unlikely(!slot_addr || IS_ERR_VALUE(slot_addr))) -+ return; -+ -+ area = tsk->mm->uprobes_state.xol_area; -+ vma_end = area->vaddr + PAGE_SIZE; -+ if (area->vaddr <= slot_addr && slot_addr < vma_end) { -+ unsigned long offset; -+ int slot_nr; -+ -+ offset = slot_addr - area->vaddr; -+ slot_nr = offset / UPROBE_XOL_SLOT_BYTES; -+ if (slot_nr >= UINSNS_PER_PAGE) -+ return; -+ -+ clear_bit(slot_nr, area->bitmap); -+ atomic_dec(&area->slot_count); -+ if (waitqueue_active(&area->wq)) -+ wake_up(&area->wq); -+ -+ tsk->utask->xol_vaddr = 0; -+ } -+} -+ - /** - * uprobe_get_swbp_addr - compute address of swbp given post-swbp regs - * @regs: Reflects the saved state of the task after it has hit a breakpoint -@@ -1070,6 +1280,7 @@ void uprobe_free_utask(struct task_struct *t) - if (utask->active_uprobe) - put_uprobe(utask->active_uprobe); - -+ xol_free_insn_slot(t); - kfree(utask); - t->utask = NULL; - } -@@ -1108,6 +1319,9 @@ static struct uprobe_task *add_utask(void) - static int - pre_ssout(struct uprobe *uprobe, struct pt_regs *regs, unsigned long vaddr) - { -+ if (xol_get_insn_slot(uprobe, vaddr) && !arch_uprobe_pre_xol(&uprobe->arch, regs)) -+ return 0; -+ - return -EFAULT; - } - -@@ -1252,6 +1466,7 @@ static void handle_singlestep(struct uprobe_task *utask, struct pt_regs *regs) - utask->active_uprobe = NULL; - utask->state = UTASK_RUNNING; - user_disable_single_step(current); -+ xol_free_insn_slot(current); - - spin_lock_irq(¤t->sighand->siglock); - recalc_sigpending(); /* see uprobe_deny_signal() */ -diff --git a/kernel/fork.c b/kernel/fork.c -index 5be9230..5fa2cbf 100644 ---- a/kernel/fork.c -+++ b/kernel/fork.c -@@ -574,6 +574,7 @@ void mmput(struct mm_struct *mm) - might_sleep(); - - if (atomic_dec_and_test(&mm->mm_users)) { -+ uprobe_clear_state(mm); - exit_aio(mm); - ksm_exit(mm); - khugepaged_exit(mm); /* must run before exit_mmap */ -@@ -808,6 +809,7 @@ struct mm_struct *dup_mm(struct task_struct *tsk) - #ifdef CONFIG_TRANSPARENT_HUGEPAGE - mm->pmd_huge_pte = NULL; - #endif -+ uprobe_reset_state(mm); - - if (!mm_init(mm, tsk)) - goto fail_nomem; --- -1.7.5.4 - diff --git a/features/uprobe/uprobes-core-Clean-up-refactor-and-improve-the-code.patch b/features/uprobe/uprobes-core-Clean-up-refactor-and-improve-the-code.patch deleted file mode 100644 index 7ef73ef9849576faed7edebd9cab6631a0488af2..0000000000000000000000000000000000000000 --- a/features/uprobe/uprobes-core-Clean-up-refactor-and-improve-the-code.patch +++ /dev/null @@ -1,1159 +0,0 @@ -From 0a7ad1cefe170125c2ee7cb04a03410848c4a48a Mon Sep 17 00:00:00 2001 -From: Ingo Molnar <mingo@elte.hu> -Date: Fri, 17 Feb 2012 09:27:41 +0100 -Subject: [PATCH 02/24] uprobes/core: Clean up, refactor and improve the code - -Make the uprobes code readable to me: - - - improve the Kconfig text so that a mere mortal gets some idea - what CONFIG_UPROBES=y is really about - - - do trivial renames to standardize around the uprobes_*() namespace - - - clean up and simplify various code flow details - - - separate basic blocks of functionality - - - line break artifact and white space related removal - - - use standard local varible definition blocks - - - use vertical spacing to make things more readable - - - remove unnecessary volatile - - - restructure comment blocks to make them more uniform and - more readable in general - -commit 7b2d81d48a2d8e37efb6ce7b4d5ef58822b30d89 upstream - -Cc: Srikar Dronamraju <srikar@linux.vnet.ibm.com> -Cc: Jim Keniston <jkenisto@us.ibm.com> -Cc: Peter Zijlstra <a.p.zijlstra@chello.nl> -Cc: Oleg Nesterov <oleg@redhat.com> -Cc: Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com> -Cc: Arnaldo Carvalho de Melo <acme@infradead.org> -Cc: Anton Arapov <anton@redhat.com> -Cc: Ananth N Mavinakayanahalli <ananth@in.ibm.com> -Link: http://lkml.kernel.org/n/tip-ewbwhb8o6navvllsauu7k07p@git.kernel.org -Signed-off-by: Ingo Molnar <mingo@elte.hu> -Signed-off-by: Paul Barrette <paul.barrette@windriver.com> ---- - arch/Kconfig | 14 ++- - arch/x86/include/asm/uprobes.h | 17 ++-- - arch/x86/kernel/uprobes.c | 129 ++++++++++++----------- - include/linux/uprobes.h | 28 +++--- - kernel/uprobes.c | 219 +++++++++++++++++++++++----------------- - mm/mmap.c | 12 +- - 6 files changed, 233 insertions(+), 186 deletions(-) - -diff --git a/arch/Kconfig b/arch/Kconfig -index 5083bf2..b78bf33 100644 ---- a/arch/Kconfig -+++ b/arch/Kconfig -@@ -77,13 +77,19 @@ config OPTPROBES - depends on !PREEMPT - - config UPROBES -- bool "User-space probes (EXPERIMENTAL)" -+ bool "Transparent user-space probes (EXPERIMENTAL)" - depends on ARCH_SUPPORTS_UPROBES - default n - help -- Uprobes enables kernel subsystems to establish probepoints -- in user applications and execute handler functions when -- the probepoints are hit. -+ Uprobes is the user-space counterpart to kprobes: they -+ enable instrumentation applications (such as 'perf probe') -+ to establish unintrusive probes in user-space binaries and -+ libraries, by executing handler functions when the probes -+ are hit by user-space applications. -+ -+ ( These probes come in the form of single-byte breakpoints, -+ managed by the kernel and kept transparent to the probed -+ application. ) - - If in doubt, say "N". - -diff --git a/arch/x86/include/asm/uprobes.h b/arch/x86/include/asm/uprobes.h -index 8208234..072df39 100644 ---- a/arch/x86/include/asm/uprobes.h -+++ b/arch/x86/include/asm/uprobes.h -@@ -1,7 +1,7 @@ - #ifndef _ASM_UPROBES_H - #define _ASM_UPROBES_H - /* -- * Userspace Probes (UProbes) for x86 -+ * User-space Probes (UProbes) for x86 - * - * 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 -@@ -24,19 +24,20 @@ - */ - - typedef u8 uprobe_opcode_t; --#define MAX_UINSN_BYTES 16 --#define UPROBES_XOL_SLOT_BYTES 128 /* to keep it cache aligned */ - --#define UPROBES_BKPT_INSN 0xcc --#define UPROBES_BKPT_INSN_SIZE 1 -+#define MAX_UINSN_BYTES 16 -+#define UPROBES_XOL_SLOT_BYTES 128 /* to keep it cache aligned */ -+ -+#define UPROBES_BKPT_INSN 0xcc -+#define UPROBES_BKPT_INSN_SIZE 1 - - struct uprobe_arch_info { -- u16 fixups; -+ u16 fixups; - #ifdef CONFIG_X86_64 -- unsigned long rip_rela_target_address; -+ unsigned long rip_rela_target_address; - #endif - }; - - struct uprobe; --extern int analyze_insn(struct mm_struct *mm, struct uprobe *uprobe); -+extern int arch_uprobes_analyze_insn(struct mm_struct *mm, struct uprobe *uprobe); - #endif /* _ASM_UPROBES_H */ -diff --git a/arch/x86/kernel/uprobes.c b/arch/x86/kernel/uprobes.c -index 2a301bb..cf2a184 100644 ---- a/arch/x86/kernel/uprobes.c -+++ b/arch/x86/kernel/uprobes.c -@@ -1,5 +1,5 @@ - /* -- * Userspace Probes (UProbes) for x86 -+ * User-space Probes (UProbes) for x86 - * - * 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 -@@ -20,7 +20,6 @@ - * Srikar Dronamraju - * Jim Keniston - */ -- - #include <linux/kernel.h> - #include <linux/sched.h> - #include <linux/ptrace.h> -@@ -42,10 +41,10 @@ - #define UPROBES_FIX_RIP_CX 0x4000 - - /* Adaptations for mhiramat x86 decoder v14. */ --#define OPCODE1(insn) ((insn)->opcode.bytes[0]) --#define OPCODE2(insn) ((insn)->opcode.bytes[1]) --#define OPCODE3(insn) ((insn)->opcode.bytes[2]) --#define MODRM_REG(insn) X86_MODRM_REG(insn->modrm.value) -+#define OPCODE1(insn) ((insn)->opcode.bytes[0]) -+#define OPCODE2(insn) ((insn)->opcode.bytes[1]) -+#define OPCODE3(insn) ((insn)->opcode.bytes[2]) -+#define MODRM_REG(insn) X86_MODRM_REG(insn->modrm.value) - - #define W(row, b0, b1, b2, b3, b4, b5, b6, b7, b8, b9, ba, bb, bc, bd, be, bf)\ - (((b0##UL << 0x0)|(b1##UL << 0x1)|(b2##UL << 0x2)|(b3##UL << 0x3) | \ -@@ -55,7 +54,7 @@ - << (row % 32)) - - #ifdef CONFIG_X86_64 --static volatile u32 good_insns_64[256 / 32] = { -+static u32 good_insns_64[256 / 32] = { - /* 0 1 2 3 4 5 6 7 8 9 a b c d e f */ - /* ---------------------------------------------- */ - W(0x00, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0) | /* 00 */ -@@ -81,7 +80,7 @@ static volatile u32 good_insns_64[256 / 32] = { - - /* Good-instruction tables for 32-bit apps */ - --static volatile u32 good_insns_32[256 / 32] = { -+static u32 good_insns_32[256 / 32] = { - /* 0 1 2 3 4 5 6 7 8 9 a b c d e f */ - /* ---------------------------------------------- */ - W(0x00, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 0) | /* 00 */ -@@ -105,7 +104,7 @@ static volatile u32 good_insns_32[256 / 32] = { - }; - - /* Using this for both 64-bit and 32-bit apps */ --static volatile u32 good_2byte_insns[256 / 32] = { -+static u32 good_2byte_insns[256 / 32] = { - /* 0 1 2 3 4 5 6 7 8 9 a b c d e f */ - /* ---------------------------------------------- */ - W(0x00, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1) | /* 00 */ -@@ -132,42 +131,47 @@ static volatile u32 good_2byte_insns[256 / 32] = { - - /* - * opcodes we'll probably never support: -- * 6c-6d, e4-e5, ec-ed - in -- * 6e-6f, e6-e7, ee-ef - out -- * cc, cd - int3, int -- * cf - iret -- * d6 - illegal instruction -- * f1 - int1/icebp -- * f4 - hlt -- * fa, fb - cli, sti -- * 0f - lar, lsl, syscall, clts, sysret, sysenter, sysexit, invd, wbinvd, ud2 -+ * -+ * 6c-6d, e4-e5, ec-ed - in -+ * 6e-6f, e6-e7, ee-ef - out -+ * cc, cd - int3, int -+ * cf - iret -+ * d6 - illegal instruction -+ * f1 - int1/icebp -+ * f4 - hlt -+ * fa, fb - cli, sti -+ * 0f - lar, lsl, syscall, clts, sysret, sysenter, sysexit, invd, wbinvd, ud2 - * - * invalid opcodes in 64-bit mode: -- * 06, 0e, 16, 1e, 27, 2f, 37, 3f, 60-62, 82, c4-c5, d4-d5 - * -- * 63 - we support this opcode in x86_64 but not in i386. -+ * 06, 0e, 16, 1e, 27, 2f, 37, 3f, 60-62, 82, c4-c5, d4-d5 -+ * 63 - we support this opcode in x86_64 but not in i386. - * - * opcodes we may need to refine support for: -- * 0f - 2-byte instructions: For many of these instructions, the validity -- * depends on the prefix and/or the reg field. On such instructions, we -- * just consider the opcode combination valid if it corresponds to any -- * valid instruction. -- * 8f - Group 1 - only reg = 0 is OK -- * c6-c7 - Group 11 - only reg = 0 is OK -- * d9-df - fpu insns with some illegal encodings -- * f2, f3 - repnz, repz prefixes. These are also the first byte for -- * certain floating-point instructions, such as addsd. -- * fe - Group 4 - only reg = 0 or 1 is OK -- * ff - Group 5 - only reg = 0-6 is OK -+ * -+ * 0f - 2-byte instructions: For many of these instructions, the validity -+ * depends on the prefix and/or the reg field. On such instructions, we -+ * just consider the opcode combination valid if it corresponds to any -+ * valid instruction. -+ * -+ * 8f - Group 1 - only reg = 0 is OK -+ * c6-c7 - Group 11 - only reg = 0 is OK -+ * d9-df - fpu insns with some illegal encodings -+ * f2, f3 - repnz, repz prefixes. These are also the first byte for -+ * certain floating-point instructions, such as addsd. -+ * -+ * fe - Group 4 - only reg = 0 or 1 is OK -+ * ff - Group 5 - only reg = 0-6 is OK - * - * others -- Do we need to support these? -- * 0f - (floating-point?) prefetch instructions -- * 07, 17, 1f - pop es, pop ss, pop ds -- * 26, 2e, 36, 3e - es:, cs:, ss:, ds: segment prefixes -- -+ * -+ * 0f - (floating-point?) prefetch instructions -+ * 07, 17, 1f - pop es, pop ss, pop ds -+ * 26, 2e, 36, 3e - es:, cs:, ss:, ds: segment prefixes -- - * but 64 and 65 (fs: and gs:) seem to be used, so we support them -- * 67 - addr16 prefix -- * ce - into -- * f0 - lock prefix -+ * 67 - addr16 prefix -+ * ce - into -+ * f0 - lock prefix - */ - - /* -@@ -182,11 +186,11 @@ static bool is_prefix_bad(struct insn *insn) - - for (i = 0; i < insn->prefixes.nbytes; i++) { - switch (insn->prefixes.bytes[i]) { -- case 0x26: /*INAT_PFX_ES */ -- case 0x2E: /*INAT_PFX_CS */ -- case 0x36: /*INAT_PFX_DS */ -- case 0x3E: /*INAT_PFX_SS */ -- case 0xF0: /*INAT_PFX_LOCK */ -+ case 0x26: /* INAT_PFX_ES */ -+ case 0x2E: /* INAT_PFX_CS */ -+ case 0x36: /* INAT_PFX_DS */ -+ case 0x3E: /* INAT_PFX_SS */ -+ case 0xF0: /* INAT_PFX_LOCK */ - return true; - } - } -@@ -201,12 +205,15 @@ static int validate_insn_32bits(struct uprobe *uprobe, struct insn *insn) - insn_get_opcode(insn); - if (is_prefix_bad(insn)) - return -ENOTSUPP; -+ - if (test_bit(OPCODE1(insn), (unsigned long *)good_insns_32)) - return 0; -+ - if (insn->opcode.nbytes == 2) { - if (test_bit(OPCODE2(insn), (unsigned long *)good_2byte_insns)) - return 0; - } -+ - return -ENOTSUPP; - } - -@@ -282,12 +289,12 @@ static void prepare_fixups(struct uprobe *uprobe, struct insn *insn) - * disastrous. - * - * Some useful facts about rip-relative instructions: -- * - There's always a modrm byte. -- * - There's never a SIB byte. -- * - The displacement is always 4 bytes. -+ * -+ * - There's always a modrm byte. -+ * - There's never a SIB byte. -+ * - The displacement is always 4 bytes. - */ --static void handle_riprel_insn(struct mm_struct *mm, struct uprobe *uprobe, -- struct insn *insn) -+static void handle_riprel_insn(struct mm_struct *mm, struct uprobe *uprobe, struct insn *insn) - { - u8 *cursor; - u8 reg; -@@ -342,13 +349,12 @@ static void handle_riprel_insn(struct mm_struct *mm, struct uprobe *uprobe, - } - - /* Target address = address of next instruction + (signed) offset */ -- uprobe->arch_info.rip_rela_target_address = (long)insn->length -- + insn->displacement.value; -+ uprobe->arch_info.rip_rela_target_address = (long)insn->length + insn->displacement.value; -+ - /* Displacement field is gone; slide immediate field (if any) over. */ - if (insn->immediate.nbytes) { - cursor++; -- memmove(cursor, cursor + insn->displacement.nbytes, -- insn->immediate.nbytes); -+ memmove(cursor, cursor + insn->displacement.nbytes, insn->immediate.nbytes); - } - return; - } -@@ -361,8 +367,10 @@ static int validate_insn_64bits(struct uprobe *uprobe, struct insn *insn) - insn_get_opcode(insn); - if (is_prefix_bad(insn)) - return -ENOTSUPP; -+ - if (test_bit(OPCODE1(insn), (unsigned long *)good_insns_64)) - return 0; -+ - if (insn->opcode.nbytes == 2) { - if (test_bit(OPCODE2(insn), (unsigned long *)good_2byte_insns)) - return 0; -@@ -370,34 +378,31 @@ static int validate_insn_64bits(struct uprobe *uprobe, struct insn *insn) - return -ENOTSUPP; - } - --static int validate_insn_bits(struct mm_struct *mm, struct uprobe *uprobe, -- struct insn *insn) -+static int validate_insn_bits(struct mm_struct *mm, struct uprobe *uprobe, struct insn *insn) - { - if (mm->context.ia32_compat) - return validate_insn_32bits(uprobe, insn); - return validate_insn_64bits(uprobe, insn); - } --#else --static void handle_riprel_insn(struct mm_struct *mm, struct uprobe *uprobe, -- struct insn *insn) -+#else /* 32-bit: */ -+static void handle_riprel_insn(struct mm_struct *mm, struct uprobe *uprobe, struct insn *insn) - { -- return; -+ /* No RIP-relative addressing on 32-bit */ - } - --static int validate_insn_bits(struct mm_struct *mm, struct uprobe *uprobe, -- struct insn *insn) -+static int validate_insn_bits(struct mm_struct *mm, struct uprobe *uprobe, struct insn *insn) - { - return validate_insn_32bits(uprobe, insn); - } - #endif /* CONFIG_X86_64 */ - - /** -- * analyze_insn - instruction analysis including validity and fixups. -+ * arch_uprobes_analyze_insn - instruction analysis including validity and fixups. - * @mm: the probed address space. - * @uprobe: the probepoint information. - * Return 0 on success or a -ve number on error. - */ --int analyze_insn(struct mm_struct *mm, struct uprobe *uprobe) -+int arch_uprobes_analyze_insn(struct mm_struct *mm, struct uprobe *uprobe) - { - int ret; - struct insn insn; -@@ -406,7 +411,9 @@ int analyze_insn(struct mm_struct *mm, struct uprobe *uprobe) - ret = validate_insn_bits(mm, uprobe, &insn); - if (ret != 0) - return ret; -+ - handle_riprel_insn(mm, uprobe, &insn); - prepare_fixups(uprobe, &insn); -+ - return 0; - } -diff --git a/include/linux/uprobes.h b/include/linux/uprobes.h -index f1d13fd..64e45f1 100644 ---- a/include/linux/uprobes.h -+++ b/include/linux/uprobes.h -@@ -1,7 +1,7 @@ - #ifndef _LINUX_UPROBES_H - #define _LINUX_UPROBES_H - /* -- * Userspace Probes (UProbes) -+ * User-space Probes (UProbes) - * - * 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 -@@ -40,8 +40,10 @@ struct uprobe_arch_info {}; - #define uprobe_opcode_sz sizeof(uprobe_opcode_t) - - /* flags that denote/change uprobes behaviour */ -+ - /* Have a copy of original instruction */ - #define UPROBES_COPY_INSN 0x1 -+ - /* Dont run handlers when first register/ last unregister in progress*/ - #define UPROBES_RUN_HANDLER 0x2 - -@@ -70,27 +72,23 @@ struct uprobe { - }; - - #ifdef CONFIG_UPROBES --extern int __weak set_bkpt(struct mm_struct *mm, struct uprobe *uprobe, -- unsigned long vaddr); --extern int __weak set_orig_insn(struct mm_struct *mm, struct uprobe *uprobe, -- unsigned long vaddr, bool verify); -+extern int __weak set_bkpt(struct mm_struct *mm, struct uprobe *uprobe, unsigned long vaddr); -+extern int __weak set_orig_insn(struct mm_struct *mm, struct uprobe *uprobe, unsigned long vaddr, bool verify); - extern bool __weak is_bkpt_insn(uprobe_opcode_t *insn); --extern int register_uprobe(struct inode *inode, loff_t offset, -- struct uprobe_consumer *consumer); --extern void unregister_uprobe(struct inode *inode, loff_t offset, -- struct uprobe_consumer *consumer); --extern int mmap_uprobe(struct vm_area_struct *vma); -+extern int uprobe_register(struct inode *inode, loff_t offset, struct uprobe_consumer *consumer); -+extern void uprobe_unregister(struct inode *inode, loff_t offset, struct uprobe_consumer *consumer); -+extern int uprobe_mmap(struct vm_area_struct *vma); - #else /* CONFIG_UPROBES is not defined */ --static inline int register_uprobe(struct inode *inode, loff_t offset, -- struct uprobe_consumer *consumer) -+static inline int -+uprobe_register(struct inode *inode, loff_t offset, struct uprobe_consumer *consumer) - { - return -ENOSYS; - } --static inline void unregister_uprobe(struct inode *inode, loff_t offset, -- struct uprobe_consumer *consumer) -+static inline void -+uprobe_unregister(struct inode *inode, loff_t offset, struct uprobe_consumer *consumer) - { - } --static inline int mmap_uprobe(struct vm_area_struct *vma) -+static inline int uprobe_mmap(struct vm_area_struct *vma) - { - return 0; - } -diff --git a/kernel/uprobes.c b/kernel/uprobes.c -index 72e8bb3..884817f 100644 ---- a/kernel/uprobes.c -+++ b/kernel/uprobes.c -@@ -1,5 +1,5 @@ - /* -- * Userspace Probes (UProbes) -+ * User-space Probes (UProbes) - * - * 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 -@@ -29,24 +29,26 @@ - #include <linux/rmap.h> /* anon_vma_prepare */ - #include <linux/mmu_notifier.h> /* set_pte_at_notify */ - #include <linux/swap.h> /* try_to_free_swap */ -+ - #include <linux/uprobes.h> - - static struct rb_root uprobes_tree = RB_ROOT; -+ - static DEFINE_SPINLOCK(uprobes_treelock); /* serialize rbtree access */ - - #define UPROBES_HASH_SZ 13 -+ - /* serialize (un)register */ - static struct mutex uprobes_mutex[UPROBES_HASH_SZ]; --#define uprobes_hash(v) (&uprobes_mutex[((unsigned long)(v)) %\ -- UPROBES_HASH_SZ]) -+ -+#define uprobes_hash(v) (&uprobes_mutex[((unsigned long)(v)) % UPROBES_HASH_SZ]) - - /* serialize uprobe->pending_list */ - static struct mutex uprobes_mmap_mutex[UPROBES_HASH_SZ]; --#define uprobes_mmap_hash(v) (&uprobes_mmap_mutex[((unsigned long)(v)) %\ -- UPROBES_HASH_SZ]) -+#define uprobes_mmap_hash(v) (&uprobes_mmap_mutex[((unsigned long)(v)) % UPROBES_HASH_SZ]) - - /* -- * uprobe_events allows us to skip the mmap_uprobe if there are no uprobe -+ * uprobe_events allows us to skip the uprobe_mmap if there are no uprobe - * events active at this time. Probably a fine grained per inode count is - * better? - */ -@@ -58,9 +60,9 @@ static atomic_t uprobe_events = ATOMIC_INIT(0); - * vm_area_struct wasnt recommended. - */ - struct vma_info { -- struct list_head probe_list; -- struct mm_struct *mm; -- loff_t vaddr; -+ struct list_head probe_list; -+ struct mm_struct *mm; -+ loff_t vaddr; - }; - - /* -@@ -79,8 +81,7 @@ static bool valid_vma(struct vm_area_struct *vma, bool is_register) - if (!is_register) - return true; - -- if ((vma->vm_flags & (VM_READ|VM_WRITE|VM_EXEC|VM_SHARED)) == -- (VM_READ|VM_EXEC)) -+ if ((vma->vm_flags & (VM_READ|VM_WRITE|VM_EXEC|VM_SHARED)) == (VM_READ|VM_EXEC)) - return true; - - return false; -@@ -92,6 +93,7 @@ static loff_t vma_address(struct vm_area_struct *vma, loff_t offset) - - vaddr = vma->vm_start + offset; - vaddr -= vma->vm_pgoff << PAGE_SHIFT; -+ - return vaddr; - } - -@@ -105,8 +107,7 @@ static loff_t vma_address(struct vm_area_struct *vma, loff_t offset) - * - * Returns 0 on success, -EFAULT on failure. - */ --static int __replace_page(struct vm_area_struct *vma, struct page *page, -- struct page *kpage) -+static int __replace_page(struct vm_area_struct *vma, struct page *page, struct page *kpage) - { - struct mm_struct *mm = vma->vm_mm; - pgd_t *pgd; -@@ -163,7 +164,7 @@ out: - */ - bool __weak is_bkpt_insn(uprobe_opcode_t *insn) - { -- return (*insn == UPROBES_BKPT_INSN); -+ return *insn == UPROBES_BKPT_INSN; - } - - /* -@@ -203,6 +204,7 @@ static int write_opcode(struct mm_struct *mm, struct uprobe *uprobe, - ret = get_user_pages(NULL, mm, vaddr, 1, 0, 0, &old_page, &vma); - if (ret <= 0) - return ret; -+ - ret = -EINVAL; - - /* -@@ -239,6 +241,7 @@ static int write_opcode(struct mm_struct *mm, struct uprobe *uprobe, - vaddr_new = kmap_atomic(new_page); - - memcpy(vaddr_new, vaddr_old, PAGE_SIZE); -+ - /* poke the new insn in, ASSUMES we don't cross page boundary */ - vaddr &= ~PAGE_MASK; - BUG_ON(vaddr + uprobe_opcode_sz > PAGE_SIZE); -@@ -260,7 +263,8 @@ unlock_out: - page_cache_release(new_page); - - put_out: -- put_page(old_page); /* we did a get_page in the beginning */ -+ put_page(old_page); -+ - return ret; - } - -@@ -276,8 +280,7 @@ put_out: - * For mm @mm, read the opcode at @vaddr and store it in @opcode. - * Return 0 (success) or a negative errno. - */ --static int read_opcode(struct mm_struct *mm, unsigned long vaddr, -- uprobe_opcode_t *opcode) -+static int read_opcode(struct mm_struct *mm, unsigned long vaddr, uprobe_opcode_t *opcode) - { - struct page *page; - void *vaddr_new; -@@ -293,15 +296,18 @@ static int read_opcode(struct mm_struct *mm, unsigned long vaddr, - memcpy(opcode, vaddr_new + vaddr, uprobe_opcode_sz); - kunmap_atomic(vaddr_new); - unlock_page(page); -- put_page(page); /* we did a get_user_pages in the beginning */ -+ -+ put_page(page); -+ - return 0; - } - - static int is_bkpt_at_addr(struct mm_struct *mm, unsigned long vaddr) - { - uprobe_opcode_t opcode; -- int result = read_opcode(mm, vaddr, &opcode); -+ int result; - -+ result = read_opcode(mm, vaddr, &opcode); - if (result) - return result; - -@@ -320,11 +326,11 @@ static int is_bkpt_at_addr(struct mm_struct *mm, unsigned long vaddr) - * For mm @mm, store the breakpoint instruction at @vaddr. - * Return 0 (success) or a negative errno. - */ --int __weak set_bkpt(struct mm_struct *mm, struct uprobe *uprobe, -- unsigned long vaddr) -+int __weak set_bkpt(struct mm_struct *mm, struct uprobe *uprobe, unsigned long vaddr) - { -- int result = is_bkpt_at_addr(mm, vaddr); -+ int result; - -+ result = is_bkpt_at_addr(mm, vaddr); - if (result == 1) - return -EEXIST; - -@@ -344,35 +350,35 @@ int __weak set_bkpt(struct mm_struct *mm, struct uprobe *uprobe, - * For mm @mm, restore the original opcode (opcode) at @vaddr. - * Return 0 (success) or a negative errno. - */ --int __weak set_orig_insn(struct mm_struct *mm, struct uprobe *uprobe, -- unsigned long vaddr, bool verify) -+int __weak -+set_orig_insn(struct mm_struct *mm, struct uprobe *uprobe, unsigned long vaddr, bool verify) - { - if (verify) { -- int result = is_bkpt_at_addr(mm, vaddr); -+ int result; - -+ result = is_bkpt_at_addr(mm, vaddr); - if (!result) - return -EINVAL; - - if (result != 1) - return result; - } -- return write_opcode(mm, uprobe, vaddr, -- *(uprobe_opcode_t *)uprobe->insn); -+ return write_opcode(mm, uprobe, vaddr, *(uprobe_opcode_t *)uprobe->insn); - } - - static int match_uprobe(struct uprobe *l, struct uprobe *r) - { - if (l->inode < r->inode) - return -1; -+ - if (l->inode > r->inode) - return 1; -- else { -- if (l->offset < r->offset) -- return -1; - -- if (l->offset > r->offset) -- return 1; -- } -+ if (l->offset < r->offset) -+ return -1; -+ -+ if (l->offset > r->offset) -+ return 1; - - return 0; - } -@@ -391,6 +397,7 @@ static struct uprobe *__find_uprobe(struct inode *inode, loff_t offset) - atomic_inc(&uprobe->ref); - return uprobe; - } -+ - if (match < 0) - n = n->rb_left; - else -@@ -411,6 +418,7 @@ static struct uprobe *find_uprobe(struct inode *inode, loff_t offset) - spin_lock_irqsave(&uprobes_treelock, flags); - uprobe = __find_uprobe(inode, offset); - spin_unlock_irqrestore(&uprobes_treelock, flags); -+ - return uprobe; - } - -@@ -436,16 +444,18 @@ static struct uprobe *__insert_uprobe(struct uprobe *uprobe) - p = &parent->rb_right; - - } -+ - u = NULL; - rb_link_node(&uprobe->rb_node, parent, p); - rb_insert_color(&uprobe->rb_node, &uprobes_tree); - /* get access + creation ref */ - atomic_set(&uprobe->ref, 2); -+ - return u; - } - - /* -- * Acquires uprobes_treelock. -+ * Acquire uprobes_treelock. - * Matching uprobe already exists in rbtree; - * increment (access refcount) and return the matching uprobe. - * -@@ -460,6 +470,7 @@ static struct uprobe *insert_uprobe(struct uprobe *uprobe) - spin_lock_irqsave(&uprobes_treelock, flags); - u = __insert_uprobe(uprobe); - spin_unlock_irqrestore(&uprobes_treelock, flags); -+ - return u; - } - -@@ -490,19 +501,22 @@ static struct uprobe *alloc_uprobe(struct inode *inode, loff_t offset) - kfree(uprobe); - uprobe = cur_uprobe; - iput(inode); -- } else -+ } else { - atomic_inc(&uprobe_events); -+ } -+ - return uprobe; - } - - /* Returns the previous consumer */ --static struct uprobe_consumer *add_consumer(struct uprobe *uprobe, -- struct uprobe_consumer *consumer) -+static struct uprobe_consumer * -+consumer_add(struct uprobe *uprobe, struct uprobe_consumer *consumer) - { - down_write(&uprobe->consumer_rwsem); - consumer->next = uprobe->consumers; - uprobe->consumers = consumer; - up_write(&uprobe->consumer_rwsem); -+ - return consumer->next; - } - -@@ -511,8 +525,7 @@ static struct uprobe_consumer *add_consumer(struct uprobe *uprobe, - * Return true if the @consumer is deleted successfully - * or return false. - */ --static bool del_consumer(struct uprobe *uprobe, -- struct uprobe_consumer *consumer) -+static bool consumer_del(struct uprobe *uprobe, struct uprobe_consumer *consumer) - { - struct uprobe_consumer **con; - bool ret = false; -@@ -526,6 +539,7 @@ static bool del_consumer(struct uprobe *uprobe, - } - } - up_write(&uprobe->consumer_rwsem); -+ - return ret; - } - -@@ -557,15 +571,15 @@ static int __copy_insn(struct address_space *mapping, - memcpy(insn, vaddr + off1, nbytes); - kunmap_atomic(vaddr); - page_cache_release(page); -+ - return 0; - } - --static int copy_insn(struct uprobe *uprobe, struct vm_area_struct *vma, -- unsigned long addr) -+static int copy_insn(struct uprobe *uprobe, struct vm_area_struct *vma, unsigned long addr) - { - struct address_space *mapping; -- int bytes; - unsigned long nbytes; -+ int bytes; - - addr &= ~PAGE_MASK; - nbytes = PAGE_SIZE - addr; -@@ -605,6 +619,7 @@ static int install_breakpoint(struct mm_struct *mm, struct uprobe *uprobe, - return -EEXIST; - - addr = (unsigned long)vaddr; -+ - if (!(uprobe->flags & UPROBES_COPY_INSN)) { - ret = copy_insn(uprobe, vma, addr); - if (ret) -@@ -613,7 +628,7 @@ static int install_breakpoint(struct mm_struct *mm, struct uprobe *uprobe, - if (is_bkpt_insn((uprobe_opcode_t *)uprobe->insn)) - return -EEXIST; - -- ret = analyze_insn(mm, uprobe); -+ ret = arch_uprobes_analyze_insn(mm, uprobe); - if (ret) - return ret; - -@@ -624,8 +639,7 @@ static int install_breakpoint(struct mm_struct *mm, struct uprobe *uprobe, - return ret; - } - --static void remove_breakpoint(struct mm_struct *mm, struct uprobe *uprobe, -- loff_t vaddr) -+static void remove_breakpoint(struct mm_struct *mm, struct uprobe *uprobe, loff_t vaddr) - { - set_orig_insn(mm, uprobe, (unsigned long)vaddr, true); - } -@@ -649,9 +663,11 @@ static struct vma_info *__find_next_vma_info(struct list_head *head, - struct prio_tree_iter iter; - struct vm_area_struct *vma; - struct vma_info *tmpvi; -- loff_t vaddr; -- unsigned long pgoff = offset >> PAGE_SHIFT; -+ unsigned long pgoff; - int existing_vma; -+ loff_t vaddr; -+ -+ pgoff = offset >> PAGE_SHIFT; - - vma_prio_tree_foreach(vma, &iter, &mapping->i_mmap, pgoff, pgoff) { - if (!valid_vma(vma, is_register)) -@@ -659,6 +675,7 @@ static struct vma_info *__find_next_vma_info(struct list_head *head, - - existing_vma = 0; - vaddr = vma_address(vma, offset); -+ - list_for_each_entry(tmpvi, head, probe_list) { - if (tmpvi->mm == vma->vm_mm && tmpvi->vaddr == vaddr) { - existing_vma = 1; -@@ -670,14 +687,15 @@ static struct vma_info *__find_next_vma_info(struct list_head *head, - * Another vma needs a probe to be installed. However skip - * installing the probe if the vma is about to be unlinked. - */ -- if (!existing_vma && -- atomic_inc_not_zero(&vma->vm_mm->mm_users)) { -+ if (!existing_vma && atomic_inc_not_zero(&vma->vm_mm->mm_users)) { - vi->mm = vma->vm_mm; - vi->vaddr = vaddr; - list_add(&vi->probe_list, head); -+ - return vi; - } - } -+ - return NULL; - } - -@@ -685,11 +703,12 @@ static struct vma_info *__find_next_vma_info(struct list_head *head, - * Iterate in the rmap prio tree and find a vma where a probe has not - * yet been inserted. - */ --static struct vma_info *find_next_vma_info(struct list_head *head, -- loff_t offset, struct address_space *mapping, -- bool is_register) -+static struct vma_info * -+find_next_vma_info(struct list_head *head, loff_t offset, struct address_space *mapping, -+ bool is_register) - { - struct vma_info *vi, *retvi; -+ - vi = kzalloc(sizeof(struct vma_info), GFP_KERNEL); - if (!vi) - return ERR_PTR(-ENOMEM); -@@ -700,6 +719,7 @@ static struct vma_info *find_next_vma_info(struct list_head *head, - - if (!retvi) - kfree(vi); -+ - return retvi; - } - -@@ -711,16 +731,23 @@ static int register_for_each_vma(struct uprobe *uprobe, bool is_register) - struct vma_info *vi, *tmpvi; - struct mm_struct *mm; - loff_t vaddr; -- int ret = 0; -+ int ret; - - mapping = uprobe->inode->i_mapping; - INIT_LIST_HEAD(&try_list); -- while ((vi = find_next_vma_info(&try_list, uprobe->offset, -- mapping, is_register)) != NULL) { -+ -+ ret = 0; -+ -+ for (;;) { -+ vi = find_next_vma_info(&try_list, uprobe->offset, mapping, is_register); -+ if (!vi) -+ break; -+ - if (IS_ERR(vi)) { - ret = PTR_ERR(vi); - break; - } -+ - mm = vi->mm; - down_read(&mm->mmap_sem); - vma = find_vma(mm, (unsigned long)vi->vaddr); -@@ -755,19 +782,21 @@ static int register_for_each_vma(struct uprobe *uprobe, bool is_register) - break; - } - } -+ - list_for_each_entry_safe(vi, tmpvi, &try_list, probe_list) { - list_del(&vi->probe_list); - kfree(vi); - } -+ - return ret; - } - --static int __register_uprobe(struct uprobe *uprobe) -+static int __uprobe_register(struct uprobe *uprobe) - { - return register_for_each_vma(uprobe, true); - } - --static void __unregister_uprobe(struct uprobe *uprobe) -+static void __uprobe_unregister(struct uprobe *uprobe) - { - if (!register_for_each_vma(uprobe, false)) - delete_uprobe(uprobe); -@@ -776,15 +805,15 @@ static void __unregister_uprobe(struct uprobe *uprobe) - } - - /* -- * register_uprobe - register a probe -+ * uprobe_register - register a probe - * @inode: the file in which the probe has to be placed. - * @offset: offset from the start of the file. - * @consumer: information on howto handle the probe.. - * -- * Apart from the access refcount, register_uprobe() takes a creation -+ * Apart from the access refcount, uprobe_register() takes a creation - * refcount (thro alloc_uprobe) if and only if this @uprobe is getting - * inserted into the rbtree (i.e first consumer for a @inode:@offset -- * tuple). Creation refcount stops unregister_uprobe from freeing the -+ * tuple). Creation refcount stops uprobe_unregister from freeing the - * @uprobe even before the register operation is complete. Creation - * refcount is released when the last @consumer for the @uprobe - * unregisters. -@@ -792,28 +821,29 @@ static void __unregister_uprobe(struct uprobe *uprobe) - * Return errno if it cannot successully install probes - * else return 0 (success) - */ --int register_uprobe(struct inode *inode, loff_t offset, -- struct uprobe_consumer *consumer) -+int uprobe_register(struct inode *inode, loff_t offset, struct uprobe_consumer *consumer) - { - struct uprobe *uprobe; -- int ret = -EINVAL; -+ int ret; - - if (!inode || !consumer || consumer->next) -- return ret; -+ return -EINVAL; - - if (offset > i_size_read(inode)) -- return ret; -+ return -EINVAL; - - ret = 0; - mutex_lock(uprobes_hash(inode)); - uprobe = alloc_uprobe(inode, offset); -- if (uprobe && !add_consumer(uprobe, consumer)) { -- ret = __register_uprobe(uprobe); -+ -+ if (uprobe && !consumer_add(uprobe, consumer)) { -+ ret = __uprobe_register(uprobe); - if (ret) { - uprobe->consumers = NULL; -- __unregister_uprobe(uprobe); -- } else -+ __uprobe_unregister(uprobe); -+ } else { - uprobe->flags |= UPROBES_RUN_HANDLER; -+ } - } - - mutex_unlock(uprobes_hash(inode)); -@@ -823,15 +853,14 @@ int register_uprobe(struct inode *inode, loff_t offset, - } - - /* -- * unregister_uprobe - unregister a already registered probe. -+ * uprobe_unregister - unregister a already registered probe. - * @inode: the file in which the probe has to be removed. - * @offset: offset from the start of the file. - * @consumer: identify which probe if multiple probes are colocated. - */ --void unregister_uprobe(struct inode *inode, loff_t offset, -- struct uprobe_consumer *consumer) -+void uprobe_unregister(struct inode *inode, loff_t offset, struct uprobe_consumer *consumer) - { -- struct uprobe *uprobe = NULL; -+ struct uprobe *uprobe; - - if (!inode || !consumer) - return; -@@ -841,15 +870,14 @@ void unregister_uprobe(struct inode *inode, loff_t offset, - return; - - mutex_lock(uprobes_hash(inode)); -- if (!del_consumer(uprobe, consumer)) -- goto unreg_out; - -- if (!uprobe->consumers) { -- __unregister_uprobe(uprobe); -- uprobe->flags &= ~UPROBES_RUN_HANDLER; -+ if (consumer_del(uprobe, consumer)) { -+ if (!uprobe->consumers) { -+ __uprobe_unregister(uprobe); -+ uprobe->flags &= ~UPROBES_RUN_HANDLER; -+ } - } - --unreg_out: - mutex_unlock(uprobes_hash(inode)); - if (uprobe) - put_uprobe(uprobe); -@@ -870,6 +898,7 @@ static struct rb_node *find_least_offset_node(struct inode *inode) - while (n) { - uprobe = rb_entry(n, struct uprobe, rb_node); - match = match_uprobe(&u, uprobe); -+ - if (uprobe->inode == inode) - close_node = n; - -@@ -881,6 +910,7 @@ static struct rb_node *find_least_offset_node(struct inode *inode) - else - n = n->rb_right; - } -+ - return close_node; - } - -@@ -890,11 +920,13 @@ static struct rb_node *find_least_offset_node(struct inode *inode) - static void build_probe_list(struct inode *inode, struct list_head *head) - { - struct uprobe *uprobe; -- struct rb_node *n; - unsigned long flags; -+ struct rb_node *n; - - spin_lock_irqsave(&uprobes_treelock, flags); -+ - n = find_least_offset_node(inode); -+ - for (; n; n = rb_next(n)) { - uprobe = rb_entry(n, struct uprobe, rb_node); - if (uprobe->inode != inode) -@@ -903,6 +935,7 @@ static void build_probe_list(struct inode *inode, struct list_head *head) - list_add(&uprobe->pending_list, head); - atomic_inc(&uprobe->ref); - } -+ - spin_unlock_irqrestore(&uprobes_treelock, flags); - } - -@@ -912,42 +945,44 @@ static void build_probe_list(struct inode *inode, struct list_head *head) - * - * Return -ve no if we fail to insert probes and we cannot - * bail-out. -- * Return 0 otherwise. i.e : -+ * Return 0 otherwise. i.e: -+ * - * - successful insertion of probes - * - (or) no possible probes to be inserted. - * - (or) insertion of probes failed but we can bail-out. - */ --int mmap_uprobe(struct vm_area_struct *vma) -+int uprobe_mmap(struct vm_area_struct *vma) - { - struct list_head tmp_list; - struct uprobe *uprobe, *u; - struct inode *inode; -- int ret = 0; -+ int ret; - - if (!atomic_read(&uprobe_events) || !valid_vma(vma, true)) -- return ret; /* Bail-out */ -+ return 0; - - inode = vma->vm_file->f_mapping->host; - if (!inode) -- return ret; -+ return 0; - - INIT_LIST_HEAD(&tmp_list); - mutex_lock(uprobes_mmap_hash(inode)); - build_probe_list(inode, &tmp_list); -+ -+ ret = 0; -+ - list_for_each_entry_safe(uprobe, u, &tmp_list, pending_list) { - loff_t vaddr; - - list_del(&uprobe->pending_list); - if (!ret) { - vaddr = vma_address(vma, uprobe->offset); -- if (vaddr < vma->vm_start || vaddr >= vma->vm_end) { -- put_uprobe(uprobe); -- continue; -+ if (vaddr >= vma->vm_start && vaddr < vma->vm_end) { -+ ret = install_breakpoint(vma->vm_mm, uprobe, vma, vaddr); -+ /* Ignore double add: */ -+ if (ret == -EEXIST) -+ ret = 0; - } -- ret = install_breakpoint(vma->vm_mm, uprobe, vma, -- vaddr); -- if (ret == -EEXIST) -- ret = 0; - } - put_uprobe(uprobe); - } -diff --git a/mm/mmap.c b/mm/mmap.c -index f6ea842..397bcb5 100644 ---- a/mm/mmap.c -+++ b/mm/mmap.c -@@ -619,10 +619,10 @@ again: remove_next = 1 + (end > next->vm_end); - mutex_unlock(&mapping->i_mmap_mutex); - - if (root) { -- mmap_uprobe(vma); -+ uprobe_mmap(vma); - - if (adjust_next) -- mmap_uprobe(next); -+ uprobe_mmap(next); - } - - if (remove_next) { -@@ -647,7 +647,7 @@ again: remove_next = 1 + (end > next->vm_end); - } - } - if (insert && file) -- mmap_uprobe(insert); -+ uprobe_mmap(insert); - - validate_mm(mm); - -@@ -1382,7 +1382,7 @@ out: - } else if ((flags & MAP_POPULATE) && !(flags & MAP_NONBLOCK)) - make_pages_present(addr, addr + len); - -- if (file && mmap_uprobe(vma)) -+ if (file && uprobe_mmap(vma)) - /* matching probes but cannot insert */ - goto unmap_and_free_vma; - -@@ -2368,7 +2368,7 @@ int insert_vm_struct(struct mm_struct * mm, struct vm_area_struct * vma) - security_vm_enough_memory_mm(mm, vma_pages(vma))) - return -ENOMEM; - -- if (vma->vm_file && mmap_uprobe(vma)) -+ if (vma->vm_file && uprobe_mmap(vma)) - return -EINVAL; - - vma_link(mm, vma, prev, rb_link, rb_parent); -@@ -2441,7 +2441,7 @@ struct vm_area_struct *copy_vma(struct vm_area_struct **vmap, - if (new_vma->vm_file) { - get_file(new_vma->vm_file); - -- if (mmap_uprobe(new_vma)) -+ if (uprobe_mmap(new_vma)) - goto out_free_mempol; - - if (vma->vm_flags & VM_EXECUTABLE) --- -1.7.5.4 - diff --git a/features/uprobe/uprobes-core-Decrement-uprobe-count-before-the-pages.patch b/features/uprobe/uprobes-core-Decrement-uprobe-count-before-the-pages.patch deleted file mode 100644 index 64e5242fe81d533e93547fc5c5d289646bd02d6d..0000000000000000000000000000000000000000 --- a/features/uprobe/uprobes-core-Decrement-uprobe-count-before-the-pages.patch +++ /dev/null @@ -1,150 +0,0 @@ -From a8600f2e9c62613ca4073a25be14c50039f50ad7 Mon Sep 17 00:00:00 2001 -From: Srikar Dronamraju <srikar@linux.vnet.ibm.com> -Date: Wed, 11 Apr 2012 16:05:27 +0530 -Subject: [PATCH 15/24] uprobes/core: Decrement uprobe count before the pages - are unmapped - -Uprobes has a callback (uprobe_munmap()) in the unmap path to -maintain the uprobes count. - -In the exit path this callback gets called in unlink_file_vma(). -However by the time unlink_file_vma() is called, the pages would -have been unmapped (in unmap_vmas()) and the task->rss_stat counts -accounted (in zap_pte_range()). - -If the exiting process has probepoints, uprobe_munmap() checks if -the breakpoint instruction was around before decrementing the probe -count. - -This results in a file backed page being reread by uprobe_munmap() -and hence it does not find the breakpoint. - -This patch fixes this problem by moving the callback to -unmap_single_vma(). Since unmap_single_vma() may not unmap the -complete vma, add start and end parameters to uprobe_munmap(). - -This bug became apparent courtesy of commit c3f0327f8e9d -("mm: add rss counters consistency check"). - -commit cbc91f71b51b8335f1fc7ccfca8011f31a717367 upstream - -Signed-off-by: Srikar Dronamraju <srikar@linux.vnet.ibm.com> -Cc: Linus Torvalds <torvalds@linux-foundation.org> -Cc: Ananth N Mavinakayanahalli <ananth@in.ibm.com> -Cc: Jim Keniston <jkenisto@linux.vnet.ibm.com> -Cc: Linux-mm <linux-mm@kvack.org> -Cc: Oleg Nesterov <oleg@redhat.com> -Cc: Andi Kleen <andi@firstfloor.org> -Cc: Christoph Hellwig <hch@infradead.org> -Cc: Steven Rostedt <rostedt@goodmis.org> -Cc: Arnaldo Carvalho de Melo <acme@infradead.org> -Cc: Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com> -Cc: Anton Arapov <anton@redhat.com> -Cc: Peter Zijlstra <peterz@infradead.org> -Link: http://lkml.kernel.org/r/20120411103527.23245.9835.sendpatchset@srdronam.in.ibm.com -Signed-off-by: Ingo Molnar <mingo@kernel.org> -Signed-off-by: Paul Barrette <paul.barrette@windriver.com> ---- - include/linux/uprobes.h | 5 +++-- - kernel/events/uprobes.c | 4 ++-- - mm/memory.c | 3 +++ - mm/mmap.c | 8 ++++---- - 4 files changed, 12 insertions(+), 8 deletions(-) - -diff --git a/include/linux/uprobes.h b/include/linux/uprobes.h -index d594d3b..efe4b33 100644 ---- a/include/linux/uprobes.h -+++ b/include/linux/uprobes.h -@@ -107,7 +107,7 @@ extern bool __weak is_swbp_insn(uprobe_opcode_t *insn); - extern int uprobe_register(struct inode *inode, loff_t offset, struct uprobe_consumer *uc); - extern void uprobe_unregister(struct inode *inode, loff_t offset, struct uprobe_consumer *uc); - extern int uprobe_mmap(struct vm_area_struct *vma); --extern void uprobe_munmap(struct vm_area_struct *vma); -+extern void uprobe_munmap(struct vm_area_struct *vma, unsigned long start, unsigned long end); - extern void uprobe_free_utask(struct task_struct *t); - extern void uprobe_copy_process(struct task_struct *t); - extern unsigned long __weak uprobe_get_swbp_addr(struct pt_regs *regs); -@@ -134,7 +134,8 @@ static inline int uprobe_mmap(struct vm_area_struct *vma) - { - return 0; - } --static inline void uprobe_munmap(struct vm_area_struct *vma) -+static inline void -+uprobe_munmap(struct vm_area_struct *vma, unsigned long start, unsigned long end) - { - } - static inline void uprobe_notify_resume(struct pt_regs *regs) -diff --git a/kernel/events/uprobes.c b/kernel/events/uprobes.c -index c5caeec..985be4d 100644 ---- a/kernel/events/uprobes.c -+++ b/kernel/events/uprobes.c -@@ -1112,7 +1112,7 @@ int uprobe_mmap(struct vm_area_struct *vma) - /* - * Called in context of a munmap of a vma. - */ --void uprobe_munmap(struct vm_area_struct *vma) -+void uprobe_munmap(struct vm_area_struct *vma, unsigned long start, unsigned long end) - { - struct list_head tmp_list; - struct uprobe *uprobe, *u; -@@ -1138,7 +1138,7 @@ void uprobe_munmap(struct vm_area_struct *vma) - list_del(&uprobe->pending_list); - vaddr = vma_address(vma, uprobe->offset); - -- if (vaddr >= vma->vm_start && vaddr < vma->vm_end) { -+ if (vaddr >= start && vaddr < end) { - /* - * An unregister could have removed the probe before - * unmap. So check before we decrement the count. -diff --git a/mm/memory.c b/mm/memory.c -index 6105f47..bf8b403 100644 ---- a/mm/memory.c -+++ b/mm/memory.c -@@ -1307,6 +1307,9 @@ static void unmap_single_vma(struct mmu_gather *tlb, - if (end <= vma->vm_start) - return; - -+ if (vma->vm_file) -+ uprobe_munmap(vma, start, end); -+ - if (vma->vm_flags & VM_ACCOUNT) - *nr_accounted += (end - start) >> PAGE_SHIFT; - -diff --git a/mm/mmap.c b/mm/mmap.c -index b0b1691..b8c4072 100644 ---- a/mm/mmap.c -+++ b/mm/mmap.c -@@ -218,7 +218,6 @@ void unlink_file_vma(struct vm_area_struct *vma) - mutex_lock(&mapping->i_mmap_mutex); - __remove_shared_vm_struct(vma, file, mapping); - mutex_unlock(&mapping->i_mmap_mutex); -- uprobe_munmap(vma); - } - } - -@@ -550,10 +549,11 @@ again: remove_next = 1 + (end > next->vm_end); - mapping = file->f_mapping; - if (!(vma->vm_flags & VM_NONLINEAR)) { - root = &mapping->i_mmap; -- uprobe_munmap(vma); -+ uprobe_munmap(vma, vma->vm_start, vma->vm_end); - - if (adjust_next) -- uprobe_munmap(next); -+ uprobe_munmap(next, next->vm_start, -+ next->vm_end); - } - - mutex_lock(&mapping->i_mmap_mutex); -@@ -634,7 +634,7 @@ again: remove_next = 1 + (end > next->vm_end); - - if (remove_next) { - if (file) { -- uprobe_munmap(next); -+ uprobe_munmap(next, next->vm_start, next->vm_end); - fput(file); - if (next->vm_flags & VM_EXECUTABLE) - removed_exe_file_vma(mm); --- -1.7.5.4 - diff --git a/features/uprobe/uprobes-core-Handle-breakpoint-and-singlestep-except.patch b/features/uprobe/uprobes-core-Handle-breakpoint-and-singlestep-except.patch deleted file mode 100644 index 2a9e35d69d2ff6057224dd20b60766c0c1fd20a9..0000000000000000000000000000000000000000 --- a/features/uprobe/uprobes-core-Handle-breakpoint-and-singlestep-except.patch +++ /dev/null @@ -1,1018 +0,0 @@ -From 77bfad8317b99fdb2f5a7e01991692e60800dddd Mon Sep 17 00:00:00 2001 -From: Srikar Dronamraju <srikar@linux.vnet.ibm.com> -Date: Tue, 13 Mar 2012 23:30:11 +0530 -Subject: [PATCH 11/24] uprobes/core: Handle breakpoint and singlestep - exceptions - -Uprobes uses exception notifiers to get to know if a thread hit -a breakpoint or a singlestep exception. - -When a thread hits a uprobe or is singlestepping post a uprobe -hit, the uprobe exception notifier sets its TIF_UPROBE bit, -which will then be checked on its return to userspace path -(do_notify_resume() ->uprobe_notify_resume()), where the -consumers handlers are run (in task context) based on the -defined filters. - -Uprobe hits are thread specific and hence we need to maintain -information about if a task hit a uprobe, what uprobe was hit, -the slot where the original instruction was copied for xol so -that it can be singlestepped with appropriate fixups. - -In some cases, special care is needed for instructions that are -executed out of line (xol). These are architecture specific -artefacts, such as handling RIP relative instructions on x86_64. - -Since the instruction at which the uprobe was inserted is -executed out of line, architecture specific fixups are added so -that the thread continues normal execution in the presence of a -uprobe. - -Postpone the signals until we execute the probed insn. -post_xol() path does a recalc_sigpending() before return to -user-mode, this ensures the signal can't be lost. - -Uprobes relies on DIE_DEBUG notification to notify if a -singlestep is complete. - -Adds x86 specific uprobe exception notifiers and appropriate -hooks needed to determine a uprobe hit and subsequent post -processing. - -Add requisite x86 fixups for xol for uprobes. Specific cases -needing fixups include relative jumps (x86_64), calls, etc. - -Where possible, we check and skip singlestepping the -breakpointed instructions. For now we skip single byte as well -as few multibyte nop instructions. However this can be extended -to other instructions too. - -Credits to Oleg Nesterov for suggestions/patches related to -signal, breakpoint, singlestep handling code. - -commit 0326f5a94ddea33fa331b2519f4172f4fb387baa upstream - -Signed-off-by: Srikar Dronamraju <srikar@linux.vnet.ibm.com> -Cc: Linus Torvalds <torvalds@linux-foundation.org> -Cc: Ananth N Mavinakayanahalli <ananth@in.ibm.com> -Cc: Jim Keniston <jkenisto@linux.vnet.ibm.com> -Cc: Linux-mm <linux-mm@kvack.org> -Cc: Oleg Nesterov <oleg@redhat.com> -Cc: Andi Kleen <andi@firstfloor.org> -Cc: Christoph Hellwig <hch@infradead.org> -Cc: Steven Rostedt <rostedt@goodmis.org> -Cc: Arnaldo Carvalho de Melo <acme@infradead.org> -Cc: Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com> -Cc: Peter Zijlstra <peterz@infradead.org> -Link: http://lkml.kernel.org/r/20120313180011.29771.89027.sendpatchset@srdronam.in.ibm.com -[ Performed various cleanliness edits ] -Signed-off-by: Ingo Molnar <mingo@elte.hu> -Signed-off-by: Paul Barrette <paul.barrette@windriver.com> ---- - arch/x86/include/asm/thread_info.h | 2 + - arch/x86/include/asm/uprobes.h | 16 ++- - arch/x86/kernel/signal.c | 6 + - arch/x86/kernel/uprobes.c | 265 ++++++++++++++++++++++++++++- - include/linux/sched.h | 4 + - include/linux/uprobes.h | 55 ++++++- - kernel/events/uprobes.c | 323 +++++++++++++++++++++++++++++++++++- - kernel/fork.c | 4 + - kernel/signal.c | 4 + - 9 files changed, 664 insertions(+), 15 deletions(-) - -diff --git a/arch/x86/include/asm/thread_info.h b/arch/x86/include/asm/thread_info.h -index ad6df8c..0710c11 100644 ---- a/arch/x86/include/asm/thread_info.h -+++ b/arch/x86/include/asm/thread_info.h -@@ -85,6 +85,7 @@ struct thread_info { - #define TIF_SECCOMP 8 /* secure computing */ - #define TIF_MCE_NOTIFY 10 /* notify userspace of an MCE */ - #define TIF_USER_RETURN_NOTIFY 11 /* notify kernel of userspace return */ -+#define TIF_UPROBE 12 /* breakpointed or singlestepping */ - #define TIF_NOTSC 16 /* TSC is not accessible in userland */ - #define TIF_IA32 17 /* IA32 compatibility process */ - #define TIF_FORK 18 /* ret_from_fork */ -@@ -109,6 +110,7 @@ struct thread_info { - #define _TIF_SECCOMP (1 << TIF_SECCOMP) - #define _TIF_MCE_NOTIFY (1 << TIF_MCE_NOTIFY) - #define _TIF_USER_RETURN_NOTIFY (1 << TIF_USER_RETURN_NOTIFY) -+#define _TIF_UPROBE (1 << TIF_UPROBE) - #define _TIF_NOTSC (1 << TIF_NOTSC) - #define _TIF_IA32 (1 << TIF_IA32) - #define _TIF_FORK (1 << TIF_FORK) -diff --git a/arch/x86/include/asm/uprobes.h b/arch/x86/include/asm/uprobes.h -index 0500391..1e9bed1 100644 ---- a/arch/x86/include/asm/uprobes.h -+++ b/arch/x86/include/asm/uprobes.h -@@ -23,6 +23,8 @@ - * Jim Keniston - */ - -+#include <linux/notifier.h> -+ - typedef u8 uprobe_opcode_t; - - #define MAX_UINSN_BYTES 16 -@@ -39,5 +41,17 @@ struct arch_uprobe { - #endif - }; - --extern int arch_uprobes_analyze_insn(struct arch_uprobe *aup, struct mm_struct *mm); -+struct arch_uprobe_task { -+ unsigned long saved_trap_nr; -+#ifdef CONFIG_X86_64 -+ unsigned long saved_scratch_register; -+#endif -+}; -+ -+extern int arch_uprobe_analyze_insn(struct arch_uprobe *aup, struct mm_struct *mm); -+extern int arch_uprobe_pre_xol(struct arch_uprobe *aup, struct pt_regs *regs); -+extern int arch_uprobe_post_xol(struct arch_uprobe *aup, struct pt_regs *regs); -+extern bool arch_uprobe_xol_was_trapped(struct task_struct *tsk); -+extern int arch_uprobe_exception_notify(struct notifier_block *self, unsigned long val, void *data); -+extern void arch_uprobe_abort_xol(struct arch_uprobe *aup, struct pt_regs *regs); - #endif /* _ASM_UPROBES_H */ -diff --git a/arch/x86/kernel/signal.c b/arch/x86/kernel/signal.c -index 115eac4..041af2f 100644 ---- a/arch/x86/kernel/signal.c -+++ b/arch/x86/kernel/signal.c -@@ -18,6 +18,7 @@ - #include <linux/personality.h> - #include <linux/uaccess.h> - #include <linux/user-return-notifier.h> -+#include <linux/uprobes.h> - - #include <asm/processor.h> - #include <asm/ucontext.h> -@@ -824,6 +825,11 @@ do_notify_resume(struct pt_regs *regs, void *unused, __u32 thread_info_flags) - mce_notify_process(); - #endif /* CONFIG_X86_64 && CONFIG_X86_MCE */ - -+ if (thread_info_flags & _TIF_UPROBE) { -+ clear_thread_flag(TIF_UPROBE); -+ uprobe_notify_resume(regs); -+ } -+ - /* deal with pending signal delivery */ - if (thread_info_flags & _TIF_SIGPENDING) - do_signal(regs); -diff --git a/arch/x86/kernel/uprobes.c b/arch/x86/kernel/uprobes.c -index 851a11b..dc4e910 100644 ---- a/arch/x86/kernel/uprobes.c -+++ b/arch/x86/kernel/uprobes.c -@@ -24,22 +24,28 @@ - #include <linux/sched.h> - #include <linux/ptrace.h> - #include <linux/uprobes.h> -+#include <linux/uaccess.h> - - #include <linux/kdebug.h> -+#include <asm/processor.h> - #include <asm/insn.h> - - /* Post-execution fixups. */ - - /* No fixup needed */ --#define UPROBE_FIX_NONE 0x0 -+#define UPROBE_FIX_NONE 0x0 -+ - /* Adjust IP back to vicinity of actual insn */ - #define UPROBE_FIX_IP 0x1 -+ - /* Adjust the return address of a call insn */ - #define UPROBE_FIX_CALL 0x2 - - #define UPROBE_FIX_RIP_AX 0x8000 - #define UPROBE_FIX_RIP_CX 0x4000 - -+#define UPROBE_TRAP_NR UINT_MAX -+ - /* Adaptations for mhiramat x86 decoder v14. */ - #define OPCODE1(insn) ((insn)->opcode.bytes[0]) - #define OPCODE2(insn) ((insn)->opcode.bytes[1]) -@@ -221,10 +227,9 @@ static int validate_insn_32bits(struct arch_uprobe *auprobe, struct insn *insn) - } - - /* -- * Figure out which fixups post_xol() will need to perform, and annotate -- * arch_uprobe->fixups accordingly. To start with, -- * arch_uprobe->fixups is either zero or it reflects rip-related -- * fixups. -+ * Figure out which fixups arch_uprobe_post_xol() will need to perform, and -+ * annotate arch_uprobe->fixups accordingly. To start with, -+ * arch_uprobe->fixups is either zero or it reflects rip-related fixups. - */ - static void prepare_fixups(struct arch_uprobe *auprobe, struct insn *insn) - { -@@ -401,12 +406,12 @@ static int validate_insn_bits(struct arch_uprobe *auprobe, struct mm_struct *mm, - #endif /* CONFIG_X86_64 */ - - /** -- * arch_uprobes_analyze_insn - instruction analysis including validity and fixups. -+ * arch_uprobe_analyze_insn - instruction analysis including validity and fixups. - * @mm: the probed address space. - * @arch_uprobe: the probepoint information. - * Return 0 on success or a -ve number on error. - */ --int arch_uprobes_analyze_insn(struct arch_uprobe *auprobe, struct mm_struct *mm) -+int arch_uprobe_analyze_insn(struct arch_uprobe *auprobe, struct mm_struct *mm) - { - int ret; - struct insn insn; -@@ -421,3 +426,249 @@ int arch_uprobes_analyze_insn(struct arch_uprobe *auprobe, struct mm_struct *mm) - - return 0; - } -+ -+#ifdef CONFIG_X86_64 -+/* -+ * If we're emulating a rip-relative instruction, save the contents -+ * of the scratch register and store the target address in that register. -+ */ -+static void -+pre_xol_rip_insn(struct arch_uprobe *auprobe, struct pt_regs *regs, -+ struct arch_uprobe_task *autask) -+{ -+ if (auprobe->fixups & UPROBE_FIX_RIP_AX) { -+ autask->saved_scratch_register = regs->ax; -+ regs->ax = current->utask->vaddr; -+ regs->ax += auprobe->rip_rela_target_address; -+ } else if (auprobe->fixups & UPROBE_FIX_RIP_CX) { -+ autask->saved_scratch_register = regs->cx; -+ regs->cx = current->utask->vaddr; -+ regs->cx += auprobe->rip_rela_target_address; -+ } -+} -+#else -+static void -+pre_xol_rip_insn(struct arch_uprobe *auprobe, struct pt_regs *regs, -+ struct arch_uprobe_task *autask) -+{ -+ /* No RIP-relative addressing on 32-bit */ -+} -+#endif -+ -+/* -+ * arch_uprobe_pre_xol - prepare to execute out of line. -+ * @auprobe: the probepoint information. -+ * @regs: reflects the saved user state of current task. -+ */ -+int arch_uprobe_pre_xol(struct arch_uprobe *auprobe, struct pt_regs *regs) -+{ -+ struct arch_uprobe_task *autask; -+ -+ autask = ¤t->utask->autask; -+ autask->saved_trap_nr = current->thread.trap_nr; -+ current->thread.trap_nr = UPROBE_TRAP_NR; -+ regs->ip = current->utask->xol_vaddr; -+ pre_xol_rip_insn(auprobe, regs, autask); -+ -+ return 0; -+} -+ -+/* -+ * This function is called by arch_uprobe_post_xol() to adjust the return -+ * address pushed by a call instruction executed out of line. -+ */ -+static int adjust_ret_addr(unsigned long sp, long correction) -+{ -+ int rasize, ncopied; -+ long ra = 0; -+ -+ if (is_ia32_task()) -+ rasize = 4; -+ else -+ rasize = 8; -+ -+ ncopied = copy_from_user(&ra, (void __user *)sp, rasize); -+ if (unlikely(ncopied)) -+ return -EFAULT; -+ -+ ra += correction; -+ ncopied = copy_to_user((void __user *)sp, &ra, rasize); -+ if (unlikely(ncopied)) -+ return -EFAULT; -+ -+ return 0; -+} -+ -+#ifdef CONFIG_X86_64 -+static bool is_riprel_insn(struct arch_uprobe *auprobe) -+{ -+ return ((auprobe->fixups & (UPROBE_FIX_RIP_AX | UPROBE_FIX_RIP_CX)) != 0); -+} -+ -+static void -+handle_riprel_post_xol(struct arch_uprobe *auprobe, struct pt_regs *regs, long *correction) -+{ -+ if (is_riprel_insn(auprobe)) { -+ struct arch_uprobe_task *autask; -+ -+ autask = ¤t->utask->autask; -+ if (auprobe->fixups & UPROBE_FIX_RIP_AX) -+ regs->ax = autask->saved_scratch_register; -+ else -+ regs->cx = autask->saved_scratch_register; -+ -+ /* -+ * The original instruction includes a displacement, and so -+ * is 4 bytes longer than what we've just single-stepped. -+ * Fall through to handle stuff like "jmpq *...(%rip)" and -+ * "callq *...(%rip)". -+ */ -+ if (correction) -+ *correction += 4; -+ } -+} -+#else -+static void -+handle_riprel_post_xol(struct arch_uprobe *auprobe, struct pt_regs *regs, long *correction) -+{ -+ /* No RIP-relative addressing on 32-bit */ -+} -+#endif -+ -+/* -+ * If xol insn itself traps and generates a signal(Say, -+ * SIGILL/SIGSEGV/etc), then detect the case where a singlestepped -+ * instruction jumps back to its own address. It is assumed that anything -+ * like do_page_fault/do_trap/etc sets thread.trap_nr != -1. -+ * -+ * arch_uprobe_pre_xol/arch_uprobe_post_xol save/restore thread.trap_nr, -+ * arch_uprobe_xol_was_trapped() simply checks that ->trap_nr is not equal to -+ * UPROBE_TRAP_NR == -1 set by arch_uprobe_pre_xol(). -+ */ -+bool arch_uprobe_xol_was_trapped(struct task_struct *t) -+{ -+ if (t->thread.trap_nr != UPROBE_TRAP_NR) -+ return true; -+ -+ return false; -+} -+ -+/* -+ * Called after single-stepping. To avoid the SMP problems that can -+ * occur when we temporarily put back the original opcode to -+ * single-step, we single-stepped a copy of the instruction. -+ * -+ * This function prepares to resume execution after the single-step. -+ * We have to fix things up as follows: -+ * -+ * Typically, the new ip is relative to the copied instruction. We need -+ * to make it relative to the original instruction (FIX_IP). Exceptions -+ * are return instructions and absolute or indirect jump or call instructions. -+ * -+ * If the single-stepped instruction was a call, the return address that -+ * is atop the stack is the address following the copied instruction. We -+ * need to make it the address following the original instruction (FIX_CALL). -+ * -+ * If the original instruction was a rip-relative instruction such as -+ * "movl %edx,0xnnnn(%rip)", we have instead executed an equivalent -+ * instruction using a scratch register -- e.g., "movl %edx,(%rax)". -+ * We need to restore the contents of the scratch register and adjust -+ * the ip, keeping in mind that the instruction we executed is 4 bytes -+ * shorter than the original instruction (since we squeezed out the offset -+ * field). (FIX_RIP_AX or FIX_RIP_CX) -+ */ -+int arch_uprobe_post_xol(struct arch_uprobe *auprobe, struct pt_regs *regs) -+{ -+ struct uprobe_task *utask; -+ long correction; -+ int result = 0; -+ -+ WARN_ON_ONCE(current->thread.trap_nr != UPROBE_TRAP_NR); -+ -+ utask = current->utask; -+ current->thread.trap_nr = utask->autask.saved_trap_nr; -+ correction = (long)(utask->vaddr - utask->xol_vaddr); -+ handle_riprel_post_xol(auprobe, regs, &correction); -+ if (auprobe->fixups & UPROBE_FIX_IP) -+ regs->ip += correction; -+ -+ if (auprobe->fixups & UPROBE_FIX_CALL) -+ result = adjust_ret_addr(regs->sp, correction); -+ -+ return result; -+} -+ -+/* callback routine for handling exceptions. */ -+int arch_uprobe_exception_notify(struct notifier_block *self, unsigned long val, void *data) -+{ -+ struct die_args *args = data; -+ struct pt_regs *regs = args->regs; -+ int ret = NOTIFY_DONE; -+ -+ /* We are only interested in userspace traps */ -+ if (regs && !user_mode_vm(regs)) -+ return NOTIFY_DONE; -+ -+ switch (val) { -+ case DIE_INT3: -+ if (uprobe_pre_sstep_notifier(regs)) -+ ret = NOTIFY_STOP; -+ -+ break; -+ -+ case DIE_DEBUG: -+ if (uprobe_post_sstep_notifier(regs)) -+ ret = NOTIFY_STOP; -+ -+ default: -+ break; -+ } -+ -+ return ret; -+} -+ -+/* -+ * This function gets called when XOL instruction either gets trapped or -+ * the thread has a fatal signal, so reset the instruction pointer to its -+ * probed address. -+ */ -+void arch_uprobe_abort_xol(struct arch_uprobe *auprobe, struct pt_regs *regs) -+{ -+ struct uprobe_task *utask = current->utask; -+ -+ current->thread.trap_nr = utask->autask.saved_trap_nr; -+ handle_riprel_post_xol(auprobe, regs, NULL); -+ instruction_pointer_set(regs, utask->vaddr); -+} -+ -+/* -+ * Skip these instructions as per the currently known x86 ISA. -+ * 0x66* { 0x90 | 0x0f 0x1f | 0x0f 0x19 | 0x87 0xc0 } -+ */ -+bool arch_uprobe_skip_sstep(struct arch_uprobe *auprobe, struct pt_regs *regs) -+{ -+ int i; -+ -+ for (i = 0; i < MAX_UINSN_BYTES; i++) { -+ if ((auprobe->insn[i] == 0x66)) -+ continue; -+ -+ if (auprobe->insn[i] == 0x90) -+ return true; -+ -+ if (i == (MAX_UINSN_BYTES - 1)) -+ break; -+ -+ if ((auprobe->insn[i] == 0x0f) && (auprobe->insn[i+1] == 0x1f)) -+ return true; -+ -+ if ((auprobe->insn[i] == 0x0f) && (auprobe->insn[i+1] == 0x19)) -+ return true; -+ -+ if ((auprobe->insn[i] == 0x87) && (auprobe->insn[i+1] == 0xc0)) -+ return true; -+ -+ break; -+ } -+ return false; -+} -diff --git a/include/linux/sched.h b/include/linux/sched.h -index a862c23..7bcc634 100644 ---- a/include/linux/sched.h -+++ b/include/linux/sched.h -@@ -1619,6 +1619,10 @@ struct task_struct { - #ifdef CONFIG_HAVE_HW_BREAKPOINT - atomic_t ptrace_bp_refcnt; - #endif -+#ifdef CONFIG_UPROBES -+ struct uprobe_task *utask; -+ int uprobe_srcu_id; -+#endif - }; - - /* Future-safe accessor for struct task_struct's cpus_allowed. */ -diff --git a/include/linux/uprobes.h b/include/linux/uprobes.h -index eac525f..5ec778f 100644 ---- a/include/linux/uprobes.h -+++ b/include/linux/uprobes.h -@@ -28,8 +28,9 @@ - #include <linux/rbtree.h> - - struct vm_area_struct; -+ - #ifdef CONFIG_ARCH_SUPPORTS_UPROBES --#include <asm/uprobes.h> -+# include <asm/uprobes.h> - #endif - - /* flags that denote/change uprobes behaviour */ -@@ -39,6 +40,8 @@ struct vm_area_struct; - - /* Dont run handlers when first register/ last unregister in progress*/ - #define UPROBE_RUN_HANDLER 0x2 -+/* Can skip singlestep */ -+#define UPROBE_SKIP_SSTEP 0x4 - - struct uprobe_consumer { - int (*handler)(struct uprobe_consumer *self, struct pt_regs *regs); -@@ -52,13 +55,42 @@ struct uprobe_consumer { - }; - - #ifdef CONFIG_UPROBES -+enum uprobe_task_state { -+ UTASK_RUNNING, -+ UTASK_BP_HIT, -+ UTASK_SSTEP, -+ UTASK_SSTEP_ACK, -+ UTASK_SSTEP_TRAPPED, -+}; -+ -+/* -+ * uprobe_task: Metadata of a task while it singlesteps. -+ */ -+struct uprobe_task { -+ enum uprobe_task_state state; -+ struct arch_uprobe_task autask; -+ -+ struct uprobe *active_uprobe; -+ -+ unsigned long xol_vaddr; -+ unsigned long vaddr; -+}; -+ - extern int __weak set_swbp(struct arch_uprobe *aup, struct mm_struct *mm, unsigned long vaddr); - extern int __weak set_orig_insn(struct arch_uprobe *aup, struct mm_struct *mm, unsigned long vaddr, bool verify); - extern bool __weak is_swbp_insn(uprobe_opcode_t *insn); - extern int uprobe_register(struct inode *inode, loff_t offset, struct uprobe_consumer *uc); - extern void uprobe_unregister(struct inode *inode, loff_t offset, struct uprobe_consumer *uc); - extern int uprobe_mmap(struct vm_area_struct *vma); --#else /* CONFIG_UPROBES is not defined */ -+extern void uprobe_free_utask(struct task_struct *t); -+extern void uprobe_copy_process(struct task_struct *t); -+extern unsigned long __weak uprobe_get_swbp_addr(struct pt_regs *regs); -+extern int uprobe_post_sstep_notifier(struct pt_regs *regs); -+extern int uprobe_pre_sstep_notifier(struct pt_regs *regs); -+extern void uprobe_notify_resume(struct pt_regs *regs); -+extern bool uprobe_deny_signal(void); -+extern bool __weak arch_uprobe_skip_sstep(struct arch_uprobe *aup, struct pt_regs *regs); -+#else /* !CONFIG_UPROBES */ - static inline int - uprobe_register(struct inode *inode, loff_t offset, struct uprobe_consumer *uc) - { -@@ -72,5 +104,22 @@ static inline int uprobe_mmap(struct vm_area_struct *vma) - { - return 0; - } --#endif /* CONFIG_UPROBES */ -+static inline void uprobe_notify_resume(struct pt_regs *regs) -+{ -+} -+static inline bool uprobe_deny_signal(void) -+{ -+ return false; -+} -+static inline unsigned long uprobe_get_swbp_addr(struct pt_regs *regs) -+{ -+ return 0; -+} -+static inline void uprobe_free_utask(struct task_struct *t) -+{ -+} -+static inline void uprobe_copy_process(struct task_struct *t) -+{ -+} -+#endif /* !CONFIG_UPROBES */ - #endif /* _LINUX_UPROBES_H */ -diff --git a/kernel/events/uprobes.c b/kernel/events/uprobes.c -index e56e56a..b807d15 100644 ---- a/kernel/events/uprobes.c -+++ b/kernel/events/uprobes.c -@@ -30,9 +30,12 @@ - #include <linux/rmap.h> /* anon_vma_prepare */ - #include <linux/mmu_notifier.h> /* set_pte_at_notify */ - #include <linux/swap.h> /* try_to_free_swap */ -+#include <linux/ptrace.h> /* user_enable_single_step */ -+#include <linux/kdebug.h> /* notifier mechanism */ - - #include <linux/uprobes.h> - -+static struct srcu_struct uprobes_srcu; - static struct rb_root uprobes_tree = RB_ROOT; - - static DEFINE_SPINLOCK(uprobes_treelock); /* serialize rbtree access */ -@@ -486,6 +489,9 @@ static struct uprobe *insert_uprobe(struct uprobe *uprobe) - u = __insert_uprobe(uprobe); - spin_unlock_irqrestore(&uprobes_treelock, flags); - -+ /* For now assume that the instruction need not be single-stepped */ -+ uprobe->flags |= UPROBE_SKIP_SSTEP; -+ - return u; - } - -@@ -523,6 +529,21 @@ static struct uprobe *alloc_uprobe(struct inode *inode, loff_t offset) - return uprobe; - } - -+static void handler_chain(struct uprobe *uprobe, struct pt_regs *regs) -+{ -+ struct uprobe_consumer *uc; -+ -+ if (!(uprobe->flags & UPROBE_RUN_HANDLER)) -+ return; -+ -+ down_read(&uprobe->consumer_rwsem); -+ for (uc = uprobe->consumers; uc; uc = uc->next) { -+ if (!uc->filter || uc->filter(uc, current)) -+ uc->handler(uc, regs); -+ } -+ up_read(&uprobe->consumer_rwsem); -+} -+ - /* Returns the previous consumer */ - static struct uprobe_consumer * - consumer_add(struct uprobe *uprobe, struct uprobe_consumer *uc) -@@ -645,7 +666,7 @@ install_breakpoint(struct uprobe *uprobe, struct mm_struct *mm, - if (is_swbp_insn((uprobe_opcode_t *)uprobe->arch.insn)) - return -EEXIST; - -- ret = arch_uprobes_analyze_insn(&uprobe->arch, mm); -+ ret = arch_uprobe_analyze_insn(&uprobe->arch, mm); - if (ret) - return ret; - -@@ -662,10 +683,21 @@ remove_breakpoint(struct uprobe *uprobe, struct mm_struct *mm, loff_t vaddr) - set_orig_insn(&uprobe->arch, mm, (unsigned long)vaddr, true); - } - -+/* -+ * There could be threads that have hit the breakpoint and are entering the -+ * notifier code and trying to acquire the uprobes_treelock. The thread -+ * calling delete_uprobe() that is removing the uprobe from the rb_tree can -+ * race with these threads and might acquire the uprobes_treelock compared -+ * to some of the breakpoint hit threads. In such a case, the breakpoint -+ * hit threads will not find the uprobe. The current unregistering thread -+ * waits till all other threads have hit a breakpoint, to acquire the -+ * uprobes_treelock before the uprobe is removed from the rbtree. -+ */ - static void delete_uprobe(struct uprobe *uprobe) - { - unsigned long flags; - -+ synchronize_srcu(&uprobes_srcu); - spin_lock_irqsave(&uprobes_treelock, flags); - rb_erase(&uprobe->rb_node, &uprobes_tree); - spin_unlock_irqrestore(&uprobes_treelock, flags); -@@ -1010,6 +1042,288 @@ int uprobe_mmap(struct vm_area_struct *vma) - return ret; - } - -+/** -+ * uprobe_get_swbp_addr - compute address of swbp given post-swbp regs -+ * @regs: Reflects the saved state of the task after it has hit a breakpoint -+ * instruction. -+ * Return the address of the breakpoint instruction. -+ */ -+unsigned long __weak uprobe_get_swbp_addr(struct pt_regs *regs) -+{ -+ return instruction_pointer(regs) - UPROBE_SWBP_INSN_SIZE; -+} -+ -+/* -+ * Called with no locks held. -+ * Called in context of a exiting or a exec-ing thread. -+ */ -+void uprobe_free_utask(struct task_struct *t) -+{ -+ struct uprobe_task *utask = t->utask; -+ -+ if (t->uprobe_srcu_id != -1) -+ srcu_read_unlock_raw(&uprobes_srcu, t->uprobe_srcu_id); -+ -+ if (!utask) -+ return; -+ -+ if (utask->active_uprobe) -+ put_uprobe(utask->active_uprobe); -+ -+ kfree(utask); -+ t->utask = NULL; -+} -+ -+/* -+ * Called in context of a new clone/fork from copy_process. -+ */ -+void uprobe_copy_process(struct task_struct *t) -+{ -+ t->utask = NULL; -+ t->uprobe_srcu_id = -1; -+} -+ -+/* -+ * Allocate a uprobe_task object for the task. -+ * Called when the thread hits a breakpoint for the first time. -+ * -+ * Returns: -+ * - pointer to new uprobe_task on success -+ * - NULL otherwise -+ */ -+static struct uprobe_task *add_utask(void) -+{ -+ struct uprobe_task *utask; -+ -+ utask = kzalloc(sizeof *utask, GFP_KERNEL); -+ if (unlikely(!utask)) -+ return NULL; -+ -+ utask->active_uprobe = NULL; -+ current->utask = utask; -+ return utask; -+} -+ -+/* Prepare to single-step probed instruction out of line. */ -+static int -+pre_ssout(struct uprobe *uprobe, struct pt_regs *regs, unsigned long vaddr) -+{ -+ return -EFAULT; -+} -+ -+/* -+ * If we are singlestepping, then ensure this thread is not connected to -+ * non-fatal signals until completion of singlestep. When xol insn itself -+ * triggers the signal, restart the original insn even if the task is -+ * already SIGKILL'ed (since coredump should report the correct ip). This -+ * is even more important if the task has a handler for SIGSEGV/etc, The -+ * _same_ instruction should be repeated again after return from the signal -+ * handler, and SSTEP can never finish in this case. -+ */ -+bool uprobe_deny_signal(void) -+{ -+ struct task_struct *t = current; -+ struct uprobe_task *utask = t->utask; -+ -+ if (likely(!utask || !utask->active_uprobe)) -+ return false; -+ -+ WARN_ON_ONCE(utask->state != UTASK_SSTEP); -+ -+ if (signal_pending(t)) { -+ spin_lock_irq(&t->sighand->siglock); -+ clear_tsk_thread_flag(t, TIF_SIGPENDING); -+ spin_unlock_irq(&t->sighand->siglock); -+ -+ if (__fatal_signal_pending(t) || arch_uprobe_xol_was_trapped(t)) { -+ utask->state = UTASK_SSTEP_TRAPPED; -+ set_tsk_thread_flag(t, TIF_UPROBE); -+ set_tsk_thread_flag(t, TIF_NOTIFY_RESUME); -+ } -+ } -+ -+ return true; -+} -+ -+/* -+ * Avoid singlestepping the original instruction if the original instruction -+ * is a NOP or can be emulated. -+ */ -+static bool can_skip_sstep(struct uprobe *uprobe, struct pt_regs *regs) -+{ -+ if (arch_uprobe_skip_sstep(&uprobe->arch, regs)) -+ return true; -+ -+ uprobe->flags &= ~UPROBE_SKIP_SSTEP; -+ return false; -+} -+ -+/* -+ * Run handler and ask thread to singlestep. -+ * Ensure all non-fatal signals cannot interrupt thread while it singlesteps. -+ */ -+static void handle_swbp(struct pt_regs *regs) -+{ -+ struct vm_area_struct *vma; -+ struct uprobe_task *utask; -+ struct uprobe *uprobe; -+ struct mm_struct *mm; -+ unsigned long bp_vaddr; -+ -+ uprobe = NULL; -+ bp_vaddr = uprobe_get_swbp_addr(regs); -+ mm = current->mm; -+ down_read(&mm->mmap_sem); -+ vma = find_vma(mm, bp_vaddr); -+ -+ if (vma && vma->vm_start <= bp_vaddr && valid_vma(vma, false)) { -+ struct inode *inode; -+ loff_t offset; -+ -+ inode = vma->vm_file->f_mapping->host; -+ offset = bp_vaddr - vma->vm_start; -+ offset += (vma->vm_pgoff << PAGE_SHIFT); -+ uprobe = find_uprobe(inode, offset); -+ } -+ -+ srcu_read_unlock_raw(&uprobes_srcu, current->uprobe_srcu_id); -+ current->uprobe_srcu_id = -1; -+ up_read(&mm->mmap_sem); -+ -+ if (!uprobe) { -+ /* No matching uprobe; signal SIGTRAP. */ -+ send_sig(SIGTRAP, current, 0); -+ return; -+ } -+ -+ utask = current->utask; -+ if (!utask) { -+ utask = add_utask(); -+ /* Cannot allocate; re-execute the instruction. */ -+ if (!utask) -+ goto cleanup_ret; -+ } -+ utask->active_uprobe = uprobe; -+ handler_chain(uprobe, regs); -+ if (uprobe->flags & UPROBE_SKIP_SSTEP && can_skip_sstep(uprobe, regs)) -+ goto cleanup_ret; -+ -+ utask->state = UTASK_SSTEP; -+ if (!pre_ssout(uprobe, regs, bp_vaddr)) { -+ user_enable_single_step(current); -+ return; -+ } -+ -+cleanup_ret: -+ if (utask) { -+ utask->active_uprobe = NULL; -+ utask->state = UTASK_RUNNING; -+ } -+ if (uprobe) { -+ if (!(uprobe->flags & UPROBE_SKIP_SSTEP)) -+ -+ /* -+ * cannot singlestep; cannot skip instruction; -+ * re-execute the instruction. -+ */ -+ instruction_pointer_set(regs, bp_vaddr); -+ -+ put_uprobe(uprobe); -+ } -+} -+ -+/* -+ * Perform required fix-ups and disable singlestep. -+ * Allow pending signals to take effect. -+ */ -+static void handle_singlestep(struct uprobe_task *utask, struct pt_regs *regs) -+{ -+ struct uprobe *uprobe; -+ -+ uprobe = utask->active_uprobe; -+ if (utask->state == UTASK_SSTEP_ACK) -+ arch_uprobe_post_xol(&uprobe->arch, regs); -+ else if (utask->state == UTASK_SSTEP_TRAPPED) -+ arch_uprobe_abort_xol(&uprobe->arch, regs); -+ else -+ WARN_ON_ONCE(1); -+ -+ put_uprobe(uprobe); -+ utask->active_uprobe = NULL; -+ utask->state = UTASK_RUNNING; -+ user_disable_single_step(current); -+ -+ spin_lock_irq(¤t->sighand->siglock); -+ recalc_sigpending(); /* see uprobe_deny_signal() */ -+ spin_unlock_irq(¤t->sighand->siglock); -+} -+ -+/* -+ * On breakpoint hit, breakpoint notifier sets the TIF_UPROBE flag. (and on -+ * subsequent probe hits on the thread sets the state to UTASK_BP_HIT) and -+ * allows the thread to return from interrupt. -+ * -+ * On singlestep exception, singlestep notifier sets the TIF_UPROBE flag and -+ * also sets the state to UTASK_SSTEP_ACK and allows the thread to return from -+ * interrupt. -+ * -+ * While returning to userspace, thread notices the TIF_UPROBE flag and calls -+ * uprobe_notify_resume(). -+ */ -+void uprobe_notify_resume(struct pt_regs *regs) -+{ -+ struct uprobe_task *utask; -+ -+ utask = current->utask; -+ if (!utask || utask->state == UTASK_BP_HIT) -+ handle_swbp(regs); -+ else -+ handle_singlestep(utask, regs); -+} -+ -+/* -+ * uprobe_pre_sstep_notifier gets called from interrupt context as part of -+ * notifier mechanism. Set TIF_UPROBE flag and indicate breakpoint hit. -+ */ -+int uprobe_pre_sstep_notifier(struct pt_regs *regs) -+{ -+ struct uprobe_task *utask; -+ -+ if (!current->mm) -+ return 0; -+ -+ utask = current->utask; -+ if (utask) -+ utask->state = UTASK_BP_HIT; -+ -+ set_thread_flag(TIF_UPROBE); -+ current->uprobe_srcu_id = srcu_read_lock_raw(&uprobes_srcu); -+ -+ return 1; -+} -+ -+/* -+ * uprobe_post_sstep_notifier gets called in interrupt context as part of notifier -+ * mechanism. Set TIF_UPROBE flag and indicate completion of singlestep. -+ */ -+int uprobe_post_sstep_notifier(struct pt_regs *regs) -+{ -+ struct uprobe_task *utask = current->utask; -+ -+ if (!current->mm || !utask || !utask->active_uprobe) -+ /* task is currently not uprobed */ -+ return 0; -+ -+ utask->state = UTASK_SSTEP_ACK; -+ set_thread_flag(TIF_UPROBE); -+ return 1; -+} -+ -+static struct notifier_block uprobe_exception_nb = { -+ .notifier_call = arch_uprobe_exception_notify, -+ .priority = INT_MAX-1, /* notified after kprobes, kgdb */ -+}; -+ - static int __init init_uprobes(void) - { - int i; -@@ -1018,12 +1332,13 @@ static int __init init_uprobes(void) - mutex_init(&uprobes_mutex[i]); - mutex_init(&uprobes_mmap_mutex[i]); - } -- return 0; -+ init_srcu_struct(&uprobes_srcu); -+ -+ return register_die_notifier(&uprobe_exception_nb); - } -+module_init(init_uprobes); - - static void __exit exit_uprobes(void) - { - } -- --module_init(init_uprobes); - module_exit(exit_uprobes); -diff --git a/kernel/fork.c b/kernel/fork.c -index 9faa812..5be9230 100644 ---- a/kernel/fork.c -+++ b/kernel/fork.c -@@ -69,6 +69,7 @@ - #include <linux/oom.h> - #include <linux/khugepaged.h> - #include <linux/signalfd.h> -+#include <linux/uprobes.h> - - #include <asm/pgtable.h> - #include <asm/pgalloc.h> -@@ -751,6 +752,8 @@ void mm_release(struct task_struct *tsk, struct mm_struct *mm) - exit_pi_state_list(tsk); - #endif - -+ uprobe_free_utask(tsk); -+ - /* Get rid of any cached register state */ - deactivate_mm(tsk, mm); - -@@ -1347,6 +1350,7 @@ static struct task_struct *copy_process(unsigned long clone_flags, - INIT_LIST_HEAD(&p->pi_state_list); - p->pi_state_cache = NULL; - #endif -+ uprobe_copy_process(p); - /* - * sigaltstack should be cleared when sharing the same VM - */ -diff --git a/kernel/signal.c b/kernel/signal.c -index 1a006b5..9da710c 100644 ---- a/kernel/signal.c -+++ b/kernel/signal.c -@@ -29,6 +29,7 @@ - #include <linux/pid_namespace.h> - #include <linux/nsproxy.h> - #include <linux/user_namespace.h> -+#include <linux/uprobes.h> - #define CREATE_TRACE_POINTS - #include <trace/events/signal.h> - -@@ -2202,6 +2203,9 @@ int get_signal_to_deliver(siginfo_t *info, struct k_sigaction *return_ka, - struct signal_struct *signal = current->signal; - int signr; - -+ if (unlikely(uprobe_deny_signal())) -+ return 0; -+ - relock: - /* - * We'll jump back here after any time we were stopped in TASK_STOPPED. --- -1.7.5.4 - diff --git a/features/uprobe/uprobes-core-Make-background-page-replacement-logic-.patch b/features/uprobe/uprobes-core-Make-background-page-replacement-logic-.patch deleted file mode 100644 index d4d812441311a901bb12716e7a85e25809fdb1f0..0000000000000000000000000000000000000000 --- a/features/uprobe/uprobes-core-Make-background-page-replacement-logic-.patch +++ /dev/null @@ -1,57 +0,0 @@ -From a25205633f0b98c88dceb56cd61adeda54f41390 Mon Sep 17 00:00:00 2001 -From: Srikar Dronamraju <srikar@linux.vnet.ibm.com> -Date: Wed, 11 Apr 2012 16:05:16 +0530 -Subject: [PATCH 14/24] uprobes/core: Make background page replacement logic - account for rss_stat counters - -Background page replacement logic adds a new anonymous page -instead of a file backed (while inserting a breakpoint) / -anonymous page (while removing a breakpoint). - -Hence the uprobes logic should take care to update the -task->ss_stat counters accordingly. - -This bug became apparent courtesy of commit c3f0327f8e9d -("mm: add rss counters consistency check"). - -commit 7396fa818d6278694a44840f389ddc40a3269a9a upstream - -Signed-off-by: Srikar Dronamraju <srikar@linux.vnet.ibm.com> -Cc: Linus Torvalds <torvalds@linux-foundation.org> -Cc: Ananth N Mavinakayanahalli <ananth@in.ibm.com> -Cc: Jim Keniston <jkenisto@linux.vnet.ibm.com> -Cc: Linux-mm <linux-mm@kvack.org> -Cc: Oleg Nesterov <oleg@redhat.com> -Cc: Andi Kleen <andi@firstfloor.org> -Cc: Christoph Hellwig <hch@infradead.org> -Cc: Steven Rostedt <rostedt@goodmis.org> -Cc: Arnaldo Carvalho de Melo <acme@infradead.org> -Cc: Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com> -Cc: Anton Arapov <anton@redhat.com> -Cc: Peter Zijlstra <peterz@infradead.org> -Link: http://lkml.kernel.org/r/20120411103516.23245.2700.sendpatchset@srdronam.in.ibm.com -Signed-off-by: Ingo Molnar <mingo@kernel.org> -Signed-off-by: Paul Barrette <paul.barrette@windriver.com> ---- - kernel/events/uprobes.c | 5 +++++ - 1 files changed, 5 insertions(+), 0 deletions(-) - -diff --git a/kernel/events/uprobes.c b/kernel/events/uprobes.c -index 29e881b..c5caeec 100644 ---- a/kernel/events/uprobes.c -+++ b/kernel/events/uprobes.c -@@ -160,6 +160,11 @@ static int __replace_page(struct vm_area_struct *vma, struct page *page, struct - get_page(kpage); - page_add_new_anon_rmap(kpage, vma, addr); - -+ if (!PageAnon(page)) { -+ dec_mm_counter(mm, MM_FILEPAGES); -+ inc_mm_counter(mm, MM_ANONPAGES); -+ } -+ - flush_cache_page(vma, addr, pte_pfn(*ptep)); - ptep_clear_flush(vma, addr, ptep); - set_pte_at_notify(mm, addr, ptep, mk_pte(kpage, vma->vm_page_prot)); --- -1.7.5.4 - diff --git a/features/uprobe/uprobes-core-Make-instruction-tables-volatile.patch b/features/uprobe/uprobes-core-Make-instruction-tables-volatile.patch deleted file mode 100644 index c1bb7308f7ff098e834d0ddf1744cdcf28efdfcd..0000000000000000000000000000000000000000 --- a/features/uprobe/uprobes-core-Make-instruction-tables-volatile.patch +++ /dev/null @@ -1,121 +0,0 @@ -From 942b91cb42642479bd074388bf25881a3c3ca450 Mon Sep 17 00:00:00 2001 -From: Srikar Dronamraju <srikar@linux.vnet.ibm.com> -Date: Wed, 22 Feb 2012 14:45:35 +0530 -Subject: [PATCH 04/24] uprobes/core: Make instruction tables volatile - -Some versions of gcc spits a warning about the asm operand for -test_bit and also causes the first long of the instruction table -to be output. - -Fix is similar to 7115e3fc on arch/x86/kernel/kprobes.c - -commit 04a3d984d32e47983770d314cdb4e4d8f38fccb7 upstream - -Signed-off-by: Srikar Dronamraju <srikar@linux.vnet.ibm.com> -Cc: Peter Zijlstra <peterz@infradead.org> -Cc: Linus Torvalds <torvalds@linux-foundation.org> -Cc: Oleg Nesterov <oleg@redhat.com> -Cc: Christoph Hellwig <hch@infradead.org> -Cc: Steven Rostedt <rostedt@goodmis.org> -Cc: Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com> -Cc: Anton Arapov <anton@redhat.com> -Cc: Ananth N Mavinakayanahalli <ananth@in.ibm.com> -Cc: Jim Keniston <jkenisto@linux.vnet.ibm.com> -Cc: Jiri Olsa <jolsa@redhat.com> -Cc: Josh Stone <jistone@redhat.com> -Link: http://lkml.kernel.org/r/20120222091535.15880.12502.sendpatchset@srdronam.in.ibm.com -Signed-off-by: Ingo Molnar <mingo@elte.hu> -Signed-off-by: Paul Barrette <paul.barrette@windriver.com> ---- - arch/x86/kernel/uprobes.c | 61 +++++++++++++++++++++++--------------------- - 1 files changed, 32 insertions(+), 29 deletions(-) - -diff --git a/arch/x86/kernel/uprobes.c b/arch/x86/kernel/uprobes.c -index cf2a184..13d616d 100644 ---- a/arch/x86/kernel/uprobes.c -+++ b/arch/x86/kernel/uprobes.c -@@ -53,34 +53,12 @@ - (bc##UL << 0xc)|(bd##UL << 0xd)|(be##UL << 0xe)|(bf##UL << 0xf)) \ - << (row % 32)) - --#ifdef CONFIG_X86_64 --static u32 good_insns_64[256 / 32] = { -- /* 0 1 2 3 4 5 6 7 8 9 a b c d e f */ -- /* ---------------------------------------------- */ -- W(0x00, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0) | /* 00 */ -- W(0x10, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0) , /* 10 */ -- W(0x20, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0) | /* 20 */ -- W(0x30, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0) , /* 30 */ -- W(0x40, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0) | /* 40 */ -- W(0x50, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1) , /* 50 */ -- W(0x60, 0, 0, 0, 1, 1, 1, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0) | /* 60 */ -- W(0x70, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1) , /* 70 */ -- W(0x80, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1) | /* 80 */ -- W(0x90, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1) , /* 90 */ -- W(0xa0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1) | /* a0 */ -- W(0xb0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1) , /* b0 */ -- W(0xc0, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0) | /* c0 */ -- W(0xd0, 1, 1, 1, 1, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1) , /* d0 */ -- W(0xe0, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0) | /* e0 */ -- W(0xf0, 0, 0, 1, 1, 0, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1) /* f0 */ -- /* ---------------------------------------------- */ -- /* 0 1 2 3 4 5 6 7 8 9 a b c d e f */ --}; --#endif -- --/* Good-instruction tables for 32-bit apps */ -- --static u32 good_insns_32[256 / 32] = { -+/* -+ * Good-instruction tables for 32-bit apps. This is non-const and volatile -+ * to keep gcc from statically optimizing it out, as variable_test_bit makes -+ * some versions of gcc to think only *(unsigned long*) is used. -+ */ -+static volatile u32 good_insns_32[256 / 32] = { - /* 0 1 2 3 4 5 6 7 8 9 a b c d e f */ - /* ---------------------------------------------- */ - W(0x00, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 0) | /* 00 */ -@@ -104,7 +82,7 @@ static u32 good_insns_32[256 / 32] = { - }; - - /* Using this for both 64-bit and 32-bit apps */ --static u32 good_2byte_insns[256 / 32] = { -+static volatile u32 good_2byte_insns[256 / 32] = { - /* 0 1 2 3 4 5 6 7 8 9 a b c d e f */ - /* ---------------------------------------------- */ - W(0x00, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1) | /* 00 */ -@@ -127,6 +105,31 @@ static u32 good_2byte_insns[256 / 32] = { - /* 0 1 2 3 4 5 6 7 8 9 a b c d e f */ - }; - -+#ifdef CONFIG_X86_64 -+/* Good-instruction tables for 64-bit apps */ -+static volatile u32 good_insns_64[256 / 32] = { -+ /* 0 1 2 3 4 5 6 7 8 9 a b c d e f */ -+ /* ---------------------------------------------- */ -+ W(0x00, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0) | /* 00 */ -+ W(0x10, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0) , /* 10 */ -+ W(0x20, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0) | /* 20 */ -+ W(0x30, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0) , /* 30 */ -+ W(0x40, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0) | /* 40 */ -+ W(0x50, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1) , /* 50 */ -+ W(0x60, 0, 0, 0, 1, 1, 1, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0) | /* 60 */ -+ W(0x70, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1) , /* 70 */ -+ W(0x80, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1) | /* 80 */ -+ W(0x90, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1) , /* 90 */ -+ W(0xa0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1) | /* a0 */ -+ W(0xb0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1) , /* b0 */ -+ W(0xc0, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0) | /* c0 */ -+ W(0xd0, 1, 1, 1, 1, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1) , /* d0 */ -+ W(0xe0, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0) | /* e0 */ -+ W(0xf0, 0, 0, 1, 1, 0, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1) /* f0 */ -+ /* ---------------------------------------------- */ -+ /* 0 1 2 3 4 5 6 7 8 9 a b c d e f */ -+}; -+#endif - #undef W - - /* --- -1.7.5.4 - diff --git a/features/uprobe/uprobes-core-Make-macro-names-consistent.patch b/features/uprobe/uprobes-core-Make-macro-names-consistent.patch deleted file mode 100644 index d72b37d379330627a4819a1166bd0eecf4df712b..0000000000000000000000000000000000000000 --- a/features/uprobe/uprobes-core-Make-macro-names-consistent.patch +++ /dev/null @@ -1,201 +0,0 @@ -From 7e9be9963c8b594bfe07145d3fe56549377f0bc4 Mon Sep 17 00:00:00 2001 -From: Srikar Dronamraju <srikar@linux.vnet.ibm.com> -Date: Mon, 12 Mar 2012 14:55:14 +0530 -Subject: [PATCH 08/24] uprobes/core: Make macro names consistent - -Rename macros that refer to individual uprobe to start with -UPROBE_ instead of UPROBES_. - -This is pure cleanup, no functional change intended. - -commit 900771a483ef28915a48066d7895d8252315607a upstream - -Signed-off-by: Srikar Dronamraju <srikar@linux.vnet.ibm.com> -Cc: Linus Torvalds <torvalds@linux-foundation.org> -Cc: Ananth N Mavinakayanahalli <ananth@in.ibm.com> -Cc: Jim Keniston <jkenisto@linux.vnet.ibm.com> -Cc: Linux-mm <linux-mm@kvack.org> -Cc: Oleg Nesterov <oleg@redhat.com> -Cc: Andi Kleen <andi@firstfloor.org> -Cc: Christoph Hellwig <hch@infradead.org> -Cc: Steven Rostedt <rostedt@goodmis.org> -Cc: Arnaldo Carvalho de Melo <acme@infradead.org> -Cc: Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com> -Cc: Peter Zijlstra <peterz@infradead.org> -Link: http://lkml.kernel.org/r/20120312092514.5379.36595.sendpatchset@srdronam.in.ibm.com -Signed-off-by: Ingo Molnar <mingo@elte.hu> -Signed-off-by: Paul Barrette <paul.barrette@windriver.com> ---- - arch/x86/include/asm/uprobes.h | 6 +++--- - arch/x86/kernel/uprobes.c | 18 +++++++++--------- - include/linux/uprobes.h | 4 ++-- - kernel/events/uprobes.c | 18 +++++++++--------- - 4 files changed, 23 insertions(+), 23 deletions(-) - -diff --git a/arch/x86/include/asm/uprobes.h b/arch/x86/include/asm/uprobes.h -index f7ce310..5c399e4 100644 ---- a/arch/x86/include/asm/uprobes.h -+++ b/arch/x86/include/asm/uprobes.h -@@ -26,10 +26,10 @@ - typedef u8 uprobe_opcode_t; - - #define MAX_UINSN_BYTES 16 --#define UPROBES_XOL_SLOT_BYTES 128 /* to keep it cache aligned */ -+#define UPROBE_XOL_SLOT_BYTES 128 /* to keep it cache aligned */ - --#define UPROBES_BKPT_INSN 0xcc --#define UPROBES_BKPT_INSN_SIZE 1 -+#define UPROBE_BKPT_INSN 0xcc -+#define UPROBE_BKPT_INSN_SIZE 1 - - struct arch_uprobe { - u16 fixups; -diff --git a/arch/x86/kernel/uprobes.c b/arch/x86/kernel/uprobes.c -index 04dfcef..6dfa89e 100644 ---- a/arch/x86/kernel/uprobes.c -+++ b/arch/x86/kernel/uprobes.c -@@ -31,14 +31,14 @@ - /* Post-execution fixups. */ - - /* No fixup needed */ --#define UPROBES_FIX_NONE 0x0 -+#define UPROBE_FIX_NONE 0x0 - /* Adjust IP back to vicinity of actual insn */ --#define UPROBES_FIX_IP 0x1 -+#define UPROBE_FIX_IP 0x1 - /* Adjust the return address of a call insn */ --#define UPROBES_FIX_CALL 0x2 -+#define UPROBE_FIX_CALL 0x2 - --#define UPROBES_FIX_RIP_AX 0x8000 --#define UPROBES_FIX_RIP_CX 0x4000 -+#define UPROBE_FIX_RIP_AX 0x8000 -+#define UPROBE_FIX_RIP_CX 0x4000 - - /* Adaptations for mhiramat x86 decoder v14. */ - #define OPCODE1(insn) ((insn)->opcode.bytes[0]) -@@ -269,9 +269,9 @@ static void prepare_fixups(struct arch_uprobe *auprobe, struct insn *insn) - break; - } - if (fix_ip) -- auprobe->fixups |= UPROBES_FIX_IP; -+ auprobe->fixups |= UPROBE_FIX_IP; - if (fix_call) -- auprobe->fixups |= UPROBES_FIX_CALL; -+ auprobe->fixups |= UPROBE_FIX_CALL; - } - - #ifdef CONFIG_X86_64 -@@ -341,12 +341,12 @@ static void handle_riprel_insn(struct mm_struct *mm, struct arch_uprobe *auprobe - * is NOT the register operand, so we use %rcx (register - * #1) for the scratch register. - */ -- auprobe->fixups = UPROBES_FIX_RIP_CX; -+ auprobe->fixups = UPROBE_FIX_RIP_CX; - /* Change modrm from 00 000 101 to 00 000 001. */ - *cursor = 0x1; - } else { - /* Use %rax (register #0) for the scratch register. */ -- auprobe->fixups = UPROBES_FIX_RIP_AX; -+ auprobe->fixups = UPROBE_FIX_RIP_AX; - /* Change modrm from 00 xxx 101 to 00 xxx 000 */ - *cursor = (reg << 3); - } -diff --git a/include/linux/uprobes.h b/include/linux/uprobes.h -index f85797e..838fb31 100644 ---- a/include/linux/uprobes.h -+++ b/include/linux/uprobes.h -@@ -35,10 +35,10 @@ struct vm_area_struct; - /* flags that denote/change uprobes behaviour */ - - /* Have a copy of original instruction */ --#define UPROBES_COPY_INSN 0x1 -+#define UPROBE_COPY_INSN 0x1 - - /* Dont run handlers when first register/ last unregister in progress*/ --#define UPROBES_RUN_HANDLER 0x2 -+#define UPROBE_RUN_HANDLER 0x2 - - struct uprobe_consumer { - int (*handler)(struct uprobe_consumer *self, struct pt_regs *regs); -diff --git a/kernel/events/uprobes.c b/kernel/events/uprobes.c -index 5ce32e3..0d36bf3 100644 ---- a/kernel/events/uprobes.c -+++ b/kernel/events/uprobes.c -@@ -177,7 +177,7 @@ out: - */ - bool __weak is_bkpt_insn(uprobe_opcode_t *insn) - { -- return *insn == UPROBES_BKPT_INSN; -+ return *insn == UPROBE_BKPT_INSN; - } - - /* -@@ -259,8 +259,8 @@ static int write_opcode(struct mm_struct *mm, struct arch_uprobe *auprobe, - - /* poke the new insn in, ASSUMES we don't cross page boundary */ - vaddr &= ~PAGE_MASK; -- BUG_ON(vaddr + UPROBES_BKPT_INSN_SIZE > PAGE_SIZE); -- memcpy(vaddr_new + vaddr, &opcode, UPROBES_BKPT_INSN_SIZE); -+ BUG_ON(vaddr + UPROBE_BKPT_INSN_SIZE > PAGE_SIZE); -+ memcpy(vaddr_new + vaddr, &opcode, UPROBE_BKPT_INSN_SIZE); - - kunmap_atomic(vaddr_new); - kunmap_atomic(vaddr_old); -@@ -308,7 +308,7 @@ static int read_opcode(struct mm_struct *mm, unsigned long vaddr, uprobe_opcode_ - lock_page(page); - vaddr_new = kmap_atomic(page); - vaddr &= ~PAGE_MASK; -- memcpy(opcode, vaddr_new + vaddr, UPROBES_BKPT_INSN_SIZE); -+ memcpy(opcode, vaddr_new + vaddr, UPROBE_BKPT_INSN_SIZE); - kunmap_atomic(vaddr_new); - unlock_page(page); - -@@ -352,7 +352,7 @@ int __weak set_bkpt(struct mm_struct *mm, struct arch_uprobe *auprobe, unsigned - if (result) - return result; - -- return write_opcode(mm, auprobe, vaddr, UPROBES_BKPT_INSN); -+ return write_opcode(mm, auprobe, vaddr, UPROBE_BKPT_INSN); - } - - /** -@@ -635,7 +635,7 @@ static int install_breakpoint(struct mm_struct *mm, struct uprobe *uprobe, - - addr = (unsigned long)vaddr; - -- if (!(uprobe->flags & UPROBES_COPY_INSN)) { -+ if (!(uprobe->flags & UPROBE_COPY_INSN)) { - ret = copy_insn(uprobe, vma, addr); - if (ret) - return ret; -@@ -647,7 +647,7 @@ static int install_breakpoint(struct mm_struct *mm, struct uprobe *uprobe, - if (ret) - return ret; - -- uprobe->flags |= UPROBES_COPY_INSN; -+ uprobe->flags |= UPROBE_COPY_INSN; - } - ret = set_bkpt(mm, &uprobe->arch, addr); - -@@ -857,7 +857,7 @@ int uprobe_register(struct inode *inode, loff_t offset, struct uprobe_consumer * - uprobe->consumers = NULL; - __uprobe_unregister(uprobe); - } else { -- uprobe->flags |= UPROBES_RUN_HANDLER; -+ uprobe->flags |= UPROBE_RUN_HANDLER; - } - } - -@@ -889,7 +889,7 @@ void uprobe_unregister(struct inode *inode, loff_t offset, struct uprobe_consume - if (consumer_del(uprobe, consumer)) { - if (!uprobe->consumers) { - __uprobe_unregister(uprobe); -- uprobe->flags &= ~UPROBES_RUN_HANDLER; -+ uprobe->flags &= ~UPROBE_RUN_HANDLER; - } - } - --- -1.7.5.4 - diff --git a/features/uprobe/uprobes-core-Make-order-of-function-parameters-consi.patch b/features/uprobe/uprobes-core-Make-order-of-function-parameters-consi.patch deleted file mode 100644 index dc1b0bc594e25409584ba0a27065934751369602..0000000000000000000000000000000000000000 --- a/features/uprobe/uprobes-core-Make-order-of-function-parameters-consi.patch +++ /dev/null @@ -1,439 +0,0 @@ -From c99bc182fd0d61937402f87fdf0a29cc54ab1369 Mon Sep 17 00:00:00 2001 -From: Srikar Dronamraju <srikar@linux.vnet.ibm.com> -Date: Mon, 12 Mar 2012 14:55:30 +0530 -Subject: [PATCH 09/24] uprobes/core: Make order of function parameters - consistent across functions - -If a function takes struct uprobe or struct arch_uprobe, then it -is passed as the first parameter. - -This is pure cleanup, no functional change intended. - -commit e3343e6a2819ff5d0dfc4bb5c9fb7f9a4d04da73 upstream - -Signed-off-by: Srikar Dronamraju <srikar@linux.vnet.ibm.com> -Cc: Linus Torvalds <torvalds@linux-foundation.org> -Cc: Ananth N Mavinakayanahalli <ananth@in.ibm.com> -Cc: Jim Keniston <jkenisto@linux.vnet.ibm.com> -Cc: Linux-mm <linux-mm@kvack.org> -Cc: Oleg Nesterov <oleg@redhat.com> -Cc: Andi Kleen <andi@firstfloor.org> -Cc: Christoph Hellwig <hch@infradead.org> -Cc: Steven Rostedt <rostedt@goodmis.org> -Cc: Arnaldo Carvalho de Melo <acme@infradead.org> -Cc: Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com> -Cc: Peter Zijlstra <peterz@infradead.org> -Link: http://lkml.kernel.org/r/20120312092530.5379.18394.sendpatchset@srdronam.in.ibm.com -Signed-off-by: Ingo Molnar <mingo@elte.hu> -Signed-off-by: Paul Barrette <paul.barrette@windriver.com> ---- - arch/x86/include/asm/uprobes.h | 2 +- - arch/x86/kernel/uprobes.c | 15 +++--- - include/linux/uprobes.h | 12 +++--- - kernel/events/uprobes.c | 93 ++++++++++++++++++++------------------- - 4 files changed, 63 insertions(+), 59 deletions(-) - -diff --git a/arch/x86/include/asm/uprobes.h b/arch/x86/include/asm/uprobes.h -index 5c399e4..384f1be 100644 ---- a/arch/x86/include/asm/uprobes.h -+++ b/arch/x86/include/asm/uprobes.h -@@ -39,5 +39,5 @@ struct arch_uprobe { - #endif - }; - --extern int arch_uprobes_analyze_insn(struct mm_struct *mm, struct arch_uprobe *arch_uprobe); -+extern int arch_uprobes_analyze_insn(struct arch_uprobe *aup, struct mm_struct *mm); - #endif /* _ASM_UPROBES_H */ -diff --git a/arch/x86/kernel/uprobes.c b/arch/x86/kernel/uprobes.c -index 6dfa89e..851a11b 100644 ---- a/arch/x86/kernel/uprobes.c -+++ b/arch/x86/kernel/uprobes.c -@@ -297,7 +297,8 @@ static void prepare_fixups(struct arch_uprobe *auprobe, struct insn *insn) - * - There's never a SIB byte. - * - The displacement is always 4 bytes. - */ --static void handle_riprel_insn(struct mm_struct *mm, struct arch_uprobe *auprobe, struct insn *insn) -+static void -+handle_riprel_insn(struct arch_uprobe *auprobe, struct mm_struct *mm, struct insn *insn) - { - u8 *cursor; - u8 reg; -@@ -381,19 +382,19 @@ static int validate_insn_64bits(struct arch_uprobe *auprobe, struct insn *insn) - return -ENOTSUPP; - } - --static int validate_insn_bits(struct mm_struct *mm, struct arch_uprobe *auprobe, struct insn *insn) -+static int validate_insn_bits(struct arch_uprobe *auprobe, struct mm_struct *mm, struct insn *insn) - { - if (mm->context.ia32_compat) - return validate_insn_32bits(auprobe, insn); - return validate_insn_64bits(auprobe, insn); - } - #else /* 32-bit: */ --static void handle_riprel_insn(struct mm_struct *mm, struct arch_uprobe *auprobe, struct insn *insn) -+static void handle_riprel_insn(struct arch_uprobe *auprobe, struct mm_struct *mm, struct insn *insn) - { - /* No RIP-relative addressing on 32-bit */ - } - --static int validate_insn_bits(struct mm_struct *mm, struct arch_uprobe *auprobe, struct insn *insn) -+static int validate_insn_bits(struct arch_uprobe *auprobe, struct mm_struct *mm, struct insn *insn) - { - return validate_insn_32bits(auprobe, insn); - } -@@ -405,17 +406,17 @@ static int validate_insn_bits(struct mm_struct *mm, struct arch_uprobe *auprobe, - * @arch_uprobe: the probepoint information. - * Return 0 on success or a -ve number on error. - */ --int arch_uprobes_analyze_insn(struct mm_struct *mm, struct arch_uprobe *auprobe) -+int arch_uprobes_analyze_insn(struct arch_uprobe *auprobe, struct mm_struct *mm) - { - int ret; - struct insn insn; - - auprobe->fixups = 0; -- ret = validate_insn_bits(mm, auprobe, &insn); -+ ret = validate_insn_bits(auprobe, mm, &insn); - if (ret != 0) - return ret; - -- handle_riprel_insn(mm, auprobe, &insn); -+ handle_riprel_insn(auprobe, mm, &insn); - prepare_fixups(auprobe, &insn); - - return 0; -diff --git a/include/linux/uprobes.h b/include/linux/uprobes.h -index 838fb31..5869918 100644 ---- a/include/linux/uprobes.h -+++ b/include/linux/uprobes.h -@@ -52,20 +52,20 @@ struct uprobe_consumer { - }; - - #ifdef CONFIG_UPROBES --extern int __weak set_bkpt(struct mm_struct *mm, struct arch_uprobe *auprobe, unsigned long vaddr); --extern int __weak set_orig_insn(struct mm_struct *mm, struct arch_uprobe *auprobe, unsigned long vaddr, bool verify); -+extern int __weak set_bkpt(struct arch_uprobe *aup, struct mm_struct *mm, unsigned long vaddr); -+extern int __weak set_orig_insn(struct arch_uprobe *aup, struct mm_struct *mm, unsigned long vaddr, bool verify); - extern bool __weak is_bkpt_insn(uprobe_opcode_t *insn); --extern int uprobe_register(struct inode *inode, loff_t offset, struct uprobe_consumer *consumer); --extern void uprobe_unregister(struct inode *inode, loff_t offset, struct uprobe_consumer *consumer); -+extern int uprobe_register(struct inode *inode, loff_t offset, struct uprobe_consumer *uc); -+extern void uprobe_unregister(struct inode *inode, loff_t offset, struct uprobe_consumer *uc); - extern int uprobe_mmap(struct vm_area_struct *vma); - #else /* CONFIG_UPROBES is not defined */ - static inline int --uprobe_register(struct inode *inode, loff_t offset, struct uprobe_consumer *consumer) -+uprobe_register(struct inode *inode, loff_t offset, struct uprobe_consumer *uc) - { - return -ENOSYS; - } - static inline void --uprobe_unregister(struct inode *inode, loff_t offset, struct uprobe_consumer *consumer) -+uprobe_unregister(struct inode *inode, loff_t offset, struct uprobe_consumer *uc) - { - } - static inline int uprobe_mmap(struct vm_area_struct *vma) -diff --git a/kernel/events/uprobes.c b/kernel/events/uprobes.c -index 0d36bf3..9c5ddff 100644 ---- a/kernel/events/uprobes.c -+++ b/kernel/events/uprobes.c -@@ -192,8 +192,8 @@ bool __weak is_bkpt_insn(uprobe_opcode_t *insn) - - /* - * write_opcode - write the opcode at a given virtual address. -+ * @auprobe: arch breakpointing information. - * @mm: the probed process address space. -- * @arch_uprobe: the breakpointing information. - * @vaddr: the virtual address to store the opcode. - * @opcode: opcode to be written at @vaddr. - * -@@ -203,7 +203,7 @@ bool __weak is_bkpt_insn(uprobe_opcode_t *insn) - * For mm @mm, write the opcode at @vaddr. - * Return 0 (success) or a negative errno. - */ --static int write_opcode(struct mm_struct *mm, struct arch_uprobe *auprobe, -+static int write_opcode(struct arch_uprobe *auprobe, struct mm_struct *mm, - unsigned long vaddr, uprobe_opcode_t opcode) - { - struct page *old_page, *new_page; -@@ -334,14 +334,14 @@ static int is_bkpt_at_addr(struct mm_struct *mm, unsigned long vaddr) - - /** - * set_bkpt - store breakpoint at a given address. -+ * @auprobe: arch specific probepoint information. - * @mm: the probed process address space. -- * @uprobe: the probepoint information. - * @vaddr: the virtual address to insert the opcode. - * - * For mm @mm, store the breakpoint instruction at @vaddr. - * Return 0 (success) or a negative errno. - */ --int __weak set_bkpt(struct mm_struct *mm, struct arch_uprobe *auprobe, unsigned long vaddr) -+int __weak set_bkpt(struct arch_uprobe *auprobe, struct mm_struct *mm, unsigned long vaddr) - { - int result; - -@@ -352,13 +352,13 @@ int __weak set_bkpt(struct mm_struct *mm, struct arch_uprobe *auprobe, unsigned - if (result) - return result; - -- return write_opcode(mm, auprobe, vaddr, UPROBE_BKPT_INSN); -+ return write_opcode(auprobe, mm, vaddr, UPROBE_BKPT_INSN); - } - - /** - * set_orig_insn - Restore the original instruction. - * @mm: the probed process address space. -- * @uprobe: the probepoint information. -+ * @auprobe: arch specific probepoint information. - * @vaddr: the virtual address to insert the opcode. - * @verify: if true, verify existance of breakpoint instruction. - * -@@ -366,7 +366,7 @@ int __weak set_bkpt(struct mm_struct *mm, struct arch_uprobe *auprobe, unsigned - * Return 0 (success) or a negative errno. - */ - int __weak --set_orig_insn(struct mm_struct *mm, struct arch_uprobe *auprobe, unsigned long vaddr, bool verify) -+set_orig_insn(struct arch_uprobe *auprobe, struct mm_struct *mm, unsigned long vaddr, bool verify) - { - if (verify) { - int result; -@@ -378,7 +378,7 @@ set_orig_insn(struct mm_struct *mm, struct arch_uprobe *auprobe, unsigned long v - if (result != 1) - return result; - } -- return write_opcode(mm, auprobe, vaddr, *(uprobe_opcode_t *)auprobe->insn); -+ return write_opcode(auprobe, mm, vaddr, *(uprobe_opcode_t *)auprobe->insn); - } - - static int match_uprobe(struct uprobe *l, struct uprobe *r) -@@ -525,30 +525,30 @@ static struct uprobe *alloc_uprobe(struct inode *inode, loff_t offset) - - /* Returns the previous consumer */ - static struct uprobe_consumer * --consumer_add(struct uprobe *uprobe, struct uprobe_consumer *consumer) -+consumer_add(struct uprobe *uprobe, struct uprobe_consumer *uc) - { - down_write(&uprobe->consumer_rwsem); -- consumer->next = uprobe->consumers; -- uprobe->consumers = consumer; -+ uc->next = uprobe->consumers; -+ uprobe->consumers = uc; - up_write(&uprobe->consumer_rwsem); - -- return consumer->next; -+ return uc->next; - } - - /* -- * For uprobe @uprobe, delete the consumer @consumer. -- * Return true if the @consumer is deleted successfully -+ * For uprobe @uprobe, delete the consumer @uc. -+ * Return true if the @uc is deleted successfully - * or return false. - */ --static bool consumer_del(struct uprobe *uprobe, struct uprobe_consumer *consumer) -+static bool consumer_del(struct uprobe *uprobe, struct uprobe_consumer *uc) - { - struct uprobe_consumer **con; - bool ret = false; - - down_write(&uprobe->consumer_rwsem); - for (con = &uprobe->consumers; *con; con = &(*con)->next) { -- if (*con == consumer) { -- *con = consumer->next; -+ if (*con == uc) { -+ *con = uc->next; - ret = true; - break; - } -@@ -558,8 +558,8 @@ static bool consumer_del(struct uprobe *uprobe, struct uprobe_consumer *consumer - return ret; - } - --static int __copy_insn(struct address_space *mapping, -- struct vm_area_struct *vma, char *insn, -+static int -+__copy_insn(struct address_space *mapping, struct vm_area_struct *vma, char *insn, - unsigned long nbytes, unsigned long offset) - { - struct file *filp = vma->vm_file; -@@ -590,7 +590,8 @@ static int __copy_insn(struct address_space *mapping, - return 0; - } - --static int copy_insn(struct uprobe *uprobe, struct vm_area_struct *vma, unsigned long addr) -+static int -+copy_insn(struct uprobe *uprobe, struct vm_area_struct *vma, unsigned long addr) - { - struct address_space *mapping; - unsigned long nbytes; -@@ -617,8 +618,9 @@ static int copy_insn(struct uprobe *uprobe, struct vm_area_struct *vma, unsigned - return __copy_insn(mapping, vma, uprobe->arch.insn, bytes, uprobe->offset); - } - --static int install_breakpoint(struct mm_struct *mm, struct uprobe *uprobe, -- struct vm_area_struct *vma, loff_t vaddr) -+static int -+install_breakpoint(struct uprobe *uprobe, struct mm_struct *mm, -+ struct vm_area_struct *vma, loff_t vaddr) - { - unsigned long addr; - int ret; -@@ -643,20 +645,21 @@ static int install_breakpoint(struct mm_struct *mm, struct uprobe *uprobe, - if (is_bkpt_insn((uprobe_opcode_t *)uprobe->arch.insn)) - return -EEXIST; - -- ret = arch_uprobes_analyze_insn(mm, &uprobe->arch); -+ ret = arch_uprobes_analyze_insn(&uprobe->arch, mm); - if (ret) - return ret; - - uprobe->flags |= UPROBE_COPY_INSN; - } -- ret = set_bkpt(mm, &uprobe->arch, addr); -+ ret = set_bkpt(&uprobe->arch, mm, addr); - - return ret; - } - --static void remove_breakpoint(struct mm_struct *mm, struct uprobe *uprobe, loff_t vaddr) -+static void -+remove_breakpoint(struct uprobe *uprobe, struct mm_struct *mm, loff_t vaddr) - { -- set_orig_insn(mm, &uprobe->arch, (unsigned long)vaddr, true); -+ set_orig_insn(&uprobe->arch, mm, (unsigned long)vaddr, true); - } - - static void delete_uprobe(struct uprobe *uprobe) -@@ -671,9 +674,9 @@ static void delete_uprobe(struct uprobe *uprobe) - atomic_dec(&uprobe_events); - } - --static struct vma_info *__find_next_vma_info(struct list_head *head, -- loff_t offset, struct address_space *mapping, -- struct vma_info *vi, bool is_register) -+static struct vma_info * -+__find_next_vma_info(struct address_space *mapping, struct list_head *head, -+ struct vma_info *vi, loff_t offset, bool is_register) - { - struct prio_tree_iter iter; - struct vm_area_struct *vma; -@@ -719,8 +722,8 @@ static struct vma_info *__find_next_vma_info(struct list_head *head, - * yet been inserted. - */ - static struct vma_info * --find_next_vma_info(struct list_head *head, loff_t offset, struct address_space *mapping, -- bool is_register) -+find_next_vma_info(struct address_space *mapping, struct list_head *head, -+ loff_t offset, bool is_register) - { - struct vma_info *vi, *retvi; - -@@ -729,7 +732,7 @@ find_next_vma_info(struct list_head *head, loff_t offset, struct address_space * - return ERR_PTR(-ENOMEM); - - mutex_lock(&mapping->i_mmap_mutex); -- retvi = __find_next_vma_info(head, offset, mapping, vi, is_register); -+ retvi = __find_next_vma_info(mapping, head, vi, offset, is_register); - mutex_unlock(&mapping->i_mmap_mutex); - - if (!retvi) -@@ -754,7 +757,7 @@ static int register_for_each_vma(struct uprobe *uprobe, bool is_register) - ret = 0; - - for (;;) { -- vi = find_next_vma_info(&try_list, uprobe->offset, mapping, is_register); -+ vi = find_next_vma_info(mapping, &try_list, uprobe->offset, is_register); - if (!vi) - break; - -@@ -784,9 +787,9 @@ static int register_for_each_vma(struct uprobe *uprobe, bool is_register) - } - - if (is_register) -- ret = install_breakpoint(mm, uprobe, vma, vi->vaddr); -+ ret = install_breakpoint(uprobe, mm, vma, vi->vaddr); - else -- remove_breakpoint(mm, uprobe, vi->vaddr); -+ remove_breakpoint(uprobe, mm, vi->vaddr); - - up_read(&mm->mmap_sem); - mmput(mm); -@@ -823,25 +826,25 @@ static void __uprobe_unregister(struct uprobe *uprobe) - * uprobe_register - register a probe - * @inode: the file in which the probe has to be placed. - * @offset: offset from the start of the file. -- * @consumer: information on howto handle the probe.. -+ * @uc: information on howto handle the probe.. - * - * Apart from the access refcount, uprobe_register() takes a creation - * refcount (thro alloc_uprobe) if and only if this @uprobe is getting - * inserted into the rbtree (i.e first consumer for a @inode:@offset - * tuple). Creation refcount stops uprobe_unregister from freeing the - * @uprobe even before the register operation is complete. Creation -- * refcount is released when the last @consumer for the @uprobe -+ * refcount is released when the last @uc for the @uprobe - * unregisters. - * - * Return errno if it cannot successully install probes - * else return 0 (success) - */ --int uprobe_register(struct inode *inode, loff_t offset, struct uprobe_consumer *consumer) -+int uprobe_register(struct inode *inode, loff_t offset, struct uprobe_consumer *uc) - { - struct uprobe *uprobe; - int ret; - -- if (!inode || !consumer || consumer->next) -+ if (!inode || !uc || uc->next) - return -EINVAL; - - if (offset > i_size_read(inode)) -@@ -851,7 +854,7 @@ int uprobe_register(struct inode *inode, loff_t offset, struct uprobe_consumer * - mutex_lock(uprobes_hash(inode)); - uprobe = alloc_uprobe(inode, offset); - -- if (uprobe && !consumer_add(uprobe, consumer)) { -+ if (uprobe && !consumer_add(uprobe, uc)) { - ret = __uprobe_register(uprobe); - if (ret) { - uprobe->consumers = NULL; -@@ -871,13 +874,13 @@ int uprobe_register(struct inode *inode, loff_t offset, struct uprobe_consumer * - * uprobe_unregister - unregister a already registered probe. - * @inode: the file in which the probe has to be removed. - * @offset: offset from the start of the file. -- * @consumer: identify which probe if multiple probes are colocated. -+ * @uc: identify which probe if multiple probes are colocated. - */ --void uprobe_unregister(struct inode *inode, loff_t offset, struct uprobe_consumer *consumer) -+void uprobe_unregister(struct inode *inode, loff_t offset, struct uprobe_consumer *uc) - { - struct uprobe *uprobe; - -- if (!inode || !consumer) -+ if (!inode || !uc) - return; - - uprobe = find_uprobe(inode, offset); -@@ -886,7 +889,7 @@ void uprobe_unregister(struct inode *inode, loff_t offset, struct uprobe_consume - - mutex_lock(uprobes_hash(inode)); - -- if (consumer_del(uprobe, consumer)) { -+ if (consumer_del(uprobe, uc)) { - if (!uprobe->consumers) { - __uprobe_unregister(uprobe); - uprobe->flags &= ~UPROBE_RUN_HANDLER; -@@ -993,7 +996,7 @@ int uprobe_mmap(struct vm_area_struct *vma) - if (!ret) { - vaddr = vma_address(vma, uprobe->offset); - if (vaddr >= vma->vm_start && vaddr < vma->vm_end) { -- ret = install_breakpoint(vma->vm_mm, uprobe, vma, vaddr); -+ ret = install_breakpoint(uprobe, vma->vm_mm, vma, vaddr); - /* Ignore double add: */ - if (ret == -EEXIST) - ret = 0; --- -1.7.5.4 - diff --git a/features/uprobe/uprobes-core-Move-insn-to-arch-specific-structure.patch b/features/uprobe/uprobes-core-Move-insn-to-arch-specific-structure.patch deleted file mode 100644 index 2f0dcf531a82a009376efe3bc8aa6512c3179b3c..0000000000000000000000000000000000000000 --- a/features/uprobe/uprobes-core-Move-insn-to-arch-specific-structure.patch +++ /dev/null @@ -1,418 +0,0 @@ -From f066ff9cd2dc1e58a967f1847c780b90bfdf4a05 Mon Sep 17 00:00:00 2001 -From: Srikar Dronamraju <srikar@linux.vnet.ibm.com> -Date: Wed, 22 Feb 2012 14:46:02 +0530 -Subject: [PATCH 06/24] uprobes/core: Move insn to arch specific structure - -Few cleanups suggested by Ingo Molnar. - -- Rename struct uprobe_arch_info to struct arch_uprobe. -- Move insn from struct uprobe to struct arch_uprobe. -- Make arch specific uprobe functions to accept struct arch_uprobe - instead of struct uprobe. -- Move struct uprobe to kernel/uprobes.c from include/linux/uprobes.h - -commit 3ff54efdfaace9e9b2b7c1959a865be6b91de96c upstream - -Signed-off-by: Srikar Dronamraju <srikar@linux.vnet.ibm.com> -Cc: Peter Zijlstra <peterz@infradead.org> -Cc: Linus Torvalds <torvalds@linux-foundation.org> -Cc: Oleg Nesterov <oleg@redhat.com> -Cc: Christoph Hellwig <hch@infradead.org> -Cc: Steven Rostedt <rostedt@goodmis.org> -Cc: Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com> -Cc: Anton Arapov <anton@redhat.com> -Cc: Ananth N Mavinakayanahalli <ananth@in.ibm.com> -Cc: Jim Keniston <jkenisto@linux.vnet.ibm.com> -Cc: Jiri Olsa <jolsa@redhat.com> -Cc: Josh Stone <jistone@redhat.com> -Link: http://lkml.kernel.org/r/20120222091602.15880.40249.sendpatchset@srdronam.in.ibm.com -[ Made various small improvements ] -Signed-off-by: Ingo Molnar <mingo@elte.hu> -Signed-off-by: Paul Barrette <paul.barrette@windriver.com> ---- - arch/x86/include/asm/uprobes.h | 6 ++-- - arch/x86/kernel/uprobes.c | 60 ++++++++++++++++++++-------------------- - include/linux/uprobes.h | 23 +-------------- - kernel/events/uprobes.c | 38 +++++++++++++++++-------- - 4 files changed, 61 insertions(+), 66 deletions(-) - -diff --git a/arch/x86/include/asm/uprobes.h b/arch/x86/include/asm/uprobes.h -index 072df39..f7ce310 100644 ---- a/arch/x86/include/asm/uprobes.h -+++ b/arch/x86/include/asm/uprobes.h -@@ -31,13 +31,13 @@ typedef u8 uprobe_opcode_t; - #define UPROBES_BKPT_INSN 0xcc - #define UPROBES_BKPT_INSN_SIZE 1 - --struct uprobe_arch_info { -+struct arch_uprobe { - u16 fixups; -+ u8 insn[MAX_UINSN_BYTES]; - #ifdef CONFIG_X86_64 - unsigned long rip_rela_target_address; - #endif - }; - --struct uprobe; --extern int arch_uprobes_analyze_insn(struct mm_struct *mm, struct uprobe *uprobe); -+extern int arch_uprobes_analyze_insn(struct mm_struct *mm, struct arch_uprobe *arch_uprobe); - #endif /* _ASM_UPROBES_H */ -diff --git a/arch/x86/kernel/uprobes.c b/arch/x86/kernel/uprobes.c -index 13d616d..04dfcef 100644 ---- a/arch/x86/kernel/uprobes.c -+++ b/arch/x86/kernel/uprobes.c -@@ -200,9 +200,9 @@ static bool is_prefix_bad(struct insn *insn) - return false; - } - --static int validate_insn_32bits(struct uprobe *uprobe, struct insn *insn) -+static int validate_insn_32bits(struct arch_uprobe *auprobe, struct insn *insn) - { -- insn_init(insn, uprobe->insn, false); -+ insn_init(insn, auprobe->insn, false); - - /* Skip good instruction prefixes; reject "bad" ones. */ - insn_get_opcode(insn); -@@ -222,11 +222,11 @@ static int validate_insn_32bits(struct uprobe *uprobe, struct insn *insn) - - /* - * Figure out which fixups post_xol() will need to perform, and annotate -- * uprobe->arch_info.fixups accordingly. To start with, -- * uprobe->arch_info.fixups is either zero or it reflects rip-related -+ * arch_uprobe->fixups accordingly. To start with, -+ * arch_uprobe->fixups is either zero or it reflects rip-related - * fixups. - */ --static void prepare_fixups(struct uprobe *uprobe, struct insn *insn) -+static void prepare_fixups(struct arch_uprobe *auprobe, struct insn *insn) - { - bool fix_ip = true, fix_call = false; /* defaults */ - int reg; -@@ -269,17 +269,17 @@ static void prepare_fixups(struct uprobe *uprobe, struct insn *insn) - break; - } - if (fix_ip) -- uprobe->arch_info.fixups |= UPROBES_FIX_IP; -+ auprobe->fixups |= UPROBES_FIX_IP; - if (fix_call) -- uprobe->arch_info.fixups |= UPROBES_FIX_CALL; -+ auprobe->fixups |= UPROBES_FIX_CALL; - } - - #ifdef CONFIG_X86_64 - /* -- * If uprobe->insn doesn't use rip-relative addressing, return -+ * If arch_uprobe->insn doesn't use rip-relative addressing, return - * immediately. Otherwise, rewrite the instruction so that it accesses - * its memory operand indirectly through a scratch register. Set -- * uprobe->arch_info.fixups and uprobe->arch_info.rip_rela_target_address -+ * arch_uprobe->fixups and arch_uprobe->rip_rela_target_address - * accordingly. (The contents of the scratch register will be saved - * before we single-step the modified instruction, and restored - * afterward.) -@@ -297,7 +297,7 @@ static void prepare_fixups(struct uprobe *uprobe, struct insn *insn) - * - There's never a SIB byte. - * - The displacement is always 4 bytes. - */ --static void handle_riprel_insn(struct mm_struct *mm, struct uprobe *uprobe, struct insn *insn) -+static void handle_riprel_insn(struct mm_struct *mm, struct arch_uprobe *auprobe, struct insn *insn) - { - u8 *cursor; - u8 reg; -@@ -305,7 +305,7 @@ static void handle_riprel_insn(struct mm_struct *mm, struct uprobe *uprobe, stru - if (mm->context.ia32_compat) - return; - -- uprobe->arch_info.rip_rela_target_address = 0x0; -+ auprobe->rip_rela_target_address = 0x0; - if (!insn_rip_relative(insn)) - return; - -@@ -315,7 +315,7 @@ static void handle_riprel_insn(struct mm_struct *mm, struct uprobe *uprobe, stru - * we want to encode rax/rcx, not r8/r9. - */ - if (insn->rex_prefix.nbytes) { -- cursor = uprobe->insn + insn_offset_rex_prefix(insn); -+ cursor = auprobe->insn + insn_offset_rex_prefix(insn); - *cursor &= 0xfe; /* Clearing REX.B bit */ - } - -@@ -324,7 +324,7 @@ static void handle_riprel_insn(struct mm_struct *mm, struct uprobe *uprobe, stru - * displacement. Beyond the displacement, for some instructions, - * is the immediate operand. - */ -- cursor = uprobe->insn + insn_offset_modrm(insn); -+ cursor = auprobe->insn + insn_offset_modrm(insn); - insn_get_length(insn); - - /* -@@ -341,18 +341,18 @@ static void handle_riprel_insn(struct mm_struct *mm, struct uprobe *uprobe, stru - * is NOT the register operand, so we use %rcx (register - * #1) for the scratch register. - */ -- uprobe->arch_info.fixups = UPROBES_FIX_RIP_CX; -+ auprobe->fixups = UPROBES_FIX_RIP_CX; - /* Change modrm from 00 000 101 to 00 000 001. */ - *cursor = 0x1; - } else { - /* Use %rax (register #0) for the scratch register. */ -- uprobe->arch_info.fixups = UPROBES_FIX_RIP_AX; -+ auprobe->fixups = UPROBES_FIX_RIP_AX; - /* Change modrm from 00 xxx 101 to 00 xxx 000 */ - *cursor = (reg << 3); - } - - /* Target address = address of next instruction + (signed) offset */ -- uprobe->arch_info.rip_rela_target_address = (long)insn->length + insn->displacement.value; -+ auprobe->rip_rela_target_address = (long)insn->length + insn->displacement.value; - - /* Displacement field is gone; slide immediate field (if any) over. */ - if (insn->immediate.nbytes) { -@@ -362,9 +362,9 @@ static void handle_riprel_insn(struct mm_struct *mm, struct uprobe *uprobe, stru - return; - } - --static int validate_insn_64bits(struct uprobe *uprobe, struct insn *insn) -+static int validate_insn_64bits(struct arch_uprobe *auprobe, struct insn *insn) - { -- insn_init(insn, uprobe->insn, true); -+ insn_init(insn, auprobe->insn, true); - - /* Skip good instruction prefixes; reject "bad" ones. */ - insn_get_opcode(insn); -@@ -381,42 +381,42 @@ static int validate_insn_64bits(struct uprobe *uprobe, struct insn *insn) - return -ENOTSUPP; - } - --static int validate_insn_bits(struct mm_struct *mm, struct uprobe *uprobe, struct insn *insn) -+static int validate_insn_bits(struct mm_struct *mm, struct arch_uprobe *auprobe, struct insn *insn) - { - if (mm->context.ia32_compat) -- return validate_insn_32bits(uprobe, insn); -- return validate_insn_64bits(uprobe, insn); -+ return validate_insn_32bits(auprobe, insn); -+ return validate_insn_64bits(auprobe, insn); - } - #else /* 32-bit: */ --static void handle_riprel_insn(struct mm_struct *mm, struct uprobe *uprobe, struct insn *insn) -+static void handle_riprel_insn(struct mm_struct *mm, struct arch_uprobe *auprobe, struct insn *insn) - { - /* No RIP-relative addressing on 32-bit */ - } - --static int validate_insn_bits(struct mm_struct *mm, struct uprobe *uprobe, struct insn *insn) -+static int validate_insn_bits(struct mm_struct *mm, struct arch_uprobe *auprobe, struct insn *insn) - { -- return validate_insn_32bits(uprobe, insn); -+ return validate_insn_32bits(auprobe, insn); - } - #endif /* CONFIG_X86_64 */ - - /** - * arch_uprobes_analyze_insn - instruction analysis including validity and fixups. - * @mm: the probed address space. -- * @uprobe: the probepoint information. -+ * @arch_uprobe: the probepoint information. - * Return 0 on success or a -ve number on error. - */ --int arch_uprobes_analyze_insn(struct mm_struct *mm, struct uprobe *uprobe) -+int arch_uprobes_analyze_insn(struct mm_struct *mm, struct arch_uprobe *auprobe) - { - int ret; - struct insn insn; - -- uprobe->arch_info.fixups = 0; -- ret = validate_insn_bits(mm, uprobe, &insn); -+ auprobe->fixups = 0; -+ ret = validate_insn_bits(mm, auprobe, &insn); - if (ret != 0) - return ret; - -- handle_riprel_insn(mm, uprobe, &insn); -- prepare_fixups(uprobe, &insn); -+ handle_riprel_insn(mm, auprobe, &insn); -+ prepare_fixups(auprobe, &insn); - - return 0; - } -diff --git a/include/linux/uprobes.h b/include/linux/uprobes.h -index fd45b70..9c6be62 100644 ---- a/include/linux/uprobes.h -+++ b/include/linux/uprobes.h -@@ -29,12 +29,6 @@ - struct vm_area_struct; - #ifdef CONFIG_ARCH_SUPPORTS_UPROBES - #include <asm/uprobes.h> --#else -- --typedef u8 uprobe_opcode_t; --struct uprobe_arch_info {}; -- --#define MAX_UINSN_BYTES 4 - #endif - - /* flags that denote/change uprobes behaviour */ -@@ -56,22 +50,9 @@ struct uprobe_consumer { - struct uprobe_consumer *next; - }; - --struct uprobe { -- struct rb_node rb_node; /* node in the rb tree */ -- atomic_t ref; -- struct rw_semaphore consumer_rwsem; -- struct list_head pending_list; -- struct uprobe_arch_info arch_info; -- struct uprobe_consumer *consumers; -- struct inode *inode; /* Also hold a ref to inode */ -- loff_t offset; -- int flags; -- u8 insn[MAX_UINSN_BYTES]; --}; -- - #ifdef CONFIG_UPROBES --extern int __weak set_bkpt(struct mm_struct *mm, struct uprobe *uprobe, unsigned long vaddr); --extern int __weak set_orig_insn(struct mm_struct *mm, struct uprobe *uprobe, unsigned long vaddr, bool verify); -+extern int __weak set_bkpt(struct mm_struct *mm, struct arch_uprobe *auprobe, unsigned long vaddr); -+extern int __weak set_orig_insn(struct mm_struct *mm, struct arch_uprobe *auprobe, unsigned long vaddr, bool verify); - extern bool __weak is_bkpt_insn(uprobe_opcode_t *insn); - extern int uprobe_register(struct inode *inode, loff_t offset, struct uprobe_consumer *consumer); - extern void uprobe_unregister(struct inode *inode, loff_t offset, struct uprobe_consumer *consumer); -diff --git a/kernel/events/uprobes.c b/kernel/events/uprobes.c -index ee496ad..13f1b59 100644 ---- a/kernel/events/uprobes.c -+++ b/kernel/events/uprobes.c -@@ -65,6 +65,18 @@ struct vma_info { - loff_t vaddr; - }; - -+struct uprobe { -+ struct rb_node rb_node; /* node in the rb tree */ -+ atomic_t ref; -+ struct rw_semaphore consumer_rwsem; -+ struct list_head pending_list; -+ struct uprobe_consumer *consumers; -+ struct inode *inode; /* Also hold a ref to inode */ -+ loff_t offset; -+ int flags; -+ struct arch_uprobe arch; -+}; -+ - /* - * valid_vma: Verify if the specified vma is an executable vma - * Relax restrictions while unregistering: vm_flags might have -@@ -180,7 +192,7 @@ bool __weak is_bkpt_insn(uprobe_opcode_t *insn) - /* - * write_opcode - write the opcode at a given virtual address. - * @mm: the probed process address space. -- * @uprobe: the breakpointing information. -+ * @arch_uprobe: the breakpointing information. - * @vaddr: the virtual address to store the opcode. - * @opcode: opcode to be written at @vaddr. - * -@@ -190,13 +202,14 @@ bool __weak is_bkpt_insn(uprobe_opcode_t *insn) - * For mm @mm, write the opcode at @vaddr. - * Return 0 (success) or a negative errno. - */ --static int write_opcode(struct mm_struct *mm, struct uprobe *uprobe, -+static int write_opcode(struct mm_struct *mm, struct arch_uprobe *auprobe, - unsigned long vaddr, uprobe_opcode_t opcode) - { - struct page *old_page, *new_page; - struct address_space *mapping; - void *vaddr_old, *vaddr_new; - struct vm_area_struct *vma; -+ struct uprobe *uprobe; - loff_t addr; - int ret; - -@@ -216,6 +229,7 @@ static int write_opcode(struct mm_struct *mm, struct uprobe *uprobe, - if (!valid_vma(vma, is_bkpt_insn(&opcode))) - goto put_out; - -+ uprobe = container_of(auprobe, struct uprobe, arch); - mapping = uprobe->inode->i_mapping; - if (mapping != vma->vm_file->f_mapping) - goto put_out; -@@ -326,7 +340,7 @@ static int is_bkpt_at_addr(struct mm_struct *mm, unsigned long vaddr) - * For mm @mm, store the breakpoint instruction at @vaddr. - * Return 0 (success) or a negative errno. - */ --int __weak set_bkpt(struct mm_struct *mm, struct uprobe *uprobe, unsigned long vaddr) -+int __weak set_bkpt(struct mm_struct *mm, struct arch_uprobe *auprobe, unsigned long vaddr) - { - int result; - -@@ -337,7 +351,7 @@ int __weak set_bkpt(struct mm_struct *mm, struct uprobe *uprobe, unsigned long v - if (result) - return result; - -- return write_opcode(mm, uprobe, vaddr, UPROBES_BKPT_INSN); -+ return write_opcode(mm, auprobe, vaddr, UPROBES_BKPT_INSN); - } - - /** -@@ -351,7 +365,7 @@ int __weak set_bkpt(struct mm_struct *mm, struct uprobe *uprobe, unsigned long v - * Return 0 (success) or a negative errno. - */ - int __weak --set_orig_insn(struct mm_struct *mm, struct uprobe *uprobe, unsigned long vaddr, bool verify) -+set_orig_insn(struct mm_struct *mm, struct arch_uprobe *auprobe, unsigned long vaddr, bool verify) - { - if (verify) { - int result; -@@ -363,7 +377,7 @@ set_orig_insn(struct mm_struct *mm, struct uprobe *uprobe, unsigned long vaddr, - if (result != 1) - return result; - } -- return write_opcode(mm, uprobe, vaddr, *(uprobe_opcode_t *)uprobe->insn); -+ return write_opcode(mm, auprobe, vaddr, *(uprobe_opcode_t *)auprobe->insn); - } - - static int match_uprobe(struct uprobe *l, struct uprobe *r) -@@ -593,13 +607,13 @@ static int copy_insn(struct uprobe *uprobe, struct vm_area_struct *vma, unsigned - - /* Instruction at the page-boundary; copy bytes in second page */ - if (nbytes < bytes) { -- if (__copy_insn(mapping, vma, uprobe->insn + nbytes, -+ if (__copy_insn(mapping, vma, uprobe->arch.insn + nbytes, - bytes - nbytes, uprobe->offset + nbytes)) - return -ENOMEM; - - bytes = nbytes; - } -- return __copy_insn(mapping, vma, uprobe->insn, bytes, uprobe->offset); -+ return __copy_insn(mapping, vma, uprobe->arch.insn, bytes, uprobe->offset); - } - - static int install_breakpoint(struct mm_struct *mm, struct uprobe *uprobe, -@@ -625,23 +639,23 @@ static int install_breakpoint(struct mm_struct *mm, struct uprobe *uprobe, - if (ret) - return ret; - -- if (is_bkpt_insn((uprobe_opcode_t *)uprobe->insn)) -+ if (is_bkpt_insn((uprobe_opcode_t *)uprobe->arch.insn)) - return -EEXIST; - -- ret = arch_uprobes_analyze_insn(mm, uprobe); -+ ret = arch_uprobes_analyze_insn(mm, &uprobe->arch); - if (ret) - return ret; - - uprobe->flags |= UPROBES_COPY_INSN; - } -- ret = set_bkpt(mm, uprobe, addr); -+ ret = set_bkpt(mm, &uprobe->arch, addr); - - return ret; - } - - static void remove_breakpoint(struct mm_struct *mm, struct uprobe *uprobe, loff_t vaddr) - { -- set_orig_insn(mm, uprobe, (unsigned long)vaddr, true); -+ set_orig_insn(mm, &uprobe->arch, (unsigned long)vaddr, true); - } - - static void delete_uprobe(struct uprobe *uprobe) --- -1.7.5.4 - diff --git a/features/uprobe/uprobes-core-Optimize-probe-hits-with-the-help-of-a-.patch b/features/uprobe/uprobes-core-Optimize-probe-hits-with-the-help-of-a-.patch deleted file mode 100644 index 229b44f2992cc1c61d6c143d7ab38344aeeb08b2..0000000000000000000000000000000000000000 --- a/features/uprobe/uprobes-core-Optimize-probe-hits-with-the-help-of-a-.patch +++ /dev/null @@ -1,334 +0,0 @@ -From 3efc15b8288e32ad40ce0f45b7e9a40c43f9f048 Mon Sep 17 00:00:00 2001 -From: Srikar Dronamraju <srikar@linux.vnet.ibm.com> -Date: Fri, 30 Mar 2012 23:56:46 +0530 -Subject: [PATCH 13/24] uprobes/core: Optimize probe hits with the help of a - counter - -Maintain a per-mm counter: number of uprobes that are inserted -on this process address space. - -This counter can be used at probe hit time to determine if we -need a lookup in the uprobes rbtree. Everytime a probe gets -inserted successfully, the probe count is incremented and -everytime a probe gets removed, the probe count is decremented. - -The new uprobe_munmap hook ensures the count is correct on a -unmap or remap of a region. We expect that once a -uprobe_munmap() is called, the vma goes away. So -uprobe_unregister() finding a probe to unregister would either -mean unmap event hasnt occurred yet or a mmap event on the same -executable file occured after a unmap event. - -Additionally, uprobe_mmap hook now also gets called: - - a. on every executable vma that is COWed at fork. - b. a vma of interest is newly mapped; breakpoint insertion also - happens at the required address. - -On process creation, make sure the probes count in the child is -set correctly. - -Special cases that are taken care include: - - a. mremap - b. VM_DONTCOPY vmas on fork() - c. insertion/removal races in the parent during fork(). - -commit 682968e0c425c60f0dde37977e5beb2b12ddc4cc upstream - -Signed-off-by: Srikar Dronamraju <srikar@linux.vnet.ibm.com> -Cc: Linus Torvalds <torvalds@linux-foundation.org> -Cc: Ananth N Mavinakayanahalli <ananth@in.ibm.com> -Cc: Jim Keniston <jkenisto@linux.vnet.ibm.com> -Cc: Linux-mm <linux-mm@kvack.org> -Cc: Oleg Nesterov <oleg@redhat.com> -Cc: Andi Kleen <andi@firstfloor.org> -Cc: Christoph Hellwig <hch@infradead.org> -Cc: Steven Rostedt <rostedt@goodmis.org> -Cc: Arnaldo Carvalho de Melo <acme@infradead.org> -Cc: Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com> -Cc: Anton Arapov <anton@redhat.com> -Cc: Peter Zijlstra <peterz@infradead.org> -Link: http://lkml.kernel.org/r/20120330182646.10018.85805.sendpatchset@srdronam.in.ibm.com -Signed-off-by: Ingo Molnar <mingo@kernel.org> -Signed-off-by: Paul Barrette <paul.barrette@windriver.com> ---- - include/linux/uprobes.h | 5 ++ - kernel/events/uprobes.c | 119 +++++++++++++++++++++++++++++++++++++++++++--- - kernel/fork.c | 3 + - mm/mmap.c | 10 ++++- - 4 files changed, 128 insertions(+), 9 deletions(-) - -diff --git a/include/linux/uprobes.h b/include/linux/uprobes.h -index a111460..d594d3b 100644 ---- a/include/linux/uprobes.h -+++ b/include/linux/uprobes.h -@@ -99,6 +99,7 @@ struct xol_area { - - struct uprobes_state { - struct xol_area *xol_area; -+ atomic_t count; - }; - extern int __weak set_swbp(struct arch_uprobe *aup, struct mm_struct *mm, unsigned long vaddr); - extern int __weak set_orig_insn(struct arch_uprobe *aup, struct mm_struct *mm, unsigned long vaddr, bool verify); -@@ -106,6 +107,7 @@ extern bool __weak is_swbp_insn(uprobe_opcode_t *insn); - extern int uprobe_register(struct inode *inode, loff_t offset, struct uprobe_consumer *uc); - extern void uprobe_unregister(struct inode *inode, loff_t offset, struct uprobe_consumer *uc); - extern int uprobe_mmap(struct vm_area_struct *vma); -+extern void uprobe_munmap(struct vm_area_struct *vma); - extern void uprobe_free_utask(struct task_struct *t); - extern void uprobe_copy_process(struct task_struct *t); - extern unsigned long __weak uprobe_get_swbp_addr(struct pt_regs *regs); -@@ -132,6 +134,9 @@ static inline int uprobe_mmap(struct vm_area_struct *vma) - { - return 0; - } -+static inline void uprobe_munmap(struct vm_area_struct *vma) -+{ -+} - static inline void uprobe_notify_resume(struct pt_regs *regs) - { - } -diff --git a/kernel/events/uprobes.c b/kernel/events/uprobes.c -index b395edb..29e881b 100644 ---- a/kernel/events/uprobes.c -+++ b/kernel/events/uprobes.c -@@ -642,6 +642,29 @@ copy_insn(struct uprobe *uprobe, struct vm_area_struct *vma, unsigned long addr) - return __copy_insn(mapping, vma, uprobe->arch.insn, bytes, uprobe->offset); - } - -+/* -+ * How mm->uprobes_state.count gets updated -+ * uprobe_mmap() increments the count if -+ * - it successfully adds a breakpoint. -+ * - it cannot add a breakpoint, but sees that there is a underlying -+ * breakpoint (via a is_swbp_at_addr()). -+ * -+ * uprobe_munmap() decrements the count if -+ * - it sees a underlying breakpoint, (via is_swbp_at_addr) -+ * (Subsequent uprobe_unregister wouldnt find the breakpoint -+ * unless a uprobe_mmap kicks in, since the old vma would be -+ * dropped just after uprobe_munmap.) -+ * -+ * uprobe_register increments the count if: -+ * - it successfully adds a breakpoint. -+ * -+ * uprobe_unregister decrements the count if: -+ * - it sees a underlying breakpoint and removes successfully. -+ * (via is_swbp_at_addr) -+ * (Subsequent uprobe_munmap wouldnt find the breakpoint -+ * since there is no underlying breakpoint after the -+ * breakpoint removal.) -+ */ - static int - install_breakpoint(struct uprobe *uprobe, struct mm_struct *mm, - struct vm_area_struct *vma, loff_t vaddr) -@@ -675,7 +698,19 @@ install_breakpoint(struct uprobe *uprobe, struct mm_struct *mm, - - uprobe->flags |= UPROBE_COPY_INSN; - } -+ -+ /* -+ * Ideally, should be updating the probe count after the breakpoint -+ * has been successfully inserted. However a thread could hit the -+ * breakpoint we just inserted even before the probe count is -+ * incremented. If this is the first breakpoint placed, breakpoint -+ * notifier might ignore uprobes and pass the trap to the thread. -+ * Hence increment before and decrement on failure. -+ */ -+ atomic_inc(&mm->uprobes_state.count); - ret = set_swbp(&uprobe->arch, mm, addr); -+ if (ret) -+ atomic_dec(&mm->uprobes_state.count); - - return ret; - } -@@ -683,7 +718,8 @@ install_breakpoint(struct uprobe *uprobe, struct mm_struct *mm, - static void - remove_breakpoint(struct uprobe *uprobe, struct mm_struct *mm, loff_t vaddr) - { -- set_orig_insn(&uprobe->arch, mm, (unsigned long)vaddr, true); -+ if (!set_orig_insn(&uprobe->arch, mm, (unsigned long)vaddr, true)) -+ atomic_dec(&mm->uprobes_state.count); - } - - /* -@@ -1009,7 +1045,7 @@ int uprobe_mmap(struct vm_area_struct *vma) - struct list_head tmp_list; - struct uprobe *uprobe, *u; - struct inode *inode; -- int ret; -+ int ret, count; - - if (!atomic_read(&uprobe_events) || !valid_vma(vma, true)) - return 0; -@@ -1023,6 +1059,7 @@ int uprobe_mmap(struct vm_area_struct *vma) - build_probe_list(inode, &tmp_list); - - ret = 0; -+ count = 0; - - list_for_each_entry_safe(uprobe, u, &tmp_list, pending_list) { - loff_t vaddr; -@@ -1030,21 +1067,85 @@ int uprobe_mmap(struct vm_area_struct *vma) - list_del(&uprobe->pending_list); - if (!ret) { - vaddr = vma_address(vma, uprobe->offset); -- if (vaddr >= vma->vm_start && vaddr < vma->vm_end) { -- ret = install_breakpoint(uprobe, vma->vm_mm, vma, vaddr); -- /* Ignore double add: */ -- if (ret == -EEXIST) -- ret = 0; -+ -+ if (vaddr < vma->vm_start || vaddr >= vma->vm_end) { -+ put_uprobe(uprobe); -+ continue; - } -+ -+ ret = install_breakpoint(uprobe, vma->vm_mm, vma, vaddr); -+ -+ /* Ignore double add: */ -+ if (ret == -EEXIST) { -+ ret = 0; -+ -+ if (!is_swbp_at_addr(vma->vm_mm, vaddr)) -+ continue; -+ -+ /* -+ * Unable to insert a breakpoint, but -+ * breakpoint lies underneath. Increment the -+ * probe count. -+ */ -+ atomic_inc(&vma->vm_mm->uprobes_state.count); -+ } -+ -+ if (!ret) -+ count++; - } - put_uprobe(uprobe); - } - - mutex_unlock(uprobes_mmap_hash(inode)); - -+ if (ret) -+ atomic_sub(count, &vma->vm_mm->uprobes_state.count); -+ - return ret; - } - -+/* -+ * Called in context of a munmap of a vma. -+ */ -+void uprobe_munmap(struct vm_area_struct *vma) -+{ -+ struct list_head tmp_list; -+ struct uprobe *uprobe, *u; -+ struct inode *inode; -+ -+ if (!atomic_read(&uprobe_events) || !valid_vma(vma, false)) -+ return; -+ -+ if (!atomic_read(&vma->vm_mm->uprobes_state.count)) -+ return; -+ -+ inode = vma->vm_file->f_mapping->host; -+ if (!inode) -+ return; -+ -+ INIT_LIST_HEAD(&tmp_list); -+ mutex_lock(uprobes_mmap_hash(inode)); -+ build_probe_list(inode, &tmp_list); -+ -+ list_for_each_entry_safe(uprobe, u, &tmp_list, pending_list) { -+ loff_t vaddr; -+ -+ list_del(&uprobe->pending_list); -+ vaddr = vma_address(vma, uprobe->offset); -+ -+ if (vaddr >= vma->vm_start && vaddr < vma->vm_end) { -+ /* -+ * An unregister could have removed the probe before -+ * unmap. So check before we decrement the count. -+ */ -+ if (is_swbp_at_addr(vma->vm_mm, vaddr) == 1) -+ atomic_dec(&vma->vm_mm->uprobes_state.count); -+ } -+ put_uprobe(uprobe); -+ } -+ mutex_unlock(uprobes_mmap_hash(inode)); -+} -+ - /* Slot allocation for XOL */ - static int xol_add_vma(struct xol_area *area) - { -@@ -1150,6 +1251,7 @@ void uprobe_clear_state(struct mm_struct *mm) - void uprobe_reset_state(struct mm_struct *mm) - { - mm->uprobes_state.xol_area = NULL; -+ atomic_set(&mm->uprobes_state.count, 0); - } - - /* -@@ -1504,7 +1606,8 @@ int uprobe_pre_sstep_notifier(struct pt_regs *regs) - { - struct uprobe_task *utask; - -- if (!current->mm) -+ if (!current->mm || !atomic_read(¤t->mm->uprobes_state.count)) -+ /* task is currently not uprobed */ - return 0; - - utask = current->utask; -diff --git a/kernel/fork.c b/kernel/fork.c -index 5fa2cbf..764efe3 100644 ---- a/kernel/fork.c -+++ b/kernel/fork.c -@@ -426,6 +426,9 @@ static int dup_mmap(struct mm_struct *mm, struct mm_struct *oldmm) - - if (retval) - goto out; -+ -+ if (file && uprobe_mmap(tmp)) -+ goto out; - } - /* a new mm has just been created */ - arch_dup_mmap(oldmm, mm); -diff --git a/mm/mmap.c b/mm/mmap.c -index 397bcb5..b0b1691 100644 ---- a/mm/mmap.c -+++ b/mm/mmap.c -@@ -218,6 +218,7 @@ void unlink_file_vma(struct vm_area_struct *vma) - mutex_lock(&mapping->i_mmap_mutex); - __remove_shared_vm_struct(vma, file, mapping); - mutex_unlock(&mapping->i_mmap_mutex); -+ uprobe_munmap(vma); - } - } - -@@ -547,8 +548,14 @@ again: remove_next = 1 + (end > next->vm_end); - - if (file) { - mapping = file->f_mapping; -- if (!(vma->vm_flags & VM_NONLINEAR)) -+ if (!(vma->vm_flags & VM_NONLINEAR)) { - root = &mapping->i_mmap; -+ uprobe_munmap(vma); -+ -+ if (adjust_next) -+ uprobe_munmap(next); -+ } -+ - mutex_lock(&mapping->i_mmap_mutex); - if (insert) { - /* -@@ -627,6 +634,7 @@ again: remove_next = 1 + (end > next->vm_end); - - if (remove_next) { - if (file) { -+ uprobe_munmap(next); - fput(file); - if (next->vm_flags & VM_EXECUTABLE) - removed_exe_file_vma(mm); --- -1.7.5.4 - diff --git a/features/uprobe/uprobes-core-Remove-uprobe_opcode_sz.patch b/features/uprobe/uprobes-core-Remove-uprobe_opcode_sz.patch deleted file mode 100644 index 2880a171629414825735c1c081ff1db6464bf903..0000000000000000000000000000000000000000 --- a/features/uprobe/uprobes-core-Remove-uprobe_opcode_sz.patch +++ /dev/null @@ -1,79 +0,0 @@ -From e91cf65d77f259c00ecf8e345004dff2e6c4f67a Mon Sep 17 00:00:00 2001 -From: Srikar Dronamraju <srikar@linux.vnet.ibm.com> -Date: Wed, 22 Feb 2012 14:45:49 +0530 -Subject: [PATCH 05/24] uprobes/core: Remove uprobe_opcode_sz - -uprobe_opcode_sz refers to the smallest instruction size for -that architecture. UPROBES_BKPT_INSN_SIZE refers to the size of -the breakpoint instruction for that architecture. - -For now we are assuming that both uprobe_opcode_sz and -UPROBES_BKPT_INSN_SIZE are the same for all archs and hence -removing uprobe_opcode_sz in favour of UPROBES_BKPT_INSN_SIZE. - -However if we have to support architectures where the smallest -instruction size is different from the size of breakpoint -instruction, we may have to re-introduce uprobe_opcode_sz. - -commit 96379f60075c75b261328aa7830ef8aa158247ac upstream - -Signed-off-by: Srikar Dronamraju <srikar@linux.vnet.ibm.com> -Cc: Peter Zijlstra <peterz@infradead.org> -Cc: Linus Torvalds <torvalds@linux-foundation.org> -Cc: Oleg Nesterov <oleg@redhat.com> -Cc: Christoph Hellwig <hch@infradead.org> -Cc: Steven Rostedt <rostedt@goodmis.org> -Cc: Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com> -Cc: Anton Arapov <anton@redhat.com> -Cc: Ananth N Mavinakayanahalli <ananth@in.ibm.com> -Cc: Jim Keniston <jkenisto@linux.vnet.ibm.com> -Cc: Jiri Olsa <jolsa@redhat.com> -Cc: Josh Stone <jistone@redhat.com> -Link: http://lkml.kernel.org/r/20120222091549.15880.67020.sendpatchset@srdronam.in.ibm.com -Signed-off-by: Ingo Molnar <mingo@elte.hu> -Signed-off-by: Paul Barrette <paul.barrette@windriver.com> ---- - include/linux/uprobes.h | 2 -- - kernel/events/uprobes.c | 6 +++--- - 2 files changed, 3 insertions(+), 5 deletions(-) - -diff --git a/include/linux/uprobes.h b/include/linux/uprobes.h -index 64e45f1..fd45b70 100644 ---- a/include/linux/uprobes.h -+++ b/include/linux/uprobes.h -@@ -37,8 +37,6 @@ struct uprobe_arch_info {}; - #define MAX_UINSN_BYTES 4 - #endif - --#define uprobe_opcode_sz sizeof(uprobe_opcode_t) -- - /* flags that denote/change uprobes behaviour */ - - /* Have a copy of original instruction */ -diff --git a/kernel/events/uprobes.c b/kernel/events/uprobes.c -index 884817f..ee496ad 100644 ---- a/kernel/events/uprobes.c -+++ b/kernel/events/uprobes.c -@@ -244,8 +244,8 @@ static int write_opcode(struct mm_struct *mm, struct uprobe *uprobe, - - /* poke the new insn in, ASSUMES we don't cross page boundary */ - vaddr &= ~PAGE_MASK; -- BUG_ON(vaddr + uprobe_opcode_sz > PAGE_SIZE); -- memcpy(vaddr_new + vaddr, &opcode, uprobe_opcode_sz); -+ BUG_ON(vaddr + UPROBES_BKPT_INSN_SIZE > PAGE_SIZE); -+ memcpy(vaddr_new + vaddr, &opcode, UPROBES_BKPT_INSN_SIZE); - - kunmap_atomic(vaddr_new); - kunmap_atomic(vaddr_old); -@@ -293,7 +293,7 @@ static int read_opcode(struct mm_struct *mm, unsigned long vaddr, uprobe_opcode_ - lock_page(page); - vaddr_new = kmap_atomic(page); - vaddr &= ~PAGE_MASK; -- memcpy(opcode, vaddr_new + vaddr, uprobe_opcode_sz); -+ memcpy(opcode, vaddr_new + vaddr, UPROBES_BKPT_INSN_SIZE); - kunmap_atomic(vaddr_new); - unlock_page(page); - --- -1.7.5.4 - diff --git a/features/uprobe/uprobes-core-Rename-bkpt-to-swbp.patch b/features/uprobe/uprobes-core-Rename-bkpt-to-swbp.patch deleted file mode 100644 index 4453ed1094d0e9949c1cc5cbe02a1bf881514c93..0000000000000000000000000000000000000000 --- a/features/uprobe/uprobes-core-Rename-bkpt-to-swbp.patch +++ /dev/null @@ -1,195 +0,0 @@ -From 7196d9a3a208e63063325b5c91fbeae703e5b5f3 Mon Sep 17 00:00:00 2001 -From: Srikar Dronamraju <srikar@linux.vnet.ibm.com> -Date: Mon, 12 Mar 2012 14:55:45 +0530 -Subject: [PATCH 10/24] uprobes/core: Rename bkpt to swbp - -bkpt doesnt seem to be a correct abbrevation for breakpoint. -Choice was between bp and breakpoint. Since bp can refer to -things other than breakpoint, use swbp to refer to breakpoints. - -This is pure cleanup, no functional change intended. - -commit 5cb4ac3a583d4ee18c8682ab857e093c4a0d0895 upstream - -Signed-off-by: Srikar Dronamraju <srikar@linux.vnet.ibm.com> -Cc: Linus Torvalds <torvalds@linux-foundation.org> -Cc: Ananth N Mavinakayanahalli <ananth@in.ibm.com> -Cc: Jim Keniston <jkenisto@linux.vnet.ibm.com> -Cc: Linux-mm <linux-mm@kvack.org> -Cc: Oleg Nesterov <oleg@redhat.com> -Cc: Andi Kleen <andi@firstfloor.org> -Cc: Christoph Hellwig <hch@infradead.org> -Cc: Steven Rostedt <rostedt@goodmis.org> -Cc: Arnaldo Carvalho de Melo <acme@infradead.org> -Cc: Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com> -Cc: Peter Zijlstra <peterz@infradead.org> -Link: http://lkml.kernel.org/r/20120312092545.5379.91251.sendpatchset@srdronam.in.ibm.com -Signed-off-by: Ingo Molnar <mingo@elte.hu> -Signed-off-by: Paul Barrette <paul.barrette@windriver.com> ---- - arch/x86/include/asm/uprobes.h | 4 ++-- - include/linux/uprobes.h | 4 ++-- - kernel/events/uprobes.c | 34 +++++++++++++++++----------------- - 3 files changed, 21 insertions(+), 21 deletions(-) - -diff --git a/arch/x86/include/asm/uprobes.h b/arch/x86/include/asm/uprobes.h -index 384f1be..0500391 100644 ---- a/arch/x86/include/asm/uprobes.h -+++ b/arch/x86/include/asm/uprobes.h -@@ -28,8 +28,8 @@ typedef u8 uprobe_opcode_t; - #define MAX_UINSN_BYTES 16 - #define UPROBE_XOL_SLOT_BYTES 128 /* to keep it cache aligned */ - --#define UPROBE_BKPT_INSN 0xcc --#define UPROBE_BKPT_INSN_SIZE 1 -+#define UPROBE_SWBP_INSN 0xcc -+#define UPROBE_SWBP_INSN_SIZE 1 - - struct arch_uprobe { - u16 fixups; -diff --git a/include/linux/uprobes.h b/include/linux/uprobes.h -index 5869918..eac525f 100644 ---- a/include/linux/uprobes.h -+++ b/include/linux/uprobes.h -@@ -52,9 +52,9 @@ struct uprobe_consumer { - }; - - #ifdef CONFIG_UPROBES --extern int __weak set_bkpt(struct arch_uprobe *aup, struct mm_struct *mm, unsigned long vaddr); -+extern int __weak set_swbp(struct arch_uprobe *aup, struct mm_struct *mm, unsigned long vaddr); - extern int __weak set_orig_insn(struct arch_uprobe *aup, struct mm_struct *mm, unsigned long vaddr, bool verify); --extern bool __weak is_bkpt_insn(uprobe_opcode_t *insn); -+extern bool __weak is_swbp_insn(uprobe_opcode_t *insn); - extern int uprobe_register(struct inode *inode, loff_t offset, struct uprobe_consumer *uc); - extern void uprobe_unregister(struct inode *inode, loff_t offset, struct uprobe_consumer *uc); - extern int uprobe_mmap(struct vm_area_struct *vma); -diff --git a/kernel/events/uprobes.c b/kernel/events/uprobes.c -index 9c5ddff..e56e56a 100644 ---- a/kernel/events/uprobes.c -+++ b/kernel/events/uprobes.c -@@ -170,14 +170,14 @@ out: - } - - /** -- * is_bkpt_insn - check if instruction is breakpoint instruction. -+ * is_swbp_insn - check if instruction is breakpoint instruction. - * @insn: instruction to be checked. -- * Default implementation of is_bkpt_insn -+ * Default implementation of is_swbp_insn - * Returns true if @insn is a breakpoint instruction. - */ --bool __weak is_bkpt_insn(uprobe_opcode_t *insn) -+bool __weak is_swbp_insn(uprobe_opcode_t *insn) - { -- return *insn == UPROBE_BKPT_INSN; -+ return *insn == UPROBE_SWBP_INSN; - } - - /* -@@ -227,7 +227,7 @@ static int write_opcode(struct arch_uprobe *auprobe, struct mm_struct *mm, - * adding probes in write mapped pages since the breakpoints - * might end up in the file copy. - */ -- if (!valid_vma(vma, is_bkpt_insn(&opcode))) -+ if (!valid_vma(vma, is_swbp_insn(&opcode))) - goto put_out; - - uprobe = container_of(auprobe, struct uprobe, arch); -@@ -259,8 +259,8 @@ static int write_opcode(struct arch_uprobe *auprobe, struct mm_struct *mm, - - /* poke the new insn in, ASSUMES we don't cross page boundary */ - vaddr &= ~PAGE_MASK; -- BUG_ON(vaddr + UPROBE_BKPT_INSN_SIZE > PAGE_SIZE); -- memcpy(vaddr_new + vaddr, &opcode, UPROBE_BKPT_INSN_SIZE); -+ BUG_ON(vaddr + UPROBE_SWBP_INSN_SIZE > PAGE_SIZE); -+ memcpy(vaddr_new + vaddr, &opcode, UPROBE_SWBP_INSN_SIZE); - - kunmap_atomic(vaddr_new); - kunmap_atomic(vaddr_old); -@@ -308,7 +308,7 @@ static int read_opcode(struct mm_struct *mm, unsigned long vaddr, uprobe_opcode_ - lock_page(page); - vaddr_new = kmap_atomic(page); - vaddr &= ~PAGE_MASK; -- memcpy(opcode, vaddr_new + vaddr, UPROBE_BKPT_INSN_SIZE); -+ memcpy(opcode, vaddr_new + vaddr, UPROBE_SWBP_INSN_SIZE); - kunmap_atomic(vaddr_new); - unlock_page(page); - -@@ -317,7 +317,7 @@ static int read_opcode(struct mm_struct *mm, unsigned long vaddr, uprobe_opcode_ - return 0; - } - --static int is_bkpt_at_addr(struct mm_struct *mm, unsigned long vaddr) -+static int is_swbp_at_addr(struct mm_struct *mm, unsigned long vaddr) - { - uprobe_opcode_t opcode; - int result; -@@ -326,14 +326,14 @@ static int is_bkpt_at_addr(struct mm_struct *mm, unsigned long vaddr) - if (result) - return result; - -- if (is_bkpt_insn(&opcode)) -+ if (is_swbp_insn(&opcode)) - return 1; - - return 0; - } - - /** -- * set_bkpt - store breakpoint at a given address. -+ * set_swbp - store breakpoint at a given address. - * @auprobe: arch specific probepoint information. - * @mm: the probed process address space. - * @vaddr: the virtual address to insert the opcode. -@@ -341,18 +341,18 @@ static int is_bkpt_at_addr(struct mm_struct *mm, unsigned long vaddr) - * For mm @mm, store the breakpoint instruction at @vaddr. - * Return 0 (success) or a negative errno. - */ --int __weak set_bkpt(struct arch_uprobe *auprobe, struct mm_struct *mm, unsigned long vaddr) -+int __weak set_swbp(struct arch_uprobe *auprobe, struct mm_struct *mm, unsigned long vaddr) - { - int result; - -- result = is_bkpt_at_addr(mm, vaddr); -+ result = is_swbp_at_addr(mm, vaddr); - if (result == 1) - return -EEXIST; - - if (result) - return result; - -- return write_opcode(auprobe, mm, vaddr, UPROBE_BKPT_INSN); -+ return write_opcode(auprobe, mm, vaddr, UPROBE_SWBP_INSN); - } - - /** -@@ -371,7 +371,7 @@ set_orig_insn(struct arch_uprobe *auprobe, struct mm_struct *mm, unsigned long v - if (verify) { - int result; - -- result = is_bkpt_at_addr(mm, vaddr); -+ result = is_swbp_at_addr(mm, vaddr); - if (!result) - return -EINVAL; - -@@ -642,7 +642,7 @@ install_breakpoint(struct uprobe *uprobe, struct mm_struct *mm, - if (ret) - return ret; - -- if (is_bkpt_insn((uprobe_opcode_t *)uprobe->arch.insn)) -+ if (is_swbp_insn((uprobe_opcode_t *)uprobe->arch.insn)) - return -EEXIST; - - ret = arch_uprobes_analyze_insn(&uprobe->arch, mm); -@@ -651,7 +651,7 @@ install_breakpoint(struct uprobe *uprobe, struct mm_struct *mm, - - uprobe->flags |= UPROBE_COPY_INSN; - } -- ret = set_bkpt(&uprobe->arch, mm, addr); -+ ret = set_swbp(&uprobe->arch, mm, addr); - - return ret; - } --- -1.7.5.4 - diff --git a/features/uprobe/uprobes-mm-x86-Add-the-ability-to-install-and-remove.patch b/features/uprobe/uprobes-mm-x86-Add-the-ability-to-install-and-remove.patch deleted file mode 100644 index 84c75480b7396047660359d16e5564fcf1e8342f..0000000000000000000000000000000000000000 --- a/features/uprobe/uprobes-mm-x86-Add-the-ability-to-install-and-remove.patch +++ /dev/null @@ -1,1883 +0,0 @@ -From 3760d62e72e4c63e47a58cc199b7b260799faa86 Mon Sep 17 00:00:00 2001 -From: Srikar Dronamraju <srikar@linux.vnet.ibm.com> -Date: Thu, 9 Feb 2012 14:56:42 +0530 -Subject: [PATCH 01/24] uprobes, mm, x86: Add the ability to install and - remove uprobes breakpoints - -Add uprobes support to the core kernel, with x86 support. - -This commit adds the kernel facilities, the actual uprobes -user-space ABI and perf probe support comes in later commits. - -General design: - -Uprobes are maintained in an rb-tree indexed by inode and offset -(the offset here is from the start of the mapping). For a unique -(inode, offset) tuple, there can be at most one uprobe in the -rb-tree. - -Since the (inode, offset) tuple identifies a unique uprobe, more -than one user may be interested in the same uprobe. This provides -the ability to connect multiple 'consumers' to the same uprobe. - -Each consumer defines a handler and a filter (optional). The -'handler' is run every time the uprobe is hit, if it matches the -'filter' criteria. - -The first consumer of a uprobe causes the breakpoint to be -inserted at the specified address and subsequent consumers are -appended to this list. On subsequent probes, the consumer gets -appended to the existing list of consumers. The breakpoint is -removed when the last consumer unregisters. For all other -unregisterations, the consumer is removed from the list of -consumers. - -Given a inode, we get a list of the mms that have mapped the -inode. Do the actual registration if mm maps the page where a -probe needs to be inserted/removed. - -We use a temporary list to walk through the vmas that map the -inode. - -- The number of maps that map the inode, is not known before we - walk the rmap and keeps changing. -- extending vm_area_struct wasn't recommended, it's a - size-critical data structure. -- There can be more than one maps of the inode in the same mm. - -We add callbacks to the mmap methods to keep an eye on text vmas -that are of interest to uprobes. When a vma of interest is mapped, -we insert the breakpoint at the right address. - -Uprobe works by replacing the instruction at the address defined -by (inode, offset) with the arch specific breakpoint -instruction. We save a copy of the original instruction at the -uprobed address. - -This is needed for: - - a. executing the instruction out-of-line (xol). - b. instruction analysis for any subsequent fixups. - c. restoring the instruction back when the uprobe is unregistered. - -We insert or delete a breakpoint instruction, and this -breakpoint instruction is assumed to be the smallest instruction -available on the platform. For fixed size instruction platforms -this is trivially true, for variable size instruction platforms -the breakpoint instruction is typically the smallest (often a -single byte). - -Writing the instruction is done by COWing the page and changing -the instruction during the copy, this even though most platforms -allow atomic writes of the breakpoint instruction. This also -mirrors the behaviour of a ptrace() memory write to a PRIVATE -file map. - -The core worker is derived from KSM's replace_page() logic. - -In essence, similar to KSM: - - a. allocate a new page and copy over contents of the page that - has the uprobed vaddr - b. modify the copy and insert the breakpoint at the required - address - c. switch the original page with the copy containing the - breakpoint - d. flush page tables. - -replace_page() is being replicated here because of some minor -changes in the type of pages and also because Hugh Dickins had -plans to improve replace_page() for KSM specific work. - -Instruction analysis on x86 is based on instruction decoder and -determines if an instruction can be probed and determines the -necessary fixups after singlestep. Instruction analysis is done -at probe insertion time so that we avoid having to repeat the -same analysis every time a probe is hit. - -A lot of code here is due to the improvement/suggestions/inputs -from Peter Zijlstra. - -Changelog: - -(v10): - - Add code to clear REX.B prefix as suggested by Denys Vlasenko - and Masami Hiramatsu. - -(v9): - - Use insn_offset_modrm as suggested by Masami Hiramatsu. - -(v7): - - Handle comments from Peter Zijlstra: - - - Dont take reference to inode. (expect inode to uprobe_register to be sane). - - Use PTR_ERR to set the return value. - - No need to take reference to inode. - - use PTR_ERR to return error value. - - register and uprobe_unregister share code. - -(v5): - - - Modified del_consumer as per comments from Peter. - - Drop reference to inode before dropping reference to uprobe. - - Use i_size_read(inode) instead of inode->i_size. - - Ensure uprobe->consumers is NULL, before __uprobe_unregister() is called. - - Includes errno.h as recommended by Stephen Rothwell to fix a build issue - on sparc defconfig - - Remove restrictions while unregistering. - - Earlier code leaked inode references under some conditions while - registering/unregistering. - - Continue the vma-rmap walk even if the intermediate vma doesnt - meet the requirements. - - Validate the vma found by find_vma before inserting/removing the - breakpoint - - Call del_consumer under mutex_lock. - - Use hash locks. - - Handle mremap. - - Introduce find_least_offset_node() instead of close match logic in - find_uprobe - - Uprobes no more depends on MM_OWNER; No reference to task_structs - while inserting/removing a probe. - - Uses read_mapping_page instead of grab_cache_page so that the pages - have valid content. - - pass NULL to get_user_pages for the task parameter. - - call SetPageUptodate on the new page allocated in write_opcode. - - fix leaking a reference to the new page under certain conditions. - - Include Instruction Decoder if Uprobes gets defined. - - Remove const attributes for instruction prefix arrays. - - Uses mm_context to know if the application is 32 bit. - -commit 2b144498350860b6ee9dc57ff27a93ad488de5dc upstream - -Signed-off-by: Srikar Dronamraju <srikar@linux.vnet.ibm.com> -Also-written-by: Jim Keniston <jkenisto@us.ibm.com> -Reviewed-by: Peter Zijlstra <a.p.zijlstra@chello.nl> -Cc: Oleg Nesterov <oleg@redhat.com> -Cc: Andi Kleen <andi@firstfloor.org> -Cc: Christoph Hellwig <hch@infradead.org> -Cc: Steven Rostedt <rostedt@goodmis.org> -Cc: Roland McGrath <roland@hack.frob.com> -Cc: Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com> -Cc: Arnaldo Carvalho de Melo <acme@infradead.org> -Cc: Anton Arapov <anton@redhat.com> -Cc: Ananth N Mavinakayanahalli <ananth@in.ibm.com> -Cc: Stephen Rothwell <sfr@canb.auug.org.au> -Cc: Denys Vlasenko <vda.linux@googlemail.com> -Cc: Peter Zijlstra <peterz@infradead.org> -Cc: Linus Torvalds <torvalds@linux-foundation.org> -Cc: Andrew Morton <akpm@linux-foundation.org> -Cc: Linux-mm <linux-mm@kvack.org> -Link: http://lkml.kernel.org/r/20120209092642.GE16600@linux.vnet.ibm.com -[ Made various small edits to the commit log ] -Signed-off-by: Ingo Molnar <mingo@elte.hu> -Signed-off-by: Paul Barrette <paul.barrette@windriver.com> ---- - arch/Kconfig | 11 + - arch/x86/Kconfig | 5 +- - arch/x86/include/asm/uprobes.h | 42 ++ - arch/x86/kernel/Makefile | 1 + - arch/x86/kernel/uprobes.c | 412 +++++++++++++++++ - include/linux/uprobes.h | 98 ++++ - kernel/Makefile | 1 + - kernel/uprobes.c | 976 ++++++++++++++++++++++++++++++++++++++++ - mm/mmap.c | 23 + - 9 files changed, 1568 insertions(+), 1 deletions(-) - create mode 100644 arch/x86/include/asm/uprobes.h - create mode 100644 arch/x86/kernel/uprobes.c - create mode 100644 include/linux/uprobes.h - create mode 100644 kernel/uprobes.c - -diff --git a/arch/Kconfig b/arch/Kconfig -index c024b3e..5083bf2 100644 ---- a/arch/Kconfig -+++ b/arch/Kconfig -@@ -76,6 +76,17 @@ config OPTPROBES - depends on KPROBES && HAVE_OPTPROBES - depends on !PREEMPT - -+config UPROBES -+ bool "User-space probes (EXPERIMENTAL)" -+ depends on ARCH_SUPPORTS_UPROBES -+ default n -+ help -+ Uprobes enables kernel subsystems to establish probepoints -+ in user applications and execute handler functions when -+ the probepoints are hit. -+ -+ If in doubt, say "N". -+ - config HAVE_EFFICIENT_UNALIGNED_ACCESS - bool - help -diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig -index 2b79d94..fb0c234 100644 ---- a/arch/x86/Kconfig -+++ b/arch/x86/Kconfig -@@ -85,7 +85,7 @@ config X86 - select HAVE_ARCH_SECCOMP_FILTER - - config INSTRUCTION_DECODER -- def_bool (KPROBES || PERF_EVENTS) -+ def_bool (KPROBES || PERF_EVENTS || UPROBES) - - config OUTPUT_FORMAT - string -@@ -244,6 +244,9 @@ config ARCH_CPU_PROBE_RELEASE - def_bool y - depends on HOTPLUG_CPU - -+config ARCH_SUPPORTS_UPROBES -+ def_bool y -+ - source "init/Kconfig" - source "kernel/Kconfig.freezer" - -diff --git a/arch/x86/include/asm/uprobes.h b/arch/x86/include/asm/uprobes.h -new file mode 100644 -index 0000000..8208234 ---- /dev/null -+++ b/arch/x86/include/asm/uprobes.h -@@ -0,0 +1,42 @@ -+#ifndef _ASM_UPROBES_H -+#define _ASM_UPROBES_H -+/* -+ * Userspace Probes (UProbes) for x86 -+ * -+ * 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. -+ * -+ * 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. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -+ * -+ * Copyright (C) IBM Corporation, 2008-2011 -+ * Authors: -+ * Srikar Dronamraju -+ * Jim Keniston -+ */ -+ -+typedef u8 uprobe_opcode_t; -+#define MAX_UINSN_BYTES 16 -+#define UPROBES_XOL_SLOT_BYTES 128 /* to keep it cache aligned */ -+ -+#define UPROBES_BKPT_INSN 0xcc -+#define UPROBES_BKPT_INSN_SIZE 1 -+ -+struct uprobe_arch_info { -+ u16 fixups; -+#ifdef CONFIG_X86_64 -+ unsigned long rip_rela_target_address; -+#endif -+}; -+ -+struct uprobe; -+extern int analyze_insn(struct mm_struct *mm, struct uprobe *uprobe); -+#endif /* _ASM_UPROBES_H */ -diff --git a/arch/x86/kernel/Makefile b/arch/x86/kernel/Makefile -index 532d2e0..d23d835 100644 ---- a/arch/x86/kernel/Makefile -+++ b/arch/x86/kernel/Makefile -@@ -101,6 +101,7 @@ obj-$(CONFIG_X86_CHECK_BIOS_CORRUPTION) += check.o - - obj-$(CONFIG_SWIOTLB) += pci-swiotlb.o - obj-$(CONFIG_OF) += devicetree.o -+obj-$(CONFIG_UPROBES) += uprobes.o - - ### - # 64 bit specific files -diff --git a/arch/x86/kernel/uprobes.c b/arch/x86/kernel/uprobes.c -new file mode 100644 -index 0000000..2a301bb ---- /dev/null -+++ b/arch/x86/kernel/uprobes.c -@@ -0,0 +1,412 @@ -+/* -+ * Userspace Probes (UProbes) for x86 -+ * -+ * 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. -+ * -+ * 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. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -+ * -+ * Copyright (C) IBM Corporation, 2008-2011 -+ * Authors: -+ * Srikar Dronamraju -+ * Jim Keniston -+ */ -+ -+#include <linux/kernel.h> -+#include <linux/sched.h> -+#include <linux/ptrace.h> -+#include <linux/uprobes.h> -+ -+#include <linux/kdebug.h> -+#include <asm/insn.h> -+ -+/* Post-execution fixups. */ -+ -+/* No fixup needed */ -+#define UPROBES_FIX_NONE 0x0 -+/* Adjust IP back to vicinity of actual insn */ -+#define UPROBES_FIX_IP 0x1 -+/* Adjust the return address of a call insn */ -+#define UPROBES_FIX_CALL 0x2 -+ -+#define UPROBES_FIX_RIP_AX 0x8000 -+#define UPROBES_FIX_RIP_CX 0x4000 -+ -+/* Adaptations for mhiramat x86 decoder v14. */ -+#define OPCODE1(insn) ((insn)->opcode.bytes[0]) -+#define OPCODE2(insn) ((insn)->opcode.bytes[1]) -+#define OPCODE3(insn) ((insn)->opcode.bytes[2]) -+#define MODRM_REG(insn) X86_MODRM_REG(insn->modrm.value) -+ -+#define W(row, b0, b1, b2, b3, b4, b5, b6, b7, b8, b9, ba, bb, bc, bd, be, bf)\ -+ (((b0##UL << 0x0)|(b1##UL << 0x1)|(b2##UL << 0x2)|(b3##UL << 0x3) | \ -+ (b4##UL << 0x4)|(b5##UL << 0x5)|(b6##UL << 0x6)|(b7##UL << 0x7) | \ -+ (b8##UL << 0x8)|(b9##UL << 0x9)|(ba##UL << 0xa)|(bb##UL << 0xb) | \ -+ (bc##UL << 0xc)|(bd##UL << 0xd)|(be##UL << 0xe)|(bf##UL << 0xf)) \ -+ << (row % 32)) -+ -+#ifdef CONFIG_X86_64 -+static volatile u32 good_insns_64[256 / 32] = { -+ /* 0 1 2 3 4 5 6 7 8 9 a b c d e f */ -+ /* ---------------------------------------------- */ -+ W(0x00, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0) | /* 00 */ -+ W(0x10, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0) , /* 10 */ -+ W(0x20, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0) | /* 20 */ -+ W(0x30, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0) , /* 30 */ -+ W(0x40, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0) | /* 40 */ -+ W(0x50, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1) , /* 50 */ -+ W(0x60, 0, 0, 0, 1, 1, 1, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0) | /* 60 */ -+ W(0x70, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1) , /* 70 */ -+ W(0x80, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1) | /* 80 */ -+ W(0x90, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1) , /* 90 */ -+ W(0xa0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1) | /* a0 */ -+ W(0xb0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1) , /* b0 */ -+ W(0xc0, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0) | /* c0 */ -+ W(0xd0, 1, 1, 1, 1, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1) , /* d0 */ -+ W(0xe0, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0) | /* e0 */ -+ W(0xf0, 0, 0, 1, 1, 0, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1) /* f0 */ -+ /* ---------------------------------------------- */ -+ /* 0 1 2 3 4 5 6 7 8 9 a b c d e f */ -+}; -+#endif -+ -+/* Good-instruction tables for 32-bit apps */ -+ -+static volatile u32 good_insns_32[256 / 32] = { -+ /* 0 1 2 3 4 5 6 7 8 9 a b c d e f */ -+ /* ---------------------------------------------- */ -+ W(0x00, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 0) | /* 00 */ -+ W(0x10, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 0) , /* 10 */ -+ W(0x20, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 0, 1) | /* 20 */ -+ W(0x30, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 0, 1) , /* 30 */ -+ W(0x40, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1) | /* 40 */ -+ W(0x50, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1) , /* 50 */ -+ W(0x60, 1, 1, 1, 0, 1, 1, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0) | /* 60 */ -+ W(0x70, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1) , /* 70 */ -+ W(0x80, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1) | /* 80 */ -+ W(0x90, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1) , /* 90 */ -+ W(0xa0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1) | /* a0 */ -+ W(0xb0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1) , /* b0 */ -+ W(0xc0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0) | /* c0 */ -+ W(0xd0, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1) , /* d0 */ -+ W(0xe0, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0) | /* e0 */ -+ W(0xf0, 0, 0, 1, 1, 0, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1) /* f0 */ -+ /* ---------------------------------------------- */ -+ /* 0 1 2 3 4 5 6 7 8 9 a b c d e f */ -+}; -+ -+/* Using this for both 64-bit and 32-bit apps */ -+static volatile u32 good_2byte_insns[256 / 32] = { -+ /* 0 1 2 3 4 5 6 7 8 9 a b c d e f */ -+ /* ---------------------------------------------- */ -+ W(0x00, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1) | /* 00 */ -+ W(0x10, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1) , /* 10 */ -+ W(0x20, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1) | /* 20 */ -+ W(0x30, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0) , /* 30 */ -+ W(0x40, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1) | /* 40 */ -+ W(0x50, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1) , /* 50 */ -+ W(0x60, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1) | /* 60 */ -+ W(0x70, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1) , /* 70 */ -+ W(0x80, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1) | /* 80 */ -+ W(0x90, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1) , /* 90 */ -+ W(0xa0, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 0, 1) | /* a0 */ -+ W(0xb0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1) , /* b0 */ -+ W(0xc0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1) | /* c0 */ -+ W(0xd0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1) , /* d0 */ -+ W(0xe0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1) | /* e0 */ -+ W(0xf0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0) /* f0 */ -+ /* ---------------------------------------------- */ -+ /* 0 1 2 3 4 5 6 7 8 9 a b c d e f */ -+}; -+ -+#undef W -+ -+/* -+ * opcodes we'll probably never support: -+ * 6c-6d, e4-e5, ec-ed - in -+ * 6e-6f, e6-e7, ee-ef - out -+ * cc, cd - int3, int -+ * cf - iret -+ * d6 - illegal instruction -+ * f1 - int1/icebp -+ * f4 - hlt -+ * fa, fb - cli, sti -+ * 0f - lar, lsl, syscall, clts, sysret, sysenter, sysexit, invd, wbinvd, ud2 -+ * -+ * invalid opcodes in 64-bit mode: -+ * 06, 0e, 16, 1e, 27, 2f, 37, 3f, 60-62, 82, c4-c5, d4-d5 -+ * -+ * 63 - we support this opcode in x86_64 but not in i386. -+ * -+ * opcodes we may need to refine support for: -+ * 0f - 2-byte instructions: For many of these instructions, the validity -+ * depends on the prefix and/or the reg field. On such instructions, we -+ * just consider the opcode combination valid if it corresponds to any -+ * valid instruction. -+ * 8f - Group 1 - only reg = 0 is OK -+ * c6-c7 - Group 11 - only reg = 0 is OK -+ * d9-df - fpu insns with some illegal encodings -+ * f2, f3 - repnz, repz prefixes. These are also the first byte for -+ * certain floating-point instructions, such as addsd. -+ * fe - Group 4 - only reg = 0 or 1 is OK -+ * ff - Group 5 - only reg = 0-6 is OK -+ * -+ * others -- Do we need to support these? -+ * 0f - (floating-point?) prefetch instructions -+ * 07, 17, 1f - pop es, pop ss, pop ds -+ * 26, 2e, 36, 3e - es:, cs:, ss:, ds: segment prefixes -- -+ * but 64 and 65 (fs: and gs:) seem to be used, so we support them -+ * 67 - addr16 prefix -+ * ce - into -+ * f0 - lock prefix -+ */ -+ -+/* -+ * TODO: -+ * - Where necessary, examine the modrm byte and allow only valid instructions -+ * in the different Groups and fpu instructions. -+ */ -+ -+static bool is_prefix_bad(struct insn *insn) -+{ -+ int i; -+ -+ for (i = 0; i < insn->prefixes.nbytes; i++) { -+ switch (insn->prefixes.bytes[i]) { -+ case 0x26: /*INAT_PFX_ES */ -+ case 0x2E: /*INAT_PFX_CS */ -+ case 0x36: /*INAT_PFX_DS */ -+ case 0x3E: /*INAT_PFX_SS */ -+ case 0xF0: /*INAT_PFX_LOCK */ -+ return true; -+ } -+ } -+ return false; -+} -+ -+static int validate_insn_32bits(struct uprobe *uprobe, struct insn *insn) -+{ -+ insn_init(insn, uprobe->insn, false); -+ -+ /* Skip good instruction prefixes; reject "bad" ones. */ -+ insn_get_opcode(insn); -+ if (is_prefix_bad(insn)) -+ return -ENOTSUPP; -+ if (test_bit(OPCODE1(insn), (unsigned long *)good_insns_32)) -+ return 0; -+ if (insn->opcode.nbytes == 2) { -+ if (test_bit(OPCODE2(insn), (unsigned long *)good_2byte_insns)) -+ return 0; -+ } -+ return -ENOTSUPP; -+} -+ -+/* -+ * Figure out which fixups post_xol() will need to perform, and annotate -+ * uprobe->arch_info.fixups accordingly. To start with, -+ * uprobe->arch_info.fixups is either zero or it reflects rip-related -+ * fixups. -+ */ -+static void prepare_fixups(struct uprobe *uprobe, struct insn *insn) -+{ -+ bool fix_ip = true, fix_call = false; /* defaults */ -+ int reg; -+ -+ insn_get_opcode(insn); /* should be a nop */ -+ -+ switch (OPCODE1(insn)) { -+ case 0xc3: /* ret/lret */ -+ case 0xcb: -+ case 0xc2: -+ case 0xca: -+ /* ip is correct */ -+ fix_ip = false; -+ break; -+ case 0xe8: /* call relative - Fix return addr */ -+ fix_call = true; -+ break; -+ case 0x9a: /* call absolute - Fix return addr, not ip */ -+ fix_call = true; -+ fix_ip = false; -+ break; -+ case 0xff: -+ insn_get_modrm(insn); -+ reg = MODRM_REG(insn); -+ if (reg == 2 || reg == 3) { -+ /* call or lcall, indirect */ -+ /* Fix return addr; ip is correct. */ -+ fix_call = true; -+ fix_ip = false; -+ } else if (reg == 4 || reg == 5) { -+ /* jmp or ljmp, indirect */ -+ /* ip is correct. */ -+ fix_ip = false; -+ } -+ break; -+ case 0xea: /* jmp absolute -- ip is correct */ -+ fix_ip = false; -+ break; -+ default: -+ break; -+ } -+ if (fix_ip) -+ uprobe->arch_info.fixups |= UPROBES_FIX_IP; -+ if (fix_call) -+ uprobe->arch_info.fixups |= UPROBES_FIX_CALL; -+} -+ -+#ifdef CONFIG_X86_64 -+/* -+ * If uprobe->insn doesn't use rip-relative addressing, return -+ * immediately. Otherwise, rewrite the instruction so that it accesses -+ * its memory operand indirectly through a scratch register. Set -+ * uprobe->arch_info.fixups and uprobe->arch_info.rip_rela_target_address -+ * accordingly. (The contents of the scratch register will be saved -+ * before we single-step the modified instruction, and restored -+ * afterward.) -+ * -+ * We do this because a rip-relative instruction can access only a -+ * relatively small area (+/- 2 GB from the instruction), and the XOL -+ * area typically lies beyond that area. At least for instructions -+ * that store to memory, we can't execute the original instruction -+ * and "fix things up" later, because the misdirected store could be -+ * disastrous. -+ * -+ * Some useful facts about rip-relative instructions: -+ * - There's always a modrm byte. -+ * - There's never a SIB byte. -+ * - The displacement is always 4 bytes. -+ */ -+static void handle_riprel_insn(struct mm_struct *mm, struct uprobe *uprobe, -+ struct insn *insn) -+{ -+ u8 *cursor; -+ u8 reg; -+ -+ if (mm->context.ia32_compat) -+ return; -+ -+ uprobe->arch_info.rip_rela_target_address = 0x0; -+ if (!insn_rip_relative(insn)) -+ return; -+ -+ /* -+ * insn_rip_relative() would have decoded rex_prefix, modrm. -+ * Clear REX.b bit (extension of MODRM.rm field): -+ * we want to encode rax/rcx, not r8/r9. -+ */ -+ if (insn->rex_prefix.nbytes) { -+ cursor = uprobe->insn + insn_offset_rex_prefix(insn); -+ *cursor &= 0xfe; /* Clearing REX.B bit */ -+ } -+ -+ /* -+ * Point cursor at the modrm byte. The next 4 bytes are the -+ * displacement. Beyond the displacement, for some instructions, -+ * is the immediate operand. -+ */ -+ cursor = uprobe->insn + insn_offset_modrm(insn); -+ insn_get_length(insn); -+ -+ /* -+ * Convert from rip-relative addressing to indirect addressing -+ * via a scratch register. Change the r/m field from 0x5 (%rip) -+ * to 0x0 (%rax) or 0x1 (%rcx), and squeeze out the offset field. -+ */ -+ reg = MODRM_REG(insn); -+ if (reg == 0) { -+ /* -+ * The register operand (if any) is either the A register -+ * (%rax, %eax, etc.) or (if the 0x4 bit is set in the -+ * REX prefix) %r8. In any case, we know the C register -+ * is NOT the register operand, so we use %rcx (register -+ * #1) for the scratch register. -+ */ -+ uprobe->arch_info.fixups = UPROBES_FIX_RIP_CX; -+ /* Change modrm from 00 000 101 to 00 000 001. */ -+ *cursor = 0x1; -+ } else { -+ /* Use %rax (register #0) for the scratch register. */ -+ uprobe->arch_info.fixups = UPROBES_FIX_RIP_AX; -+ /* Change modrm from 00 xxx 101 to 00 xxx 000 */ -+ *cursor = (reg << 3); -+ } -+ -+ /* Target address = address of next instruction + (signed) offset */ -+ uprobe->arch_info.rip_rela_target_address = (long)insn->length -+ + insn->displacement.value; -+ /* Displacement field is gone; slide immediate field (if any) over. */ -+ if (insn->immediate.nbytes) { -+ cursor++; -+ memmove(cursor, cursor + insn->displacement.nbytes, -+ insn->immediate.nbytes); -+ } -+ return; -+} -+ -+static int validate_insn_64bits(struct uprobe *uprobe, struct insn *insn) -+{ -+ insn_init(insn, uprobe->insn, true); -+ -+ /* Skip good instruction prefixes; reject "bad" ones. */ -+ insn_get_opcode(insn); -+ if (is_prefix_bad(insn)) -+ return -ENOTSUPP; -+ if (test_bit(OPCODE1(insn), (unsigned long *)good_insns_64)) -+ return 0; -+ if (insn->opcode.nbytes == 2) { -+ if (test_bit(OPCODE2(insn), (unsigned long *)good_2byte_insns)) -+ return 0; -+ } -+ return -ENOTSUPP; -+} -+ -+static int validate_insn_bits(struct mm_struct *mm, struct uprobe *uprobe, -+ struct insn *insn) -+{ -+ if (mm->context.ia32_compat) -+ return validate_insn_32bits(uprobe, insn); -+ return validate_insn_64bits(uprobe, insn); -+} -+#else -+static void handle_riprel_insn(struct mm_struct *mm, struct uprobe *uprobe, -+ struct insn *insn) -+{ -+ return; -+} -+ -+static int validate_insn_bits(struct mm_struct *mm, struct uprobe *uprobe, -+ struct insn *insn) -+{ -+ return validate_insn_32bits(uprobe, insn); -+} -+#endif /* CONFIG_X86_64 */ -+ -+/** -+ * analyze_insn - instruction analysis including validity and fixups. -+ * @mm: the probed address space. -+ * @uprobe: the probepoint information. -+ * Return 0 on success or a -ve number on error. -+ */ -+int analyze_insn(struct mm_struct *mm, struct uprobe *uprobe) -+{ -+ int ret; -+ struct insn insn; -+ -+ uprobe->arch_info.fixups = 0; -+ ret = validate_insn_bits(mm, uprobe, &insn); -+ if (ret != 0) -+ return ret; -+ handle_riprel_insn(mm, uprobe, &insn); -+ prepare_fixups(uprobe, &insn); -+ return 0; -+} -diff --git a/include/linux/uprobes.h b/include/linux/uprobes.h -new file mode 100644 -index 0000000..f1d13fd ---- /dev/null -+++ b/include/linux/uprobes.h -@@ -0,0 +1,98 @@ -+#ifndef _LINUX_UPROBES_H -+#define _LINUX_UPROBES_H -+/* -+ * Userspace Probes (UProbes) -+ * -+ * 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. -+ * -+ * 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. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -+ * -+ * Copyright (C) IBM Corporation, 2008-2011 -+ * Authors: -+ * Srikar Dronamraju -+ * Jim Keniston -+ */ -+ -+#include <linux/errno.h> -+#include <linux/rbtree.h> -+ -+struct vm_area_struct; -+#ifdef CONFIG_ARCH_SUPPORTS_UPROBES -+#include <asm/uprobes.h> -+#else -+ -+typedef u8 uprobe_opcode_t; -+struct uprobe_arch_info {}; -+ -+#define MAX_UINSN_BYTES 4 -+#endif -+ -+#define uprobe_opcode_sz sizeof(uprobe_opcode_t) -+ -+/* flags that denote/change uprobes behaviour */ -+/* Have a copy of original instruction */ -+#define UPROBES_COPY_INSN 0x1 -+/* Dont run handlers when first register/ last unregister in progress*/ -+#define UPROBES_RUN_HANDLER 0x2 -+ -+struct uprobe_consumer { -+ int (*handler)(struct uprobe_consumer *self, struct pt_regs *regs); -+ /* -+ * filter is optional; If a filter exists, handler is run -+ * if and only if filter returns true. -+ */ -+ bool (*filter)(struct uprobe_consumer *self, struct task_struct *task); -+ -+ struct uprobe_consumer *next; -+}; -+ -+struct uprobe { -+ struct rb_node rb_node; /* node in the rb tree */ -+ atomic_t ref; -+ struct rw_semaphore consumer_rwsem; -+ struct list_head pending_list; -+ struct uprobe_arch_info arch_info; -+ struct uprobe_consumer *consumers; -+ struct inode *inode; /* Also hold a ref to inode */ -+ loff_t offset; -+ int flags; -+ u8 insn[MAX_UINSN_BYTES]; -+}; -+ -+#ifdef CONFIG_UPROBES -+extern int __weak set_bkpt(struct mm_struct *mm, struct uprobe *uprobe, -+ unsigned long vaddr); -+extern int __weak set_orig_insn(struct mm_struct *mm, struct uprobe *uprobe, -+ unsigned long vaddr, bool verify); -+extern bool __weak is_bkpt_insn(uprobe_opcode_t *insn); -+extern int register_uprobe(struct inode *inode, loff_t offset, -+ struct uprobe_consumer *consumer); -+extern void unregister_uprobe(struct inode *inode, loff_t offset, -+ struct uprobe_consumer *consumer); -+extern int mmap_uprobe(struct vm_area_struct *vma); -+#else /* CONFIG_UPROBES is not defined */ -+static inline int register_uprobe(struct inode *inode, loff_t offset, -+ struct uprobe_consumer *consumer) -+{ -+ return -ENOSYS; -+} -+static inline void unregister_uprobe(struct inode *inode, loff_t offset, -+ struct uprobe_consumer *consumer) -+{ -+} -+static inline int mmap_uprobe(struct vm_area_struct *vma) -+{ -+ return 0; -+} -+#endif /* CONFIG_UPROBES */ -+#endif /* _LINUX_UPROBES_H */ -diff --git a/kernel/Makefile b/kernel/Makefile -index 633b548..72ea789 100644 ---- a/kernel/Makefile -+++ b/kernel/Makefile -@@ -107,6 +107,7 @@ obj-$(CONFIG_USER_RETURN_NOTIFIER) += user-return-notifier.o - obj-$(CONFIG_PADATA) += padata.o - obj-$(CONFIG_CRASH_DUMP) += crash_dump.o - obj-$(CONFIG_JUMP_LABEL) += jump_label.o -+obj-$(CONFIG_UPROBES) += uprobes.o - - $(obj)/configs.o: $(obj)/config_data.h - -diff --git a/kernel/uprobes.c b/kernel/uprobes.c -new file mode 100644 -index 0000000..72e8bb3 ---- /dev/null -+++ b/kernel/uprobes.c -@@ -0,0 +1,976 @@ -+/* -+ * Userspace Probes (UProbes) -+ * -+ * 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. -+ * -+ * 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. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -+ * -+ * Copyright (C) IBM Corporation, 2008-2011 -+ * Authors: -+ * Srikar Dronamraju -+ * Jim Keniston -+ */ -+ -+#include <linux/kernel.h> -+#include <linux/highmem.h> -+#include <linux/pagemap.h> /* read_mapping_page */ -+#include <linux/slab.h> -+#include <linux/sched.h> -+#include <linux/rmap.h> /* anon_vma_prepare */ -+#include <linux/mmu_notifier.h> /* set_pte_at_notify */ -+#include <linux/swap.h> /* try_to_free_swap */ -+#include <linux/uprobes.h> -+ -+static struct rb_root uprobes_tree = RB_ROOT; -+static DEFINE_SPINLOCK(uprobes_treelock); /* serialize rbtree access */ -+ -+#define UPROBES_HASH_SZ 13 -+/* serialize (un)register */ -+static struct mutex uprobes_mutex[UPROBES_HASH_SZ]; -+#define uprobes_hash(v) (&uprobes_mutex[((unsigned long)(v)) %\ -+ UPROBES_HASH_SZ]) -+ -+/* serialize uprobe->pending_list */ -+static struct mutex uprobes_mmap_mutex[UPROBES_HASH_SZ]; -+#define uprobes_mmap_hash(v) (&uprobes_mmap_mutex[((unsigned long)(v)) %\ -+ UPROBES_HASH_SZ]) -+ -+/* -+ * uprobe_events allows us to skip the mmap_uprobe if there are no uprobe -+ * events active at this time. Probably a fine grained per inode count is -+ * better? -+ */ -+static atomic_t uprobe_events = ATOMIC_INIT(0); -+ -+/* -+ * Maintain a temporary per vma info that can be used to search if a vma -+ * has already been handled. This structure is introduced since extending -+ * vm_area_struct wasnt recommended. -+ */ -+struct vma_info { -+ struct list_head probe_list; -+ struct mm_struct *mm; -+ loff_t vaddr; -+}; -+ -+/* -+ * valid_vma: Verify if the specified vma is an executable vma -+ * Relax restrictions while unregistering: vm_flags might have -+ * changed after breakpoint was inserted. -+ * - is_register: indicates if we are in register context. -+ * - Return 1 if the specified virtual address is in an -+ * executable vma. -+ */ -+static bool valid_vma(struct vm_area_struct *vma, bool is_register) -+{ -+ if (!vma->vm_file) -+ return false; -+ -+ if (!is_register) -+ return true; -+ -+ if ((vma->vm_flags & (VM_READ|VM_WRITE|VM_EXEC|VM_SHARED)) == -+ (VM_READ|VM_EXEC)) -+ return true; -+ -+ return false; -+} -+ -+static loff_t vma_address(struct vm_area_struct *vma, loff_t offset) -+{ -+ loff_t vaddr; -+ -+ vaddr = vma->vm_start + offset; -+ vaddr -= vma->vm_pgoff << PAGE_SHIFT; -+ return vaddr; -+} -+ -+/** -+ * __replace_page - replace page in vma by new page. -+ * based on replace_page in mm/ksm.c -+ * -+ * @vma: vma that holds the pte pointing to page -+ * @page: the cowed page we are replacing by kpage -+ * @kpage: the modified page we replace page by -+ * -+ * Returns 0 on success, -EFAULT on failure. -+ */ -+static int __replace_page(struct vm_area_struct *vma, struct page *page, -+ struct page *kpage) -+{ -+ struct mm_struct *mm = vma->vm_mm; -+ pgd_t *pgd; -+ pud_t *pud; -+ pmd_t *pmd; -+ pte_t *ptep; -+ spinlock_t *ptl; -+ unsigned long addr; -+ int err = -EFAULT; -+ -+ addr = page_address_in_vma(page, vma); -+ if (addr == -EFAULT) -+ goto out; -+ -+ pgd = pgd_offset(mm, addr); -+ if (!pgd_present(*pgd)) -+ goto out; -+ -+ pud = pud_offset(pgd, addr); -+ if (!pud_present(*pud)) -+ goto out; -+ -+ pmd = pmd_offset(pud, addr); -+ if (!pmd_present(*pmd)) -+ goto out; -+ -+ ptep = pte_offset_map_lock(mm, pmd, addr, &ptl); -+ if (!ptep) -+ goto out; -+ -+ get_page(kpage); -+ page_add_new_anon_rmap(kpage, vma, addr); -+ -+ flush_cache_page(vma, addr, pte_pfn(*ptep)); -+ ptep_clear_flush(vma, addr, ptep); -+ set_pte_at_notify(mm, addr, ptep, mk_pte(kpage, vma->vm_page_prot)); -+ -+ page_remove_rmap(page); -+ if (!page_mapped(page)) -+ try_to_free_swap(page); -+ put_page(page); -+ pte_unmap_unlock(ptep, ptl); -+ err = 0; -+ -+out: -+ return err; -+} -+ -+/** -+ * is_bkpt_insn - check if instruction is breakpoint instruction. -+ * @insn: instruction to be checked. -+ * Default implementation of is_bkpt_insn -+ * Returns true if @insn is a breakpoint instruction. -+ */ -+bool __weak is_bkpt_insn(uprobe_opcode_t *insn) -+{ -+ return (*insn == UPROBES_BKPT_INSN); -+} -+ -+/* -+ * NOTE: -+ * Expect the breakpoint instruction to be the smallest size instruction for -+ * the architecture. If an arch has variable length instruction and the -+ * breakpoint instruction is not of the smallest length instruction -+ * supported by that architecture then we need to modify read_opcode / -+ * write_opcode accordingly. This would never be a problem for archs that -+ * have fixed length instructions. -+ */ -+ -+/* -+ * write_opcode - write the opcode at a given virtual address. -+ * @mm: the probed process address space. -+ * @uprobe: the breakpointing information. -+ * @vaddr: the virtual address to store the opcode. -+ * @opcode: opcode to be written at @vaddr. -+ * -+ * Called with mm->mmap_sem held (for read and with a reference to -+ * mm). -+ * -+ * For mm @mm, write the opcode at @vaddr. -+ * Return 0 (success) or a negative errno. -+ */ -+static int write_opcode(struct mm_struct *mm, struct uprobe *uprobe, -+ unsigned long vaddr, uprobe_opcode_t opcode) -+{ -+ struct page *old_page, *new_page; -+ struct address_space *mapping; -+ void *vaddr_old, *vaddr_new; -+ struct vm_area_struct *vma; -+ loff_t addr; -+ int ret; -+ -+ /* Read the page with vaddr into memory */ -+ ret = get_user_pages(NULL, mm, vaddr, 1, 0, 0, &old_page, &vma); -+ if (ret <= 0) -+ return ret; -+ ret = -EINVAL; -+ -+ /* -+ * We are interested in text pages only. Our pages of interest -+ * should be mapped for read and execute only. We desist from -+ * adding probes in write mapped pages since the breakpoints -+ * might end up in the file copy. -+ */ -+ if (!valid_vma(vma, is_bkpt_insn(&opcode))) -+ goto put_out; -+ -+ mapping = uprobe->inode->i_mapping; -+ if (mapping != vma->vm_file->f_mapping) -+ goto put_out; -+ -+ addr = vma_address(vma, uprobe->offset); -+ if (vaddr != (unsigned long)addr) -+ goto put_out; -+ -+ ret = -ENOMEM; -+ new_page = alloc_page_vma(GFP_HIGHUSER_MOVABLE, vma, vaddr); -+ if (!new_page) -+ goto put_out; -+ -+ __SetPageUptodate(new_page); -+ -+ /* -+ * lock page will serialize against do_wp_page()'s -+ * PageAnon() handling -+ */ -+ lock_page(old_page); -+ /* copy the page now that we've got it stable */ -+ vaddr_old = kmap_atomic(old_page); -+ vaddr_new = kmap_atomic(new_page); -+ -+ memcpy(vaddr_new, vaddr_old, PAGE_SIZE); -+ /* poke the new insn in, ASSUMES we don't cross page boundary */ -+ vaddr &= ~PAGE_MASK; -+ BUG_ON(vaddr + uprobe_opcode_sz > PAGE_SIZE); -+ memcpy(vaddr_new + vaddr, &opcode, uprobe_opcode_sz); -+ -+ kunmap_atomic(vaddr_new); -+ kunmap_atomic(vaddr_old); -+ -+ ret = anon_vma_prepare(vma); -+ if (ret) -+ goto unlock_out; -+ -+ lock_page(new_page); -+ ret = __replace_page(vma, old_page, new_page); -+ unlock_page(new_page); -+ -+unlock_out: -+ unlock_page(old_page); -+ page_cache_release(new_page); -+ -+put_out: -+ put_page(old_page); /* we did a get_page in the beginning */ -+ return ret; -+} -+ -+/** -+ * read_opcode - read the opcode at a given virtual address. -+ * @mm: the probed process address space. -+ * @vaddr: the virtual address to read the opcode. -+ * @opcode: location to store the read opcode. -+ * -+ * Called with mm->mmap_sem held (for read and with a reference to -+ * mm. -+ * -+ * For mm @mm, read the opcode at @vaddr and store it in @opcode. -+ * Return 0 (success) or a negative errno. -+ */ -+static int read_opcode(struct mm_struct *mm, unsigned long vaddr, -+ uprobe_opcode_t *opcode) -+{ -+ struct page *page; -+ void *vaddr_new; -+ int ret; -+ -+ ret = get_user_pages(NULL, mm, vaddr, 1, 0, 0, &page, NULL); -+ if (ret <= 0) -+ return ret; -+ -+ lock_page(page); -+ vaddr_new = kmap_atomic(page); -+ vaddr &= ~PAGE_MASK; -+ memcpy(opcode, vaddr_new + vaddr, uprobe_opcode_sz); -+ kunmap_atomic(vaddr_new); -+ unlock_page(page); -+ put_page(page); /* we did a get_user_pages in the beginning */ -+ return 0; -+} -+ -+static int is_bkpt_at_addr(struct mm_struct *mm, unsigned long vaddr) -+{ -+ uprobe_opcode_t opcode; -+ int result = read_opcode(mm, vaddr, &opcode); -+ -+ if (result) -+ return result; -+ -+ if (is_bkpt_insn(&opcode)) -+ return 1; -+ -+ return 0; -+} -+ -+/** -+ * set_bkpt - store breakpoint at a given address. -+ * @mm: the probed process address space. -+ * @uprobe: the probepoint information. -+ * @vaddr: the virtual address to insert the opcode. -+ * -+ * For mm @mm, store the breakpoint instruction at @vaddr. -+ * Return 0 (success) or a negative errno. -+ */ -+int __weak set_bkpt(struct mm_struct *mm, struct uprobe *uprobe, -+ unsigned long vaddr) -+{ -+ int result = is_bkpt_at_addr(mm, vaddr); -+ -+ if (result == 1) -+ return -EEXIST; -+ -+ if (result) -+ return result; -+ -+ return write_opcode(mm, uprobe, vaddr, UPROBES_BKPT_INSN); -+} -+ -+/** -+ * set_orig_insn - Restore the original instruction. -+ * @mm: the probed process address space. -+ * @uprobe: the probepoint information. -+ * @vaddr: the virtual address to insert the opcode. -+ * @verify: if true, verify existance of breakpoint instruction. -+ * -+ * For mm @mm, restore the original opcode (opcode) at @vaddr. -+ * Return 0 (success) or a negative errno. -+ */ -+int __weak set_orig_insn(struct mm_struct *mm, struct uprobe *uprobe, -+ unsigned long vaddr, bool verify) -+{ -+ if (verify) { -+ int result = is_bkpt_at_addr(mm, vaddr); -+ -+ if (!result) -+ return -EINVAL; -+ -+ if (result != 1) -+ return result; -+ } -+ return write_opcode(mm, uprobe, vaddr, -+ *(uprobe_opcode_t *)uprobe->insn); -+} -+ -+static int match_uprobe(struct uprobe *l, struct uprobe *r) -+{ -+ if (l->inode < r->inode) -+ return -1; -+ if (l->inode > r->inode) -+ return 1; -+ else { -+ if (l->offset < r->offset) -+ return -1; -+ -+ if (l->offset > r->offset) -+ return 1; -+ } -+ -+ return 0; -+} -+ -+static struct uprobe *__find_uprobe(struct inode *inode, loff_t offset) -+{ -+ struct uprobe u = { .inode = inode, .offset = offset }; -+ struct rb_node *n = uprobes_tree.rb_node; -+ struct uprobe *uprobe; -+ int match; -+ -+ while (n) { -+ uprobe = rb_entry(n, struct uprobe, rb_node); -+ match = match_uprobe(&u, uprobe); -+ if (!match) { -+ atomic_inc(&uprobe->ref); -+ return uprobe; -+ } -+ if (match < 0) -+ n = n->rb_left; -+ else -+ n = n->rb_right; -+ } -+ return NULL; -+} -+ -+/* -+ * Find a uprobe corresponding to a given inode:offset -+ * Acquires uprobes_treelock -+ */ -+static struct uprobe *find_uprobe(struct inode *inode, loff_t offset) -+{ -+ struct uprobe *uprobe; -+ unsigned long flags; -+ -+ spin_lock_irqsave(&uprobes_treelock, flags); -+ uprobe = __find_uprobe(inode, offset); -+ spin_unlock_irqrestore(&uprobes_treelock, flags); -+ return uprobe; -+} -+ -+static struct uprobe *__insert_uprobe(struct uprobe *uprobe) -+{ -+ struct rb_node **p = &uprobes_tree.rb_node; -+ struct rb_node *parent = NULL; -+ struct uprobe *u; -+ int match; -+ -+ while (*p) { -+ parent = *p; -+ u = rb_entry(parent, struct uprobe, rb_node); -+ match = match_uprobe(uprobe, u); -+ if (!match) { -+ atomic_inc(&u->ref); -+ return u; -+ } -+ -+ if (match < 0) -+ p = &parent->rb_left; -+ else -+ p = &parent->rb_right; -+ -+ } -+ u = NULL; -+ rb_link_node(&uprobe->rb_node, parent, p); -+ rb_insert_color(&uprobe->rb_node, &uprobes_tree); -+ /* get access + creation ref */ -+ atomic_set(&uprobe->ref, 2); -+ return u; -+} -+ -+/* -+ * Acquires uprobes_treelock. -+ * Matching uprobe already exists in rbtree; -+ * increment (access refcount) and return the matching uprobe. -+ * -+ * No matching uprobe; insert the uprobe in rb_tree; -+ * get a double refcount (access + creation) and return NULL. -+ */ -+static struct uprobe *insert_uprobe(struct uprobe *uprobe) -+{ -+ unsigned long flags; -+ struct uprobe *u; -+ -+ spin_lock_irqsave(&uprobes_treelock, flags); -+ u = __insert_uprobe(uprobe); -+ spin_unlock_irqrestore(&uprobes_treelock, flags); -+ return u; -+} -+ -+static void put_uprobe(struct uprobe *uprobe) -+{ -+ if (atomic_dec_and_test(&uprobe->ref)) -+ kfree(uprobe); -+} -+ -+static struct uprobe *alloc_uprobe(struct inode *inode, loff_t offset) -+{ -+ struct uprobe *uprobe, *cur_uprobe; -+ -+ uprobe = kzalloc(sizeof(struct uprobe), GFP_KERNEL); -+ if (!uprobe) -+ return NULL; -+ -+ uprobe->inode = igrab(inode); -+ uprobe->offset = offset; -+ init_rwsem(&uprobe->consumer_rwsem); -+ INIT_LIST_HEAD(&uprobe->pending_list); -+ -+ /* add to uprobes_tree, sorted on inode:offset */ -+ cur_uprobe = insert_uprobe(uprobe); -+ -+ /* a uprobe exists for this inode:offset combination */ -+ if (cur_uprobe) { -+ kfree(uprobe); -+ uprobe = cur_uprobe; -+ iput(inode); -+ } else -+ atomic_inc(&uprobe_events); -+ return uprobe; -+} -+ -+/* Returns the previous consumer */ -+static struct uprobe_consumer *add_consumer(struct uprobe *uprobe, -+ struct uprobe_consumer *consumer) -+{ -+ down_write(&uprobe->consumer_rwsem); -+ consumer->next = uprobe->consumers; -+ uprobe->consumers = consumer; -+ up_write(&uprobe->consumer_rwsem); -+ return consumer->next; -+} -+ -+/* -+ * For uprobe @uprobe, delete the consumer @consumer. -+ * Return true if the @consumer is deleted successfully -+ * or return false. -+ */ -+static bool del_consumer(struct uprobe *uprobe, -+ struct uprobe_consumer *consumer) -+{ -+ struct uprobe_consumer **con; -+ bool ret = false; -+ -+ down_write(&uprobe->consumer_rwsem); -+ for (con = &uprobe->consumers; *con; con = &(*con)->next) { -+ if (*con == consumer) { -+ *con = consumer->next; -+ ret = true; -+ break; -+ } -+ } -+ up_write(&uprobe->consumer_rwsem); -+ return ret; -+} -+ -+static int __copy_insn(struct address_space *mapping, -+ struct vm_area_struct *vma, char *insn, -+ unsigned long nbytes, unsigned long offset) -+{ -+ struct file *filp = vma->vm_file; -+ struct page *page; -+ void *vaddr; -+ unsigned long off1; -+ unsigned long idx; -+ -+ if (!filp) -+ return -EINVAL; -+ -+ idx = (unsigned long)(offset >> PAGE_CACHE_SHIFT); -+ off1 = offset &= ~PAGE_MASK; -+ -+ /* -+ * Ensure that the page that has the original instruction is -+ * populated and in page-cache. -+ */ -+ page = read_mapping_page(mapping, idx, filp); -+ if (IS_ERR(page)) -+ return PTR_ERR(page); -+ -+ vaddr = kmap_atomic(page); -+ memcpy(insn, vaddr + off1, nbytes); -+ kunmap_atomic(vaddr); -+ page_cache_release(page); -+ return 0; -+} -+ -+static int copy_insn(struct uprobe *uprobe, struct vm_area_struct *vma, -+ unsigned long addr) -+{ -+ struct address_space *mapping; -+ int bytes; -+ unsigned long nbytes; -+ -+ addr &= ~PAGE_MASK; -+ nbytes = PAGE_SIZE - addr; -+ mapping = uprobe->inode->i_mapping; -+ -+ /* Instruction at end of binary; copy only available bytes */ -+ if (uprobe->offset + MAX_UINSN_BYTES > uprobe->inode->i_size) -+ bytes = uprobe->inode->i_size - uprobe->offset; -+ else -+ bytes = MAX_UINSN_BYTES; -+ -+ /* Instruction at the page-boundary; copy bytes in second page */ -+ if (nbytes < bytes) { -+ if (__copy_insn(mapping, vma, uprobe->insn + nbytes, -+ bytes - nbytes, uprobe->offset + nbytes)) -+ return -ENOMEM; -+ -+ bytes = nbytes; -+ } -+ return __copy_insn(mapping, vma, uprobe->insn, bytes, uprobe->offset); -+} -+ -+static int install_breakpoint(struct mm_struct *mm, struct uprobe *uprobe, -+ struct vm_area_struct *vma, loff_t vaddr) -+{ -+ unsigned long addr; -+ int ret; -+ -+ /* -+ * If probe is being deleted, unregister thread could be done with -+ * the vma-rmap-walk through. Adding a probe now can be fatal since -+ * nobody will be able to cleanup. Also we could be from fork or -+ * mremap path, where the probe might have already been inserted. -+ * Hence behave as if probe already existed. -+ */ -+ if (!uprobe->consumers) -+ return -EEXIST; -+ -+ addr = (unsigned long)vaddr; -+ if (!(uprobe->flags & UPROBES_COPY_INSN)) { -+ ret = copy_insn(uprobe, vma, addr); -+ if (ret) -+ return ret; -+ -+ if (is_bkpt_insn((uprobe_opcode_t *)uprobe->insn)) -+ return -EEXIST; -+ -+ ret = analyze_insn(mm, uprobe); -+ if (ret) -+ return ret; -+ -+ uprobe->flags |= UPROBES_COPY_INSN; -+ } -+ ret = set_bkpt(mm, uprobe, addr); -+ -+ return ret; -+} -+ -+static void remove_breakpoint(struct mm_struct *mm, struct uprobe *uprobe, -+ loff_t vaddr) -+{ -+ set_orig_insn(mm, uprobe, (unsigned long)vaddr, true); -+} -+ -+static void delete_uprobe(struct uprobe *uprobe) -+{ -+ unsigned long flags; -+ -+ spin_lock_irqsave(&uprobes_treelock, flags); -+ rb_erase(&uprobe->rb_node, &uprobes_tree); -+ spin_unlock_irqrestore(&uprobes_treelock, flags); -+ iput(uprobe->inode); -+ put_uprobe(uprobe); -+ atomic_dec(&uprobe_events); -+} -+ -+static struct vma_info *__find_next_vma_info(struct list_head *head, -+ loff_t offset, struct address_space *mapping, -+ struct vma_info *vi, bool is_register) -+{ -+ struct prio_tree_iter iter; -+ struct vm_area_struct *vma; -+ struct vma_info *tmpvi; -+ loff_t vaddr; -+ unsigned long pgoff = offset >> PAGE_SHIFT; -+ int existing_vma; -+ -+ vma_prio_tree_foreach(vma, &iter, &mapping->i_mmap, pgoff, pgoff) { -+ if (!valid_vma(vma, is_register)) -+ continue; -+ -+ existing_vma = 0; -+ vaddr = vma_address(vma, offset); -+ list_for_each_entry(tmpvi, head, probe_list) { -+ if (tmpvi->mm == vma->vm_mm && tmpvi->vaddr == vaddr) { -+ existing_vma = 1; -+ break; -+ } -+ } -+ -+ /* -+ * Another vma needs a probe to be installed. However skip -+ * installing the probe if the vma is about to be unlinked. -+ */ -+ if (!existing_vma && -+ atomic_inc_not_zero(&vma->vm_mm->mm_users)) { -+ vi->mm = vma->vm_mm; -+ vi->vaddr = vaddr; -+ list_add(&vi->probe_list, head); -+ return vi; -+ } -+ } -+ return NULL; -+} -+ -+/* -+ * Iterate in the rmap prio tree and find a vma where a probe has not -+ * yet been inserted. -+ */ -+static struct vma_info *find_next_vma_info(struct list_head *head, -+ loff_t offset, struct address_space *mapping, -+ bool is_register) -+{ -+ struct vma_info *vi, *retvi; -+ vi = kzalloc(sizeof(struct vma_info), GFP_KERNEL); -+ if (!vi) -+ return ERR_PTR(-ENOMEM); -+ -+ mutex_lock(&mapping->i_mmap_mutex); -+ retvi = __find_next_vma_info(head, offset, mapping, vi, is_register); -+ mutex_unlock(&mapping->i_mmap_mutex); -+ -+ if (!retvi) -+ kfree(vi); -+ return retvi; -+} -+ -+static int register_for_each_vma(struct uprobe *uprobe, bool is_register) -+{ -+ struct list_head try_list; -+ struct vm_area_struct *vma; -+ struct address_space *mapping; -+ struct vma_info *vi, *tmpvi; -+ struct mm_struct *mm; -+ loff_t vaddr; -+ int ret = 0; -+ -+ mapping = uprobe->inode->i_mapping; -+ INIT_LIST_HEAD(&try_list); -+ while ((vi = find_next_vma_info(&try_list, uprobe->offset, -+ mapping, is_register)) != NULL) { -+ if (IS_ERR(vi)) { -+ ret = PTR_ERR(vi); -+ break; -+ } -+ mm = vi->mm; -+ down_read(&mm->mmap_sem); -+ vma = find_vma(mm, (unsigned long)vi->vaddr); -+ if (!vma || !valid_vma(vma, is_register)) { -+ list_del(&vi->probe_list); -+ kfree(vi); -+ up_read(&mm->mmap_sem); -+ mmput(mm); -+ continue; -+ } -+ vaddr = vma_address(vma, uprobe->offset); -+ if (vma->vm_file->f_mapping->host != uprobe->inode || -+ vaddr != vi->vaddr) { -+ list_del(&vi->probe_list); -+ kfree(vi); -+ up_read(&mm->mmap_sem); -+ mmput(mm); -+ continue; -+ } -+ -+ if (is_register) -+ ret = install_breakpoint(mm, uprobe, vma, vi->vaddr); -+ else -+ remove_breakpoint(mm, uprobe, vi->vaddr); -+ -+ up_read(&mm->mmap_sem); -+ mmput(mm); -+ if (is_register) { -+ if (ret && ret == -EEXIST) -+ ret = 0; -+ if (ret) -+ break; -+ } -+ } -+ list_for_each_entry_safe(vi, tmpvi, &try_list, probe_list) { -+ list_del(&vi->probe_list); -+ kfree(vi); -+ } -+ return ret; -+} -+ -+static int __register_uprobe(struct uprobe *uprobe) -+{ -+ return register_for_each_vma(uprobe, true); -+} -+ -+static void __unregister_uprobe(struct uprobe *uprobe) -+{ -+ if (!register_for_each_vma(uprobe, false)) -+ delete_uprobe(uprobe); -+ -+ /* TODO : cant unregister? schedule a worker thread */ -+} -+ -+/* -+ * register_uprobe - register a probe -+ * @inode: the file in which the probe has to be placed. -+ * @offset: offset from the start of the file. -+ * @consumer: information on howto handle the probe.. -+ * -+ * Apart from the access refcount, register_uprobe() takes a creation -+ * refcount (thro alloc_uprobe) if and only if this @uprobe is getting -+ * inserted into the rbtree (i.e first consumer for a @inode:@offset -+ * tuple). Creation refcount stops unregister_uprobe from freeing the -+ * @uprobe even before the register operation is complete. Creation -+ * refcount is released when the last @consumer for the @uprobe -+ * unregisters. -+ * -+ * Return errno if it cannot successully install probes -+ * else return 0 (success) -+ */ -+int register_uprobe(struct inode *inode, loff_t offset, -+ struct uprobe_consumer *consumer) -+{ -+ struct uprobe *uprobe; -+ int ret = -EINVAL; -+ -+ if (!inode || !consumer || consumer->next) -+ return ret; -+ -+ if (offset > i_size_read(inode)) -+ return ret; -+ -+ ret = 0; -+ mutex_lock(uprobes_hash(inode)); -+ uprobe = alloc_uprobe(inode, offset); -+ if (uprobe && !add_consumer(uprobe, consumer)) { -+ ret = __register_uprobe(uprobe); -+ if (ret) { -+ uprobe->consumers = NULL; -+ __unregister_uprobe(uprobe); -+ } else -+ uprobe->flags |= UPROBES_RUN_HANDLER; -+ } -+ -+ mutex_unlock(uprobes_hash(inode)); -+ put_uprobe(uprobe); -+ -+ return ret; -+} -+ -+/* -+ * unregister_uprobe - unregister a already registered probe. -+ * @inode: the file in which the probe has to be removed. -+ * @offset: offset from the start of the file. -+ * @consumer: identify which probe if multiple probes are colocated. -+ */ -+void unregister_uprobe(struct inode *inode, loff_t offset, -+ struct uprobe_consumer *consumer) -+{ -+ struct uprobe *uprobe = NULL; -+ -+ if (!inode || !consumer) -+ return; -+ -+ uprobe = find_uprobe(inode, offset); -+ if (!uprobe) -+ return; -+ -+ mutex_lock(uprobes_hash(inode)); -+ if (!del_consumer(uprobe, consumer)) -+ goto unreg_out; -+ -+ if (!uprobe->consumers) { -+ __unregister_uprobe(uprobe); -+ uprobe->flags &= ~UPROBES_RUN_HANDLER; -+ } -+ -+unreg_out: -+ mutex_unlock(uprobes_hash(inode)); -+ if (uprobe) -+ put_uprobe(uprobe); -+} -+ -+/* -+ * Of all the nodes that correspond to the given inode, return the node -+ * with the least offset. -+ */ -+static struct rb_node *find_least_offset_node(struct inode *inode) -+{ -+ struct uprobe u = { .inode = inode, .offset = 0}; -+ struct rb_node *n = uprobes_tree.rb_node; -+ struct rb_node *close_node = NULL; -+ struct uprobe *uprobe; -+ int match; -+ -+ while (n) { -+ uprobe = rb_entry(n, struct uprobe, rb_node); -+ match = match_uprobe(&u, uprobe); -+ if (uprobe->inode == inode) -+ close_node = n; -+ -+ if (!match) -+ return close_node; -+ -+ if (match < 0) -+ n = n->rb_left; -+ else -+ n = n->rb_right; -+ } -+ return close_node; -+} -+ -+/* -+ * For a given inode, build a list of probes that need to be inserted. -+ */ -+static void build_probe_list(struct inode *inode, struct list_head *head) -+{ -+ struct uprobe *uprobe; -+ struct rb_node *n; -+ unsigned long flags; -+ -+ spin_lock_irqsave(&uprobes_treelock, flags); -+ n = find_least_offset_node(inode); -+ for (; n; n = rb_next(n)) { -+ uprobe = rb_entry(n, struct uprobe, rb_node); -+ if (uprobe->inode != inode) -+ break; -+ -+ list_add(&uprobe->pending_list, head); -+ atomic_inc(&uprobe->ref); -+ } -+ spin_unlock_irqrestore(&uprobes_treelock, flags); -+} -+ -+/* -+ * Called from mmap_region. -+ * called with mm->mmap_sem acquired. -+ * -+ * Return -ve no if we fail to insert probes and we cannot -+ * bail-out. -+ * Return 0 otherwise. i.e : -+ * - successful insertion of probes -+ * - (or) no possible probes to be inserted. -+ * - (or) insertion of probes failed but we can bail-out. -+ */ -+int mmap_uprobe(struct vm_area_struct *vma) -+{ -+ struct list_head tmp_list; -+ struct uprobe *uprobe, *u; -+ struct inode *inode; -+ int ret = 0; -+ -+ if (!atomic_read(&uprobe_events) || !valid_vma(vma, true)) -+ return ret; /* Bail-out */ -+ -+ inode = vma->vm_file->f_mapping->host; -+ if (!inode) -+ return ret; -+ -+ INIT_LIST_HEAD(&tmp_list); -+ mutex_lock(uprobes_mmap_hash(inode)); -+ build_probe_list(inode, &tmp_list); -+ list_for_each_entry_safe(uprobe, u, &tmp_list, pending_list) { -+ loff_t vaddr; -+ -+ list_del(&uprobe->pending_list); -+ if (!ret) { -+ vaddr = vma_address(vma, uprobe->offset); -+ if (vaddr < vma->vm_start || vaddr >= vma->vm_end) { -+ put_uprobe(uprobe); -+ continue; -+ } -+ ret = install_breakpoint(vma->vm_mm, uprobe, vma, -+ vaddr); -+ if (ret == -EEXIST) -+ ret = 0; -+ } -+ put_uprobe(uprobe); -+ } -+ -+ mutex_unlock(uprobes_mmap_hash(inode)); -+ -+ return ret; -+} -+ -+static int __init init_uprobes(void) -+{ -+ int i; -+ -+ for (i = 0; i < UPROBES_HASH_SZ; i++) { -+ mutex_init(&uprobes_mutex[i]); -+ mutex_init(&uprobes_mmap_mutex[i]); -+ } -+ return 0; -+} -+ -+static void __exit exit_uprobes(void) -+{ -+} -+ -+module_init(init_uprobes); -+module_exit(exit_uprobes); -diff --git a/mm/mmap.c b/mm/mmap.c -index 848ef52..f6ea842 100644 ---- a/mm/mmap.c -+++ b/mm/mmap.c -@@ -30,6 +30,7 @@ - #include <linux/perf_event.h> - #include <linux/audit.h> - #include <linux/khugepaged.h> -+#include <linux/uprobes.h> - - #include <asm/uaccess.h> - #include <asm/cacheflush.h> -@@ -617,6 +618,13 @@ again: remove_next = 1 + (end > next->vm_end); - if (mapping) - mutex_unlock(&mapping->i_mmap_mutex); - -+ if (root) { -+ mmap_uprobe(vma); -+ -+ if (adjust_next) -+ mmap_uprobe(next); -+ } -+ - if (remove_next) { - if (file) { - fput(file); -@@ -638,6 +646,8 @@ again: remove_next = 1 + (end > next->vm_end); - goto again; - } - } -+ if (insert && file) -+ mmap_uprobe(insert); - - validate_mm(mm); - -@@ -1371,6 +1381,11 @@ out: - mm->locked_vm += (len >> PAGE_SHIFT); - } else if ((flags & MAP_POPULATE) && !(flags & MAP_NONBLOCK)) - make_pages_present(addr, addr + len); -+ -+ if (file && mmap_uprobe(vma)) -+ /* matching probes but cannot insert */ -+ goto unmap_and_free_vma; -+ - return addr; - - unmap_and_free_vma: -@@ -2352,6 +2367,10 @@ int insert_vm_struct(struct mm_struct * mm, struct vm_area_struct * vma) - if ((vma->vm_flags & VM_ACCOUNT) && - security_vm_enough_memory_mm(mm, vma_pages(vma))) - return -ENOMEM; -+ -+ if (vma->vm_file && mmap_uprobe(vma)) -+ return -EINVAL; -+ - vma_link(mm, vma, prev, rb_link, rb_parent); - return 0; - } -@@ -2421,6 +2440,10 @@ struct vm_area_struct *copy_vma(struct vm_area_struct **vmap, - new_vma->vm_pgoff = pgoff; - if (new_vma->vm_file) { - get_file(new_vma->vm_file); -+ -+ if (mmap_uprobe(new_vma)) -+ goto out_free_mempol; -+ - if (vma->vm_flags & VM_EXECUTABLE) - added_exe_file_vma(mm); - } --- -1.7.5.4 - diff --git a/features/vfat/FAT-Added-FAT_NO_83NAME.patch b/features/vfat/FAT-Added-FAT_NO_83NAME.patch index 34cce4895d40f2d707361a85d5de3794b05d19d5..b24b912d379cf17c9bf6e5f50b41bf57f05c24d6 100644 --- a/features/vfat/FAT-Added-FAT_NO_83NAME.patch +++ b/features/vfat/FAT-Added-FAT_NO_83NAME.patch @@ -10,30 +10,28 @@ inaccessible. For VFAT it makes the file only accessible by the long filename. Signed-off-by: Andrew Tridgell <tridge@samba.org> ---- - fs/fat/dir.c | 14 ++++++++++++++ - include/linux/msdos_fs.h | 1 + - 2 files changed, 15 insertions(+), 0 deletions(-) - diff --git a/fs/fat/dir.c b/fs/fat/dir.c -index 530b4ca..2d0ef72 100644 +index dc49ed2..43ffba1 100644 --- a/fs/fat/dir.c +++ b/fs/fat/dir.c -@@ -384,6 +384,13 @@ parse_record: - goto end_of_dir; - } +@@ -368,7 +368,15 @@ static int fat_parse_short(struct super_block *sb, + dotoffset = 1; + } -+ /* -+ * The FAT_NO_83NAME flag is used to mark files -+ * created with no 8.3 short name -+ */ -+ if (de->lcase & FAT_NO_83NAME) -+ goto compare_longname; +- memcpy(work, de->name, sizeof(work)); ++ /* ++ * The FAT_NO_83NAME flag is used to mark files ++ * created with no 8.3 short name ++ */ ++ if (de->lcase & FAT_NO_83NAME) ++ goto compare_longname; + - memcpy(work, de->name, sizeof(de->name)); - /* see namei.c, msdos_format_name */ - if (work[0] == 0x05) -@@ -428,6 +435,7 @@ parse_record: ++ memcpy(work, de->name, sizeof(de->name)); ++ + /* see namei.c, msdos_format_name */ + if (work[0] == 0x05) + work[0] = 0xE5; +@@ -512,6 +520,7 @@ parse_record: if (fat_name_match(sbi, name, name_len, bufname, len)) goto found; @@ -41,7 +39,7 @@ index 530b4ca..2d0ef72 100644 if (nr_slots) { void *longname = unicode + FAT_MAX_UNI_CHARS; int size = PATH_MAX - FAT_MAX_UNI_SIZE; -@@ -529,6 +537,8 @@ parse_record: +@@ -608,6 +617,8 @@ parse_record: if (de->attr != ATTR_EXT && IS_FREE(de->name)) goto record_end; } else { @@ -50,7 +48,7 @@ index 530b4ca..2d0ef72 100644 if ((de->attr & ATTR_VOLUME) || IS_FREE(de->name)) goto record_end; } -@@ -934,6 +944,10 @@ int fat_scan(struct inode *dir, const unsigned char *name, +@@ -950,6 +961,10 @@ int fat_scan(struct inode *dir, const unsigned char *name, sinfo->bh = NULL; while (fat_get_short_entry(dir, &sinfo->slot_off, &sinfo->bh, &sinfo->de) >= 0) { @@ -62,10 +60,10 @@ index 530b4ca..2d0ef72 100644 sinfo->slot_off -= sizeof(*sinfo->de); sinfo->nr_slots = 1; diff --git a/include/linux/msdos_fs.h b/include/linux/msdos_fs.h -index 34066e6..12ba0ba 100644 +index 11cc2ac..0e3c229 100644 --- a/include/linux/msdos_fs.h +++ b/include/linux/msdos_fs.h -@@ -44,6 +44,7 @@ +@@ -45,6 +45,7 @@ #define CASE_LOWER_BASE 8 /* base is lower case */ #define CASE_LOWER_EXT 16 /* extension is lower case */ @@ -73,6 +71,3 @@ index 34066e6..12ba0ba 100644 #define DELETED_FLAG 0xe5 /* marks file as deleted when in name[0] */ #define IS_FREE(n) (!*(n) || *(n) == DELETED_FLAG) --- -1.6.5.2 - diff --git a/patches/boot/NFS-allow-nfs-root-mount-to-use-alternate-rpc-ports.patch b/patches/boot/NFS-allow-nfs-root-mount-to-use-alternate-rpc-ports.patch index dcf9f3e33ca6c79697cbf9f16c2f882fc6394c3c..abad650d4a150f58c16e7f96b12bce5570779b83 100644 --- a/patches/boot/NFS-allow-nfs-root-mount-to-use-alternate-rpc-ports.patch +++ b/patches/boot/NFS-allow-nfs-root-mount-to-use-alternate-rpc-ports.patch @@ -8,21 +8,27 @@ Allow an nfs root mount to use alternate RPC ports for mountd and nfsd. Signed-off-by: Jason Wessel <jason.wessel@windriver.com> [forward port to 2.6.33+] Signed-off-by: Bruce Ashfield <bruce.ashfield@windriver.com> ---- - fs/nfs/client.c | 12 +++++++++++- - fs/nfs/internal.h | 6 ++++-- - fs/nfs/mount_clnt.c | 7 ++++--- - fs/nfs/super.c | 33 ++++++++++++++++++++++++++++++++- - include/linux/nfs_fs_sb.h | 3 +++ - include/linux/nfs_mount.h | 4 +++- - 6 files changed, 57 insertions(+), 8 deletions(-) - diff --git a/fs/nfs/client.c b/fs/nfs/client.c -index 4a108a0..745d2f2 100644 +index 9969444..0742c9e 100644 --- a/fs/nfs/client.c +++ b/fs/nfs/client.c -@@ -100,7 +100,7 @@ static const struct rpc_version *nfs_version[5] = { - #endif +@@ -7,7 +7,14 @@ + * 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. ++<<<<<<< + */ ++||||||| ++}; ++======= ++ int nfs_prog; ++}; ++>>>>>>> + + + #include <linux/module.h> +@@ -70,7 +77,7 @@ static const struct rpc_version *nfs_version[5] = { + [4] = NULL, }; -const struct rpc_program nfs_program = { @@ -30,23 +36,15 @@ index 4a108a0..745d2f2 100644 .name = "nfs", .number = NFS_PROGRAM, .nrvers = ARRAY_SIZE(nfs_version), -@@ -137,6 +137,7 @@ struct nfs_client_initdata { - int proto; - u32 minorversion; - struct net *net; -+ int nfs_prog; - }; - - /* -@@ -155,6 +156,7 @@ static struct nfs_client *nfs_alloc_client(const struct nfs_client_initdata *cl_ - goto error_0; +@@ -161,6 +168,7 @@ struct nfs_client *nfs_alloc_client(const struct nfs_client_initdata *cl_init) + try_module_get(clp->cl_nfs_mod->owner); - clp->rpc_ops = cl_init->rpc_ops; + clp->rpc_ops = clp->cl_nfs_mod->rpc_ops; + clp->nfs_prog = cl_init->nfs_prog; atomic_set(&clp->cl_count, 1); clp->cl_cons_state = NFS_CS_INITING; -@@ -495,6 +497,9 @@ static struct nfs_client *nfs_match_client(const struct nfs_client_initdata *dat +@@ -419,6 +427,9 @@ static struct nfs_client *nfs_match_client(const struct nfs_client_initdata *dat /* Match nfsv4 minorversion */ if (clp->cl_minorversion != data->minorversion) continue; @@ -56,7 +54,7 @@ index 4a108a0..745d2f2 100644 /* Match the full socket address */ if (!nfs_sockaddr_cmp(sap, clap)) continue; -@@ -679,6 +684,10 @@ static int nfs_create_rpc_client(struct nfs_client *clp, +@@ -597,6 +608,10 @@ int nfs_create_rpc_client(struct nfs_client *clp, if (!IS_ERR(clp->cl_rpcclient)) return 0; @@ -67,8 +65,8 @@ index 4a108a0..745d2f2 100644 clnt = rpc_create(&args); if (IS_ERR(clnt)) { dprintk("%s: cannot create RPC client. Error = %ld\n", -@@ -851,6 +860,7 @@ static int nfs_init_server(struct nfs_server *server, - .rpc_ops = &nfs_v2_clientops, +@@ -750,6 +765,7 @@ static int nfs_init_server(struct nfs_server *server, + .nfs_mod = nfs_mod, .proto = data->nfs_server.protocol, .net = data->net, + .nfs_prog = data->nfs_prog, @@ -76,10 +74,18 @@ index 4a108a0..745d2f2 100644 struct rpc_timeout timeparms; struct nfs_client *clp; diff --git a/fs/nfs/internal.h b/fs/nfs/internal.h -index 2476dc6..dd36bc8 100644 +index 31fdb03..1c8f2b5 100644 --- a/fs/nfs/internal.h +++ b/fs/nfs/internal.h -@@ -94,6 +94,8 @@ struct nfs_parsed_mount_data { +@@ -94,6 +94,7 @@ struct nfs_client_initdata { + int proto; + u32 minorversion; + struct net *net; ++ int nfs_prog; + }; + + /* +@@ -105,6 +106,8 @@ struct nfs_parsed_mount_data { int timeo, retrans; int acregmin, acregmax, acdirmin, acdirmax; @@ -88,8 +94,8 @@ index 2476dc6..dd36bc8 100644 int namlen; unsigned int options; unsigned int bsize; -@@ -141,11 +143,11 @@ struct nfs_mount_request { - struct net *net; +@@ -161,11 +164,11 @@ struct nfs_mount_info { + struct nfs_fh *mntfh; }; -extern int nfs_mount(struct nfs_mount_request *info); @@ -100,8 +106,8 @@ index 2476dc6..dd36bc8 100644 -extern const struct rpc_program nfs_program; +extern struct rpc_program nfs_program; extern void nfs_clients_init(struct net *net); - - extern void nfs_cleanup_cb_ident_idr(struct net *); + extern struct nfs_client *nfs_alloc_client(const struct nfs_client_initdata *); + int nfs_create_rpc_client(struct nfs_client *, const struct rpc_timeout *, rpc_authflavor_t); diff --git a/fs/nfs/mount_clnt.c b/fs/nfs/mount_clnt.c index 8e65c7f..9794450 100644 --- a/fs/nfs/mount_clnt.c @@ -142,10 +148,10 @@ index 8e65c7f..9794450 100644 .number = NFS_MNT_PROGRAM, .nrvers = ARRAY_SIZE(mnt_version), diff --git a/fs/nfs/super.c b/fs/nfs/super.c -index ccc4cdb..47305a2 100644 +index 239aff7..e063958 100644 --- a/fs/nfs/super.c +++ b/fs/nfs/super.c -@@ -99,6 +99,8 @@ enum { +@@ -100,6 +100,8 @@ enum { Opt_mountport, Opt_mountvers, Opt_minorversion, @@ -154,7 +160,7 @@ index ccc4cdb..47305a2 100644 /* Mount options that take string arguments */ Opt_nfsvers, -@@ -162,6 +164,8 @@ static const match_table_t nfs_mount_option_tokens = { +@@ -163,6 +165,8 @@ static const match_table_t nfs_mount_option_tokens = { { Opt_mountport, "mountport=%s" }, { Opt_mountvers, "mountvers=%s" }, { Opt_minorversion, "minorversion=%s" }, @@ -163,7 +169,7 @@ index ccc4cdb..47305a2 100644 { Opt_nfsvers, "nfsvers=%s" }, { Opt_nfsvers, "vers=%s" }, -@@ -949,6 +953,8 @@ static struct nfs_parsed_mount_data *nfs_alloc_parsed_mount_data(unsigned int ve +@@ -905,6 +909,8 @@ static struct nfs_parsed_mount_data *nfs_alloc_parsed_mount_data(void) data->acregmax = NFS_DEF_ACREGMAX; data->acdirmin = NFS_DEF_ACDIRMIN; data->acdirmax = NFS_DEF_ACDIRMAX; @@ -172,7 +178,7 @@ index ccc4cdb..47305a2 100644 data->mount_server.port = NFS_UNSPEC_PORT; data->nfs_server.port = NFS_UNSPEC_PORT; data->nfs_server.protocol = XPRT_TRANSPORT_TCP; -@@ -1342,6 +1348,26 @@ static int nfs_parse_mount_options(char *raw, +@@ -1298,6 +1304,26 @@ static int nfs_parse_mount_options(char *raw, goto out_invalid_value; mnt->acdirmax = option; break; @@ -199,7 +205,7 @@ index ccc4cdb..47305a2 100644 case Opt_actimeo: if (nfs_get_option_ul(args, &option)) goto out_invalid_value; -@@ -1724,7 +1750,7 @@ static int nfs_try_mount(struct nfs_parsed_mount_data *args, +@@ -1680,7 +1706,7 @@ static int nfs_request_mount(struct nfs_parsed_mount_data *args, * Now ask the mount server to map our export path * to a file handle. */ @@ -208,7 +214,7 @@ index ccc4cdb..47305a2 100644 if (status != 0) { dfprintk(MOUNT, "NFS: unable to mount server %s, error %d\n", request.hostname, status); -@@ -1834,6 +1860,7 @@ static int nfs_validate_mount_data(void *options, +@@ -1812,6 +1838,7 @@ static int nfs23_validate_mount_data(void *options, { struct nfs_mount_data *data = (struct nfs_mount_data *)options; struct sockaddr *sap = (struct sockaddr *)&args->nfs_server.address; @@ -216,7 +222,7 @@ index ccc4cdb..47305a2 100644 if (data == NULL) goto out_no_data; -@@ -1853,6 +1880,8 @@ static int nfs_validate_mount_data(void *options, +@@ -1832,6 +1859,8 @@ static int nfs23_validate_mount_data(void *options, goto out_no_sec; case 5: memset(data->context, 0, sizeof(data->context)); @@ -225,9 +231,9 @@ index ccc4cdb..47305a2 100644 case 6: if (data->flags & NFS_MOUNT_VER3) { if (data->root.size > NFS3_FHSIZE || data->root.size == 0) -@@ -2588,6 +2617,8 @@ static int nfs4_validate_mount_data(void *options, - if (data == NULL) - goto out_no_data; +@@ -2553,6 +2582,8 @@ static int nfs4_validate_mount_data(void *options, + + args->version = 4; + args->nfs_prog = NFS_PROGRAM; + @@ -235,21 +241,21 @@ index ccc4cdb..47305a2 100644 case 1: if (data->host_addrlen > sizeof(args->nfs_server.address)) diff --git a/include/linux/nfs_fs_sb.h b/include/linux/nfs_fs_sb.h -index 7073fc7..1b056df 100644 +index 310c63c..ac826d0 100644 --- a/include/linux/nfs_fs_sb.h +++ b/include/linux/nfs_fs_sb.h -@@ -47,6 +47,7 @@ struct nfs_client { +@@ -52,6 +52,7 @@ struct nfs_client { u32 cl_minorversion;/* NFSv4 minorversion */ struct rpc_cred *cl_machine_cred; + int nfs_prog; - #ifdef CONFIG_NFS_V4 + #if IS_ENABLED(CONFIG_NFS_V4) u64 cl_clientid; /* constant */ -@@ -72,7 +73,9 @@ struct nfs_client { +@@ -73,7 +74,9 @@ struct nfs_client { + * This is used to generate the mv0 callback address. */ char cl_ipaddr[48]; - unsigned char cl_id_uniquifier; + u32 cl_cb_ident; /* v4.0 callback identifier */ + @@ -278,6 +284,3 @@ index 576bddd..9541d71 100644 }; /* bits in the flags field visible to user space */ --- -1.7.5.4 - diff --git a/staging/emgd-1.14.scc b/staging/emgd-1.14.scc index ef80aa3ecb8890b82fbcc03ab06a1af228204023..f2dd169707e8a40cd5c8d361f20acd4bfe20645e 100644 --- a/staging/emgd-1.14.scc +++ b/staging/emgd-1.14.scc @@ -1,4 +1,4 @@ git branch emgd-1.14 master -patch yocto-emgd-emgd-1.14-driver.patch -patch emgd-pvr-get-it-building-with-v3.4-kernel.patch +#patch yocto-emgd-emgd-1.14-driver.patch +#patch emgd-pvr-get-it-building-with-v3.4-kernel.patch