]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/commitdiff
3.3-stable patches
authorGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Thu, 24 May 2012 05:05:51 +0000 (22:05 -0700)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Thu, 24 May 2012 05:05:51 +0000 (22:05 -0700)
added patches:
bio-allocation-failure-due-to-bio_get_nr_vecs.patch
block-don-t-mark-buffers-beyond-end-of-disk-as-mapped.patch
block-fix-buffer-overflow-when-printing-partition-uuids.patch
parisc-fix-crash-in-flush_icache_page_asm-on-pa1.1.patch
parisc-fix-pa1.1-oops-on-boot.patch
parisc-fix-panic-on-prefetch-null-on-pa7300lc.patch
tilegx-enable-syscall_wrappers-support.patch
x86-realmode-16-bit-real-mode-code-support-for-relocs-tool.patch

queue-3.3/bio-allocation-failure-due-to-bio_get_nr_vecs.patch [new file with mode: 0644]
queue-3.3/block-don-t-mark-buffers-beyond-end-of-disk-as-mapped.patch [new file with mode: 0644]
queue-3.3/block-fix-buffer-overflow-when-printing-partition-uuids.patch [new file with mode: 0644]
queue-3.3/parisc-fix-crash-in-flush_icache_page_asm-on-pa1.1.patch [new file with mode: 0644]
queue-3.3/parisc-fix-pa1.1-oops-on-boot.patch [new file with mode: 0644]
queue-3.3/parisc-fix-panic-on-prefetch-null-on-pa7300lc.patch [new file with mode: 0644]
queue-3.3/series [new file with mode: 0644]
queue-3.3/tilegx-enable-syscall_wrappers-support.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]

diff --git a/queue-3.3/bio-allocation-failure-due-to-bio_get_nr_vecs.patch b/queue-3.3/bio-allocation-failure-due-to-bio_get_nr_vecs.patch
new file mode 100644 (file)
index 0000000..b171244
--- /dev/null
@@ -0,0 +1,47 @@
+From f908ee9463b09ddd05e1c1a0111132212dc05fac Mon Sep 17 00:00:00 2001
+From: Bernd Schubert <bernd.schubert@itwm.fraunhofer.de>
+Date: Fri, 11 May 2012 16:36:44 +0200
+Subject: bio allocation failure due to bio_get_nr_vecs()
+
+From: Bernd Schubert <bernd.schubert@itwm.fraunhofer.de>
+
+commit f908ee9463b09ddd05e1c1a0111132212dc05fac upstream.
+
+The number of bio_get_nr_vecs() is passed down via bio_alloc() to
+bvec_alloc_bs(), which fails the bio allocation if
+nr_iovecs > BIO_MAX_PAGES. For the underlying caller this causes an
+unexpected bio allocation failure.
+Limiting to queue_max_segments() is not sufficient, as max_segments
+also might be very large.
+
+bvec_alloc_bs(gfp_mask, nr_iovecs, ) => NULL when nr_iovecs  > BIO_MAX_PAGES
+bio_alloc_bioset(gfp_mask, nr_iovecs, ...)
+bio_alloc(GFP_NOIO, nvecs)
+xfs_alloc_ioend_bio()
+
+Signed-off-by: Bernd Schubert <bernd.schubert@itwm.fraunhofer.de>
+Signed-off-by: Jens Axboe <axboe@kernel.dk>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ fs/bio.c |    7 ++++++-
+ 1 file changed, 6 insertions(+), 1 deletion(-)
+
+--- a/fs/bio.c
++++ b/fs/bio.c
+@@ -505,9 +505,14 @@ EXPORT_SYMBOL(bio_clone);
+ int bio_get_nr_vecs(struct block_device *bdev)
+ {
+       struct request_queue *q = bdev_get_queue(bdev);
+-      return min_t(unsigned,
++      int nr_pages;
++
++      nr_pages = min_t(unsigned,
+                    queue_max_segments(q),
+                    queue_max_sectors(q) / (PAGE_SIZE >> 9) + 1);
++
++      return min_t(unsigned, nr_pages, BIO_MAX_PAGES);
++
+ }
+ EXPORT_SYMBOL(bio_get_nr_vecs);
diff --git a/queue-3.3/block-don-t-mark-buffers-beyond-end-of-disk-as-mapped.patch b/queue-3.3/block-don-t-mark-buffers-beyond-end-of-disk-as-mapped.patch
new file mode 100644 (file)
index 0000000..2b3b69c
--- /dev/null
@@ -0,0 +1,150 @@
+From 080399aaaf3531f5b8761ec0ac30ff98891e8686 Mon Sep 17 00:00:00 2001
+From: Jeff Moyer <jmoyer@redhat.com>
+Date: Fri, 11 May 2012 16:34:10 +0200
+Subject: block: don't mark buffers beyond end of disk as mapped
+
+From: Jeff Moyer <jmoyer@redhat.com>
+
+commit 080399aaaf3531f5b8761ec0ac30ff98891e8686 upstream.
+
+Hi,
+
+We have a bug report open where a squashfs image mounted on ppc64 would
+exhibit errors due to trying to read beyond the end of the disk.  It can
+easily be reproduced by doing the following:
+
+[root@ibm-p750e-02-lp3 ~]# ls -l install.img
+-rw-r--r-- 1 root root 142032896 Apr 30 16:46 install.img
+[root@ibm-p750e-02-lp3 ~]# mount -o loop ./install.img /mnt/test
+[root@ibm-p750e-02-lp3 ~]# dd if=/dev/loop0 of=/dev/null
+dd: reading `/dev/loop0': Input/output error
+277376+0 records in
+277376+0 records out
+142016512 bytes (142 MB) copied, 0.9465 s, 150 MB/s
+
+In dmesg, you'll find the following:
+
+squashfs: version 4.0 (2009/01/31) Phillip Lougher
+[   43.106012] attempt to access beyond end of device
+[   43.106029] loop0: rw=0, want=277410, limit=277408
+[   43.106039] Buffer I/O error on device loop0, logical block 138704
+[   43.106053] attempt to access beyond end of device
+[   43.106057] loop0: rw=0, want=277412, limit=277408
+[   43.106061] Buffer I/O error on device loop0, logical block 138705
+[   43.106066] attempt to access beyond end of device
+[   43.106070] loop0: rw=0, want=277414, limit=277408
+[   43.106073] Buffer I/O error on device loop0, logical block 138706
+[   43.106078] attempt to access beyond end of device
+[   43.106081] loop0: rw=0, want=277416, limit=277408
+[   43.106085] Buffer I/O error on device loop0, logical block 138707
+[   43.106089] attempt to access beyond end of device
+[   43.106093] loop0: rw=0, want=277418, limit=277408
+[   43.106096] Buffer I/O error on device loop0, logical block 138708
+[   43.106101] attempt to access beyond end of device
+[   43.106104] loop0: rw=0, want=277420, limit=277408
+[   43.106108] Buffer I/O error on device loop0, logical block 138709
+[   43.106112] attempt to access beyond end of device
+[   43.106116] loop0: rw=0, want=277422, limit=277408
+[   43.106120] Buffer I/O error on device loop0, logical block 138710
+[   43.106124] attempt to access beyond end of device
+[   43.106128] loop0: rw=0, want=277424, limit=277408
+[   43.106131] Buffer I/O error on device loop0, logical block 138711
+[   43.106135] attempt to access beyond end of device
+[   43.106139] loop0: rw=0, want=277426, limit=277408
+[   43.106143] Buffer I/O error on device loop0, logical block 138712
+[   43.106147] attempt to access beyond end of device
+[   43.106151] loop0: rw=0, want=277428, limit=277408
+[   43.106154] Buffer I/O error on device loop0, logical block 138713
+[   43.106158] attempt to access beyond end of device
+[   43.106162] loop0: rw=0, want=277430, limit=277408
+[   43.106166] attempt to access beyond end of device
+[   43.106169] loop0: rw=0, want=277432, limit=277408
+...
+[   43.106307] attempt to access beyond end of device
+[   43.106311] loop0: rw=0, want=277470, limit=2774
+
+Squashfs manages to read in the end block(s) of the disk during the
+mount operation.  Then, when dd reads the block device, it leads to
+block_read_full_page being called with buffers that are beyond end of
+disk, but are marked as mapped.  Thus, it would end up submitting read
+I/O against them, resulting in the errors mentioned above.  I fixed the
+problem by modifying init_page_buffers to only set the buffer mapped if
+it fell inside of i_size.
+
+Cheers,
+Jeff
+
+Signed-off-by: Jeff Moyer <jmoyer@redhat.com>
+Acked-by: Nick Piggin <npiggin@kernel.dk>
+
+--
+
+Changes from v1->v2: re-used max_block, as suggested by Nick Piggin.
+Signed-off-by: Jens Axboe <axboe@kernel.dk>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ fs/block_dev.c     |    6 +++---
+ fs/buffer.c        |    4 +++-
+ include/linux/fs.h |    1 +
+ 3 files changed, 7 insertions(+), 4 deletions(-)
+
+--- a/fs/block_dev.c
++++ b/fs/block_dev.c
+@@ -69,7 +69,7 @@ static void bdev_inode_switch_bdi(struct
+       spin_unlock(&dst->wb.list_lock);
+ }
+-static sector_t max_block(struct block_device *bdev)
++sector_t blkdev_max_block(struct block_device *bdev)
+ {
+       sector_t retval = ~((sector_t)0);
+       loff_t sz = i_size_read(bdev->bd_inode);
+@@ -162,7 +162,7 @@ static int
+ blkdev_get_block(struct inode *inode, sector_t iblock,
+               struct buffer_head *bh, int create)
+ {
+-      if (iblock >= max_block(I_BDEV(inode))) {
++      if (iblock >= blkdev_max_block(I_BDEV(inode))) {
+               if (create)
+                       return -EIO;
+@@ -184,7 +184,7 @@ static int
+ blkdev_get_blocks(struct inode *inode, sector_t iblock,
+               struct buffer_head *bh, int create)
+ {
+-      sector_t end_block = max_block(I_BDEV(inode));
++      sector_t end_block = blkdev_max_block(I_BDEV(inode));
+       unsigned long max_blocks = bh->b_size >> inode->i_blkbits;
+       if ((iblock + max_blocks) > end_block) {
+--- a/fs/buffer.c
++++ b/fs/buffer.c
+@@ -921,6 +921,7 @@ init_page_buffers(struct page *page, str
+       struct buffer_head *head = page_buffers(page);
+       struct buffer_head *bh = head;
+       int uptodate = PageUptodate(page);
++      sector_t end_block = blkdev_max_block(I_BDEV(bdev->bd_inode));
+       do {
+               if (!buffer_mapped(bh)) {
+@@ -929,7 +930,8 @@ init_page_buffers(struct page *page, str
+                       bh->b_blocknr = block;
+                       if (uptodate)
+                               set_buffer_uptodate(bh);
+-                      set_buffer_mapped(bh);
++                      if (block < end_block)
++                              set_buffer_mapped(bh);
+               }
+               block++;
+               bh = bh->b_this_page;
+--- a/include/linux/fs.h
++++ b/include/linux/fs.h
+@@ -2058,6 +2058,7 @@ extern void unregister_blkdev(unsigned i
+ extern struct block_device *bdget(dev_t);
+ extern struct block_device *bdgrab(struct block_device *bdev);
+ extern void bd_set_size(struct block_device *, loff_t size);
++extern sector_t blkdev_max_block(struct block_device *bdev);
+ extern void bd_forget(struct inode *inode);
+ extern void bdput(struct block_device *);
+ extern void invalidate_bdev(struct block_device *);
diff --git a/queue-3.3/block-fix-buffer-overflow-when-printing-partition-uuids.patch b/queue-3.3/block-fix-buffer-overflow-when-printing-partition-uuids.patch
new file mode 100644 (file)
index 0000000..deb6a3a
--- /dev/null
@@ -0,0 +1,93 @@
+From 05c69d298c96703741cac9a5cbbf6c53bd55a6e2 Mon Sep 17 00:00:00 2001
+From: Tejun Heo <tj@kernel.org>
+Date: Tue, 15 May 2012 08:22:04 +0200
+Subject: block: fix buffer overflow when printing partition UUIDs
+
+From: Tejun Heo <tj@kernel.org>
+
+commit 05c69d298c96703741cac9a5cbbf6c53bd55a6e2 upstream.
+
+6d1d8050b4bc8 "block, partition: add partition_meta_info to hd_struct"
+added part_unpack_uuid() which assumes that the passed in buffer has
+enough space for sprintfing "%pU" - 37 characters including '\0'.
+
+Unfortunately, b5af921ec0233 "init: add support for root devices
+specified by partition UUID" supplied 33 bytes buffer to the function
+leading to the following panic with stackprotector enabled.
+
+  Kernel panic - not syncing: stack-protector: Kernel stack corrupted in: ffffffff81b14c7e
+
+  [<ffffffff815e226b>] panic+0xba/0x1c6
+  [<ffffffff81b14c7e>] ? printk_all_partitions+0x259/0x26xb
+  [<ffffffff810566bb>] __stack_chk_fail+0x1b/0x20
+  [<ffffffff81b15c7e>] printk_all_paritions+0x259/0x26xb
+  [<ffffffff81aedfe0>] mount_block_root+0x1bc/0x27f
+  [<ffffffff81aee0fa>] mount_root+0x57/0x5b
+  [<ffffffff81aee23b>] prepare_namespace+0x13d/0x176
+  [<ffffffff8107eec0>] ? release_tgcred.isra.4+0x330/0x30
+  [<ffffffff81aedd60>] kernel_init+0x155/0x15a
+  [<ffffffff81087b97>] ? schedule_tail+0x27/0xb0
+  [<ffffffff815f4d24>] kernel_thread_helper+0x5/0x10
+  [<ffffffff81aedc0b>] ? start_kernel+0x3c5/0x3c5
+  [<ffffffff815f4d20>] ? gs_change+0x13/0x13
+
+Increase the buffer size, remove the dangerous part_unpack_uuid() and
+use snprintf() directly from printk_all_partitions().
+
+Signed-off-by: Tejun Heo <tj@kernel.org>
+Reported-by: Szymon Gruszczynski <sz.gruszczynski@googlemail.com>
+Cc: Will Drewry <wad@chromium.org>
+Signed-off-by: Jens Axboe <axboe@kernel.dk>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ block/genhd.c         |   10 ++++++----
+ include/linux/genhd.h |    6 ------
+ 2 files changed, 6 insertions(+), 10 deletions(-)
+
+--- a/block/genhd.c
++++ b/block/genhd.c
+@@ -743,7 +743,7 @@ void __init printk_all_partitions(void)
+               struct hd_struct *part;
+               char name_buf[BDEVNAME_SIZE];
+               char devt_buf[BDEVT_SIZE];
+-              u8 uuid[PARTITION_META_INFO_UUIDLTH * 2 + 1];
++              char uuid_buf[PARTITION_META_INFO_UUIDLTH * 2 + 5];
+               /*
+                * Don't show empty devices or things that have been
+@@ -762,14 +762,16 @@ void __init printk_all_partitions(void)
+               while ((part = disk_part_iter_next(&piter))) {
+                       bool is_part0 = part == &disk->part0;
+-                      uuid[0] = 0;
++                      uuid_buf[0] = '\0';
+                       if (part->info)
+-                              part_unpack_uuid(part->info->uuid, uuid);
++                              snprintf(uuid_buf, sizeof(uuid_buf), "%pU",
++                                       part->info->uuid);
+                       printk("%s%s %10llu %s %s", is_part0 ? "" : "  ",
+                              bdevt_str(part_devt(part), devt_buf),
+                              (unsigned long long)part->nr_sects >> 1,
+-                             disk_name(disk, part->partno, name_buf), uuid);
++                             disk_name(disk, part->partno, name_buf),
++                             uuid_buf);
+                       if (is_part0) {
+                               if (disk->driverfs_dev != NULL &&
+                                   disk->driverfs_dev->driver != NULL)
+--- a/include/linux/genhd.h
++++ b/include/linux/genhd.h
+@@ -222,12 +222,6 @@ static inline void part_pack_uuid(const
+       }
+ }
+-static inline char *part_unpack_uuid(const u8 *uuid, char *out)
+-{
+-      sprintf(out, "%pU", uuid);
+-      return out;
+-}
+-
+ static inline int disk_max_parts(struct gendisk *disk)
+ {
+       if (disk->flags & GENHD_FL_EXT_DEVT)
diff --git a/queue-3.3/parisc-fix-crash-in-flush_icache_page_asm-on-pa1.1.patch b/queue-3.3/parisc-fix-crash-in-flush_icache_page_asm-on-pa1.1.patch
new file mode 100644 (file)
index 0000000..c838377
--- /dev/null
@@ -0,0 +1,89 @@
+From 207f583d7179f707f402c36a7bda5ca1fd03ad5b Mon Sep 17 00:00:00 2001
+From: John David Anglin <dave.anglin@bell.net>
+Date: Wed, 16 May 2012 10:14:52 +0100
+Subject: PARISC: fix crash in flush_icache_page_asm on PA1.1
+
+From: John David Anglin <dave.anglin@bell.net>
+
+commit 207f583d7179f707f402c36a7bda5ca1fd03ad5b upstream.
+
+As pointed out by serveral people, PA1.1 only has a type 26 instruction
+meaning that the space register must be explicitly encoded.  Not giving an
+explicit space means that the compiler uses the type 24 version which is PA2.0
+only resulting in an illegal instruction crash.
+
+This regression was caused by
+
+    commit f311847c2fcebd81912e2f0caf8a461dec28db41
+    Author: James Bottomley <James.Bottomley@HansenPartnership.com>
+    Date:   Wed Dec 22 10:22:11 2010 -0600
+
+        parisc: flush pages through tmpalias space
+
+Reported-by: Helge Deller <deller@gmx.de>
+Signed-off-by: John David Anglin <dave.anglin@bell.net>
+Signed-off-by: James Bottomley <JBottomley@Parallels.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ arch/parisc/kernel/pacache.S |   38 ++++++++++++++++++++------------------
+ 1 file changed, 20 insertions(+), 18 deletions(-)
+
+--- a/arch/parisc/kernel/pacache.S
++++ b/arch/parisc/kernel/pacache.S
+@@ -692,7 +692,7 @@ ENTRY(flush_icache_page_asm)
+       /* Purge any old translation */
+-      pitlb           (%sr0,%r28)
++      pitlb           (%sr4,%r28)
+       ldil            L%icache_stride, %r1
+       ldw             R%icache_stride(%r1), %r1
+@@ -706,27 +706,29 @@ ENTRY(flush_icache_page_asm)
+       sub             %r25, %r1, %r25
+-1:      fic,m         %r1(%r28)
+-      fic,m           %r1(%r28)
+-      fic,m           %r1(%r28)
+-      fic,m           %r1(%r28)
+-      fic,m           %r1(%r28)
+-      fic,m           %r1(%r28)
+-      fic,m           %r1(%r28)
+-      fic,m           %r1(%r28)
+-      fic,m           %r1(%r28)
+-      fic,m           %r1(%r28)
+-      fic,m           %r1(%r28)
+-      fic,m           %r1(%r28)
+-      fic,m           %r1(%r28)
+-      fic,m           %r1(%r28)
+-      fic,m           %r1(%r28)
++      /* fic only has the type 26 form on PA1.1, requiring an
++       * explicit space specification, so use %sr4 */
++1:      fic,m         %r1(%sr4,%r28)
++      fic,m           %r1(%sr4,%r28)
++      fic,m           %r1(%sr4,%r28)
++      fic,m           %r1(%sr4,%r28)
++      fic,m           %r1(%sr4,%r28)
++      fic,m           %r1(%sr4,%r28)
++      fic,m           %r1(%sr4,%r28)
++      fic,m           %r1(%sr4,%r28)
++      fic,m           %r1(%sr4,%r28)
++      fic,m           %r1(%sr4,%r28)
++      fic,m           %r1(%sr4,%r28)
++      fic,m           %r1(%sr4,%r28)
++      fic,m           %r1(%sr4,%r28)
++      fic,m           %r1(%sr4,%r28)
++      fic,m           %r1(%sr4,%r28)
+       cmpb,COND(<<)           %r28, %r25,1b
+-      fic,m           %r1(%r28)
++      fic,m           %r1(%sr4,%r28)
+       sync
+       bv              %r0(%r2)
+-      pitlb           (%sr0,%r25)
++      pitlb           (%sr4,%r25)
+       .exit
+       .procend
diff --git a/queue-3.3/parisc-fix-pa1.1-oops-on-boot.patch b/queue-3.3/parisc-fix-pa1.1-oops-on-boot.patch
new file mode 100644 (file)
index 0000000..6ffc82f
--- /dev/null
@@ -0,0 +1,42 @@
+From 5e185581d7c46ddd33cd9c01106d1fc86efb9376 Mon Sep 17 00:00:00 2001
+From: James Bottomley <JBottomley@Parallels.com>
+Date: Tue, 15 May 2012 11:04:19 +0100
+Subject: PARISC: fix PA1.1 oops on boot
+
+From: James Bottomley <JBottomley@Parallels.com>
+
+commit 5e185581d7c46ddd33cd9c01106d1fc86efb9376 upstream.
+
+All PA1.1 systems have been oopsing on boot since
+
+commit f311847c2fcebd81912e2f0caf8a461dec28db41
+Author: James Bottomley <James.Bottomley@HansenPartnership.com>
+Date:   Wed Dec 22 10:22:11 2010 -0600
+
+    parisc: flush pages through tmpalias space
+
+because a PA2.0 instruction was accidentally introduced into the PA1.1 TLB
+insertion interruption path when it was consolidated with the do_alias macro.
+Fix the do_alias macro only to use PA2.0 instructions if compiled for 64 bit.
+
+Signed-off-by: James Bottomley <JBottomley@Parallels.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ arch/parisc/kernel/entry.S |    4 ++++
+ 1 file changed, 4 insertions(+)
+
+--- a/arch/parisc/kernel/entry.S
++++ b/arch/parisc/kernel/entry.S
+@@ -581,7 +581,11 @@
+        */
+       cmpiclr,=       0x01,\tmp,%r0
+       ldi             (_PAGE_DIRTY|_PAGE_READ|_PAGE_WRITE),\prot
++#ifdef CONFIG_64BIT
+       depd,z          \prot,8,7,\prot
++#else
++      depw,z          \prot,8,7,\prot
++#endif
+       /*
+        * OK, it is in the temp alias region, check whether "from" or "to".
+        * Check "subtle" note in pacache.S re: r23/r26.
diff --git a/queue-3.3/parisc-fix-panic-on-prefetch-null-on-pa7300lc.patch b/queue-3.3/parisc-fix-panic-on-prefetch-null-on-pa7300lc.patch
new file mode 100644 (file)
index 0000000..87b4b6d
--- /dev/null
@@ -0,0 +1,37 @@
+From b3cb8674811d1851bbf1486a73d62b90c119b994 Mon Sep 17 00:00:00 2001
+From: James Bottomley <JBottomley@Parallels.com>
+Date: Wed, 16 May 2012 11:10:27 +0100
+Subject: PARISC: fix panic on prefetch(NULL) on PA7300LC
+
+From: James Bottomley <JBottomley@Parallels.com>
+
+commit b3cb8674811d1851bbf1486a73d62b90c119b994 upstream.
+
+Due to an errata, the PA7300LC generates a TLB miss interruption even on the
+prefetch instruction.  This means that prefetch(NULL), which is supposed to be
+a nop on linux actually generates a NULL deref fault.  Fix this by testing the
+address of prefetch against NULL before doing the prefetch.
+
+Signed-off-by: James Bottomley <JBottomley@Parallels.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ arch/parisc/include/asm/prefetch.h |    7 ++++++-
+ 1 file changed, 6 insertions(+), 1 deletion(-)
+
+--- a/arch/parisc/include/asm/prefetch.h
++++ b/arch/parisc/include/asm/prefetch.h
+@@ -21,7 +21,12 @@
+ #define ARCH_HAS_PREFETCH
+ static inline void prefetch(const void *addr)
+ {
+-      __asm__("ldw 0(%0), %%r0" : : "r" (addr));
++      __asm__(
++#ifndef CONFIG_PA20
++              /* Need to avoid prefetch of NULL on PA7300LC */
++              "       extrw,u,= %0,31,32,%%r0\n"
++#endif
++              "       ldw 0(%0), %%r0" : : "r" (addr));
+ }
+ /* LDD is a PA2.0 addition. */
diff --git a/queue-3.3/series b/queue-3.3/series
new file mode 100644 (file)
index 0000000..8900cb4
--- /dev/null
@@ -0,0 +1,8 @@
+tilegx-enable-syscall_wrappers-support.patch
+bio-allocation-failure-due-to-bio_get_nr_vecs.patch
+block-fix-buffer-overflow-when-printing-partition-uuids.patch
+block-don-t-mark-buffers-beyond-end-of-disk-as-mapped.patch
+parisc-fix-pa1.1-oops-on-boot.patch
+parisc-fix-crash-in-flush_icache_page_asm-on-pa1.1.patch
+parisc-fix-panic-on-prefetch-null-on-pa7300lc.patch
+x86-realmode-16-bit-real-mode-code-support-for-relocs-tool.patch
diff --git a/queue-3.3/tilegx-enable-syscall_wrappers-support.patch b/queue-3.3/tilegx-enable-syscall_wrappers-support.patch
new file mode 100644 (file)
index 0000000..e9447b3
--- /dev/null
@@ -0,0 +1,37 @@
+From e6d9668e119af44ae5bcd5f1197174531458afe3 Mon Sep 17 00:00:00 2001
+From: Chris Metcalf <cmetcalf@tilera.com>
+Date: Fri, 18 May 2012 13:33:24 -0400
+Subject: tilegx: enable SYSCALL_WRAPPERS support
+
+From: Chris Metcalf <cmetcalf@tilera.com>
+
+commit e6d9668e119af44ae5bcd5f1197174531458afe3 upstream.
+
+Some discussion with the glibc mailing lists revealed that this was
+necessary for 64-bit platforms with MIPS-like sign-extension rules
+for 32-bit values.  The original symptom was that passing (uid_t)-1 to
+setreuid() was failing in programs linked -pthread because of the "setxid"
+mechanism for passing setxid-type function arguments to the syscall code.
+SYSCALL_WRAPPERS handles ensuring that all syscall arguments end up with
+proper sign-extension and is thus the appropriate fix for this problem.
+
+On other platforms (s390, powerpc, sparc64, and mips) this was fixed
+in 2.6.28.6.  The general issue is tracked as CVE-2009-0029.
+
+Signed-off-by: Chris Metcalf <cmetcalf@tilera.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ arch/tile/Kconfig |    1 +
+ 1 file changed, 1 insertion(+)
+
+--- a/arch/tile/Kconfig
++++ b/arch/tile/Kconfig
+@@ -11,6 +11,7 @@ config TILE
+       select GENERIC_IRQ_PROBE
+       select GENERIC_PENDING_IRQ if SMP
+       select GENERIC_IRQ_SHOW
++      select HAVE_SYSCALL_WRAPPERS if TILEGX
+       select SYS_HYPERVISOR
+       select ARCH_HAVE_NMI_SAFE_CMPXCHG if !M386
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..2155c0b
--- /dev/null
@@ -0,0 +1,1629 @@
+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. ]
+
+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: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+diff --git a/Makefile b/Makefile
+index 48bd1f5..db2bcf3 100644
+--- 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.h include/generated/utsrelease.h \
+                    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=include/asm-$(hdr-arch), dst=include/asm)
+ 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
+diff --git a/arch/x86/Makefile b/arch/x86/Makefile
+index 41a7237..94e91e4 100644
+--- a/arch/x86/Makefile
++++ b/arch/x86/Makefile
+@@ -134,6 +134,9 @@ KBUILD_CFLAGS += $(call cc-option,-mno-avx,)
+ KBUILD_CFLAGS += $(mflags-y)
+ KBUILD_AFLAGS += $(mflags-y)
++archscripts:
++      $(Q)$(MAKE) $(build)=arch/x86/tools relocs
++
+ ###
+ # Syscall table generation
+diff --git a/arch/x86/boot/compressed/Makefile b/arch/x86/boot/compressed/Makefile
+index fd55a2f..e398bb5 100644
+--- a/arch/x86/boot/compressed/Makefile
++++ b/arch/x86/boot/compressed/Makefile
+@@ -40,13 +40,12 @@ OBJCOPYFLAGS_vmlinux.bin :=  -R .comment -S
+ $(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
+diff --git a/arch/x86/boot/compressed/relocs.c b/arch/x86/boot/compressed/relocs.c
+deleted file mode 100644
+index fb7117a..0000000
+--- a/arch/x86/boot/compressed/relocs.c
++++ /dev/null
+@@ -1,678 +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>
+-#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;
+-
+-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++) {
+-                      put_unaligned_le32(relocs[i], buf);
+-                      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;
+-}
+diff --git a/arch/x86/tools/.gitignore b/arch/x86/tools/.gitignore
+new file mode 100644
+index 0000000..be0ed06
+--- /dev/null
++++ b/arch/x86/tools/.gitignore
+@@ -0,0 +1 @@
++relocs
+diff --git a/arch/x86/tools/Makefile b/arch/x86/tools/Makefile
+index d511aa9..733057b 100644
+--- a/arch/x86/tools/Makefile
++++ b/arch/x86/tools/Makefile
+@@ -36,3 +36,7 @@ HOSTCFLAGS_insn_sanity.o := -Wall -I$(objtree)/arch/x86/lib/ -I$(srctree)/arch/x
+ $(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
+diff --git a/arch/x86/tools/relocs.c b/arch/x86/tools/relocs.c
+new file mode 100644
+index 0000000..0291470
+--- /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;
++}
+diff --git a/scripts/Makefile b/scripts/Makefile
+index df7678f..3626666 100644
+--- 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