]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/commitdiff
3.3-stable patches
authorGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Sun, 27 May 2012 00:20:42 +0000 (09:20 +0900)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Sun, 27 May 2012 00:20:42 +0000 (09:20 +0900)
added patches:
arm-7365-1-drop-unused-parameter-from-flush_cache_user_range.patch
arm-7409-1-do-not-call-flush_cache_user_range-with-mmap_sem-held.patch
i2c-davinci-free-requested-irq-in-remove.patch
i2c-tegra-notify-transfer-complete-after-clearing-status.patch
intel-iommu-add-device-info-into-list-before-doing-context-mapping.patch
iommu-fix-off-by-one-in-dmar_get_fault_reason.patch
mce-fix-vm86-handling-for-32bit-mce-handler.patch
mmc-cd-gpio-protect-against-null-context-in-mmc_cd_gpio_free.patch
mmc-omap_hsmmc-pass-irqf_oneshot-to-request_threaded_irq.patch
mmc-sdio-avoid-spurious-calls-to-interrupt-handlers.patch
rtlwifi-fix-for-race-condition-when-firmware-is-cached.patch
tile-fix-bug-where-fls-0-was-not-returning-0.patch
x86-32-relocs-whitelist-more-symbols-for-ld-bug-workaround.patch
x86-mce-fix-check-for-processor-context-when-machine-check-was-taken.patch
x86-realmode-16-bit-real-mode-code-support-for-relocs-tool.patch
x86-relocs-add-jiffies-and-jiffies_64-to-the-relative-whitelist.patch
x86-relocs-build-clean-fix.patch
x86-relocs-when-printing-an-error-say-relative-or-absolute.patch
x86-relocs-workaround-for-binutils-2.22.52.0.1-section-bug.patch

20 files changed:
queue-3.3/arm-7365-1-drop-unused-parameter-from-flush_cache_user_range.patch [new file with mode: 0644]
queue-3.3/arm-7409-1-do-not-call-flush_cache_user_range-with-mmap_sem-held.patch [new file with mode: 0644]
queue-3.3/i2c-davinci-free-requested-irq-in-remove.patch [new file with mode: 0644]
queue-3.3/i2c-tegra-notify-transfer-complete-after-clearing-status.patch [new file with mode: 0644]
queue-3.3/intel-iommu-add-device-info-into-list-before-doing-context-mapping.patch [new file with mode: 0644]
queue-3.3/iommu-fix-off-by-one-in-dmar_get_fault_reason.patch [new file with mode: 0644]
queue-3.3/mce-fix-vm86-handling-for-32bit-mce-handler.patch [new file with mode: 0644]
queue-3.3/mmc-cd-gpio-protect-against-null-context-in-mmc_cd_gpio_free.patch [new file with mode: 0644]
queue-3.3/mmc-omap_hsmmc-pass-irqf_oneshot-to-request_threaded_irq.patch [new file with mode: 0644]
queue-3.3/mmc-sdio-avoid-spurious-calls-to-interrupt-handlers.patch [new file with mode: 0644]
queue-3.3/rtlwifi-fix-for-race-condition-when-firmware-is-cached.patch [new file with mode: 0644]
queue-3.3/series
queue-3.3/tile-fix-bug-where-fls-0-was-not-returning-0.patch [new file with mode: 0644]
queue-3.3/x86-32-relocs-whitelist-more-symbols-for-ld-bug-workaround.patch [new file with mode: 0644]
queue-3.3/x86-mce-fix-check-for-processor-context-when-machine-check-was-taken.patch [new file with mode: 0644]
queue-3.3/x86-realmode-16-bit-real-mode-code-support-for-relocs-tool.patch [new file with mode: 0644]
queue-3.3/x86-relocs-add-jiffies-and-jiffies_64-to-the-relative-whitelist.patch [new file with mode: 0644]
queue-3.3/x86-relocs-build-clean-fix.patch [new file with mode: 0644]
queue-3.3/x86-relocs-when-printing-an-error-say-relative-or-absolute.patch [new file with mode: 0644]
queue-3.3/x86-relocs-workaround-for-binutils-2.22.52.0.1-section-bug.patch [new file with mode: 0644]

diff --git a/queue-3.3/arm-7365-1-drop-unused-parameter-from-flush_cache_user_range.patch b/queue-3.3/arm-7365-1-drop-unused-parameter-from-flush_cache_user_range.patch
new file mode 100644 (file)
index 0000000..c5708fd
--- /dev/null
@@ -0,0 +1,56 @@
+From 4542b6a0fa6b48d9ae6b41c1efeb618b7a221b2a Mon Sep 17 00:00:00 2001
+From: Dima Zavin <dima@android.com>
+Date: Thu, 29 Mar 2012 20:44:06 +0100
+Subject: ARM: 7365/1: drop unused parameter from flush_cache_user_range
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: Dima Zavin <dima@android.com>
+
+commit 4542b6a0fa6b48d9ae6b41c1efeb618b7a221b2a upstream.
+
+vma isn't used and flush_cache_user_range isn't a standard macro that
+is used on several archs with the same prototype. In fact only unicore32
+has a macro with the same name (with an identical implementation and no
+in-tree users).
+
+This is a part of a patch proposed by Dima Zavin (with Message-id:
+1272439931-12795-1-git-send-email-dima@android.com) that didn't get
+accepted.
+
+Cc: Dima Zavin <dima@android.com>
+Acked-by: Catalin Marinas <catalin.marinas@arm.com>
+Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
+Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
+Cc: Will Deacon <will.deacon@arm.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+
+---
+ arch/arm/include/asm/cacheflush.h |    2 +-
+ arch/arm/kernel/traps.c           |    2 +-
+ 2 files changed, 2 insertions(+), 2 deletions(-)
+
+--- a/arch/arm/include/asm/cacheflush.h
++++ b/arch/arm/include/asm/cacheflush.h
+@@ -249,7 +249,7 @@ extern void flush_cache_page(struct vm_a
+  * Harvard caches are synchronised for the user space address range.
+  * This is used for the ARM private sys_cacheflush system call.
+  */
+-#define flush_cache_user_range(vma,start,end) \
++#define flush_cache_user_range(start,end) \
+       __cpuc_coherent_user_range((start) & PAGE_MASK, PAGE_ALIGN(end))
+ /*
+--- a/arch/arm/kernel/traps.c
++++ b/arch/arm/kernel/traps.c
+@@ -491,7 +491,7 @@ do_cache_op(unsigned long start, unsigne
+               if (end > vma->vm_end)
+                       end = vma->vm_end;
+-              flush_cache_user_range(vma, start, end);
++              flush_cache_user_range(start, end);
+       }
+       up_read(&mm->mmap_sem);
+ }
diff --git a/queue-3.3/arm-7409-1-do-not-call-flush_cache_user_range-with-mmap_sem-held.patch b/queue-3.3/arm-7409-1-do-not-call-flush_cache_user_range-with-mmap_sem-held.patch
new file mode 100644 (file)
index 0000000..03bb864
--- /dev/null
@@ -0,0 +1,42 @@
+From 435a7ef52db7d86e67a009b36cac1457f8972391 Mon Sep 17 00:00:00 2001
+From: Dima Zavin <dima@android.com>
+Date: Mon, 30 Apr 2012 10:26:14 +0100
+Subject: ARM: 7409/1: Do not call flush_cache_user_range with mmap_sem held
+
+From: Dima Zavin <dima@android.com>
+
+commit 435a7ef52db7d86e67a009b36cac1457f8972391 upstream.
+
+We can't be holding the mmap_sem while calling flush_cache_user_range
+because the flush can fault. If we fault on a user address, the
+page fault handler will try to take mmap_sem again. Since both places
+acquire the read lock, most of the time it succeeds. However, if another
+thread tries to acquire the write lock on the mmap_sem (e.g. mmap) in
+between the call to flush_cache_user_range and the fault, the down_read
+in do_page_fault will deadlock.
+
+[will: removed drop of vma parameter as already queued by rmk (7365/1)]
+
+Acked-by: Catalin Marinas <catalin.marinas@arm.com>
+Signed-off-by: Dima Zavin <dima@android.com>
+Signed-off-by: John Stultz <john.stultz@linaro.org>
+Signed-off-by: Will Deacon <will.deacon@arm.com>
+Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ arch/arm/kernel/traps.c |    2 ++
+ 1 file changed, 2 insertions(+)
+
+--- a/arch/arm/kernel/traps.c
++++ b/arch/arm/kernel/traps.c
+@@ -491,7 +491,9 @@ do_cache_op(unsigned long start, unsigne
+               if (end > vma->vm_end)
+                       end = vma->vm_end;
++              up_read(&mm->mmap_sem);
+               flush_cache_user_range(start, end);
++              return;
+       }
+       up_read(&mm->mmap_sem);
+ }
diff --git a/queue-3.3/i2c-davinci-free-requested-irq-in-remove.patch b/queue-3.3/i2c-davinci-free-requested-irq-in-remove.patch
new file mode 100644 (file)
index 0000000..974db2f
--- /dev/null
@@ -0,0 +1,31 @@
+From 9868a060ccf769c08ec378a9829137e272e9a92c Mon Sep 17 00:00:00 2001
+From: Marcus Folkesson <marcus.folkesson@gmail.com>
+Date: Thu, 3 May 2012 15:56:36 +0200
+Subject: i2c: davinci: Free requested IRQ in remove
+
+From: Marcus Folkesson <marcus.folkesson@gmail.com>
+
+commit 9868a060ccf769c08ec378a9829137e272e9a92c upstream.
+
+The freed IRQ is not necessary the one requested in probe.
+Even if it was, with two or more i2c-controllers it will fails anyway.
+
+Signed-off-by: Marcus Folkesson <marcus.folkesson@gmail.com>
+Signed-off-by: Wolfram Sang <w.sang@pengutronix.de>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ drivers/i2c/busses/i2c-davinci.c |    2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/drivers/i2c/busses/i2c-davinci.c
++++ b/drivers/i2c/busses/i2c-davinci.c
+@@ -755,7 +755,7 @@ static int davinci_i2c_remove(struct pla
+       dev->clk = NULL;
+       davinci_i2c_write_reg(dev, DAVINCI_I2C_MDR_REG, 0);
+-      free_irq(IRQ_I2C, dev);
++      free_irq(dev->irq, dev);
+       iounmap(dev->base);
+       kfree(dev);
diff --git a/queue-3.3/i2c-tegra-notify-transfer-complete-after-clearing-status.patch b/queue-3.3/i2c-tegra-notify-transfer-complete-after-clearing-status.patch
new file mode 100644 (file)
index 0000000..c4f2014
--- /dev/null
@@ -0,0 +1,70 @@
+From c889e91d2cc22123f20f40dde0c0a91856a20eea Mon Sep 17 00:00:00 2001
+From: Laxman Dewangan <ldewangan@nvidia.com>
+Date: Mon, 7 May 2012 12:16:19 +0530
+Subject: i2c: tegra: notify transfer-complete after clearing status.
+
+From: Laxman Dewangan <ldewangan@nvidia.com>
+
+commit c889e91d2cc22123f20f40dde0c0a91856a20eea upstream.
+
+The notification of the transfer complete by calling complete()
+should be done after clearing all interrupt status.
+This avoids the race condition of misconfigure the i2c controller
+in multi-core environment.
+
+Signed-off-by: Laxman Dewangan <ldewangan@nvidia.com>
+Acked-by: Stephen Warren <swarren@wwwdotorg.org>
+Signed-off-by: Wolfram Sang <w.sang@pengutronix.de>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ drivers/i2c/busses/i2c-tegra.c |   13 ++++++-------
+ 1 file changed, 6 insertions(+), 7 deletions(-)
+
+--- a/drivers/i2c/busses/i2c-tegra.c
++++ b/drivers/i2c/busses/i2c-tegra.c
+@@ -401,8 +401,6 @@ static irqreturn_t tegra_i2c_isr(int irq
+                       disable_irq_nosync(i2c_dev->irq);
+                       i2c_dev->irq_disabled = 1;
+               }
+-
+-              complete(&i2c_dev->msg_complete);
+               goto err;
+       }
+@@ -411,7 +409,6 @@ static irqreturn_t tegra_i2c_isr(int irq
+                       i2c_dev->msg_err |= I2C_ERR_NO_ACK;
+               if (status & I2C_INT_ARBITRATION_LOST)
+                       i2c_dev->msg_err |= I2C_ERR_ARBITRATION_LOST;
+-              complete(&i2c_dev->msg_complete);
+               goto err;
+       }
+@@ -429,14 +426,14 @@ static irqreturn_t tegra_i2c_isr(int irq
+                       tegra_i2c_mask_irq(i2c_dev, I2C_INT_TX_FIFO_DATA_REQ);
+       }
++      i2c_writel(i2c_dev, status, I2C_INT_STATUS);
++      if (i2c_dev->is_dvc)
++              dvc_writel(i2c_dev, DVC_STATUS_I2C_DONE_INTR, DVC_STATUS);
++
+       if (status & I2C_INT_PACKET_XFER_COMPLETE) {
+               BUG_ON(i2c_dev->msg_buf_remaining);
+               complete(&i2c_dev->msg_complete);
+       }
+-
+-      i2c_writel(i2c_dev, status, I2C_INT_STATUS);
+-      if (i2c_dev->is_dvc)
+-              dvc_writel(i2c_dev, DVC_STATUS_I2C_DONE_INTR, DVC_STATUS);
+       return IRQ_HANDLED;
+ err:
+       /* An error occurred, mask all interrupts */
+@@ -446,6 +443,8 @@ err:
+       i2c_writel(i2c_dev, status, I2C_INT_STATUS);
+       if (i2c_dev->is_dvc)
+               dvc_writel(i2c_dev, DVC_STATUS_I2C_DONE_INTR, DVC_STATUS);
++
++      complete(&i2c_dev->msg_complete);
+       return IRQ_HANDLED;
+ }
diff --git a/queue-3.3/intel-iommu-add-device-info-into-list-before-doing-context-mapping.patch b/queue-3.3/intel-iommu-add-device-info-into-list-before-doing-context-mapping.patch
new file mode 100644 (file)
index 0000000..4f683da
--- /dev/null
@@ -0,0 +1,60 @@
+From e2ad23d04c1304431ab5176c89b7b476ded2d995 Mon Sep 17 00:00:00 2001
+From: David Woodhouse <dwmw2@infradead.org>
+Date: Fri, 25 May 2012 17:42:54 +0100
+Subject: intel-iommu: Add device info into list before doing context mapping
+
+From: David Woodhouse <dwmw2@infradead.org>
+
+commit e2ad23d04c1304431ab5176c89b7b476ded2d995 upstream.
+
+Add device info into list before doing context mapping, because device
+info will be used by iommu_enable_dev_iotlb(). Without it, ATS won't get
+enabled as it should be.
+
+ATS, while a dubious decision from a security point of view, can be very
+important for performance.
+
+Signed-off-by: Xudong Hao <xudong.hao@intel.com>
+Signed-off-by: Xiantao Zhang <xiantao.zhang@intel.com>
+Acked-by: Chris Wright <chrisw@sous-sol.org>
+Signed-off-by: David Woodhouse <David.Woodhouse@intel.com>
+Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ drivers/iommu/intel-iommu.c |   17 +++++++++++------
+ 1 file changed, 11 insertions(+), 6 deletions(-)
+
+--- a/drivers/iommu/intel-iommu.c
++++ b/drivers/iommu/intel-iommu.c
+@@ -2280,12 +2280,6 @@ static int domain_add_dev_info(struct dm
+       if (!info)
+               return -ENOMEM;
+-      ret = domain_context_mapping(domain, pdev, translation);
+-      if (ret) {
+-              free_devinfo_mem(info);
+-              return ret;
+-      }
+-
+       info->segment = pci_domain_nr(pdev->bus);
+       info->bus = pdev->bus->number;
+       info->devfn = pdev->devfn;
+@@ -2298,6 +2292,17 @@ static int domain_add_dev_info(struct dm
+       pdev->dev.archdata.iommu = info;
+       spin_unlock_irqrestore(&device_domain_lock, flags);
++      ret = domain_context_mapping(domain, pdev, translation);
++      if (ret) {
++              spin_lock_irqsave(&device_domain_lock, flags);
++              list_del(&info->link);
++              list_del(&info->global);
++              pdev->dev.archdata.iommu = NULL;
++              spin_unlock_irqrestore(&device_domain_lock, flags);
++              free_devinfo_mem(info);
++              return ret;
++      }
++
+       return 0;
+ }
diff --git a/queue-3.3/iommu-fix-off-by-one-in-dmar_get_fault_reason.patch b/queue-3.3/iommu-fix-off-by-one-in-dmar_get_fault_reason.patch
new file mode 100644 (file)
index 0000000..3c790c2
--- /dev/null
@@ -0,0 +1,38 @@
+From: Dan Carpenter <dan.carpenter@oracle.com>
+Date: Sun, 13 May 2012 20:09:38 +0300
+Subject: iommu: Fix off by one in dmar_get_fault_reason()
+
+From: Dan Carpenter <dan.carpenter@oracle.com>
+
+commit fefe1ed1398b81e3fadc92d11d91162d343c8836 upstream.
+
+fault_reason - 0x20 == ARRAY_SIZE(irq_remap_fault_reasons) is
+one past the end of the array.
+
+Signed-off-by: Dan Carpenter <dan.carpenter@oracle.com>
+Cc: Joerg Roedel <joerg.roedel@amd.com>
+Cc: Youquan Song <youquan.song@intel.com>
+Cc: walter harms <wharms@bfs.de>
+Cc: Suresh Siddha <suresh.b.siddha@intel.com>
+Link: http://lkml.kernel.org/r/20120513170938.GA4280@elgon.mountain
+Signed-off-by: Ingo Molnar <mingo@kernel.org>
+[bwh: Backported to 3.2: s/irq_remap_fault_reasons/intr_remap_fault_reasons/]
+Signed-off-by: Ben Hutchings <ben@decadent.org.uk>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/iommu/dmar.c |    4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+--- a/drivers/iommu/dmar.c
++++ b/drivers/iommu/dmar.c
+@@ -1056,8 +1056,8 @@ static const char *intr_remap_fault_reas
+ const char *dmar_get_fault_reason(u8 fault_reason, int *fault_type)
+ {
+-      if (fault_reason >= 0x20 && (fault_reason <= 0x20 +
+-                                   ARRAY_SIZE(intr_remap_fault_reasons))) {
++      if (fault_reason >= 0x20 && (fault_reason - 0x20 <
++                                      ARRAY_SIZE(intr_remap_fault_reasons))) {
+               *fault_type = INTR_REMAP;
+               return intr_remap_fault_reasons[fault_reason - 0x20];
+       } else if (fault_reason < ARRAY_SIZE(dma_remap_fault_reasons)) {
diff --git a/queue-3.3/mce-fix-vm86-handling-for-32bit-mce-handler.patch b/queue-3.3/mce-fix-vm86-handling-for-32bit-mce-handler.patch
new file mode 100644 (file)
index 0000000..fda5bb4
--- /dev/null
@@ -0,0 +1,41 @@
+From a129a7c84582629741e5fa6f40026efcd7a65bd4 Mon Sep 17 00:00:00 2001
+From: Andi Kleen <andi@firstfloor.org>
+Date: Fri, 19 Nov 2010 13:16:22 +0100
+Subject: MCE: Fix vm86 handling for 32bit mce handler
+
+From: Andi Kleen <andi@firstfloor.org>
+
+commit a129a7c84582629741e5fa6f40026efcd7a65bd4 upstream.
+
+When running on 32bit the mce handler could misinterpret
+vm86 mode as ring 0. This can affect whether it does recovery
+or not; it was possible to panic when recovery was actually
+possible.
+
+Fix this by always forcing vm86 to look like ring 3.
+
+Signed-off-by: Andi Kleen <ak@linux.intel.com>
+Signed-off-by: Tony Luck <tony.luck@intel.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ arch/x86/kernel/cpu/mcheck/mce.c |    8 ++++++++
+ 1 file changed, 8 insertions(+)
+
+--- a/arch/x86/kernel/cpu/mcheck/mce.c
++++ b/arch/x86/kernel/cpu/mcheck/mce.c
+@@ -437,6 +437,14 @@ static inline void mce_gather_info(struc
+               if (m->mcgstatus & (MCG_STATUS_RIPV|MCG_STATUS_EIPV)) {
+                       m->ip = regs->ip;
+                       m->cs = regs->cs;
++
++                      /*
++                       * When in VM86 mode make the cs look like ring 3
++                       * always. This is a lie, but it's better than passing
++                       * the additional vm86 bit around everywhere.
++                       */
++                      if (v8086_mode(regs))
++                              m->cs |= 3;
+               }
+               /* Use accurate RIP reporting if available. */
+               if (rip_msr)
diff --git a/queue-3.3/mmc-cd-gpio-protect-against-null-context-in-mmc_cd_gpio_free.patch b/queue-3.3/mmc-cd-gpio-protect-against-null-context-in-mmc_cd_gpio_free.patch
new file mode 100644 (file)
index 0000000..ffbeec6
--- /dev/null
@@ -0,0 +1,33 @@
+From 0e9f480bb553d39ee06ccd45639ba7a5446a7b81 Mon Sep 17 00:00:00 2001
+From: Guennadi Liakhovetski <g.liakhovetski@gmx.de>
+Date: Tue, 24 Apr 2012 17:56:29 +0200
+Subject: mmc: cd-gpio: protect against NULL context in mmc_cd_gpio_free()
+
+From: Guennadi Liakhovetski <g.liakhovetski@gmx.de>
+
+commit 0e9f480bb553d39ee06ccd45639ba7a5446a7b81 upstream.
+
+Do not oops, even if mmc_cd_gpio_free() is mistakenly called on a driver
+cleanup path, even though a previous call to mmc_cd_gpio_request() failed.
+
+Signed-off-by: Guennadi Liakhovetski <g.liakhovetski@gmx.de>
+[stable@: please apply to 3.3-stable]
+Signed-off-by: Chris Ball <cjb@laptop.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ drivers/mmc/core/cd-gpio.c |    3 +++
+ 1 file changed, 3 insertions(+)
+
+--- a/drivers/mmc/core/cd-gpio.c
++++ b/drivers/mmc/core/cd-gpio.c
+@@ -67,6 +67,9 @@ void mmc_cd_gpio_free(struct mmc_host *h
+ {
+       struct mmc_cd_gpio *cd = host->hotplug.handler_priv;
++      if (!cd)
++              return;
++
+       free_irq(host->hotplug.irq, host);
+       gpio_free(cd->gpio);
+       kfree(cd);
diff --git a/queue-3.3/mmc-omap_hsmmc-pass-irqf_oneshot-to-request_threaded_irq.patch b/queue-3.3/mmc-omap_hsmmc-pass-irqf_oneshot-to-request_threaded_irq.patch
new file mode 100644 (file)
index 0000000..0c3d719
--- /dev/null
@@ -0,0 +1,40 @@
+From db35f83ef47b5f180f2670d11f5f93992314ea09 Mon Sep 17 00:00:00 2001
+From: Ming Lei <ming.lei@canonical.com>
+Date: Thu, 17 May 2012 10:27:12 +0800
+Subject: mmc: omap_hsmmc: pass IRQF_ONESHOT to request_threaded_irq
+
+From: Ming Lei <ming.lei@canonical.com>
+
+commit db35f83ef47b5f180f2670d11f5f93992314ea09 upstream.
+
+The flag of IRQF_ONESHOT should be passed to request_threaded_irq,
+otherwise the following failure message should be dumped because
+hardware handler is defined as NULL:
+
+[    3.383483] genirq: Threaded irq requested with handler=NULL and
+!ONESHOT for irq 368
+[    3.392730] omap_hsmmc: probe of omap_hsmmc.0 failed with error -22
+
+The patch fixes one kernel hang bug which is caused by mmc card
+probe failure and root device can't be brought up.
+
+Signed-off-by: Ming Lei <ming.lei@canonical.com>
+Acked-by: Venkatraman S <svenkatr@ti.com>
+Signed-off-by: Chris Ball <cjb@laptop.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ drivers/mmc/host/omap_hsmmc.c |    2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/drivers/mmc/host/omap_hsmmc.c
++++ b/drivers/mmc/host/omap_hsmmc.c
+@@ -2034,7 +2034,7 @@ static int __init omap_hsmmc_probe(struc
+               ret = request_threaded_irq(mmc_slot(host).card_detect_irq,
+                                          NULL,
+                                          omap_hsmmc_detect,
+-                                         IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
++                                         IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
+                                          mmc_hostname(mmc), host);
+               if (ret) {
+                       dev_dbg(mmc_dev(host->mmc),
diff --git a/queue-3.3/mmc-sdio-avoid-spurious-calls-to-interrupt-handlers.patch b/queue-3.3/mmc-sdio-avoid-spurious-calls-to-interrupt-handlers.patch
new file mode 100644 (file)
index 0000000..03943b8
--- /dev/null
@@ -0,0 +1,92 @@
+From bbbc4c4d8c5face097d695f9bf3a39647ba6b7e7 Mon Sep 17 00:00:00 2001
+From: Nicolas Pitre <nicolas.pitre@linaro.org>
+Date: Mon, 16 Apr 2012 19:16:54 -0400
+Subject: mmc: sdio: avoid spurious calls to interrupt handlers
+
+From: Nicolas Pitre <nicolas.pitre@linaro.org>
+
+commit bbbc4c4d8c5face097d695f9bf3a39647ba6b7e7 upstream.
+
+Commit 06e8935feb ("optimized SDIO IRQ handling for single irq")
+introduced some spurious calls to SDIO function interrupt handlers,
+such as when the SDIO IRQ thread is started, or the safety check
+performed upon a system resume.  Let's add a flag to perform the
+optimization only when a real interrupt is signaled by the host
+driver and we know there is no point confirming it.
+
+Reported-by: Sujit Reddy Thumma <sthumma@codeaurora.org>
+Signed-off-by: Nicolas Pitre <nico@linaro.org>
+Signed-off-by: Chris Ball <cjb@laptop.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ drivers/mmc/core/sdio.c     |    2 +-
+ drivers/mmc/core/sdio_irq.c |   11 +++++++----
+ include/linux/mmc/host.h    |    2 ++
+ 3 files changed, 10 insertions(+), 5 deletions(-)
+
+--- a/drivers/mmc/core/sdio.c
++++ b/drivers/mmc/core/sdio.c
+@@ -947,7 +947,7 @@ static int mmc_sdio_resume(struct mmc_ho
+       }
+       if (!err && host->sdio_irqs)
+-              mmc_signal_sdio_irq(host);
++              wake_up_process(host->sdio_irq_thread);
+       mmc_release_host(host);
+       /*
+--- a/drivers/mmc/core/sdio_irq.c
++++ b/drivers/mmc/core/sdio_irq.c
+@@ -28,18 +28,20 @@
+ #include "sdio_ops.h"
+-static int process_sdio_pending_irqs(struct mmc_card *card)
++static int process_sdio_pending_irqs(struct mmc_host *host)
+ {
++      struct mmc_card *card = host->card;
+       int i, ret, count;
+       unsigned char pending;
+       struct sdio_func *func;
+       /*
+        * Optimization, if there is only 1 function interrupt registered
+-       * call irq handler directly
++       * and we know an IRQ was signaled then call irq handler directly.
++       * Otherwise do the full probe.
+        */
+       func = card->sdio_single_irq;
+-      if (func) {
++      if (func && host->sdio_irq_pending) {
+               func->irq_handler(func);
+               return 1;
+       }
+@@ -116,7 +118,8 @@ static int sdio_irq_thread(void *_host)
+               ret = __mmc_claim_host(host, &host->sdio_irq_thread_abort);
+               if (ret)
+                       break;
+-              ret = process_sdio_pending_irqs(host->card);
++              ret = process_sdio_pending_irqs(host);
++              host->sdio_irq_pending = false;
+               mmc_release_host(host);
+               /*
+--- a/include/linux/mmc/host.h
++++ b/include/linux/mmc/host.h
+@@ -323,6 +323,7 @@ struct mmc_host {
+       unsigned int            sdio_irqs;
+       struct task_struct      *sdio_irq_thread;
++      bool                    sdio_irq_pending;
+       atomic_t                sdio_irq_thread_abort;
+       mmc_pm_flag_t           pm_flags;       /* requested pm features */
+@@ -378,6 +379,7 @@ extern int mmc_cache_ctrl(struct mmc_hos
+ static inline void mmc_signal_sdio_irq(struct mmc_host *host)
+ {
+       host->ops->enable_sdio_irq(host, 0);
++      host->sdio_irq_pending = true;
+       wake_up_process(host->sdio_irq_thread);
+ }
diff --git a/queue-3.3/rtlwifi-fix-for-race-condition-when-firmware-is-cached.patch b/queue-3.3/rtlwifi-fix-for-race-condition-when-firmware-is-cached.patch
new file mode 100644 (file)
index 0000000..14970d1
--- /dev/null
@@ -0,0 +1,88 @@
+From 574e02abaf816b582685805f0c1150ca9f1f18ee Mon Sep 17 00:00:00 2001
+From: Larry Finger <Larry.Finger@lwfinger.net>
+Date: Fri, 4 May 2012 08:27:43 -0500
+Subject: rtlwifi: fix for race condition when firmware is cached
+
+From: Larry Finger <Larry.Finger@lwfinger.net>
+
+commit 574e02abaf816b582685805f0c1150ca9f1f18ee upstream.
+
+In commit b0302ab, the rtlwifi family of drivers was converted to use
+asynchronous firmware loading. Unfortumately, the implementation was
+racy, and the ieee80211 routines could be started before rtl_init_core()
+was called to setup the data.
+
+This patch fixes the bug noted in https://bugzilla.kernel.org/show_bug.cgi?id=43187.
+
+Reported-by: Joshua Roys <Joshua.Roys@gtri.gatech.edu>
+Tested-by: Neptune Ning <frostyplanet@gmail.com>
+Signed-off-by: Larry Finger <Larry.Finger@lwfinger.net>
+Signed-off-by: John W. Linville <linville@tuxdriver.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ drivers/net/wireless/rtlwifi/pci.c |   17 +++++++++--------
+ drivers/net/wireless/rtlwifi/usb.c |   12 ++++++------
+ 2 files changed, 15 insertions(+), 14 deletions(-)
+
+--- a/drivers/net/wireless/rtlwifi/pci.c
++++ b/drivers/net/wireless/rtlwifi/pci.c
+@@ -1865,14 +1865,6 @@ int __devinit rtl_pci_probe(struct pci_d
+       /*like read eeprom and so on */
+       rtlpriv->cfg->ops->read_eeprom_info(hw);
+-      if (rtlpriv->cfg->ops->init_sw_vars(hw)) {
+-              RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
+-                       ("Can't init_sw_vars.\n"));
+-              goto fail3;
+-      }
+-
+-      rtlpriv->cfg->ops->init_sw_leds(hw);
+-
+       /*aspm */
+       rtl_pci_init_aspm(hw);
+@@ -1892,6 +1884,15 @@ int __devinit rtl_pci_probe(struct pci_d
+               goto fail3;
+       }
++      if (rtlpriv->cfg->ops->init_sw_vars(hw)) {
++              RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
++                       ("Can't init_sw_vars.\n"));
++              err = -ENODEV;
++              goto fail3;
++      }
++
++      rtlpriv->cfg->ops->init_sw_leds(hw);
++
+       err = sysfs_create_group(&pdev->dev.kobj, &rtl_attribute_group);
+       if (err) {
+               RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
+--- a/drivers/net/wireless/rtlwifi/usb.c
++++ b/drivers/net/wireless/rtlwifi/usb.c
+@@ -970,12 +970,6 @@ int __devinit rtl_usb_probe(struct usb_i
+       rtlpriv->cfg->ops->read_chip_version(hw);
+       /*like read eeprom and so on */
+       rtlpriv->cfg->ops->read_eeprom_info(hw);
+-      if (rtlpriv->cfg->ops->init_sw_vars(hw)) {
+-              RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
+-                       ("Can't init_sw_vars.\n"));
+-              goto error_out;
+-      }
+-      rtlpriv->cfg->ops->init_sw_leds(hw);
+       err = _rtl_usb_init(hw);
+       err = _rtl_usb_init_sw(hw);
+       /* Init mac80211 sw */
+@@ -985,6 +979,12 @@ int __devinit rtl_usb_probe(struct usb_i
+                        ("Can't allocate sw for mac80211.\n"));
+               goto error_out;
+       }
++      if (rtlpriv->cfg->ops->init_sw_vars(hw)) {
++              RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
++                       ("Can't init_sw_vars.\n"));
++              goto error_out;
++      }
++      rtlpriv->cfg->ops->init_sw_leds(hw);
+       return 0;
+ error_out:
index e7dce2a3d9bc9d94e9300c6b56ebe014dc55187a..31b894d7a2c3e65b0067b90cfc4205c25d595043 100644 (file)
@@ -73,3 +73,22 @@ xen-do-not-map-the-same-gsi-twice-in-pvhvm-guests.patch
 nouveau-nouveau_set_bo_placement-takes-ttm-flags.patch
 smsusb-add-autodetection-support-for-usb-id-2040-c0a0.patch
 media-uvcvideo-fix-enuminput-handling.patch
+x86-realmode-16-bit-real-mode-code-support-for-relocs-tool.patch
+x86-relocs-workaround-for-binutils-2.22.52.0.1-section-bug.patch
+x86-relocs-when-printing-an-error-say-relative-or-absolute.patch
+x86-relocs-build-clean-fix.patch
+x86-32-relocs-whitelist-more-symbols-for-ld-bug-workaround.patch
+x86-relocs-add-jiffies-and-jiffies_64-to-the-relative-whitelist.patch
+x86-mce-fix-check-for-processor-context-when-machine-check-was-taken.patch
+mmc-sdio-avoid-spurious-calls-to-interrupt-handlers.patch
+mmc-cd-gpio-protect-against-null-context-in-mmc_cd_gpio_free.patch
+mmc-omap_hsmmc-pass-irqf_oneshot-to-request_threaded_irq.patch
+tile-fix-bug-where-fls-0-was-not-returning-0.patch
+intel-iommu-add-device-info-into-list-before-doing-context-mapping.patch
+iommu-fix-off-by-one-in-dmar_get_fault_reason.patch
+rtlwifi-fix-for-race-condition-when-firmware-is-cached.patch
+arm-7365-1-drop-unused-parameter-from-flush_cache_user_range.patch
+arm-7409-1-do-not-call-flush_cache_user_range-with-mmap_sem-held.patch
+mce-fix-vm86-handling-for-32bit-mce-handler.patch
+i2c-davinci-free-requested-irq-in-remove.patch
+i2c-tegra-notify-transfer-complete-after-clearing-status.patch
diff --git a/queue-3.3/tile-fix-bug-where-fls-0-was-not-returning-0.patch b/queue-3.3/tile-fix-bug-where-fls-0-was-not-returning-0.patch
new file mode 100644 (file)
index 0000000..3b41aab
--- /dev/null
@@ -0,0 +1,48 @@
+From 9f1d62bed7f015d11b9164078b7fea433b474114 Mon Sep 17 00:00:00 2001
+From: Chris Metcalf <cmetcalf@tilera.com>
+Date: Fri, 25 May 2012 12:32:09 -0400
+Subject: tile: fix bug where fls(0) was not returning 0
+
+From: Chris Metcalf <cmetcalf@tilera.com>
+
+commit 9f1d62bed7f015d11b9164078b7fea433b474114 upstream.
+
+This is because __builtin_clz(0) returns 64 for the "undefined" case
+of 0, since the builtin just does a right-shift 32 and "clz" instruction.
+So, use the alpha approach of casting to u32 and using __builtin_clzll().
+
+Signed-off-by: Chris Metcalf <cmetcalf@tilera.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ arch/tile/include/asm/bitops.h |   12 ++++++------
+ 1 file changed, 6 insertions(+), 6 deletions(-)
+
+--- a/arch/tile/include/asm/bitops.h
++++ b/arch/tile/include/asm/bitops.h
+@@ -77,6 +77,11 @@ static inline int ffs(int x)
+       return __builtin_ffs(x);
+ }
++static inline int fls64(__u64 w)
++{
++      return (sizeof(__u64) * 8) - __builtin_clzll(w);
++}
++
+ /**
+  * fls - find last set bit in word
+  * @x: the word to search
+@@ -90,12 +95,7 @@ static inline int ffs(int x)
+  */
+ static inline int fls(int x)
+ {
+-      return (sizeof(int) * 8) - __builtin_clz(x);
+-}
+-
+-static inline int fls64(__u64 w)
+-{
+-      return (sizeof(__u64) * 8) - __builtin_clzll(w);
++      return fls64((unsigned int) x);
+ }
+ static inline unsigned int __arch_hweight32(unsigned int w)
diff --git a/queue-3.3/x86-32-relocs-whitelist-more-symbols-for-ld-bug-workaround.patch b/queue-3.3/x86-32-relocs-whitelist-more-symbols-for-ld-bug-workaround.patch
new file mode 100644 (file)
index 0000000..722328f
--- /dev/null
@@ -0,0 +1,70 @@
+From fd952815307f0f272bf49fd364a7fd2f9992bc42 Mon Sep 17 00:00:00 2001
+From: "H. Peter Anvin" <hpa@zytor.com>
+Date: Wed, 23 May 2012 14:02:34 -0700
+Subject: x86-32, relocs: Whitelist more symbols for ld bug workaround
+
+From: "H. Peter Anvin" <hpa@zytor.com>
+
+commit fd952815307f0f272bf49fd364a7fd2f9992bc42 upstream.
+
+As noted in checkin:
+
+a3e854d95 x86, relocs: Workaround for binutils 2.22.52.0.1 section bug
+
+ld version 2.22.52.0.[12] can incorrectly promote relative symbols to
+absolute, if the output section they appear in is otherwise empty.
+
+Since checkin:
+
+6520fe55 x86, realmode: 16-bit real-mode code support for relocs tool
+
+we actually check for this and error out rather than silently creating
+a kernel which will malfunction if relocated.
+
+Ingo found a configuration in which __start_builtin_fw triggered the
+warning.
+
+Go through the linker script sources and look for more symbols that
+could plausibly get bogusly promoted to absolute, and add them to the
+whitelist.
+
+In general, if the following error triggers:
+
+       Invalid absolute R_386_32 relocation: <symbol>
+
+... then we should verify that <symbol> is really meant to be
+relocated, and add it and any related symbols manually to the S_REL
+regexp.
+
+Please note that 6520fe55 does not introduce the error, only the check
+for the error -- without 6520fe55 this version of ld will simply
+produce a corrupt kernel if CONFIG_RELOCATABLE is set on x86-32.
+
+Reported-by: Ingo Molnar <mingo@kernel.org>
+Signed-off-by: H. Peter Anvin <hpa@zytor.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ arch/x86/tools/relocs.c |   11 +++++++++++
+ 1 file changed, 11 insertions(+)
+
+--- a/arch/x86/tools/relocs.c
++++ b/arch/x86/tools/relocs.c
+@@ -60,6 +60,17 @@ static const char * const sym_regex_kern
+       "__x86_cpu_dev_(start|end)|"
+       "(__parainstructions|__alt_instructions)(|_end)|"
+       "(__iommu_table|__apicdrivers|__smp_locks)(|_end)|"
++      "__(start|end)_pci_.*|"
++      "__(start|end)_builtin_fw|"
++      "__(start|stop)___ksymtab(|_gpl|_unused|_unused_gpl|_gpl_future)|"
++      "__(start|stop)___kcrctab(|_gpl|_unused|_unused_gpl|_gpl_future)|"
++      "__(start|stop)___param|"
++      "__(start|stop)___modver|"
++      "__(start|stop)___bug_table|"
++      "__tracedata_(start|end)|"
++      "__(start|stop)_notes|"
++      "__end_rodata|"
++      "__initramfs_start|"
+       "_end)$"
+ };
diff --git a/queue-3.3/x86-mce-fix-check-for-processor-context-when-machine-check-was-taken.patch b/queue-3.3/x86-mce-fix-check-for-processor-context-when-machine-check-was-taken.patch
new file mode 100644 (file)
index 0000000..6d9f370
--- /dev/null
@@ -0,0 +1,50 @@
+From 875e26648cf9b6db9d8dc07b7959d7c61fb3f49c Mon Sep 17 00:00:00 2001
+From: Tony Luck <tony.luck@intel.com>
+Date: Wed, 23 May 2012 14:14:22 -0700
+Subject: x86/mce: Fix check for processor context when machine check was taken.
+
+From: Tony Luck <tony.luck@intel.com>
+
+commit 875e26648cf9b6db9d8dc07b7959d7c61fb3f49c upstream.
+
+Linus pointed out that there was no value is checking whether m->ip
+was zero - because zero is a legimate value.  If we have a reliable
+(or faked in the VM86 case) "m->cs" we can use it to tell whether we
+were in user mode or kernelwhen the machine check hit.
+
+Reported-by: Linus Torvalds <torvalds@linuxfoundation.org>
+Signed-off-by: Tony Luck <tony.luck@intel.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ arch/x86/kernel/cpu/mcheck/mce-severity.c |   16 ++++++++++------
+ 1 file changed, 10 insertions(+), 6 deletions(-)
+
+--- a/arch/x86/kernel/cpu/mcheck/mce-severity.c
++++ b/arch/x86/kernel/cpu/mcheck/mce-severity.c
+@@ -145,15 +145,19 @@ static struct severity {
+ };
+ /*
+- * If the EIPV bit is set, it means the saved IP is the
+- * instruction which caused the MCE.
++ * If mcgstatus indicated that ip/cs on the stack were
++ * no good, then "m->cs" will be zero and we will have
++ * to assume the worst case (IN_KERNEL) as we actually
++ * have no idea what we were executing when the machine
++ * check hit.
++ * If we do have a good "m->cs" (or a faked one in the
++ * case we were executing in VM86 mode) we can use it to
++ * distinguish an exception taken in user from from one
++ * taken in the kernel.
+  */
+ static int error_context(struct mce *m)
+ {
+-      if (m->mcgstatus & MCG_STATUS_EIPV)
+-              return (m->ip && (m->cs & 3) == 3) ? IN_USER : IN_KERNEL;
+-      /* Unknown, assume kernel */
+-      return IN_KERNEL;
++      return ((m->cs & 3) == 3) ? IN_USER : IN_KERNEL;
+ }
+ int mce_severity(struct mce *m, int tolerant, char **msg)
diff --git a/queue-3.3/x86-realmode-16-bit-real-mode-code-support-for-relocs-tool.patch b/queue-3.3/x86-realmode-16-bit-real-mode-code-support-for-relocs-tool.patch
new file mode 100644 (file)
index 0000000..fc9954f
--- /dev/null
@@ -0,0 +1,1628 @@
+From 6520fe5564acf07ade7b18a1272db1184835c487 Mon Sep 17 00:00:00 2001
+From: "H. Peter Anvin" <hpa@linux.intel.com>
+Date: Tue, 8 May 2012 21:22:24 +0300
+Subject: x86, realmode: 16-bit real-mode code support for relocs tool
+
+From: "H. Peter Anvin" <hpa@linux.intel.com>
+
+commit 6520fe5564acf07ade7b18a1272db1184835c487 upstream.
+
+A new option is added to the relocs tool called '--realmode'.
+This option causes the generation of 16-bit segment relocations
+and 32-bit linear relocations for the real-mode code. When
+the real-mode code is moved to the low-memory during kernel
+initialization, these relocation entries can be used to
+relocate the code properly.
+
+In the assembly code 16-bit segment relocations must be relative
+to the 'real_mode_seg' absolute symbol. Linear relocations must be
+relative to a symbol prefixed with 'pa_'.
+
+16-bit segment relocation is used to load cs:ip in 16-bit code.
+Linear relocations are used in the 32-bit code for relocatable
+data references. They are declared in the linker script of the
+real-mode code.
+
+The relocs tool is moved to arch/x86/tools/relocs.c, and added new
+target archscripts that can be used to build scripts needed building
+an architecture.  be compiled before building the arch/x86 tree.
+
+[ hpa: accelerating this because it detects invalid absolute
+  relocations, a serious bug in binutils 2.22.52.0.x which currently
+  produces bad kernels. ]
+
+[ jsakkine: applied against 3.3.7 ]
+
+Signed-off-by: H. Peter Anvin <hpa@linux.intel.com>
+Link: http://lkml.kernel.org/r/1336501366-28617-2-git-send-email-jarkko.sakkinen@intel.com
+Signed-off-by: Jarkko Sakkinen <jarkko.sakkinen@intel.com>
+Signed-off-by: H. Peter Anvin <hpa@linux.intel.com>
+Signed-off-by: Jarkko Sakkinen <jarkko.sakkinen@iki.fi>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ Makefile                          |    9 
+ arch/x86/Makefile                 |    3 
+ arch/x86/boot/compressed/Makefile |    9 
+ arch/x86/boot/compressed/relocs.c |  680 --------------------------------
+ arch/x86/tools/.gitignore         |    1 
+ arch/x86/tools/Makefile           |    4 
+ arch/x86/tools/relocs.c           |  797 ++++++++++++++++++++++++++++++++++++++
+ scripts/Makefile                  |    2 
+ 8 files changed, 817 insertions(+), 688 deletions(-)
+ delete mode 100644 arch/x86/boot/compressed/relocs.c
+ create mode 100644 arch/x86/tools/.gitignore
+ create mode 100644 arch/x86/tools/relocs.c
+
+--- a/Makefile
++++ b/Makefile
+@@ -442,7 +442,7 @@ asm-generic:
+ no-dot-config-targets := clean mrproper distclean \
+                        cscope gtags TAGS tags help %docs check% coccicheck \
+-                       include/linux/version.h headers_% archheaders \
++                       include/linux/version.h headers_% archheaders archscripts \
+                        kernelversion %src-pkg
+ config-targets := 0
+@@ -979,7 +979,7 @@ prepare1: prepare2 include/linux/version
+                    include/config/auto.conf
+       $(cmd_crmodverdir)
+-archprepare: archheaders prepare1 scripts_basic
++archprepare: archheaders archscripts prepare1 scripts_basic
+ prepare0: archprepare FORCE
+       $(Q)$(MAKE) $(build)=.
+@@ -1049,8 +1049,11 @@ hdr-dst = $(if $(KBUILD_HEADERS), dst=in
+ PHONY += archheaders
+ archheaders:
++PHONY += archscripts
++archscripts:
++
+ PHONY += __headers
+-__headers: include/linux/version.h scripts_basic asm-generic archheaders FORCE
++__headers: include/linux/version.h scripts_basic asm-generic archheaders archscripts FORCE
+       $(Q)$(MAKE) $(build)=scripts build_unifdef
+ PHONY += headers_install_all
+--- a/arch/x86/Makefile
++++ b/arch/x86/Makefile
+@@ -117,6 +117,9 @@ KBUILD_CFLAGS += $(call cc-option,-mno-s
+ KBUILD_CFLAGS += $(mflags-y)
+ KBUILD_AFLAGS += $(mflags-y)
++archscripts:
++      $(Q)$(MAKE) $(build)=arch/x86/tools relocs
++
+ ###
+ # Syscall table generation
+--- a/arch/x86/boot/compressed/Makefile
++++ b/arch/x86/boot/compressed/Makefile
+@@ -40,13 +40,12 @@ OBJCOPYFLAGS_vmlinux.bin :=  -R .comment
+ $(obj)/vmlinux.bin: vmlinux FORCE
+       $(call if_changed,objcopy)
++targets += vmlinux.bin.all vmlinux.relocs
+-targets += vmlinux.bin.all vmlinux.relocs relocs
+-hostprogs-$(CONFIG_X86_NEED_RELOCS) += relocs
+-
++CMD_RELOCS = arch/x86/tools/relocs
+ quiet_cmd_relocs = RELOCS  $@
+-      cmd_relocs = $(obj)/relocs $< > $@;$(obj)/relocs --abs-relocs $<
+-$(obj)/vmlinux.relocs: vmlinux $(obj)/relocs FORCE
++      cmd_relocs = $(CMD_RELOCS) $< > $@;$(CMD_RELOCS) --abs-relocs $<
++$(obj)/vmlinux.relocs: vmlinux FORCE
+       $(call if_changed,relocs)
+ vmlinux.bin.all-y := $(obj)/vmlinux.bin
+--- a/arch/x86/boot/compressed/relocs.c
++++ /dev/null
+@@ -1,680 +0,0 @@
+-#include <stdio.h>
+-#include <stdarg.h>
+-#include <stdlib.h>
+-#include <stdint.h>
+-#include <string.h>
+-#include <errno.h>
+-#include <unistd.h>
+-#include <elf.h>
+-#include <byteswap.h>
+-#define USE_BSD
+-#include <endian.h>
+-#include <regex.h>
+-
+-static void die(char *fmt, ...);
+-
+-#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
+-static Elf32_Ehdr ehdr;
+-static unsigned long reloc_count, reloc_idx;
+-static unsigned long *relocs;
+-
+-struct section {
+-      Elf32_Shdr     shdr;
+-      struct section *link;
+-      Elf32_Sym      *symtab;
+-      Elf32_Rel      *reltab;
+-      char           *strtab;
+-};
+-static struct section *secs;
+-
+-/*
+- * Following symbols have been audited. There values are constant and do
+- * not change if bzImage is loaded at a different physical address than
+- * the address for which it has been compiled. Don't warn user about
+- * absolute relocations present w.r.t these symbols.
+- */
+-static const char abs_sym_regex[] =
+-      "^(xen_irq_disable_direct_reloc$|"
+-      "xen_save_fl_direct_reloc$|"
+-      "VDSO|"
+-      "__crc_)";
+-static regex_t abs_sym_regex_c;
+-static int is_abs_reloc(const char *sym_name)
+-{
+-      return !regexec(&abs_sym_regex_c, sym_name, 0, NULL, 0);
+-}
+-
+-/*
+- * These symbols are known to be relative, even if the linker marks them
+- * as absolute (typically defined outside any section in the linker script.)
+- */
+-static const char rel_sym_regex[] =
+-      "^_end$";
+-static regex_t rel_sym_regex_c;
+-static int is_rel_reloc(const char *sym_name)
+-{
+-      return !regexec(&rel_sym_regex_c, sym_name, 0, NULL, 0);
+-}
+-
+-static void regex_init(void)
+-{
+-        char errbuf[128];
+-        int err;
+-      
+-        err = regcomp(&abs_sym_regex_c, abs_sym_regex,
+-                      REG_EXTENDED|REG_NOSUB);
+-        if (err) {
+-                regerror(err, &abs_sym_regex_c, errbuf, sizeof errbuf);
+-                die("%s", errbuf);
+-        }
+-
+-        err = regcomp(&rel_sym_regex_c, rel_sym_regex,
+-                      REG_EXTENDED|REG_NOSUB);
+-        if (err) {
+-                regerror(err, &rel_sym_regex_c, errbuf, sizeof errbuf);
+-                die("%s", errbuf);
+-        }
+-}
+-
+-static void die(char *fmt, ...)
+-{
+-      va_list ap;
+-      va_start(ap, fmt);
+-      vfprintf(stderr, fmt, ap);
+-      va_end(ap);
+-      exit(1);
+-}
+-
+-static const char *sym_type(unsigned type)
+-{
+-      static const char *type_name[] = {
+-#define SYM_TYPE(X) [X] = #X
+-              SYM_TYPE(STT_NOTYPE),
+-              SYM_TYPE(STT_OBJECT),
+-              SYM_TYPE(STT_FUNC),
+-              SYM_TYPE(STT_SECTION),
+-              SYM_TYPE(STT_FILE),
+-              SYM_TYPE(STT_COMMON),
+-              SYM_TYPE(STT_TLS),
+-#undef SYM_TYPE
+-      };
+-      const char *name = "unknown sym type name";
+-      if (type < ARRAY_SIZE(type_name)) {
+-              name = type_name[type];
+-      }
+-      return name;
+-}
+-
+-static const char *sym_bind(unsigned bind)
+-{
+-      static const char *bind_name[] = {
+-#define SYM_BIND(X) [X] = #X
+-              SYM_BIND(STB_LOCAL),
+-              SYM_BIND(STB_GLOBAL),
+-              SYM_BIND(STB_WEAK),
+-#undef SYM_BIND
+-      };
+-      const char *name = "unknown sym bind name";
+-      if (bind < ARRAY_SIZE(bind_name)) {
+-              name = bind_name[bind];
+-      }
+-      return name;
+-}
+-
+-static const char *sym_visibility(unsigned visibility)
+-{
+-      static const char *visibility_name[] = {
+-#define SYM_VISIBILITY(X) [X] = #X
+-              SYM_VISIBILITY(STV_DEFAULT),
+-              SYM_VISIBILITY(STV_INTERNAL),
+-              SYM_VISIBILITY(STV_HIDDEN),
+-              SYM_VISIBILITY(STV_PROTECTED),
+-#undef SYM_VISIBILITY
+-      };
+-      const char *name = "unknown sym visibility name";
+-      if (visibility < ARRAY_SIZE(visibility_name)) {
+-              name = visibility_name[visibility];
+-      }
+-      return name;
+-}
+-
+-static const char *rel_type(unsigned type)
+-{
+-      static const char *type_name[] = {
+-#define REL_TYPE(X) [X] = #X
+-              REL_TYPE(R_386_NONE),
+-              REL_TYPE(R_386_32),
+-              REL_TYPE(R_386_PC32),
+-              REL_TYPE(R_386_GOT32),
+-              REL_TYPE(R_386_PLT32),
+-              REL_TYPE(R_386_COPY),
+-              REL_TYPE(R_386_GLOB_DAT),
+-              REL_TYPE(R_386_JMP_SLOT),
+-              REL_TYPE(R_386_RELATIVE),
+-              REL_TYPE(R_386_GOTOFF),
+-              REL_TYPE(R_386_GOTPC),
+-#undef REL_TYPE
+-      };
+-      const char *name = "unknown type rel type name";
+-      if (type < ARRAY_SIZE(type_name) && type_name[type]) {
+-              name = type_name[type];
+-      }
+-      return name;
+-}
+-
+-static const char *sec_name(unsigned shndx)
+-{
+-      const char *sec_strtab;
+-      const char *name;
+-      sec_strtab = secs[ehdr.e_shstrndx].strtab;
+-      name = "<noname>";
+-      if (shndx < ehdr.e_shnum) {
+-              name = sec_strtab + secs[shndx].shdr.sh_name;
+-      }
+-      else if (shndx == SHN_ABS) {
+-              name = "ABSOLUTE";
+-      }
+-      else if (shndx == SHN_COMMON) {
+-              name = "COMMON";
+-      }
+-      return name;
+-}
+-
+-static const char *sym_name(const char *sym_strtab, Elf32_Sym *sym)
+-{
+-      const char *name;
+-      name = "<noname>";
+-      if (sym->st_name) {
+-              name = sym_strtab + sym->st_name;
+-      }
+-      else {
+-              name = sec_name(secs[sym->st_shndx].shdr.sh_name);
+-      }
+-      return name;
+-}
+-
+-
+-
+-#if BYTE_ORDER == LITTLE_ENDIAN
+-#define le16_to_cpu(val) (val)
+-#define le32_to_cpu(val) (val)
+-#endif
+-#if BYTE_ORDER == BIG_ENDIAN
+-#define le16_to_cpu(val) bswap_16(val)
+-#define le32_to_cpu(val) bswap_32(val)
+-#endif
+-
+-static uint16_t elf16_to_cpu(uint16_t val)
+-{
+-      return le16_to_cpu(val);
+-}
+-
+-static uint32_t elf32_to_cpu(uint32_t val)
+-{
+-      return le32_to_cpu(val);
+-}
+-
+-static void read_ehdr(FILE *fp)
+-{
+-      if (fread(&ehdr, sizeof(ehdr), 1, fp) != 1) {
+-              die("Cannot read ELF header: %s\n",
+-                      strerror(errno));
+-      }
+-      if (memcmp(ehdr.e_ident, ELFMAG, SELFMAG) != 0) {
+-              die("No ELF magic\n");
+-      }
+-      if (ehdr.e_ident[EI_CLASS] != ELFCLASS32) {
+-              die("Not a 32 bit executable\n");
+-      }
+-      if (ehdr.e_ident[EI_DATA] != ELFDATA2LSB) {
+-              die("Not a LSB ELF executable\n");
+-      }
+-      if (ehdr.e_ident[EI_VERSION] != EV_CURRENT) {
+-              die("Unknown ELF version\n");
+-      }
+-      /* Convert the fields to native endian */
+-      ehdr.e_type      = elf16_to_cpu(ehdr.e_type);
+-      ehdr.e_machine   = elf16_to_cpu(ehdr.e_machine);
+-      ehdr.e_version   = elf32_to_cpu(ehdr.e_version);
+-      ehdr.e_entry     = elf32_to_cpu(ehdr.e_entry);
+-      ehdr.e_phoff     = elf32_to_cpu(ehdr.e_phoff);
+-      ehdr.e_shoff     = elf32_to_cpu(ehdr.e_shoff);
+-      ehdr.e_flags     = elf32_to_cpu(ehdr.e_flags);
+-      ehdr.e_ehsize    = elf16_to_cpu(ehdr.e_ehsize);
+-      ehdr.e_phentsize = elf16_to_cpu(ehdr.e_phentsize);
+-      ehdr.e_phnum     = elf16_to_cpu(ehdr.e_phnum);
+-      ehdr.e_shentsize = elf16_to_cpu(ehdr.e_shentsize);
+-      ehdr.e_shnum     = elf16_to_cpu(ehdr.e_shnum);
+-      ehdr.e_shstrndx  = elf16_to_cpu(ehdr.e_shstrndx);
+-
+-      if ((ehdr.e_type != ET_EXEC) && (ehdr.e_type != ET_DYN)) {
+-              die("Unsupported ELF header type\n");
+-      }
+-      if (ehdr.e_machine != EM_386) {
+-              die("Not for x86\n");
+-      }
+-      if (ehdr.e_version != EV_CURRENT) {
+-              die("Unknown ELF version\n");
+-      }
+-      if (ehdr.e_ehsize != sizeof(Elf32_Ehdr)) {
+-              die("Bad Elf header size\n");
+-      }
+-      if (ehdr.e_phentsize != sizeof(Elf32_Phdr)) {
+-              die("Bad program header entry\n");
+-      }
+-      if (ehdr.e_shentsize != sizeof(Elf32_Shdr)) {
+-              die("Bad section header entry\n");
+-      }
+-      if (ehdr.e_shstrndx >= ehdr.e_shnum) {
+-              die("String table index out of bounds\n");
+-      }
+-}
+-
+-static void read_shdrs(FILE *fp)
+-{
+-      int i;
+-      Elf32_Shdr shdr;
+-
+-      secs = calloc(ehdr.e_shnum, sizeof(struct section));
+-      if (!secs) {
+-              die("Unable to allocate %d section headers\n",
+-                  ehdr.e_shnum);
+-      }
+-      if (fseek(fp, ehdr.e_shoff, SEEK_SET) < 0) {
+-              die("Seek to %d failed: %s\n",
+-                      ehdr.e_shoff, strerror(errno));
+-      }
+-      for (i = 0; i < ehdr.e_shnum; i++) {
+-              struct section *sec = &secs[i];
+-              if (fread(&shdr, sizeof shdr, 1, fp) != 1)
+-                      die("Cannot read ELF section headers %d/%d: %s\n",
+-                          i, ehdr.e_shnum, strerror(errno));
+-              sec->shdr.sh_name      = elf32_to_cpu(shdr.sh_name);
+-              sec->shdr.sh_type      = elf32_to_cpu(shdr.sh_type);
+-              sec->shdr.sh_flags     = elf32_to_cpu(shdr.sh_flags);
+-              sec->shdr.sh_addr      = elf32_to_cpu(shdr.sh_addr);
+-              sec->shdr.sh_offset    = elf32_to_cpu(shdr.sh_offset);
+-              sec->shdr.sh_size      = elf32_to_cpu(shdr.sh_size);
+-              sec->shdr.sh_link      = elf32_to_cpu(shdr.sh_link);
+-              sec->shdr.sh_info      = elf32_to_cpu(shdr.sh_info);
+-              sec->shdr.sh_addralign = elf32_to_cpu(shdr.sh_addralign);
+-              sec->shdr.sh_entsize   = elf32_to_cpu(shdr.sh_entsize);
+-              if (sec->shdr.sh_link < ehdr.e_shnum)
+-                      sec->link = &secs[sec->shdr.sh_link];
+-      }
+-
+-}
+-
+-static void read_strtabs(FILE *fp)
+-{
+-      int i;
+-      for (i = 0; i < ehdr.e_shnum; i++) {
+-              struct section *sec = &secs[i];
+-              if (sec->shdr.sh_type != SHT_STRTAB) {
+-                      continue;
+-              }
+-              sec->strtab = malloc(sec->shdr.sh_size);
+-              if (!sec->strtab) {
+-                      die("malloc of %d bytes for strtab failed\n",
+-                              sec->shdr.sh_size);
+-              }
+-              if (fseek(fp, sec->shdr.sh_offset, SEEK_SET) < 0) {
+-                      die("Seek to %d failed: %s\n",
+-                              sec->shdr.sh_offset, strerror(errno));
+-              }
+-              if (fread(sec->strtab, 1, sec->shdr.sh_size, fp)
+-                  != sec->shdr.sh_size) {
+-                      die("Cannot read symbol table: %s\n",
+-                              strerror(errno));
+-              }
+-      }
+-}
+-
+-static void read_symtabs(FILE *fp)
+-{
+-      int i,j;
+-      for (i = 0; i < ehdr.e_shnum; i++) {
+-              struct section *sec = &secs[i];
+-              if (sec->shdr.sh_type != SHT_SYMTAB) {
+-                      continue;
+-              }
+-              sec->symtab = malloc(sec->shdr.sh_size);
+-              if (!sec->symtab) {
+-                      die("malloc of %d bytes for symtab failed\n",
+-                              sec->shdr.sh_size);
+-              }
+-              if (fseek(fp, sec->shdr.sh_offset, SEEK_SET) < 0) {
+-                      die("Seek to %d failed: %s\n",
+-                              sec->shdr.sh_offset, strerror(errno));
+-              }
+-              if (fread(sec->symtab, 1, sec->shdr.sh_size, fp)
+-                  != sec->shdr.sh_size) {
+-                      die("Cannot read symbol table: %s\n",
+-                              strerror(errno));
+-              }
+-              for (j = 0; j < sec->shdr.sh_size/sizeof(Elf32_Sym); j++) {
+-                      Elf32_Sym *sym = &sec->symtab[j];
+-                      sym->st_name  = elf32_to_cpu(sym->st_name);
+-                      sym->st_value = elf32_to_cpu(sym->st_value);
+-                      sym->st_size  = elf32_to_cpu(sym->st_size);
+-                      sym->st_shndx = elf16_to_cpu(sym->st_shndx);
+-              }
+-      }
+-}
+-
+-
+-static void read_relocs(FILE *fp)
+-{
+-      int i,j;
+-      for (i = 0; i < ehdr.e_shnum; i++) {
+-              struct section *sec = &secs[i];
+-              if (sec->shdr.sh_type != SHT_REL) {
+-                      continue;
+-              }
+-              sec->reltab = malloc(sec->shdr.sh_size);
+-              if (!sec->reltab) {
+-                      die("malloc of %d bytes for relocs failed\n",
+-                              sec->shdr.sh_size);
+-              }
+-              if (fseek(fp, sec->shdr.sh_offset, SEEK_SET) < 0) {
+-                      die("Seek to %d failed: %s\n",
+-                              sec->shdr.sh_offset, strerror(errno));
+-              }
+-              if (fread(sec->reltab, 1, sec->shdr.sh_size, fp)
+-                  != sec->shdr.sh_size) {
+-                      die("Cannot read symbol table: %s\n",
+-                              strerror(errno));
+-              }
+-              for (j = 0; j < sec->shdr.sh_size/sizeof(Elf32_Rel); j++) {
+-                      Elf32_Rel *rel = &sec->reltab[j];
+-                      rel->r_offset = elf32_to_cpu(rel->r_offset);
+-                      rel->r_info   = elf32_to_cpu(rel->r_info);
+-              }
+-      }
+-}
+-
+-
+-static void print_absolute_symbols(void)
+-{
+-      int i;
+-      printf("Absolute symbols\n");
+-      printf(" Num:    Value Size  Type       Bind        Visibility  Name\n");
+-      for (i = 0; i < ehdr.e_shnum; i++) {
+-              struct section *sec = &secs[i];
+-              char *sym_strtab;
+-              int j;
+-
+-              if (sec->shdr.sh_type != SHT_SYMTAB) {
+-                      continue;
+-              }
+-              sym_strtab = sec->link->strtab;
+-              for (j = 0; j < sec->shdr.sh_size/sizeof(Elf32_Sym); j++) {
+-                      Elf32_Sym *sym;
+-                      const char *name;
+-                      sym = &sec->symtab[j];
+-                      name = sym_name(sym_strtab, sym);
+-                      if (sym->st_shndx != SHN_ABS) {
+-                              continue;
+-                      }
+-                      printf("%5d %08x %5d %10s %10s %12s %s\n",
+-                              j, sym->st_value, sym->st_size,
+-                              sym_type(ELF32_ST_TYPE(sym->st_info)),
+-                              sym_bind(ELF32_ST_BIND(sym->st_info)),
+-                              sym_visibility(ELF32_ST_VISIBILITY(sym->st_other)),
+-                              name);
+-              }
+-      }
+-      printf("\n");
+-}
+-
+-static void print_absolute_relocs(void)
+-{
+-      int i, printed = 0;
+-
+-      for (i = 0; i < ehdr.e_shnum; i++) {
+-              struct section *sec = &secs[i];
+-              struct section *sec_applies, *sec_symtab;
+-              char *sym_strtab;
+-              Elf32_Sym *sh_symtab;
+-              int j;
+-              if (sec->shdr.sh_type != SHT_REL) {
+-                      continue;
+-              }
+-              sec_symtab  = sec->link;
+-              sec_applies = &secs[sec->shdr.sh_info];
+-              if (!(sec_applies->shdr.sh_flags & SHF_ALLOC)) {
+-                      continue;
+-              }
+-              sh_symtab  = sec_symtab->symtab;
+-              sym_strtab = sec_symtab->link->strtab;
+-              for (j = 0; j < sec->shdr.sh_size/sizeof(Elf32_Rel); j++) {
+-                      Elf32_Rel *rel;
+-                      Elf32_Sym *sym;
+-                      const char *name;
+-                      rel = &sec->reltab[j];
+-                      sym = &sh_symtab[ELF32_R_SYM(rel->r_info)];
+-                      name = sym_name(sym_strtab, sym);
+-                      if (sym->st_shndx != SHN_ABS) {
+-                              continue;
+-                      }
+-
+-                      /* Absolute symbols are not relocated if bzImage is
+-                       * loaded at a non-compiled address. Display a warning
+-                       * to user at compile time about the absolute
+-                       * relocations present.
+-                       *
+-                       * User need to audit the code to make sure
+-                       * some symbols which should have been section
+-                       * relative have not become absolute because of some
+-                       * linker optimization or wrong programming usage.
+-                       *
+-                       * Before warning check if this absolute symbol
+-                       * relocation is harmless.
+-                       */
+-                      if (is_abs_reloc(name) || is_rel_reloc(name))
+-                              continue;
+-
+-                      if (!printed) {
+-                              printf("WARNING: Absolute relocations"
+-                                      " present\n");
+-                              printf("Offset     Info     Type     Sym.Value "
+-                                      "Sym.Name\n");
+-                              printed = 1;
+-                      }
+-
+-                      printf("%08x %08x %10s %08x  %s\n",
+-                              rel->r_offset,
+-                              rel->r_info,
+-                              rel_type(ELF32_R_TYPE(rel->r_info)),
+-                              sym->st_value,
+-                              name);
+-              }
+-      }
+-
+-      if (printed)
+-              printf("\n");
+-}
+-
+-static void walk_relocs(void (*visit)(Elf32_Rel *rel, Elf32_Sym *sym))
+-{
+-      int i;
+-      /* Walk through the relocations */
+-      for (i = 0; i < ehdr.e_shnum; i++) {
+-              char *sym_strtab;
+-              Elf32_Sym *sh_symtab;
+-              struct section *sec_applies, *sec_symtab;
+-              int j;
+-              struct section *sec = &secs[i];
+-
+-              if (sec->shdr.sh_type != SHT_REL) {
+-                      continue;
+-              }
+-              sec_symtab  = sec->link;
+-              sec_applies = &secs[sec->shdr.sh_info];
+-              if (!(sec_applies->shdr.sh_flags & SHF_ALLOC)) {
+-                      continue;
+-              }
+-              sh_symtab = sec_symtab->symtab;
+-              sym_strtab = sec_symtab->link->strtab;
+-              for (j = 0; j < sec->shdr.sh_size/sizeof(Elf32_Rel); j++) {
+-                      Elf32_Rel *rel;
+-                      Elf32_Sym *sym;
+-                      unsigned r_type;
+-                      rel = &sec->reltab[j];
+-                      sym = &sh_symtab[ELF32_R_SYM(rel->r_info)];
+-                      r_type = ELF32_R_TYPE(rel->r_info);
+-                      /* Don't visit relocations to absolute symbols */
+-                      if (sym->st_shndx == SHN_ABS &&
+-                          !is_rel_reloc(sym_name(sym_strtab, sym))) {
+-                              continue;
+-                      }
+-                      switch (r_type) {
+-                      case R_386_NONE:
+-                      case R_386_PC32:
+-                              /*
+-                               * NONE can be ignored and and PC relative
+-                               * relocations don't need to be adjusted.
+-                               */
+-                              break;
+-                      case R_386_32:
+-                              /* Visit relocations that need to be adjusted */
+-                              visit(rel, sym);
+-                              break;
+-                      default:
+-                              die("Unsupported relocation type: %s (%d)\n",
+-                                  rel_type(r_type), r_type);
+-                              break;
+-                      }
+-              }
+-      }
+-}
+-
+-static void count_reloc(Elf32_Rel *rel, Elf32_Sym *sym)
+-{
+-      reloc_count += 1;
+-}
+-
+-static void collect_reloc(Elf32_Rel *rel, Elf32_Sym *sym)
+-{
+-      /* Remember the address that needs to be adjusted. */
+-      relocs[reloc_idx++] = rel->r_offset;
+-}
+-
+-static int cmp_relocs(const void *va, const void *vb)
+-{
+-      const unsigned long *a, *b;
+-      a = va; b = vb;
+-      return (*a == *b)? 0 : (*a > *b)? 1 : -1;
+-}
+-
+-static void emit_relocs(int as_text)
+-{
+-      int i;
+-      /* Count how many relocations I have and allocate space for them. */
+-      reloc_count = 0;
+-      walk_relocs(count_reloc);
+-      relocs = malloc(reloc_count * sizeof(relocs[0]));
+-      if (!relocs) {
+-              die("malloc of %d entries for relocs failed\n",
+-                      reloc_count);
+-      }
+-      /* Collect up the relocations */
+-      reloc_idx = 0;
+-      walk_relocs(collect_reloc);
+-
+-      /* Order the relocations for more efficient processing */
+-      qsort(relocs, reloc_count, sizeof(relocs[0]), cmp_relocs);
+-
+-      /* Print the relocations */
+-      if (as_text) {
+-              /* Print the relocations in a form suitable that
+-               * gas will like.
+-               */
+-              printf(".section \".data.reloc\",\"a\"\n");
+-              printf(".balign 4\n");
+-              for (i = 0; i < reloc_count; i++) {
+-                      printf("\t .long 0x%08lx\n", relocs[i]);
+-              }
+-              printf("\n");
+-      }
+-      else {
+-              unsigned char buf[4];
+-              /* Print a stop */
+-              fwrite("\0\0\0\0", 4, 1, stdout);
+-              /* Now print each relocation */
+-              for (i = 0; i < reloc_count; i++) {
+-                      buf[0] = (relocs[i] >>  0) & 0xff;
+-                      buf[1] = (relocs[i] >>  8) & 0xff;
+-                      buf[2] = (relocs[i] >> 16) & 0xff;
+-                      buf[3] = (relocs[i] >> 24) & 0xff;
+-                      fwrite(buf, 4, 1, stdout);
+-              }
+-      }
+-}
+-
+-static void usage(void)
+-{
+-      die("relocs [--abs-syms |--abs-relocs | --text] vmlinux\n");
+-}
+-
+-int main(int argc, char **argv)
+-{
+-      int show_absolute_syms, show_absolute_relocs;
+-      int as_text;
+-      const char *fname;
+-      FILE *fp;
+-      int i;
+-
+-      regex_init();
+-
+-      show_absolute_syms = 0;
+-      show_absolute_relocs = 0;
+-      as_text = 0;
+-      fname = NULL;
+-      for (i = 1; i < argc; i++) {
+-              char *arg = argv[i];
+-              if (*arg == '-') {
+-                      if (strcmp(argv[1], "--abs-syms") == 0) {
+-                              show_absolute_syms = 1;
+-                              continue;
+-                      }
+-
+-                      if (strcmp(argv[1], "--abs-relocs") == 0) {
+-                              show_absolute_relocs = 1;
+-                              continue;
+-                      }
+-                      else if (strcmp(argv[1], "--text") == 0) {
+-                              as_text = 1;
+-                              continue;
+-                      }
+-              }
+-              else if (!fname) {
+-                      fname = arg;
+-                      continue;
+-              }
+-              usage();
+-      }
+-      if (!fname) {
+-              usage();
+-      }
+-      fp = fopen(fname, "r");
+-      if (!fp) {
+-              die("Cannot open %s: %s\n",
+-                      fname, strerror(errno));
+-      }
+-      read_ehdr(fp);
+-      read_shdrs(fp);
+-      read_strtabs(fp);
+-      read_symtabs(fp);
+-      read_relocs(fp);
+-      if (show_absolute_syms) {
+-              print_absolute_symbols();
+-              return 0;
+-      }
+-      if (show_absolute_relocs) {
+-              print_absolute_relocs();
+-              return 0;
+-      }
+-      emit_relocs(as_text);
+-      return 0;
+-}
+--- /dev/null
++++ b/arch/x86/tools/.gitignore
+@@ -0,0 +1 @@
++relocs
+--- a/arch/x86/tools/Makefile
++++ b/arch/x86/tools/Makefile
+@@ -36,3 +36,7 @@ HOSTCFLAGS_insn_sanity.o := -Wall -I$(ob
+ $(obj)/test_get_len.o: $(srctree)/arch/x86/lib/insn.c $(srctree)/arch/x86/lib/inat.c $(srctree)/arch/x86/include/asm/inat_types.h $(srctree)/arch/x86/include/asm/inat.h $(srctree)/arch/x86/include/asm/insn.h $(objtree)/arch/x86/lib/inat-tables.c
+ $(obj)/insn_sanity.o: $(srctree)/arch/x86/lib/insn.c $(srctree)/arch/x86/lib/inat.c $(srctree)/arch/x86/include/asm/inat_types.h $(srctree)/arch/x86/include/asm/inat.h $(srctree)/arch/x86/include/asm/insn.h $(objtree)/arch/x86/lib/inat-tables.c
++
++HOST_EXTRACFLAGS += -I$(srctree)/tools/include
++hostprogs-y   += relocs
++relocs: $(obj)/relocs
+--- /dev/null
++++ b/arch/x86/tools/relocs.c
+@@ -0,0 +1,797 @@
++#include <stdio.h>
++#include <stdarg.h>
++#include <stdlib.h>
++#include <stdint.h>
++#include <string.h>
++#include <errno.h>
++#include <unistd.h>
++#include <elf.h>
++#include <byteswap.h>
++#define USE_BSD
++#include <endian.h>
++#include <regex.h>
++#include <tools/le_byteshift.h>
++
++static void die(char *fmt, ...);
++
++#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
++static Elf32_Ehdr ehdr;
++static unsigned long reloc_count, reloc_idx;
++static unsigned long *relocs;
++static unsigned long reloc16_count, reloc16_idx;
++static unsigned long *relocs16;
++
++struct section {
++      Elf32_Shdr     shdr;
++      struct section *link;
++      Elf32_Sym      *symtab;
++      Elf32_Rel      *reltab;
++      char           *strtab;
++};
++static struct section *secs;
++
++enum symtype {
++      S_ABS,
++      S_REL,
++      S_SEG,
++      S_LIN,
++      S_NSYMTYPES
++};
++
++static const char * const sym_regex_kernel[S_NSYMTYPES] = {
++/*
++ * Following symbols have been audited. There values are constant and do
++ * not change if bzImage is loaded at a different physical address than
++ * the address for which it has been compiled. Don't warn user about
++ * absolute relocations present w.r.t these symbols.
++ */
++      [S_ABS] =
++      "^(xen_irq_disable_direct_reloc$|"
++      "xen_save_fl_direct_reloc$|"
++      "VDSO|"
++      "__crc_)",
++
++/*
++ * These symbols are known to be relative, even if the linker marks them
++ * as absolute (typically defined outside any section in the linker script.)
++ */
++      [S_REL] =
++      "^_end$",
++};
++
++
++static const char * const sym_regex_realmode[S_NSYMTYPES] = {
++/*
++ * These are 16-bit segment symbols when compiling 16-bit code.
++ */
++      [S_SEG] =
++      "^real_mode_seg$",
++
++/*
++ * These are offsets belonging to segments, as opposed to linear addresses,
++ * when compiling 16-bit code.
++ */
++      [S_LIN] =
++      "^pa_",
++};
++
++static const char * const *sym_regex;
++
++static regex_t sym_regex_c[S_NSYMTYPES];
++static int is_reloc(enum symtype type, const char *sym_name)
++{
++      return sym_regex[type] &&
++              !regexec(&sym_regex_c[type], sym_name, 0, NULL, 0);
++}
++
++static void regex_init(int use_real_mode)
++{
++        char errbuf[128];
++        int err;
++      int i;
++
++      if (use_real_mode)
++              sym_regex = sym_regex_realmode;
++      else
++              sym_regex = sym_regex_kernel;
++
++      for (i = 0; i < S_NSYMTYPES; i++) {
++              if (!sym_regex[i])
++                      continue;
++
++              err = regcomp(&sym_regex_c[i], sym_regex[i],
++                            REG_EXTENDED|REG_NOSUB);
++
++              if (err) {
++                      regerror(err, &sym_regex_c[i], errbuf, sizeof errbuf);
++                      die("%s", errbuf);
++              }
++        }
++}
++
++static void die(char *fmt, ...)
++{
++      va_list ap;
++      va_start(ap, fmt);
++      vfprintf(stderr, fmt, ap);
++      va_end(ap);
++      exit(1);
++}
++
++static const char *sym_type(unsigned type)
++{
++      static const char *type_name[] = {
++#define SYM_TYPE(X) [X] = #X
++              SYM_TYPE(STT_NOTYPE),
++              SYM_TYPE(STT_OBJECT),
++              SYM_TYPE(STT_FUNC),
++              SYM_TYPE(STT_SECTION),
++              SYM_TYPE(STT_FILE),
++              SYM_TYPE(STT_COMMON),
++              SYM_TYPE(STT_TLS),
++#undef SYM_TYPE
++      };
++      const char *name = "unknown sym type name";
++      if (type < ARRAY_SIZE(type_name)) {
++              name = type_name[type];
++      }
++      return name;
++}
++
++static const char *sym_bind(unsigned bind)
++{
++      static const char *bind_name[] = {
++#define SYM_BIND(X) [X] = #X
++              SYM_BIND(STB_LOCAL),
++              SYM_BIND(STB_GLOBAL),
++              SYM_BIND(STB_WEAK),
++#undef SYM_BIND
++      };
++      const char *name = "unknown sym bind name";
++      if (bind < ARRAY_SIZE(bind_name)) {
++              name = bind_name[bind];
++      }
++      return name;
++}
++
++static const char *sym_visibility(unsigned visibility)
++{
++      static const char *visibility_name[] = {
++#define SYM_VISIBILITY(X) [X] = #X
++              SYM_VISIBILITY(STV_DEFAULT),
++              SYM_VISIBILITY(STV_INTERNAL),
++              SYM_VISIBILITY(STV_HIDDEN),
++              SYM_VISIBILITY(STV_PROTECTED),
++#undef SYM_VISIBILITY
++      };
++      const char *name = "unknown sym visibility name";
++      if (visibility < ARRAY_SIZE(visibility_name)) {
++              name = visibility_name[visibility];
++      }
++      return name;
++}
++
++static const char *rel_type(unsigned type)
++{
++      static const char *type_name[] = {
++#define REL_TYPE(X) [X] = #X
++              REL_TYPE(R_386_NONE),
++              REL_TYPE(R_386_32),
++              REL_TYPE(R_386_PC32),
++              REL_TYPE(R_386_GOT32),
++              REL_TYPE(R_386_PLT32),
++              REL_TYPE(R_386_COPY),
++              REL_TYPE(R_386_GLOB_DAT),
++              REL_TYPE(R_386_JMP_SLOT),
++              REL_TYPE(R_386_RELATIVE),
++              REL_TYPE(R_386_GOTOFF),
++              REL_TYPE(R_386_GOTPC),
++              REL_TYPE(R_386_8),
++              REL_TYPE(R_386_PC8),
++              REL_TYPE(R_386_16),
++              REL_TYPE(R_386_PC16),
++#undef REL_TYPE
++      };
++      const char *name = "unknown type rel type name";
++      if (type < ARRAY_SIZE(type_name) && type_name[type]) {
++              name = type_name[type];
++      }
++      return name;
++}
++
++static const char *sec_name(unsigned shndx)
++{
++      const char *sec_strtab;
++      const char *name;
++      sec_strtab = secs[ehdr.e_shstrndx].strtab;
++      name = "<noname>";
++      if (shndx < ehdr.e_shnum) {
++              name = sec_strtab + secs[shndx].shdr.sh_name;
++      }
++      else if (shndx == SHN_ABS) {
++              name = "ABSOLUTE";
++      }
++      else if (shndx == SHN_COMMON) {
++              name = "COMMON";
++      }
++      return name;
++}
++
++static const char *sym_name(const char *sym_strtab, Elf32_Sym *sym)
++{
++      const char *name;
++      name = "<noname>";
++      if (sym->st_name) {
++              name = sym_strtab + sym->st_name;
++      }
++      else {
++              name = sec_name(sym->st_shndx);
++      }
++      return name;
++}
++
++
++
++#if BYTE_ORDER == LITTLE_ENDIAN
++#define le16_to_cpu(val) (val)
++#define le32_to_cpu(val) (val)
++#endif
++#if BYTE_ORDER == BIG_ENDIAN
++#define le16_to_cpu(val) bswap_16(val)
++#define le32_to_cpu(val) bswap_32(val)
++#endif
++
++static uint16_t elf16_to_cpu(uint16_t val)
++{
++      return le16_to_cpu(val);
++}
++
++static uint32_t elf32_to_cpu(uint32_t val)
++{
++      return le32_to_cpu(val);
++}
++
++static void read_ehdr(FILE *fp)
++{
++      if (fread(&ehdr, sizeof(ehdr), 1, fp) != 1) {
++              die("Cannot read ELF header: %s\n",
++                      strerror(errno));
++      }
++      if (memcmp(ehdr.e_ident, ELFMAG, SELFMAG) != 0) {
++              die("No ELF magic\n");
++      }
++      if (ehdr.e_ident[EI_CLASS] != ELFCLASS32) {
++              die("Not a 32 bit executable\n");
++      }
++      if (ehdr.e_ident[EI_DATA] != ELFDATA2LSB) {
++              die("Not a LSB ELF executable\n");
++      }
++      if (ehdr.e_ident[EI_VERSION] != EV_CURRENT) {
++              die("Unknown ELF version\n");
++      }
++      /* Convert the fields to native endian */
++      ehdr.e_type      = elf16_to_cpu(ehdr.e_type);
++      ehdr.e_machine   = elf16_to_cpu(ehdr.e_machine);
++      ehdr.e_version   = elf32_to_cpu(ehdr.e_version);
++      ehdr.e_entry     = elf32_to_cpu(ehdr.e_entry);
++      ehdr.e_phoff     = elf32_to_cpu(ehdr.e_phoff);
++      ehdr.e_shoff     = elf32_to_cpu(ehdr.e_shoff);
++      ehdr.e_flags     = elf32_to_cpu(ehdr.e_flags);
++      ehdr.e_ehsize    = elf16_to_cpu(ehdr.e_ehsize);
++      ehdr.e_phentsize = elf16_to_cpu(ehdr.e_phentsize);
++      ehdr.e_phnum     = elf16_to_cpu(ehdr.e_phnum);
++      ehdr.e_shentsize = elf16_to_cpu(ehdr.e_shentsize);
++      ehdr.e_shnum     = elf16_to_cpu(ehdr.e_shnum);
++      ehdr.e_shstrndx  = elf16_to_cpu(ehdr.e_shstrndx);
++
++      if ((ehdr.e_type != ET_EXEC) && (ehdr.e_type != ET_DYN)) {
++              die("Unsupported ELF header type\n");
++      }
++      if (ehdr.e_machine != EM_386) {
++              die("Not for x86\n");
++      }
++      if (ehdr.e_version != EV_CURRENT) {
++              die("Unknown ELF version\n");
++      }
++      if (ehdr.e_ehsize != sizeof(Elf32_Ehdr)) {
++              die("Bad Elf header size\n");
++      }
++      if (ehdr.e_phentsize != sizeof(Elf32_Phdr)) {
++              die("Bad program header entry\n");
++      }
++      if (ehdr.e_shentsize != sizeof(Elf32_Shdr)) {
++              die("Bad section header entry\n");
++      }
++      if (ehdr.e_shstrndx >= ehdr.e_shnum) {
++              die("String table index out of bounds\n");
++      }
++}
++
++static void read_shdrs(FILE *fp)
++{
++      int i;
++      Elf32_Shdr shdr;
++
++      secs = calloc(ehdr.e_shnum, sizeof(struct section));
++      if (!secs) {
++              die("Unable to allocate %d section headers\n",
++                  ehdr.e_shnum);
++      }
++      if (fseek(fp, ehdr.e_shoff, SEEK_SET) < 0) {
++              die("Seek to %d failed: %s\n",
++                      ehdr.e_shoff, strerror(errno));
++      }
++      for (i = 0; i < ehdr.e_shnum; i++) {
++              struct section *sec = &secs[i];
++              if (fread(&shdr, sizeof shdr, 1, fp) != 1)
++                      die("Cannot read ELF section headers %d/%d: %s\n",
++                          i, ehdr.e_shnum, strerror(errno));
++              sec->shdr.sh_name      = elf32_to_cpu(shdr.sh_name);
++              sec->shdr.sh_type      = elf32_to_cpu(shdr.sh_type);
++              sec->shdr.sh_flags     = elf32_to_cpu(shdr.sh_flags);
++              sec->shdr.sh_addr      = elf32_to_cpu(shdr.sh_addr);
++              sec->shdr.sh_offset    = elf32_to_cpu(shdr.sh_offset);
++              sec->shdr.sh_size      = elf32_to_cpu(shdr.sh_size);
++              sec->shdr.sh_link      = elf32_to_cpu(shdr.sh_link);
++              sec->shdr.sh_info      = elf32_to_cpu(shdr.sh_info);
++              sec->shdr.sh_addralign = elf32_to_cpu(shdr.sh_addralign);
++              sec->shdr.sh_entsize   = elf32_to_cpu(shdr.sh_entsize);
++              if (sec->shdr.sh_link < ehdr.e_shnum)
++                      sec->link = &secs[sec->shdr.sh_link];
++      }
++
++}
++
++static void read_strtabs(FILE *fp)
++{
++      int i;
++      for (i = 0; i < ehdr.e_shnum; i++) {
++              struct section *sec = &secs[i];
++              if (sec->shdr.sh_type != SHT_STRTAB) {
++                      continue;
++              }
++              sec->strtab = malloc(sec->shdr.sh_size);
++              if (!sec->strtab) {
++                      die("malloc of %d bytes for strtab failed\n",
++                              sec->shdr.sh_size);
++              }
++              if (fseek(fp, sec->shdr.sh_offset, SEEK_SET) < 0) {
++                      die("Seek to %d failed: %s\n",
++                              sec->shdr.sh_offset, strerror(errno));
++              }
++              if (fread(sec->strtab, 1, sec->shdr.sh_size, fp)
++                  != sec->shdr.sh_size) {
++                      die("Cannot read symbol table: %s\n",
++                              strerror(errno));
++              }
++      }
++}
++
++static void read_symtabs(FILE *fp)
++{
++      int i,j;
++      for (i = 0; i < ehdr.e_shnum; i++) {
++              struct section *sec = &secs[i];
++              if (sec->shdr.sh_type != SHT_SYMTAB) {
++                      continue;
++              }
++              sec->symtab = malloc(sec->shdr.sh_size);
++              if (!sec->symtab) {
++                      die("malloc of %d bytes for symtab failed\n",
++                              sec->shdr.sh_size);
++              }
++              if (fseek(fp, sec->shdr.sh_offset, SEEK_SET) < 0) {
++                      die("Seek to %d failed: %s\n",
++                              sec->shdr.sh_offset, strerror(errno));
++              }
++              if (fread(sec->symtab, 1, sec->shdr.sh_size, fp)
++                  != sec->shdr.sh_size) {
++                      die("Cannot read symbol table: %s\n",
++                              strerror(errno));
++              }
++              for (j = 0; j < sec->shdr.sh_size/sizeof(Elf32_Sym); j++) {
++                      Elf32_Sym *sym = &sec->symtab[j];
++                      sym->st_name  = elf32_to_cpu(sym->st_name);
++                      sym->st_value = elf32_to_cpu(sym->st_value);
++                      sym->st_size  = elf32_to_cpu(sym->st_size);
++                      sym->st_shndx = elf16_to_cpu(sym->st_shndx);
++              }
++      }
++}
++
++
++static void read_relocs(FILE *fp)
++{
++      int i,j;
++      for (i = 0; i < ehdr.e_shnum; i++) {
++              struct section *sec = &secs[i];
++              if (sec->shdr.sh_type != SHT_REL) {
++                      continue;
++              }
++              sec->reltab = malloc(sec->shdr.sh_size);
++              if (!sec->reltab) {
++                      die("malloc of %d bytes for relocs failed\n",
++                              sec->shdr.sh_size);
++              }
++              if (fseek(fp, sec->shdr.sh_offset, SEEK_SET) < 0) {
++                      die("Seek to %d failed: %s\n",
++                              sec->shdr.sh_offset, strerror(errno));
++              }
++              if (fread(sec->reltab, 1, sec->shdr.sh_size, fp)
++                  != sec->shdr.sh_size) {
++                      die("Cannot read symbol table: %s\n",
++                              strerror(errno));
++              }
++              for (j = 0; j < sec->shdr.sh_size/sizeof(Elf32_Rel); j++) {
++                      Elf32_Rel *rel = &sec->reltab[j];
++                      rel->r_offset = elf32_to_cpu(rel->r_offset);
++                      rel->r_info   = elf32_to_cpu(rel->r_info);
++              }
++      }
++}
++
++
++static void print_absolute_symbols(void)
++{
++      int i;
++      printf("Absolute symbols\n");
++      printf(" Num:    Value Size  Type       Bind        Visibility  Name\n");
++      for (i = 0; i < ehdr.e_shnum; i++) {
++              struct section *sec = &secs[i];
++              char *sym_strtab;
++              int j;
++
++              if (sec->shdr.sh_type != SHT_SYMTAB) {
++                      continue;
++              }
++              sym_strtab = sec->link->strtab;
++              for (j = 0; j < sec->shdr.sh_size/sizeof(Elf32_Sym); j++) {
++                      Elf32_Sym *sym;
++                      const char *name;
++                      sym = &sec->symtab[j];
++                      name = sym_name(sym_strtab, sym);
++                      if (sym->st_shndx != SHN_ABS) {
++                              continue;
++                      }
++                      printf("%5d %08x %5d %10s %10s %12s %s\n",
++                              j, sym->st_value, sym->st_size,
++                              sym_type(ELF32_ST_TYPE(sym->st_info)),
++                              sym_bind(ELF32_ST_BIND(sym->st_info)),
++                              sym_visibility(ELF32_ST_VISIBILITY(sym->st_other)),
++                              name);
++              }
++      }
++      printf("\n");
++}
++
++static void print_absolute_relocs(void)
++{
++      int i, printed = 0;
++
++      for (i = 0; i < ehdr.e_shnum; i++) {
++              struct section *sec = &secs[i];
++              struct section *sec_applies, *sec_symtab;
++              char *sym_strtab;
++              Elf32_Sym *sh_symtab;
++              int j;
++              if (sec->shdr.sh_type != SHT_REL) {
++                      continue;
++              }
++              sec_symtab  = sec->link;
++              sec_applies = &secs[sec->shdr.sh_info];
++              if (!(sec_applies->shdr.sh_flags & SHF_ALLOC)) {
++                      continue;
++              }
++              sh_symtab  = sec_symtab->symtab;
++              sym_strtab = sec_symtab->link->strtab;
++              for (j = 0; j < sec->shdr.sh_size/sizeof(Elf32_Rel); j++) {
++                      Elf32_Rel *rel;
++                      Elf32_Sym *sym;
++                      const char *name;
++                      rel = &sec->reltab[j];
++                      sym = &sh_symtab[ELF32_R_SYM(rel->r_info)];
++                      name = sym_name(sym_strtab, sym);
++                      if (sym->st_shndx != SHN_ABS) {
++                              continue;
++                      }
++
++                      /* Absolute symbols are not relocated if bzImage is
++                       * loaded at a non-compiled address. Display a warning
++                       * to user at compile time about the absolute
++                       * relocations present.
++                       *
++                       * User need to audit the code to make sure
++                       * some symbols which should have been section
++                       * relative have not become absolute because of some
++                       * linker optimization or wrong programming usage.
++                       *
++                       * Before warning check if this absolute symbol
++                       * relocation is harmless.
++                       */
++                      if (is_reloc(S_ABS, name) || is_reloc(S_REL, name))
++                              continue;
++
++                      if (!printed) {
++                              printf("WARNING: Absolute relocations"
++                                      " present\n");
++                              printf("Offset     Info     Type     Sym.Value "
++                                      "Sym.Name\n");
++                              printed = 1;
++                      }
++
++                      printf("%08x %08x %10s %08x  %s\n",
++                              rel->r_offset,
++                              rel->r_info,
++                              rel_type(ELF32_R_TYPE(rel->r_info)),
++                              sym->st_value,
++                              name);
++              }
++      }
++
++      if (printed)
++              printf("\n");
++}
++
++static void walk_relocs(void (*visit)(Elf32_Rel *rel, Elf32_Sym *sym),
++                      int use_real_mode)
++{
++      int i;
++      /* Walk through the relocations */
++      for (i = 0; i < ehdr.e_shnum; i++) {
++              char *sym_strtab;
++              Elf32_Sym *sh_symtab;
++              struct section *sec_applies, *sec_symtab;
++              int j;
++              struct section *sec = &secs[i];
++
++              if (sec->shdr.sh_type != SHT_REL) {
++                      continue;
++              }
++              sec_symtab  = sec->link;
++              sec_applies = &secs[sec->shdr.sh_info];
++              if (!(sec_applies->shdr.sh_flags & SHF_ALLOC)) {
++                      continue;
++              }
++              sh_symtab = sec_symtab->symtab;
++              sym_strtab = sec_symtab->link->strtab;
++              for (j = 0; j < sec->shdr.sh_size/sizeof(Elf32_Rel); j++) {
++                      Elf32_Rel *rel;
++                      Elf32_Sym *sym;
++                      unsigned r_type;
++                      const char *symname;
++                      rel = &sec->reltab[j];
++                      sym = &sh_symtab[ELF32_R_SYM(rel->r_info)];
++                      r_type = ELF32_R_TYPE(rel->r_info);
++
++                      switch (r_type) {
++                      case R_386_NONE:
++                      case R_386_PC32:
++                      case R_386_PC16:
++                      case R_386_PC8:
++                              /*
++                               * NONE can be ignored and and PC relative
++                               * relocations don't need to be adjusted.
++                               */
++                              break;
++
++                      case R_386_16:
++                              symname = sym_name(sym_strtab, sym);
++                              if (!use_real_mode)
++                                      goto bad;
++                              if (sym->st_shndx == SHN_ABS) {
++                                      if (is_reloc(S_ABS, symname))
++                                              break;
++                                      else if (!is_reloc(S_SEG, symname))
++                                              goto bad;
++                              } else {
++                                      if (is_reloc(S_LIN, symname))
++                                              goto bad;
++                                      else
++                                              break;
++                              }
++                              visit(rel, sym);
++                              break;
++
++                      case R_386_32:
++                              symname = sym_name(sym_strtab, sym);
++                              if (sym->st_shndx == SHN_ABS) {
++                                      if (is_reloc(S_ABS, symname))
++                                              break;
++                                      else if (!is_reloc(S_REL, symname))
++                                              goto bad;
++                              } else {
++                                      if (use_real_mode &&
++                                          !is_reloc(S_LIN, symname))
++                                              break;
++                              }
++                              visit(rel, sym);
++                              break;
++                      default:
++                              die("Unsupported relocation type: %s (%d)\n",
++                                  rel_type(r_type), r_type);
++                              break;
++                      bad:
++                              symname = sym_name(sym_strtab, sym);
++                              die("Invalid %s relocation: %s\n",
++                                  rel_type(r_type), symname);
++                      }
++              }
++      }
++}
++
++static void count_reloc(Elf32_Rel *rel, Elf32_Sym *sym)
++{
++      if (ELF32_R_TYPE(rel->r_info) == R_386_16)
++              reloc16_count++;
++      else
++              reloc_count++;
++}
++
++static void collect_reloc(Elf32_Rel *rel, Elf32_Sym *sym)
++{
++      /* Remember the address that needs to be adjusted. */
++      if (ELF32_R_TYPE(rel->r_info) == R_386_16)
++              relocs16[reloc16_idx++] = rel->r_offset;
++      else
++              relocs[reloc_idx++] = rel->r_offset;
++}
++
++static int cmp_relocs(const void *va, const void *vb)
++{
++      const unsigned long *a, *b;
++      a = va; b = vb;
++      return (*a == *b)? 0 : (*a > *b)? 1 : -1;
++}
++
++static int write32(unsigned int v, FILE *f)
++{
++      unsigned char buf[4];
++
++      put_unaligned_le32(v, buf);
++      return fwrite(buf, 1, 4, f) == 4 ? 0 : -1;
++}
++
++static void emit_relocs(int as_text, int use_real_mode)
++{
++      int i;
++      /* Count how many relocations I have and allocate space for them. */
++      reloc_count = 0;
++      walk_relocs(count_reloc, use_real_mode);
++      relocs = malloc(reloc_count * sizeof(relocs[0]));
++      if (!relocs) {
++              die("malloc of %d entries for relocs failed\n",
++                      reloc_count);
++      }
++
++      relocs16 = malloc(reloc16_count * sizeof(relocs[0]));
++      if (!relocs16) {
++              die("malloc of %d entries for relocs16 failed\n",
++                      reloc16_count);
++      }
++      /* Collect up the relocations */
++      reloc_idx = 0;
++      walk_relocs(collect_reloc, use_real_mode);
++
++      if (reloc16_count && !use_real_mode)
++              die("Segment relocations found but --realmode not specified\n");
++
++      /* Order the relocations for more efficient processing */
++      qsort(relocs, reloc_count, sizeof(relocs[0]), cmp_relocs);
++      qsort(relocs16, reloc16_count, sizeof(relocs16[0]), cmp_relocs);
++
++      /* Print the relocations */
++      if (as_text) {
++              /* Print the relocations in a form suitable that
++               * gas will like.
++               */
++              printf(".section \".data.reloc\",\"a\"\n");
++              printf(".balign 4\n");
++              if (use_real_mode) {
++                      printf("\t.long %lu\n", reloc16_count);
++                      for (i = 0; i < reloc16_count; i++)
++                              printf("\t.long 0x%08lx\n", relocs16[i]);
++                      printf("\t.long %lu\n", reloc_count);
++                      for (i = 0; i < reloc_count; i++) {
++                              printf("\t.long 0x%08lx\n", relocs[i]);
++                      }
++              } else {
++                      /* Print a stop */
++                      printf("\t.long 0x%08lx\n", (unsigned long)0);
++                      for (i = 0; i < reloc_count; i++) {
++                              printf("\t.long 0x%08lx\n", relocs[i]);
++                      }
++              }
++
++              printf("\n");
++      }
++      else {
++              if (use_real_mode) {
++                      write32(reloc16_count, stdout);
++                      for (i = 0; i < reloc16_count; i++)
++                              write32(relocs16[i], stdout);
++                      write32(reloc_count, stdout);
++
++                      /* Now print each relocation */
++                      for (i = 0; i < reloc_count; i++)
++                              write32(relocs[i], stdout);
++              } else {
++                      /* Print a stop */
++                      write32(0, stdout);
++
++                      /* Now print each relocation */
++                      for (i = 0; i < reloc_count; i++) {
++                              write32(relocs[i], stdout);
++                      }
++              }
++      }
++}
++
++static void usage(void)
++{
++      die("relocs [--abs-syms|--abs-relocs|--text|--realmode] vmlinux\n");
++}
++
++int main(int argc, char **argv)
++{
++      int show_absolute_syms, show_absolute_relocs;
++      int as_text, use_real_mode;
++      const char *fname;
++      FILE *fp;
++      int i;
++
++      show_absolute_syms = 0;
++      show_absolute_relocs = 0;
++      as_text = 0;
++      use_real_mode = 0;
++      fname = NULL;
++      for (i = 1; i < argc; i++) {
++              char *arg = argv[i];
++              if (*arg == '-') {
++                      if (strcmp(arg, "--abs-syms") == 0) {
++                              show_absolute_syms = 1;
++                              continue;
++                      }
++                      if (strcmp(arg, "--abs-relocs") == 0) {
++                              show_absolute_relocs = 1;
++                              continue;
++                      }
++                      if (strcmp(arg, "--text") == 0) {
++                              as_text = 1;
++                              continue;
++                      }
++                      if (strcmp(arg, "--realmode") == 0) {
++                              use_real_mode = 1;
++                              continue;
++                      }
++              }
++              else if (!fname) {
++                      fname = arg;
++                      continue;
++              }
++              usage();
++      }
++      if (!fname) {
++              usage();
++      }
++      regex_init(use_real_mode);
++      fp = fopen(fname, "r");
++      if (!fp) {
++              die("Cannot open %s: %s\n",
++                      fname, strerror(errno));
++      }
++      read_ehdr(fp);
++      read_shdrs(fp);
++      read_strtabs(fp);
++      read_symtabs(fp);
++      read_relocs(fp);
++      if (show_absolute_syms) {
++              print_absolute_symbols();
++              return 0;
++      }
++      if (show_absolute_relocs) {
++              print_absolute_relocs();
++              return 0;
++      }
++      emit_relocs(as_text, use_real_mode);
++      return 0;
++}
+--- a/scripts/Makefile
++++ b/scripts/Makefile
+@@ -8,6 +8,8 @@
+ # conmakehash:         Create arrays for initializing the kernel console tables
+ # docproc:       Used in Documentation/DocBook
++HOST_EXTRACFLAGS += -I$(srctree)/tools/include
++
+ hostprogs-$(CONFIG_KALLSYMS)     += kallsyms
+ hostprogs-$(CONFIG_LOGO)         += pnmtologo
+ hostprogs-$(CONFIG_VT)           += conmakehash
diff --git a/queue-3.3/x86-relocs-add-jiffies-and-jiffies_64-to-the-relative-whitelist.patch b/queue-3.3/x86-relocs-add-jiffies-and-jiffies_64-to-the-relative-whitelist.patch
new file mode 100644 (file)
index 0000000..dbc5849
--- /dev/null
@@ -0,0 +1,39 @@
+From ea17e7414bc62e8d3bde8d08e3df1d921c518c17 Mon Sep 17 00:00:00 2001
+From: "H. Peter Anvin" <hpa@zytor.com>
+Date: Thu, 24 May 2012 07:01:38 -0700
+Subject: x86, relocs: Add jiffies and jiffies_64 to the relative whitelist
+
+From: "H. Peter Anvin" <hpa@zytor.com>
+
+commit ea17e7414bc62e8d3bde8d08e3df1d921c518c17 upstream.
+
+The symbol jiffies is created in the linker script as an alias to
+jiffies_64.  Unfortunately this is done outside any section, and
+apparently GNU ld 2.21 doesn't carry the section with it, so we end up
+with an absolute symbol and therefore a broken kernel.
+
+Add jiffies and jiffies_64 to the whitelist.
+
+The most disturbing bit with this discovery is that it shows that we
+have had multiple linker bugs in this area crossing multiple
+generations, and have been silently building bad kernels for some time.
+
+Link: http://lkml.kernel.org/r/20120524171604.0d98284f3affc643e9714470@canb.auug.org.au
+Reported-by: Stephen Rothwell <sfr@canb.auug.org.au>
+Signed-off-by: H. Peter Anvin <hpa@zytor.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ arch/x86/tools/relocs.c |    1 +
+ 1 file changed, 1 insertion(+)
+
+--- a/arch/x86/tools/relocs.c
++++ b/arch/x86/tools/relocs.c
+@@ -71,6 +71,7 @@ static const char * const sym_regex_kern
+       "__(start|stop)_notes|"
+       "__end_rodata|"
+       "__initramfs_start|"
++      "(jiffies|jiffies_64)|"
+       "_end)$"
+ };
diff --git a/queue-3.3/x86-relocs-build-clean-fix.patch b/queue-3.3/x86-relocs-build-clean-fix.patch
new file mode 100644 (file)
index 0000000..63369bf
--- /dev/null
@@ -0,0 +1,31 @@
+From b2d668da9307c4c163dd603d2bb3cadb10f9fd37 Mon Sep 17 00:00:00 2001
+From: Jarkko Sakkinen <jarkko.sakkinen@intel.com>
+Date: Mon, 21 May 2012 20:51:24 +0300
+Subject: x86, relocs: Build clean fix
+
+From: Jarkko Sakkinen <jarkko.sakkinen@intel.com>
+
+commit b2d668da9307c4c163dd603d2bb3cadb10f9fd37 upstream.
+
+relocs was not cleaned up when "make clean" is issued. This
+patch fixes the issue.
+
+Signed-off-by: Jarkko Sakkinen <jarkko.sakkinen@intel.com>
+Link: http://lkml.kernel.org/r/1337622684-6834-1-git-send-email-jarkko.sakkinen@intel.com
+Signed-off-by: H. Peter Anvin <hpa@zytor.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ arch/x86/Makefile |    1 +
+ 1 file changed, 1 insertion(+)
+
+--- a/arch/x86/Makefile
++++ b/arch/x86/Makefile
+@@ -189,6 +189,7 @@ archclean:
+       $(Q)rm -rf $(objtree)/arch/i386
+       $(Q)rm -rf $(objtree)/arch/x86_64
+       $(Q)$(MAKE) $(clean)=$(boot)
++      $(Q)$(MAKE) $(clean)=arch/x86/tools
+ define archhelp
+   echo  '* bzImage      - Compressed kernel image (arch/x86/boot/bzImage)'
diff --git a/queue-3.3/x86-relocs-when-printing-an-error-say-relative-or-absolute.patch b/queue-3.3/x86-relocs-when-printing-an-error-say-relative-or-absolute.patch
new file mode 100644 (file)
index 0000000..48104aa
--- /dev/null
@@ -0,0 +1,66 @@
+From 24ab82bd9bf18f3efc69a131d73577940941e1b7 Mon Sep 17 00:00:00 2001
+From: "H. Peter Anvin" <hpa@linux.intel.com>
+Date: Fri, 18 May 2012 09:52:01 -0700
+Subject: x86, relocs: When printing an error, say relative or absolute
+
+From: "H. Peter Anvin" <hpa@linux.intel.com>
+
+commit 24ab82bd9bf18f3efc69a131d73577940941e1b7 upstream.
+
+When the relocs tool throws an error, let the error message say if it
+is an absolute or relative symbol.  This should make it a lot more
+clear what action the programmer needs to take and should help us find
+the reason if additional symbol bugs show up.
+
+Signed-off-by: H. Peter Anvin <hpa@zytor.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ arch/x86/tools/relocs.c |   11 ++++++++---
+ 1 file changed, 8 insertions(+), 3 deletions(-)
+
+--- a/arch/x86/tools/relocs.c
++++ b/arch/x86/tools/relocs.c
+@@ -563,10 +563,14 @@ static void walk_relocs(void (*visit)(El
+                       Elf32_Sym *sym;
+                       unsigned r_type;
+                       const char *symname;
++                      int shn_abs;
++
+                       rel = &sec->reltab[j];
+                       sym = &sh_symtab[ELF32_R_SYM(rel->r_info)];
+                       r_type = ELF32_R_TYPE(rel->r_info);
++                      shn_abs = sym->st_shndx == SHN_ABS;
++
+                       switch (r_type) {
+                       case R_386_NONE:
+                       case R_386_PC32:
+@@ -582,7 +586,7 @@ static void walk_relocs(void (*visit)(El
+                               symname = sym_name(sym_strtab, sym);
+                               if (!use_real_mode)
+                                       goto bad;
+-                              if (sym->st_shndx == SHN_ABS) {
++                              if (shn_abs) {
+                                       if (is_reloc(S_ABS, symname))
+                                               break;
+                                       else if (!is_reloc(S_SEG, symname))
+@@ -598,7 +602,7 @@ static void walk_relocs(void (*visit)(El
+                       case R_386_32:
+                               symname = sym_name(sym_strtab, sym);
+-                              if (sym->st_shndx == SHN_ABS) {
++                              if (shn_abs) {
+                                       if (is_reloc(S_ABS, symname))
+                                               break;
+                                       else if (!is_reloc(S_REL, symname))
+@@ -616,7 +620,8 @@ static void walk_relocs(void (*visit)(El
+                               break;
+                       bad:
+                               symname = sym_name(sym_strtab, sym);
+-                              die("Invalid %s relocation: %s\n",
++                              die("Invalid %s %s relocation: %s\n",
++                                  shn_abs ? "absolute" : "relative",
+                                   rel_type(r_type), symname);
+                       }
+               }
diff --git a/queue-3.3/x86-relocs-workaround-for-binutils-2.22.52.0.1-section-bug.patch b/queue-3.3/x86-relocs-workaround-for-binutils-2.22.52.0.1-section-bug.patch
new file mode 100644 (file)
index 0000000..35a0f88
--- /dev/null
@@ -0,0 +1,40 @@
+From a3e854d95a76862cd37937e0b0438f540536771a Mon Sep 17 00:00:00 2001
+From: "H. Peter Anvin" <hpa@linux.intel.com>
+Date: Fri, 18 May 2012 00:24:09 -0700
+Subject: x86, relocs: Workaround for binutils 2.22.52.0.1 section bug
+
+From: "H. Peter Anvin" <hpa@linux.intel.com>
+
+commit a3e854d95a76862cd37937e0b0438f540536771a upstream.
+
+GNU ld 2.22.52.0.1 has a bug that it blindly changes symbols from
+section-relative to absolute if they are in a section of zero length.
+This turns the symbols __init_begin and __init_end into absolute
+symbols.  Let the relocs program know that those should be treated as
+relative symbols.
+
+Reported-by: Ingo Molnar <mingo@kernel.org>
+Signed-off-by: H. Peter Anvin <hpa@zytor.com>
+Cc: H.J. Lu <hjl.tools@gmail.com>
+Cc: Jarkko Sakkinen <jarkko.sakkinen@intel.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ arch/x86/tools/relocs.c |    6 +++++-
+ 1 file changed, 5 insertions(+), 1 deletion(-)
+
+--- a/arch/x86/tools/relocs.c
++++ b/arch/x86/tools/relocs.c
+@@ -56,7 +56,11 @@ static const char * const sym_regex_kern
+  * as absolute (typically defined outside any section in the linker script.)
+  */
+       [S_REL] =
+-      "^_end$",
++      "^(__init_(begin|end)|"
++      "__x86_cpu_dev_(start|end)|"
++      "(__parainstructions|__alt_instructions)(|_end)|"
++      "(__iommu_table|__apicdrivers|__smp_locks)(|_end)|"
++      "_end)$"
+ };