From ldufour at linux.vnet.ibm.com  Mon Feb  3 09:37:49 2014
From: ldufour at linux.vnet.ibm.com (Laurent Dufour)
Date: Mon, 03 Feb 2014 15:37:49 +0100
Subject: [RESEND PATCH] kexec/ppc64 ELF ABIv2 ABI support
Message-ID: <20140203143749.7503.74213.stgit@nimbus>

When building in PPC64 little endian mode, the compiler is now using the
new ABI v2. Among other changes, this new ABI removes the function
descriptors and changes the way the TOC address is computed when entering a
C function.

The purgatory assembly part where the dot symbols are removed, and ELF
relocation code are impacted in this patch.

Signed-off-by: Laurent Dufour <ldufour at linux.vnet.ibm.com>
---
 include/elf.h                          |    4 ++++
 kexec/arch/ppc64/kexec-elf-rel-ppc64.c |   27 +++++++++++++++++++++++++++
 kexec/kexec-elf-rel.c                  |   10 +++++-----
 purgatory/arch/ppc64/Makefile          |    6 ++++--
 purgatory/arch/ppc64/hvCall.S          |    5 +++--
 purgatory/arch/ppc64/ppc64_asm.h       |   16 ++++++++++++++++
 purgatory/arch/ppc64/v2wrap.S          |    4 +++-
 7 files changed, 62 insertions(+), 10 deletions(-)
 create mode 100644 purgatory/arch/ppc64/ppc64_asm.h

diff --git a/include/elf.h b/include/elf.h
index 1a2eb5a..5db637b 100644
--- a/include/elf.h
+++ b/include/elf.h
@@ -1984,6 +1984,10 @@ typedef Elf32_Addr Elf32_Conflict;
 #define R_PPC64_DTPREL16_HIGHERA 104 /* half16	(sym+add)@dtprel at highera */
 #define R_PPC64_DTPREL16_HIGHEST 105 /* half16	(sym+add)@dtprel at highest */
 #define R_PPC64_DTPREL16_HIGHESTA 106 /* half16	(sym+add)@dtprel at highesta */
+#define R_PPC64_REL16           249 /* half16   (sym+add-.) */
+#define R_PPC64_REL16_LO        250 /* half16   (sym+add-.)@l */
+#define R_PPC64_REL16_HI        251 /* half16   (sym+add-.)@h */
+#define R_PPC64_REL16_HA        252 /* half16   (sym+add-.)@ha */
 
 /* Keep this the last entry.  */
 #define R_PPC64_NUM		107
diff --git a/kexec/arch/ppc64/kexec-elf-rel-ppc64.c b/kexec/arch/ppc64/kexec-elf-rel-ppc64.c
index 5fc2f87..9b191d0 100644
--- a/kexec/arch/ppc64/kexec-elf-rel-ppc64.c
+++ b/kexec/arch/ppc64/kexec-elf-rel-ppc64.c
@@ -144,6 +144,33 @@ void machine_apply_elf_rel(struct mem_ehdr *ehdr, unsigned long r_type,
 		*(uint16_t *)location = (((uint64_t)value >> 48) & 0xffff);
 		break;
 
+		/* R_PPC64_REL16_HA and R_PPC64_REL16_LO are handled to support
+		 * ABIv2 r2 assignment based on r12 for PIC executable.
+		 * Here address is know so replace
+		 *	0:	addis 2,12,.TOC.-0b at ha
+		 *		addi 2,2,.TOC.-0b at l
+		 * by
+		 *		lis 2,.TOC. at ha
+		 *		addi 2,2,.TOC. at l
+		 */
+	case R_PPC64_REL16_HA:
+		/* check that we are dealing with the addis 2,12 instruction */
+		if (((*(uint32_t*)location) & 0xffff0000) != 0x3c4c0000)
+			die("Unexpected instruction for  R_PPC64_REL16_HA");
+		value += my_r2(ehdr);
+		/* replacing by lis 2 */
+		*(uint32_t *)location = 0x3c400000 + ((value >> 16) & 0xffff);
+		break;
+
+	case R_PPC64_REL16_LO:
+		/* check that we are dealing with the addi 2,2 instruction */
+		if (((*(uint32_t*)location) & 0xffff0000) != 0x38420000)
+			die("Unexpected instruction for R_PPC64_REL16_LO");
+
+		value += my_r2(ehdr) - 4;
+		*(uint16_t *)location = value & 0xffff;
+		break;
+
 	default:
 		die("Unknown rela relocation: %lu\n", r_type);
 		break;
diff --git a/kexec/kexec-elf-rel.c b/kexec/kexec-elf-rel.c
index 020cab0..c625f30 100644
--- a/kexec/kexec-elf-rel.c
+++ b/kexec/kexec-elf-rel.c
@@ -379,12 +379,12 @@ int elf_rel_load(struct mem_ehdr *ehdr, struct kexec_info *info,
 			 * Relocation Entries: If the index is STN_UNDEF,
 			 * the undefined symbol index, the relocation uses 0
 			 * as the "symbol value".
-			 * So, is this really an error condition to flag die?
+			 * TOC symbols appear as undefined but should be
+			 * resolved as well. Their type is STT_NOTYPE so allow
+			 * such symbols to be processed.
 			 */
-			/*
-				die("Undefined symbol: %s\n", name);
-			*/
-				continue;
+				if (ELF32_ST_TYPE(sym.st_info) != STT_NOTYPE)
+					die("Undefined symbol: %s\n", name);
 			}
 			sec_base = 0;
 			if (sym.st_shndx == SHN_COMMON) {
diff --git a/purgatory/arch/ppc64/Makefile b/purgatory/arch/ppc64/Makefile
index 6f6716e..c2d0586 100644
--- a/purgatory/arch/ppc64/Makefile
+++ b/purgatory/arch/ppc64/Makefile
@@ -9,10 +9,12 @@ ppc64_PURGATORY_SRCS += purgatory/arch/ppc64/console-ppc64.c
 ppc64_PURGATORY_SRCS += purgatory/arch/ppc64/crashdump_backup.c
 ppc64_PURGATORY_SRCS += purgatory/arch/ppc64/misc.S
 
-ppc64_PURGATORY_EXTRA_CFLAGS += -m64 -mcall-aixdesc -msoft-float
-ppc64_PURGATORY_EXTRA_ASFLAGS += -m64 -mcall-aixdesc
+ppc64_PURGATORY_EXTRA_CFLAGS += -m64 -msoft-float
+ppc64_PURGATORY_EXTRA_ASFLAGS += -m64
 ifeq ($(SUBARCH),BE)
 	ppc64_PURGATORY_EXTRA_LDFLAGS += -melf64ppc
+	ppc64_PURGATORY_EXTRA_CFLAGS += -mcall-aixdesc
+	ppc64_PURGATORY_EXTRA_ASFLAGS += -mcall-aixdesc
 else
 	ppc64_PURGATORY_EXTRA_LDFLAGS += -melf64lppc
 	ppc64_PURGATORY_EXTRA_CFLAGS += -mlittle-endian
diff --git a/purgatory/arch/ppc64/hvCall.S b/purgatory/arch/ppc64/hvCall.S
index bdc4cb0..a96c489 100644
--- a/purgatory/arch/ppc64/hvCall.S
+++ b/purgatory/arch/ppc64/hvCall.S
@@ -9,12 +9,13 @@
  * as published by the Free Software Foundation; either version
  * 2 of the License, or (at your option) any later version.
  */
+#include "ppc64_asm.h"
 
 #define HVSC	.long 0x44000022
 .text
 	.machine ppc64
-.globl .plpar_hcall_norets
-.plpar_hcall_norets:
+.globl DOTSYM(plpar_hcall_norets)
+DOTSYM(plpar_hcall_norets):
 	or	6,6,6			# medium low priority
         mfcr	0
         stw	0,8(1)
diff --git a/purgatory/arch/ppc64/ppc64_asm.h b/purgatory/arch/ppc64/ppc64_asm.h
new file mode 100644
index 0000000..b8746fd
--- /dev/null
+++ b/purgatory/arch/ppc64/ppc64_asm.h
@@ -0,0 +1,16 @@
+/*
+ * ppc64_asm.h - common defines for PPC64 assembly parts
+ *
+ * This source code is licensed under the GNU General Public License,
+ * Version 2.  See the file COPYING for more details.
+ */
+
+/*
+ * ABIv1 requires dot symbol while ABIv2 does not.
+ */
+#if defined(_CALL_ELF) && _CALL_ELF == 2
+#define DOTSYM(a)	a
+#else
+#define GLUE(a,b)	a##b
+#define DOTSYM(a)	GLUE(.,a)
+#endif
diff --git a/purgatory/arch/ppc64/v2wrap.S b/purgatory/arch/ppc64/v2wrap.S
index 16fb63d..2761c14 100644
--- a/purgatory/arch/ppc64/v2wrap.S
+++ b/purgatory/arch/ppc64/v2wrap.S
@@ -18,6 +18,8 @@
 #  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 #
 
+#include "ppc64_asm.h"
+
 # v2wrap.S
 # a wrapper to call purgatory code to backup first
 # 32kB of first kernel into the backup region
@@ -77,7 +79,7 @@ master:
 	ld      1,0(6)          #setup stack
 
 	subi    1,1,112
-	bl      .purgatory
+	bl      DOTSYM(purgatory)
 	nop
 
 	or	3,3,3		# ok now to high priority, lets boot



From dirk at dmllr.de  Mon Feb  3 12:54:52 2014
From: dirk at dmllr.de (=?UTF-8?B?RGlyayBNw7xsbGVy?=)
Date: Mon, 3 Feb 2014 18:54:52 +0100
Subject: [PATCH] Avoid buffer overflow on strncat usage
Message-ID: <CAL5wTH6B-QYbY9bcC+HuBJkk=rEEZhQsggi921YtbGNS4xUfxQ@mail.gmail.com>

strncat() does not want the total size but the maximum length.

Signed-off-by: Dirk Mueller <dmueller at suse.com>
---
 kexec/fs2dt.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/kexec/fs2dt.c b/kexec/fs2dt.c
index 73c1fb9..65a8b66 100644
--- a/kexec/fs2dt.c
+++ b/kexec/fs2dt.c
@@ -649,8 +649,8 @@ static void putnode(void)
                        goto no_debug;
                }
                strncpy(filename, "/proc/device-tree/", MAXPATH);
-               strncat(filename, buff, MAXPATH);
-               strncat(filename, "/compatible", MAXPATH);
+               strncat(filename, buff, MAXPATH-strlen(filename)-1);
+               strncat(filename, "/compatible", MAXPATH-strlen(filename)-1);
                fd = open(filename, O_RDONLY);
                if (fd == -1) {
                        printf("Unable to find %s printing from
purgatory is diabled\n",
-- 
1.8.4.1


From mcgrof at do-not-panic.com  Mon Feb  3 22:49:11 2014
From: mcgrof at do-not-panic.com (Luis R. Rodriguez)
Date: Mon, 3 Feb 2014 19:49:11 -0800
Subject: Next kexec release
Message-ID: <CAB=NE6WzCjtsq0hCUt=H62V7y2wd3dTeE-q0=R282kdobbXjcA@mail.gmail.com>

Hey folks, I see recent discussions about desire for a new recent
release of kexec, one of such reasons is kexec support on EFI systems.
SUSE is also interested in this, and it'd be great if we can all synch
up on supporting the same recent release.

Thanks!

  Luis


From horms at verge.net.au  Tue Feb  4 03:30:53 2014
From: horms at verge.net.au (Simon Horman)
Date: Tue, 4 Feb 2014 17:30:53 +0900
Subject: [PATCH] Avoid buffer overflow on strncat usage
In-Reply-To: <CAL5wTH6B-QYbY9bcC+HuBJkk=rEEZhQsggi921YtbGNS4xUfxQ@mail.gmail.com>
References: <CAL5wTH6B-QYbY9bcC+HuBJkk=rEEZhQsggi921YtbGNS4xUfxQ@mail.gmail.com>
Message-ID: <20140204083053.GC30621@verge.net.au>

On Mon, Feb 03, 2014 at 06:54:52PM +0100, Dirk M?ller wrote:
> strncat() does not want the total size but the maximum length.
> 
> Signed-off-by: Dirk Mueller <dmueller at suse.com>
> ---
>  kexec/fs2dt.c | 4 ++--
>  1 file changed, 2 insertions(+), 2 deletions(-)
> 
> diff --git a/kexec/fs2dt.c b/kexec/fs2dt.c
> index 73c1fb9..65a8b66 100644
> --- a/kexec/fs2dt.c
> +++ b/kexec/fs2dt.c
> @@ -649,8 +649,8 @@ static void putnode(void)
>                         goto no_debug;
>                 }
>                 strncpy(filename, "/proc/device-tree/", MAXPATH);
> -               strncat(filename, buff, MAXPATH);
> -               strncat(filename, "/compatible", MAXPATH);
> +               strncat(filename, buff, MAXPATH-strlen(filename)-1);
> +               strncat(filename, "/compatible", MAXPATH-strlen(filename)-1);

I don't think you need the -1 as filename will have a trailing '\0'
which is not counted in the return value of strlen()

Also, could you please put a space on each side of each '-'?

Thanks

>                 fd = open(filename, O_RDONLY);
>                 if (fd == -1) {
>                         printf("Unable to find %s printing from
> purgatory is diabled\n",
> -- 
> 1.8.4.1
> 
> _______________________________________________
> kexec mailing list
> kexec at lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/kexec
> 


From horms at verge.net.au  Tue Feb  4 03:31:23 2014
From: horms at verge.net.au (Simon Horman)
Date: Tue, 4 Feb 2014 17:31:23 +0900
Subject: [RESEND PATCH] kexec/ppc64 ELF ABIv2 ABI support
In-Reply-To: <20140203143749.7503.74213.stgit@nimbus>
References: <20140203143749.7503.74213.stgit@nimbus>
Message-ID: <20140204083123.GD30621@verge.net.au>

On Mon, Feb 03, 2014 at 03:37:49PM +0100, Laurent Dufour wrote:
> When building in PPC64 little endian mode, the compiler is now using the
> new ABI v2. Among other changes, this new ABI removes the function
> descriptors and changes the way the TOC address is computed when entering a
> C function.
> 
> The purgatory assembly part where the dot symbols are removed, and ELF
> relocation code are impacted in this patch.
> 
> Signed-off-by: Laurent Dufour <ldufour at linux.vnet.ibm.com>

Thanks, applied.


From horms at verge.net.au  Tue Feb  4 03:31:51 2014
From: horms at verge.net.au (Simon Horman)
Date: Tue, 4 Feb 2014 17:31:51 +0900
Subject: More frequent kexec-tools releases
In-Reply-To: <20140131143047.GA10594@redhat.com>
References: <20140128184042.GA7098@redhat.com>
 <52E85B26.2080203@cn.fujitsu.com>
 <20140129142311.GA15077@redhat.com>
 <20140131052304.GC25099@verge.net.au>
 <20140131143047.GA10594@redhat.com>
Message-ID: <20140204083151.GE30621@verge.net.au>

On Fri, Jan 31, 2014 at 09:30:47AM -0500, Vivek Goyal wrote:
> On Fri, Jan 31, 2014 at 02:23:04PM +0900, Simon Horman wrote:
> 
> [..]
> > > Simon what do you think? A kexec-tools release every 4 months or every
> > > 6 months. Does it make sense to you? 
> > 
> > Perhaps we could aim for every second kernel release and see how that goes?
> 
> Sounds Good. Kernel releases are roughly 3 months apart. So that would
> mean a kexec-tools release roughly around 6 months. This sounds like
> a good start.
> 
> So 3.13 was release recently. And last kexec-tools release was in march
> 2013. May be it is a good idea to do one release now and then next one
> can be after release of kernel 3.15, 3.17 and so on.

Yes, I think so too.


From horms at verge.net.au  Tue Feb  4 04:01:36 2014
From: horms at verge.net.au (Simon Horman)
Date: Tue, 4 Feb 2014 18:01:36 +0900
Subject: [PATCH] kexec/ppc64 Enable early kernel's OPAL calls
In-Reply-To: <52EB105D.2060907@linux.vnet.ibm.com>
References: <20140124141614.6404.37733.stgit@nimbus>
 <52EB105D.2060907@linux.vnet.ibm.com>
Message-ID: <20140204090136.GB8144@verge.net.au>

On Fri, Jan 31, 2014 at 08:24:21AM +0530, Mahesh Jagannath Salgaonkar wrote:
> On 01/24/2014 07:46 PM, Laurent Dufour wrote:
> > When the kernel is built with CONFIG_PPC_EARLY_DEBUG_OPAL set, it is
> > expecting to get r8 and r9 filled respectively with OPAL base address and
> > OPAL entry address (arc/power/head_64.S).
> > 
> > On the new powernv platform, having these 2 registers set allows the kernel
> > to perform OPAL calls before it parse the device tree.
> > 
> > Signed-off-by: Laurent Dufour <ldufour at linux.vnet.ibm.com>
> 
> Tested-by: Mahesh Salgaonkar <mahesh at linux.vnet.ibm.com>

Thanks, applied.


From dirk at dmllr.de  Tue Feb  4 07:03:42 2014
From: dirk at dmllr.de (=?UTF-8?B?RGlyayBNw7xsbGVy?=)
Date: Tue, 4 Feb 2014 13:03:42 +0100
Subject: [PATCH] Avoid buffer overflow on strncat usage
In-Reply-To: <20140204083053.GC30621@verge.net.au>
References: <CAL5wTH6B-QYbY9bcC+HuBJkk=rEEZhQsggi921YtbGNS4xUfxQ@mail.gmail.com>
 <20140204083053.GC30621@verge.net.au>
Message-ID: <CAL5wTH52b74cixBSfx84w5HH08hieo=pn8vGTnF_9x4GwMPv9w@mail.gmail.com>

Hi Simon,

> I don't think you need the -1 as filename will have a trailing '\0'
> which is not counted in the return value of strlen()

Thats true, but strncat always writes a trailing NUL, and to avoid
that this one overflows the buffer, you need to subtract -1.

However, this code in particular can be rewrittten to use snprintf(),
which avoids
the overflow and is also a bit more readable.

How about the attached patch?

Thanks,
Dirk
-------------- next part --------------
A non-text attachment was scrubbed...
Name: 0001-Avoid-buffer-overflow-on-strncat-usage.patch
Type: text/x-patch
Size: 1500 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/kexec/attachments/20140204/a18617cc/attachment.bin>

From horms at verge.net.au  Tue Feb  4 07:37:12 2014
From: horms at verge.net.au (Simon Horman)
Date: Tue, 4 Feb 2014 21:37:12 +0900
Subject: [PATCH] Avoid buffer overflow on strncat usage
In-Reply-To: <CAL5wTH52b74cixBSfx84w5HH08hieo=pn8vGTnF_9x4GwMPv9w@mail.gmail.com>
References: <CAL5wTH6B-QYbY9bcC+HuBJkk=rEEZhQsggi921YtbGNS4xUfxQ@mail.gmail.com>
 <20140204083053.GC30621@verge.net.au>
 <CAL5wTH52b74cixBSfx84w5HH08hieo=pn8vGTnF_9x4GwMPv9w@mail.gmail.com>
Message-ID: <20140204123712.GF17028@verge.net.au>

On Tue, Feb 04, 2014 at 01:03:42PM +0100, Dirk M?ller wrote:
> Hi Simon,
> 
> > I don't think you need the -1 as filename will have a trailing '\0'
> > which is not counted in the return value of strlen()
> 
> Thats true, but strncat always writes a trailing NUL, and to avoid
> that this one overflows the buffer, you need to subtract -1.
> 
> However, this code in particular can be rewrittten to use snprintf(),
> which avoids
> the overflow and is also a bit more readable.
> 
> How about the attached patch?

Looks good, I have applied it.



From horms at verge.net.au  Tue Feb  4 07:41:48 2014
From: horms at verge.net.au (Simon Horman)
Date: Tue, 4 Feb 2014 21:41:48 +0900
Subject: More frequent kexec-tools releases
In-Reply-To: <20140204083151.GE30621@verge.net.au>
References: <20140128184042.GA7098@redhat.com>
 <52E85B26.2080203@cn.fujitsu.com>
 <20140129142311.GA15077@redhat.com>
 <20140131052304.GC25099@verge.net.au>
 <20140131143047.GA10594@redhat.com>
 <20140204083151.GE30621@verge.net.au>
Message-ID: <20140204124148.GH17028@verge.net.au>

On Tue, Feb 04, 2014 at 05:31:51PM +0900, Simon Horman wrote:
> On Fri, Jan 31, 2014 at 09:30:47AM -0500, Vivek Goyal wrote:
> > On Fri, Jan 31, 2014 at 02:23:04PM +0900, Simon Horman wrote:
> > 
> > [..]
> > > > Simon what do you think? A kexec-tools release every 4 months or every
> > > > 6 months. Does it make sense to you? 
> > > 
> > > Perhaps we could aim for every second kernel release and see how that goes?
> > 
> > Sounds Good. Kernel releases are roughly 3 months apart. So that would
> > mean a kexec-tools release roughly around 6 months. This sounds like
> > a good start.
> > 
> > So 3.13 was release recently. And last kexec-tools release was in march
> > 2013. May be it is a good idea to do one release now and then next one
> > can be after release of kernel 3.15, 3.17 and so on.
> 
> Yes, I think so too.

Would any of you object to me doing this with the current state of the
tree as of fe2c38cc0fc32573 ("Avoid buffer overflow on strncat usage").



From vgoyal at redhat.com  Tue Feb  4 09:31:54 2014
From: vgoyal at redhat.com (Vivek Goyal)
Date: Tue, 4 Feb 2014 09:31:54 -0500
Subject: More frequent kexec-tools releases
In-Reply-To: <20140204124148.GH17028@verge.net.au>
References: <20140128184042.GA7098@redhat.com>
 <52E85B26.2080203@cn.fujitsu.com>
 <20140129142311.GA15077@redhat.com>
 <20140131052304.GC25099@verge.net.au>
 <20140131143047.GA10594@redhat.com>
 <20140204083151.GE30621@verge.net.au>
 <20140204124148.GH17028@verge.net.au>
Message-ID: <20140204143154.GA8373@redhat.com>

On Tue, Feb 04, 2014 at 09:41:48PM +0900, Simon Horman wrote:

[..]
> > > > Perhaps we could aim for every second kernel release and see how that goes?
> > > 
> > > Sounds Good. Kernel releases are roughly 3 months apart. So that would
> > > mean a kexec-tools release roughly around 6 months. This sounds like
> > > a good start.
> > > 
> > > So 3.13 was release recently. And last kexec-tools release was in march
> > > 2013. May be it is a good idea to do one release now and then next one
> > > can be after release of kernel 3.15, 3.17 and so on.
> > 
> > Yes, I think so too.
> 
> Would any of you object to me doing this with the current state of the
> tree as of fe2c38cc0fc32573 ("Avoid buffer overflow on strncat usage").

I have no objection.

Thanks
Vivek



From vgoyal at redhat.com  Tue Feb  4 11:19:08 2014
From: vgoyal at redhat.com (Vivek Goyal)
Date: Tue, 4 Feb 2014 11:19:08 -0500
Subject: Next kexec release
In-Reply-To: <CAB=NE6WzCjtsq0hCUt=H62V7y2wd3dTeE-q0=R282kdobbXjcA@mail.gmail.com>
References: <CAB=NE6WzCjtsq0hCUt=H62V7y2wd3dTeE-q0=R282kdobbXjcA@mail.gmail.com>
Message-ID: <20140204161908.GB8373@redhat.com>

On Mon, Feb 03, 2014 at 07:49:11PM -0800, Luis R. Rodriguez wrote:
> Hey folks, I see recent discussions about desire for a new recent
> release of kexec, one of such reasons is kexec support on EFI systems.
> SUSE is also interested in this, and it'd be great if we can all synch
> up on supporting the same recent release.
> 

Hi Luis,

I wanted to make sure that there are more frequent releases of kexec-tools
so that every release of Fedora, we can rebase to new kexec-tools and
support that. 

I think this should should to Suse and other distributions. More frequent
releases will allow more frequent rebases to newer versions and allow
users to test newer kexec-tools easily.

Thanks to Simon that he has agreed to release kexec-tools every alternate
kernel release (roughly every 6 months).

W.r.t syncing on supporting same kexec-tools release, I am not sure how
will that work. Every distribution will have its own release schedule.
And most likely they will rebease to newer version when window for
next release opens so that it can get maximum testing time.

Thanks
Vivek


From tonyj at suse.com  Tue Feb  4 11:39:55 2014
From: tonyj at suse.com (Tony Jones)
Date: Tue, 04 Feb 2014 08:39:55 -0800
Subject: Next kexec release
In-Reply-To: <20140204161908.GB8373@redhat.com>
References: <CAB=NE6WzCjtsq0hCUt=H62V7y2wd3dTeE-q0=R282kdobbXjcA@mail.gmail.com>
 <20140204161908.GB8373@redhat.com>
Message-ID: <52F117DB.5080408@suse.com>

On 02/04/2014 08:19 AM, Vivek Goyal wrote:

> W.r.t syncing on supporting same kexec-tools release, I am not sure how
> will that work. Every distribution will have its own release schedule.

I'd not seen Luis' e-mail.  Agree with above,  we'll all have our own differing release schedules.

tony



From zhangyanfei at cn.fujitsu.com  Tue Feb  4 20:12:26 2014
From: zhangyanfei at cn.fujitsu.com (Zhang Yanfei)
Date: Wed, 05 Feb 2014 09:12:26 +0800
Subject: More frequent kexec-tools releases
In-Reply-To: <20140204124148.GH17028@verge.net.au>
References: <20140128184042.GA7098@redhat.com>
 <52E85B26.2080203@cn.fujitsu.com> <20140129142311.GA15077@redhat.com>
 <20140131052304.GC25099@verge.net.au> <20140131143047.GA10594@redhat.com>
 <20140204083151.GE30621@verge.net.au> <20140204124148.GH17028@verge.net.au>
Message-ID: <52F18FFA.5060103@cn.fujitsu.com>

On 02/04/2014 08:41 PM, Simon Horman wrote:
> On Tue, Feb 04, 2014 at 05:31:51PM +0900, Simon Horman wrote:
>> On Fri, Jan 31, 2014 at 09:30:47AM -0500, Vivek Goyal wrote:
>>> On Fri, Jan 31, 2014 at 02:23:04PM +0900, Simon Horman wrote:
>>>
>>> [..]
>>>>> Simon what do you think? A kexec-tools release every 4 months or every
>>>>> 6 months. Does it make sense to you? 
>>>>
>>>> Perhaps we could aim for every second kernel release and see how that goes?
>>>
>>> Sounds Good. Kernel releases are roughly 3 months apart. So that would
>>> mean a kexec-tools release roughly around 6 months. This sounds like
>>> a good start.
>>>
>>> So 3.13 was release recently. And last kexec-tools release was in march
>>> 2013. May be it is a good idea to do one release now and then next one
>>> can be after release of kernel 3.15, 3.17 and so on.
>>
>> Yes, I think so too.
> 
> Would any of you object to me doing this with the current state of the
> tree as of fe2c38cc0fc32573 ("Avoid buffer overflow on strncat usage").
> 

NO objection.

Thanks

> 
> _______________________________________________
> kexec mailing list
> kexec at lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/kexec
> 


-- 
Thanks.
Zhang Yanfei


From horms at verge.net.au  Tue Feb  4 21:03:33 2014
From: horms at verge.net.au (Simon Horman)
Date: Wed, 5 Feb 2014 11:03:33 +0900
Subject: [ANNOUNCE] kexec-tools 2.0.5
Message-ID: <20140205020333.GB13630@verge.net.au>

Hi all,

I am happy to announce the release of kexec-tools 2.0.5.

The release can be downloaded from kernel.org:

	http://kernel.org/pub/linux/utils/kernel/kexec/kexec-tools-2.0.5.tar.xz
	http://kernel.org/pub/linux/utils/kernel/kexec/

I have also tagged it in git:

	git://git.kernel.org/pub/scm/utils/kernel/kexec/kexec-tools.git

Thanks to everyone who has contributed to kexec.


From horms at verge.net.au  Wed Feb  5 01:49:06 2014
From: horms at verge.net.au (Simon Horman)
Date: Wed, 5 Feb 2014 15:49:06 +0900
Subject: More frequent kexec-tools releases
In-Reply-To: <52F18FFA.5060103@cn.fujitsu.com>
References: <20140128184042.GA7098@redhat.com>
 <52E85B26.2080203@cn.fujitsu.com>
 <20140129142311.GA15077@redhat.com>
 <20140131052304.GC25099@verge.net.au>
 <20140131143047.GA10594@redhat.com>
 <20140204083151.GE30621@verge.net.au>
 <20140204124148.GH17028@verge.net.au>
 <52F18FFA.5060103@cn.fujitsu.com>
Message-ID: <20140205064906.GB29499@verge.net.au>

On Wed, Feb 05, 2014 at 09:12:26AM +0800, Zhang Yanfei wrote:
> On 02/04/2014 08:41 PM, Simon Horman wrote:
> > On Tue, Feb 04, 2014 at 05:31:51PM +0900, Simon Horman wrote:
> >> On Fri, Jan 31, 2014 at 09:30:47AM -0500, Vivek Goyal wrote:
> >>> On Fri, Jan 31, 2014 at 02:23:04PM +0900, Simon Horman wrote:
> >>>
> >>> [..]
> >>>>> Simon what do you think? A kexec-tools release every 4 months or every
> >>>>> 6 months. Does it make sense to you? 
> >>>>
> >>>> Perhaps we could aim for every second kernel release and see how that goes?
> >>>
> >>> Sounds Good. Kernel releases are roughly 3 months apart. So that would
> >>> mean a kexec-tools release roughly around 6 months. This sounds like
> >>> a good start.
> >>>
> >>> So 3.13 was release recently. And last kexec-tools release was in march
> >>> 2013. May be it is a good idea to do one release now and then next one
> >>> can be after release of kernel 3.15, 3.17 and so on.
> >>
> >> Yes, I think so too.
> > 
> > Would any of you object to me doing this with the current state of the
> > tree as of fe2c38cc0fc32573 ("Avoid buffer overflow on strncat usage").
> > 
> 
> NO objection.

Done :)


From vgoyal at redhat.com  Wed Feb  5 08:20:15 2014
From: vgoyal at redhat.com (Vivek Goyal)
Date: Wed, 5 Feb 2014 08:20:15 -0500
Subject: More frequent kexec-tools releases
In-Reply-To: <20140205064906.GB29499@verge.net.au>
References: <20140128184042.GA7098@redhat.com>
 <52E85B26.2080203@cn.fujitsu.com>
 <20140129142311.GA15077@redhat.com>
 <20140131052304.GC25099@verge.net.au>
 <20140131143047.GA10594@redhat.com>
 <20140204083151.GE30621@verge.net.au>
 <20140204124148.GH17028@verge.net.au>
 <52F18FFA.5060103@cn.fujitsu.com>
 <20140205064906.GB29499@verge.net.au>
Message-ID: <20140205132015.GA6042@redhat.com>

On Wed, Feb 05, 2014 at 03:49:06PM +0900, Simon Horman wrote:
> On Wed, Feb 05, 2014 at 09:12:26AM +0800, Zhang Yanfei wrote:
> > On 02/04/2014 08:41 PM, Simon Horman wrote:
> > > On Tue, Feb 04, 2014 at 05:31:51PM +0900, Simon Horman wrote:
> > >> On Fri, Jan 31, 2014 at 09:30:47AM -0500, Vivek Goyal wrote:
> > >>> On Fri, Jan 31, 2014 at 02:23:04PM +0900, Simon Horman wrote:
> > >>>
> > >>> [..]
> > >>>>> Simon what do you think? A kexec-tools release every 4 months or every
> > >>>>> 6 months. Does it make sense to you? 
> > >>>>
> > >>>> Perhaps we could aim for every second kernel release and see how that goes?
> > >>>
> > >>> Sounds Good. Kernel releases are roughly 3 months apart. So that would
> > >>> mean a kexec-tools release roughly around 6 months. This sounds like
> > >>> a good start.
> > >>>
> > >>> So 3.13 was release recently. And last kexec-tools release was in march
> > >>> 2013. May be it is a good idea to do one release now and then next one
> > >>> can be after release of kernel 3.15, 3.17 and so on.
> > >>
> > >> Yes, I think so too.
> > > 
> > > Would any of you object to me doing this with the current state of the
> > > tree as of fe2c38cc0fc32573 ("Avoid buffer overflow on strncat usage").
> > > 
> > 
> > NO objection.
> 
> Done :)

Thanks Simon. I did git pull but I don't see new tag in my tree. Not sure
why. 

Thanks
Vivek


From tonyj at suse.de  Wed Feb  5 12:46:23 2014
From: tonyj at suse.de (Tony Jones)
Date: Wed, 05 Feb 2014 09:46:23 -0800
Subject: [ANNOUNCE] kexec-tools 2.0.5
In-Reply-To: <20140205020333.GB13630@verge.net.au>
References: <20140205020333.GB13630@verge.net.au>
Message-ID: <52F278EF.4050407@suse.de>

On 02/04/2014 06:03 PM, Simon Horman wrote:

> I have also tagged it in git:
> 
> 	git://git.kernel.org/pub/scm/utils/kernel/kexec/kexec-tools.git

I think you forgot to push the tag.

Tony



From tonyj at suse.de  Wed Feb  5 17:32:18 2014
From: tonyj at suse.de (Tony Jones)
Date: Wed, 05 Feb 2014 14:32:18 -0800
Subject: PATCH: kexec/i386 fix build failure (bzImage_support_efi_boot)
Message-ID: <52F2BBF2.8080907@suse.de>

Commit 9c200a85de2245a850546fded96a1977b84ad24d referenced 
'bzImage_support_efi_boot' without matching 32-bit definition.

Signed-off-by: Tony Jones <tonyj at suse.de>
---
 kexec/arch/i386/kexec-bzImage.c |    1 +
 1 file changed, 1 insertion(+)

--- a/kexec/arch/i386/kexec-bzImage.c
+++ b/kexec/arch/i386/kexec-bzImage.c
@@ -40,6 +40,7 @@
 #include <arch/options.h>
 
 static const int probe_debug = 0;
+int bzImage_support_efi_boot = 0;
 
 int bzImage_probe(const char *buf, off_t len)
 {


From tonyj at suse.com  Wed Feb  5 17:38:07 2014
From: tonyj at suse.com (Tony Jones)
Date: Wed, 05 Feb 2014 14:38:07 -0800
Subject: PATCH: fix redefinition error for e820entry
Message-ID: <52F2BD4F.10707@suse.com>

At least on our systems, xenctrl.h defines (unguarded) struct e820entry
Move the (guarded) definition in include/x86/x86-linux.h to below.

Signed-off-by: Tony Jones <tonyj at suse.de>
---
 kexec/arch/i386/crashdump-x86.c |    3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

--- a/kexec/arch/i386/crashdump-x86.c
+++ b/kexec/arch/i386/crashdump-x86.c
@@ -41,12 +41,13 @@
 #include "../../crashdump.h"
 #include "kexec-x86.h"
 #include "crashdump-x86.h"
-#include "x86-linux-setup.h"

 #ifdef HAVE_LIBXENCTRL
 #include <xenctrl.h>
 #endif /* HAVE_LIBXENCTRL */

+#include "x86-linux-setup.h"
+
 #include <x86/x86-linux.h>

 extern struct arch_options_t arch_options;


From horms at verge.net.au  Wed Feb  5 19:37:44 2014
From: horms at verge.net.au (Simon Horman)
Date: Thu, 6 Feb 2014 09:37:44 +0900
Subject: [ANNOUNCE] kexec-tools 2.0.5
In-Reply-To: <52F278EF.4050407@suse.de>
References: <20140205020333.GB13630@verge.net.au>
 <52F278EF.4050407@suse.de>
Message-ID: <20140206003744.GS5125@verge.net.au>

On Wed, Feb 05, 2014 at 09:46:23AM -0800, Tony Jones wrote:
> On 02/04/2014 06:03 PM, Simon Horman wrote:
> 
> > I have also tagged it in git:
> > 
> > 	git://git.kernel.org/pub/scm/utils/kernel/kexec/kexec-tools.git
> 
> I think you forgot to push the tag.

Sorry about that, it should be there now.


From horms at verge.net.au  Wed Feb  5 20:55:13 2014
From: horms at verge.net.au (Simon Horman)
Date: Thu, 6 Feb 2014 10:55:13 +0900
Subject: More frequent kexec-tools releases
In-Reply-To: <20140205132015.GA6042@redhat.com>
References: <20140128184042.GA7098@redhat.com>
 <52E85B26.2080203@cn.fujitsu.com>
 <20140129142311.GA15077@redhat.com>
 <20140131052304.GC25099@verge.net.au>
 <20140131143047.GA10594@redhat.com>
 <20140204083151.GE30621@verge.net.au>
 <20140204124148.GH17028@verge.net.au>
 <52F18FFA.5060103@cn.fujitsu.com>
 <20140205064906.GB29499@verge.net.au>
 <20140205132015.GA6042@redhat.com>
Message-ID: <20140206015513.GX5125@verge.net.au>

On Wed, Feb 05, 2014 at 08:20:15AM -0500, Vivek Goyal wrote:
> On Wed, Feb 05, 2014 at 03:49:06PM +0900, Simon Horman wrote:
> > On Wed, Feb 05, 2014 at 09:12:26AM +0800, Zhang Yanfei wrote:
> > > On 02/04/2014 08:41 PM, Simon Horman wrote:
> > > > On Tue, Feb 04, 2014 at 05:31:51PM +0900, Simon Horman wrote:
> > > >> On Fri, Jan 31, 2014 at 09:30:47AM -0500, Vivek Goyal wrote:
> > > >>> On Fri, Jan 31, 2014 at 02:23:04PM +0900, Simon Horman wrote:
> > > >>>
> > > >>> [..]
> > > >>>>> Simon what do you think? A kexec-tools release every 4 months or every
> > > >>>>> 6 months. Does it make sense to you? 
> > > >>>>
> > > >>>> Perhaps we could aim for every second kernel release and see how that goes?
> > > >>>
> > > >>> Sounds Good. Kernel releases are roughly 3 months apart. So that would
> > > >>> mean a kexec-tools release roughly around 6 months. This sounds like
> > > >>> a good start.
> > > >>>
> > > >>> So 3.13 was release recently. And last kexec-tools release was in march
> > > >>> 2013. May be it is a good idea to do one release now and then next one
> > > >>> can be after release of kernel 3.15, 3.17 and so on.
> > > >>
> > > >> Yes, I think so too.
> > > > 
> > > > Would any of you object to me doing this with the current state of the
> > > > tree as of fe2c38cc0fc32573 ("Avoid buffer overflow on strncat usage").
> > > > 
> > > 
> > > NO objection.
> > 
> > Done :)
> 
> Thanks Simon. I did git pull but I don't see new tag in my tree. Not sure
> why. 

Could you try again? I messed up the push.


From dyoung at redhat.com  Wed Feb  5 22:44:15 2014
From: dyoung at redhat.com (Dave Young)
Date: Thu, 6 Feb 2014 11:44:15 +0800
Subject: [PATCH 1/3] kexec: align initrd when no --image-size
In-Reply-To: <1390387924-73946-2-git-send-email-wangnan0@huawei.com>
References: <1390387924-73946-1-git-send-email-wangnan0@huawei.com>
 <1390387924-73946-2-git-send-email-wangnan0@huawei.com>
Message-ID: <20140206034415.GA3943@dhcp-16-126.nay.redhat.com>

On 01/22/14 at 06:52pm, Wang Nan wrote:
> Before this patch, when no --image-size passed, initrd_base is caculated using
> base + len * 4, which is unaligned, and unable to pass check in
> add_segment_phys_virt():
> 
> 	if (base & (pagesize -1)) {
> 		die("Base address: 0x%lx is not page aligned\n", base);
> 	}
> 
> Signed-off-by: Wang Nan <wangnan0 at huawei.com>
> Cc: Simon Horman <horms at verge.net.au>
> Cc: Dave Young <dyoung at redhat.com>
> Cc: Geng Hui <hui.geng at huawei.com>
> ---
>  kexec/arch/arm/kexec-zImage-arm.c | 2 +-
>  1 file changed, 1 insertion(+), 1 deletion(-)
> 
> diff --git a/kexec/arch/arm/kexec-zImage-arm.c b/kexec/arch/arm/kexec-zImage-arm.c
> index 792187a..4547765 100644
> --- a/kexec/arch/arm/kexec-zImage-arm.c
> +++ b/kexec/arch/arm/kexec-zImage-arm.c
> @@ -351,7 +351,7 @@ int zImage_arm_load(int argc, char **argv, const char *buf, off_t len,
>  	} else {
>  		/* Otherwise, assume the maximum kernel compression ratio
>  		 * is 4, and just to be safe, place ramdisk after that */
> -		initrd_base = base + len * 4;
> +		initrd_base =  base + _ALIGN(len * 4, 4096);

get_page_size should be used instead of 4096, otherwise it looks good to me.

Thanks
Dave


From dyoung at redhat.com  Wed Feb  5 22:58:47 2014
From: dyoung at redhat.com (Dave Young)
Date: Thu, 6 Feb 2014 11:58:47 +0800
Subject: [PATCH 2/3] kexec: pass initrd position in dtb
In-Reply-To: <1390387924-73946-3-git-send-email-wangnan0@huawei.com>
References: <1390387924-73946-1-git-send-email-wangnan0@huawei.com>
 <1390387924-73946-3-git-send-email-wangnan0@huawei.com>
Message-ID: <20140206035847.GB3943@dhcp-16-126.nay.redhat.com>

On 01/22/14 at 06:52pm, Wang Nan wrote:
> This patch append the position of initrd to dtb when loading arm kernel and
> initrd without using atag.
> 
> Signed-off-by: Wang Nan <wangnan0 at huawei.com>
> Cc: Simon Horman <horms at verge.net.au>
> Cc: Dave Young <dyoung at redhat.com>
> Cc: Geng Hui <hui.geng at huawei.com>
> ---
>  kexec/arch/arm/kexec-zImage-arm.c | 35 +++++++++++++++++++++++++++++++++++
>  1 file changed, 35 insertions(+)
> 
> diff --git a/kexec/arch/arm/kexec-zImage-arm.c b/kexec/arch/arm/kexec-zImage-arm.c
> index 4547765..6d6b239 100644
> --- a/kexec/arch/arm/kexec-zImage-arm.c
> +++ b/kexec/arch/arm/kexec-zImage-arm.c
> @@ -417,6 +417,41 @@ int zImage_arm_load(int argc, char **argv, const char *buf, off_t len,
>  		if (ramdisk) {
>  			add_segment(info, ramdisk_buf, initrd_size,
>  			            initrd_base, initrd_size);
> +			const char *node_name = "/chosen";
> +			const char *prop_start_name = "linux,initrd-start";
> +			const char *prop_end_name = "linux,initrd-end";
> +			int off;
> +
> +			dtb_length = fdt_totalsize(dtb_buf) + 1024 + 8;

why +8 here? is it the "/chosen" string size? if yes please change to use
strlen.

> +			dtb_buf = xrealloc(dtb_buf, dtb_length);

Should check xrealloc return value here.

Since it is very similar with the code for appending cmdline, at least
creating a share function for adding a new node looks better.

> +			fdt_set_totalsize(dtb_buf, dtb_length);
> +
> +			/* check if a /choosen subnode already exists */
> +			off = fdt_path_offset(dtb_buf, node_name);
> +
> +			if (off == -FDT_ERR_NOTFOUND)
> +				off = fdt_add_subnode(dtb_buf, off, node_name);
> +
> +			if (off < 0) {
> +				fprintf(stderr, "FDT: Error adding %s node.\n", node_name);
> +				return -1;
> +			}
> +
> +			unsigned long start, end;
> +			start = cpu_to_be32((unsigned long)(initrd_base));
> +			end = cpu_to_be32((unsigned long)(initrd_base + initrd_size));
> +			if (fdt_setprop(dtb_buf, off, prop_start_name,
> +						&start, sizeof(start)) != 0) {
> +				fprintf(stderr, "FDT: Error setting %s/%s property.\n",
> +						node_name, prop_start_name);
> +				return -1;
> +			}
> +			if (fdt_setprop(dtb_buf, off, prop_end_name,
> +						&end, sizeof(end)) != 0) {
> +				fprintf(stderr, "FDT: Error setting %s/%s property.\n",
> +						node_name, prop_end_name);
> +				return -1;
> +			}
>  		}
>  
>  		/* Stick the dtb at the end of the initrd and page
> -- 
> 1.8.4
> 
> 
> _______________________________________________
> kexec mailing list
> kexec at lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/kexec


From dyoung at redhat.com  Wed Feb  5 23:01:32 2014
From: dyoung at redhat.com (Dave Young)
Date: Thu, 6 Feb 2014 12:01:32 +0800
Subject: [PATCH 3/3] kexec: increase zImage compression ratio from 4 to 5
In-Reply-To: <1390387924-73946-4-git-send-email-wangnan0@huawei.com>
References: <1390387924-73946-1-git-send-email-wangnan0@huawei.com>
 <1390387924-73946-4-git-send-email-wangnan0@huawei.com>
Message-ID: <20140206040132.GC3943@dhcp-16-126.nay.redhat.com>

On 01/22/14 at 06:52pm, Wang Nan wrote:
> Old code assume the zImage compression ration is 4, it is not enough, 5 shall be
> better.

4 works well during my test. Do you have real test case to reproduce this problem?

> 
> Signed-off-by: Wang Nan <wangnan0 at huawei.com>
> Cc: Simon Horman <horms at verge.net.au>
> Cc: Dave Young <dyoung at redhat.com>
> Cc: Geng Hui <hui.geng at huawei.com>
> ---
>  kexec/arch/arm/kexec-zImage-arm.c | 2 +-
>  1 file changed, 1 insertion(+), 1 deletion(-)
> 
> diff --git a/kexec/arch/arm/kexec-zImage-arm.c b/kexec/arch/arm/kexec-zImage-arm.c
> index 6d6b239..6e5e12b 100644
> --- a/kexec/arch/arm/kexec-zImage-arm.c
> +++ b/kexec/arch/arm/kexec-zImage-arm.c
> @@ -351,7 +351,7 @@ int zImage_arm_load(int argc, char **argv, const char *buf, off_t len,
>  	} else {
>  		/* Otherwise, assume the maximum kernel compression ratio
>  		 * is 4, and just to be safe, place ramdisk after that */
> -		initrd_base =  base + _ALIGN(len * 4, 4096);
> +		initrd_base =  base + _ALIGN(len * 5, 4096);
>  	}
>  
>  	if (use_atags) {
> -- 
> 1.8.4
> 
> 
> _______________________________________________
> kexec mailing list
> kexec at lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/kexec


From dyoung at redhat.com  Thu Feb  6 01:30:42 2014
From: dyoung at redhat.com (Dave Young)
Date: Thu,  6 Feb 2014 14:30:42 +0800
Subject: [PATCH 0/2] kernel probe function fixes
Message-ID: <1391668244-13631-1-git-send-email-dyoung@redhat.com>

During my testing for arm zImage, in 2nd kernel the atags pointer and the
machine_id are not valid, I did a lot of debugging in kernel, finally I found
this is caused by a kexec tools bug instead.

It is a regression since bf06cf2095. It changes uImage probe return values as
below:
 *  0		- valid uImage type
 * -1           - If the image is corrupted.
 *  1           - If the image is not a uImage.

Because uImage will be probed before zImage, but the uImage probe return 1 for
a zImage thus kexec will mistakenly think it is ok to use as uImage.

IMHO, return -1 in case it's not an uImage is better instead of 1 like before
It's not really necessary to introduce a new return value. It might be better
for a new patch to return either 0 or -1 for uImage probe.

But I did not fix the uImage return value yet. In this patchset I did below:
 - ppc64 zImage: return 0 instead of 1 in case of success
 - strictly checking if probe return 0 in kexec.c

Tested arm zImage with use_atags only.

Dave Young (2):
  zImage_ppc64_probe: return 0 instead of 1 in case of success
  kernel image probe function return value checking fix

 kexec/arch/ppc64/kexec-zImage-ppc64.c | 5 ++++-
 kexec/kexec.c                         | 2 +-
 2 files changed, 5 insertions(+), 2 deletions(-)

-- 
1.8.3.1



From dyoung at redhat.com  Thu Feb  6 01:30:43 2014
From: dyoung at redhat.com (Dave Young)
Date: Thu,  6 Feb 2014 14:30:43 +0800
Subject: [PATCH 1/2] zImage_ppc64_probe: return 0 instead of 1 in case of
 success
In-Reply-To: <1391668244-13631-1-git-send-email-dyoung@redhat.com>
References: <1391668244-13631-1-git-send-email-dyoung@redhat.com>
Message-ID: <1391668244-13631-2-git-send-email-dyoung@redhat.com>

All other _probe functions return 0 for probing the kernel
image successfully, so there's no reason to return 1 here.

Fix it to return 0 instead.

Signed-off-by: Dave Young <dyoung at redhat.com>
---
 kexec/arch/ppc64/kexec-zImage-ppc64.c | 5 ++++-
 1 file changed, 4 insertions(+), 1 deletion(-)

diff --git a/kexec/arch/ppc64/kexec-zImage-ppc64.c b/kexec/arch/ppc64/kexec-zImage-ppc64.c
index 24a87c6..d084ee5 100644
--- a/kexec/arch/ppc64/kexec-zImage-ppc64.c
+++ b/kexec/arch/ppc64/kexec-zImage-ppc64.c
@@ -36,6 +36,7 @@
 int zImage_ppc64_probe(FILE *file)
 {
 	Elf32_Ehdr elf;
+	int valid;
 
 	if (fseek(file, 0, SEEK_SET) < 0) {
 		fprintf(stderr, "seek error: %s\n",
@@ -53,7 +54,7 @@ int zImage_ppc64_probe(FILE *file)
 		return -1;
 	}
 
-	return (elf.e_ident[EI_MAG0]  == ELFMAG0        &&
+	valid = (elf.e_ident[EI_MAG0]  == ELFMAG0        &&
 		elf.e_ident[EI_MAG1]  == ELFMAG1        &&
 		elf.e_ident[EI_MAG2]  == ELFMAG2        &&
 		elf.e_ident[EI_MAG3]  == ELFMAG3        &&
@@ -61,6 +62,8 @@ int zImage_ppc64_probe(FILE *file)
 		elf.e_ident[EI_DATA]  == ELFDATA2MSB &&
 		elf.e_type            == ET_EXEC        &&
 		elf.e_machine         == EM_PPC);
+
+	return valid ? 0 : -1;
 }
 
 int zImage_ppc64_load(FILE *file, int UNUSED(argc), char **UNUSED(argv),
-- 
1.8.3.1



From dyoung at redhat.com  Thu Feb  6 01:30:44 2014
From: dyoung at redhat.com (Dave Young)
Date: Thu,  6 Feb 2014 14:30:44 +0800
Subject: [PATCH 2/2] kernel image probe function return value checking fix
In-Reply-To: <1391668244-13631-1-git-send-email-dyoung@redhat.com>
References: <1391668244-13631-1-git-send-email-dyoung@redhat.com>
Message-ID: <1391668244-13631-3-git-send-email-dyoung@redhat.com>

Currently kexec will use the kernel image type when probe function return
value >=0. It looks odd, but previously it works. Since commit bf06cf2095
it does not work anymore.

During my testing for arm zImage, in 2nd kernel the atags pointer and the
machine_id are not valid, I did a lot of debugging in kernel, finally I found
this is caused by a kexec tools bug instead.

Because uImage will be probed before zImage, also the uImage probe return 1
instead of -1 since bf06cf2095, thus kexec will mistakenly think it is uImage.

Fix this issue by regarding it's valid only when probe return 0.

Signed-off-by: Dave Young <dyoung at redhat.com>
---
 kexec/kexec.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/kexec/kexec.c b/kexec/kexec.c
index f13e512..703d524 100644
--- a/kexec/kexec.c
+++ b/kexec/kexec.c
@@ -691,7 +691,7 @@ static int my_load(const char *type, int fileind, int argc, char **argv,
 	}
 	if (!type || guess_only) {
 		for (i = 0; i < file_types; i++) {
-			if (file_type[i].probe(kernel_buf, kernel_size) >= 0)
+			if (file_type[i].probe(kernel_buf, kernel_size) == 0)
 				break;
 		}
 		if (i == file_types) {
-- 
1.8.3.1



From horms at verge.net.au  Thu Feb  6 02:30:33 2014
From: horms at verge.net.au (Simon Horman)
Date: Thu, 6 Feb 2014 16:30:33 +0900
Subject: PATCH: kexec/i386 fix build failure (bzImage_support_efi_boot)
In-Reply-To: <52F2BBF2.8080907@suse.de>
References: <52F2BBF2.8080907@suse.de>
Message-ID: <20140206073033.GC24865@verge.net.au>

On Wed, Feb 05, 2014 at 02:32:18PM -0800, Tony Jones wrote:
> Commit 9c200a85de2245a850546fded96a1977b84ad24d referenced 
> 'bzImage_support_efi_boot' without matching 32-bit definition.
> 
> Signed-off-by: Tony Jones <tonyj at suse.de>

Thanks, applied.

> ---
>  kexec/arch/i386/kexec-bzImage.c |    1 +
>  1 file changed, 1 insertion(+)
> 
> --- a/kexec/arch/i386/kexec-bzImage.c
> +++ b/kexec/arch/i386/kexec-bzImage.c
> @@ -40,6 +40,7 @@
>  #include <arch/options.h>
>  
>  static const int probe_debug = 0;
> +int bzImage_support_efi_boot = 0;
>  
>  int bzImage_probe(const char *buf, off_t len)
>  {
> 


From horms at verge.net.au  Thu Feb  6 02:30:41 2014
From: horms at verge.net.au (Simon Horman)
Date: Thu, 6 Feb 2014 16:30:41 +0900
Subject: PATCH: fix redefinition error for e820entry
In-Reply-To: <52F2BD4F.10707@suse.com>
References: <52F2BD4F.10707@suse.com>
Message-ID: <20140206073041.GD24865@verge.net.au>

On Wed, Feb 05, 2014 at 02:38:07PM -0800, Tony Jones wrote:
> At least on our systems, xenctrl.h defines (unguarded) struct e820entry
> Move the (guarded) definition in include/x86/x86-linux.h to below.
> 
> Signed-off-by: Tony Jones <tonyj at suse.de>

Thanks, applied.

> ---
>  kexec/arch/i386/crashdump-x86.c |    3 ++-
>  1 file changed, 2 insertions(+), 1 deletion(-)
> 
> --- a/kexec/arch/i386/crashdump-x86.c
> +++ b/kexec/arch/i386/crashdump-x86.c
> @@ -41,12 +41,13 @@
>  #include "../../crashdump.h"
>  #include "kexec-x86.h"
>  #include "crashdump-x86.h"
> -#include "x86-linux-setup.h"
> 
>  #ifdef HAVE_LIBXENCTRL
>  #include <xenctrl.h>
>  #endif /* HAVE_LIBXENCTRL */
> 
> +#include "x86-linux-setup.h"
> +
>  #include <x86/x86-linux.h>
> 
>  extern struct arch_options_t arch_options;
> 
> _______________________________________________
> kexec mailing list
> kexec at lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/kexec
> 


From horms at verge.net.au  Thu Feb  6 02:30:49 2014
From: horms at verge.net.au (Simon Horman)
Date: Thu, 6 Feb 2014 16:30:49 +0900
Subject: [PATCH 1/2] zImage_ppc64_probe: return 0 instead of 1 in case of
 success
In-Reply-To: <1391668244-13631-2-git-send-email-dyoung@redhat.com>
References: <1391668244-13631-1-git-send-email-dyoung@redhat.com>
 <1391668244-13631-2-git-send-email-dyoung@redhat.com>
Message-ID: <20140206073049.GE24865@verge.net.au>

On Thu, Feb 06, 2014 at 02:30:43PM +0800, Dave Young wrote:
> All other _probe functions return 0 for probing the kernel
> image successfully, so there's no reason to return 1 here.
> 
> Fix it to return 0 instead.
> 
> Signed-off-by: Dave Young <dyoung at redhat.com>

Thanks, applied.

> ---
>  kexec/arch/ppc64/kexec-zImage-ppc64.c | 5 ++++-
>  1 file changed, 4 insertions(+), 1 deletion(-)
> 
> diff --git a/kexec/arch/ppc64/kexec-zImage-ppc64.c b/kexec/arch/ppc64/kexec-zImage-ppc64.c
> index 24a87c6..d084ee5 100644
> --- a/kexec/arch/ppc64/kexec-zImage-ppc64.c
> +++ b/kexec/arch/ppc64/kexec-zImage-ppc64.c
> @@ -36,6 +36,7 @@
>  int zImage_ppc64_probe(FILE *file)
>  {
>  	Elf32_Ehdr elf;
> +	int valid;
>  
>  	if (fseek(file, 0, SEEK_SET) < 0) {
>  		fprintf(stderr, "seek error: %s\n",
> @@ -53,7 +54,7 @@ int zImage_ppc64_probe(FILE *file)
>  		return -1;
>  	}
>  
> -	return (elf.e_ident[EI_MAG0]  == ELFMAG0        &&
> +	valid = (elf.e_ident[EI_MAG0]  == ELFMAG0        &&
>  		elf.e_ident[EI_MAG1]  == ELFMAG1        &&
>  		elf.e_ident[EI_MAG2]  == ELFMAG2        &&
>  		elf.e_ident[EI_MAG3]  == ELFMAG3        &&
> @@ -61,6 +62,8 @@ int zImage_ppc64_probe(FILE *file)
>  		elf.e_ident[EI_DATA]  == ELFDATA2MSB &&
>  		elf.e_type            == ET_EXEC        &&
>  		elf.e_machine         == EM_PPC);
> +
> +	return valid ? 0 : -1;
>  }
>  
>  int zImage_ppc64_load(FILE *file, int UNUSED(argc), char **UNUSED(argv),
> -- 
> 1.8.3.1
> 


From horms at verge.net.au  Thu Feb  6 02:30:56 2014
From: horms at verge.net.au (Simon Horman)
Date: Thu, 6 Feb 2014 16:30:56 +0900
Subject: [PATCH 2/2] kernel image probe function return value checking fix
In-Reply-To: <1391668244-13631-3-git-send-email-dyoung@redhat.com>
References: <1391668244-13631-1-git-send-email-dyoung@redhat.com>
 <1391668244-13631-3-git-send-email-dyoung@redhat.com>
Message-ID: <20140206073056.GF24865@verge.net.au>

On Thu, Feb 06, 2014 at 02:30:44PM +0800, Dave Young wrote:
> Currently kexec will use the kernel image type when probe function return
> value >=0. It looks odd, but previously it works. Since commit bf06cf2095
> it does not work anymore.
> 
> During my testing for arm zImage, in 2nd kernel the atags pointer and the
> machine_id are not valid, I did a lot of debugging in kernel, finally I found
> this is caused by a kexec tools bug instead.
> 
> Because uImage will be probed before zImage, also the uImage probe return 1
> instead of -1 since bf06cf2095, thus kexec will mistakenly think it is uImage.
> 
> Fix this issue by regarding it's valid only when probe return 0.
> 
> Signed-off-by: Dave Young <dyoung at redhat.com>

Thanks, applied.

> ---
>  kexec/kexec.c | 2 +-
>  1 file changed, 1 insertion(+), 1 deletion(-)
> 
> diff --git a/kexec/kexec.c b/kexec/kexec.c
> index f13e512..703d524 100644
> --- a/kexec/kexec.c
> +++ b/kexec/kexec.c
> @@ -691,7 +691,7 @@ static int my_load(const char *type, int fileind, int argc, char **argv,
>  	}
>  	if (!type || guess_only) {
>  		for (i = 0; i < file_types; i++) {
> -			if (file_type[i].probe(kernel_buf, kernel_size) >= 0)
> +			if (file_type[i].probe(kernel_buf, kernel_size) == 0)
>  				break;
>  		}
>  		if (i == file_types) {
> -- 
> 1.8.3.1
> 


From baruch at tkos.co.il  Thu Feb  6 02:50:23 2014
From: baruch at tkos.co.il (Baruch Siach)
Date: Thu,  6 Feb 2014 09:50:23 +0200
Subject: [PATCH] kexec: fix uImage probe false positive
Message-ID: <8bf27d38eb0cf5d0c70333ef17cf9f7167a0bf56.1391673023.git.baruch@tkos.co.il>

Since bf06cf2095 (kexec/uImage: probe to identify a corrupted image)
uImage_probe_kernel() returns 1 for non uImage files. Don't treat this value
as positive probe indication.

Cc: Suzuki K. Poulose <suzuki at in.ibm.com>
Signed-off-by: Baruch Siach <baruch at tkos.co.il>
---
 kexec/kexec.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/kexec/kexec.c b/kexec/kexec.c
index f13e5124aacc..703d524836b4 100644
--- a/kexec/kexec.c
+++ b/kexec/kexec.c
@@ -691,7 +691,7 @@ static int my_load(const char *type, int fileind, int argc, char **argv,
 	}
 	if (!type || guess_only) {
 		for (i = 0; i < file_types; i++) {
-			if (file_type[i].probe(kernel_buf, kernel_size) >= 0)
+			if (file_type[i].probe(kernel_buf, kernel_size) == 0)
 				break;
 		}
 		if (i == file_types) {
-- 
1.8.5.3



From horms at verge.net.au  Thu Feb  6 03:04:17 2014
From: horms at verge.net.au (Simon Horman)
Date: Thu, 6 Feb 2014 17:04:17 +0900
Subject: [PATCH] kexec: fix uImage probe false positive
In-Reply-To: <8bf27d38eb0cf5d0c70333ef17cf9f7167a0bf56.1391673023.git.baruch@tkos.co.il>
References: <8bf27d38eb0cf5d0c70333ef17cf9f7167a0bf56.1391673023.git.baruch@tkos.co.il>
Message-ID: <20140206080416.GG24865@verge.net.au>

On Thu, Feb 06, 2014 at 09:50:23AM +0200, Baruch Siach wrote:
> Since bf06cf2095 (kexec/uImage: probe to identify a corrupted image)
> uImage_probe_kernel() returns 1 for non uImage files. Don't treat this value
> as positive probe indication.
> 
> Cc: Suzuki K. Poulose <suzuki at in.ibm.com>
> Signed-off-by: Baruch Siach <baruch at tkos.co.il>

Thanks. I had just applied the same patch from Dave Young.

> ---
>  kexec/kexec.c | 2 +-
>  1 file changed, 1 insertion(+), 1 deletion(-)
> 
> diff --git a/kexec/kexec.c b/kexec/kexec.c
> index f13e5124aacc..703d524836b4 100644
> --- a/kexec/kexec.c
> +++ b/kexec/kexec.c
> @@ -691,7 +691,7 @@ static int my_load(const char *type, int fileind, int argc, char **argv,
>  	}
>  	if (!type || guess_only) {
>  		for (i = 0; i < file_types; i++) {
> -			if (file_type[i].probe(kernel_buf, kernel_size) >= 0)
> +			if (file_type[i].probe(kernel_buf, kernel_size) == 0)
>  				break;
>  		}
>  		if (i == file_types) {
> -- 
> 1.8.5.3
> 


From kumagai-atsushi at mxc.nes.nec.co.jp  Thu Feb  6 04:38:35 2014
From: kumagai-atsushi at mxc.nes.nec.co.jp (Atsushi Kumagai)
Date: Thu, 6 Feb 2014 09:38:35 +0000
Subject: [PATCH v2] vmcore: copy fractional pages into buffers in the
 kdump 2nd kernel
In-Reply-To: <52EB73A1.3080409@jp.fujitsu.com>
References: <52A579EE.6090107@jp.fujitsu.com>
 <0910DD04CBD6DE4193FCF86B9C00BE971E47E1@BPXM01GP.gisp.nec.co.jp>
 <52EB73A1.3080409@jp.fujitsu.com>
Message-ID: <0910DD04CBD6DE4193FCF86B9C00BE971E6D19@BPXM01GP.gisp.nec.co.jp>

On 2014/01/31 18:58:08, HATAYAMA Daisuke <d.hatayama at jp.fujitsu.com> wrote:
> (2014/01/31 11:36), Atsushi Kumagai wrote:
> > Hello HATAYAMA-san,
> >
> > On 2013/12/09 17:06:18, HATAYAMA Daisuke <d.hatayama at jp.fujitsu.com> wrote:
> >> This is a patch for fixing mmap failure due to fractional page issue.
> >>
> >> This patch might be still a bit too large as a single patch and might need to split.
> >> If you think patch refactoring is needed, please suggest.
> >>
> >> Change Log:
> >>
> >> v1 => v2)
> >>
> >> - Copy fractional pages from 1st kernel to 2nd kernel to reduce read
> >>    to the fractional pages for reliability.
> >>
> >> - Deal with the case where multiple System RAM areas are contained in
> >>    a single fractional page.
> >>
> >> Test:
> >>
> >> Tested on X86_64. Fractional pages are created using memmap= kernel
> >> parameter on the kdump 1st kernel.
> >
> > Could you tell me more details about how to reproduce this ?
> > I tried to create such fractional pages to test the patch at
> > the end of this mail, by using memmap= kernel parameter as you said
> > like below:
> >
> >    # cat /proc/iomem
> >    ...
> >    100000000-10fff57ff : System RAM
> >    10fff5800-1100057ff : reserved
> >    110005800-11fffffff : System RAM
> >
> > However, I couldn't face the mmap() failure and makedumpfile worked
> > normally even using mmap() on linux-3.12.1. What am I missing here ?
> >
> 
> This patch set tries to reduce potential risk on accessing i.e. creating
> page tables reading memory outside System RAM regions. The potential risk
> I intend here is for example effect of accessing mmio region.
> 
> If you didn't see any failure except for mmap() failure on fractional pages,
> there's no potential risk on your system in the sense of what I mean above.
> Or you could probably see different behavior by choosing other System RAM
> region that resides in the memory that is used for something special.

Thanks for your response, but I couldn't see even the mmap() failure caused
by a sanity check in remap_pfn_range().
I'll describe what I did for debugging as below.

First, the 1st kernel's memory map I prepared and its PT_LOAD are here.

   # cat /proc/iomem

   ...
   100000000-10fff57ff : System RAM
   10fff5800-1100057ff : ACPI Tables
   110005800-11fffffff : System RAM

   ...

   Type           Offset             VirtAddr           PhysAddr
                  FileSiz            MemSiz              Flags  Align
   LOAD           0x00000000d07ca000 0xffff880100000000 0x0000000100000000
                  0x000000000fff5800 0x000000000fff5800  RWE    0
   LOAD           0x00000000e07c0800 0xffff880110005800 0x0000000110005800
                  0x000000000fffa800 0x000000000fffa800  RWE    0


The fractional page I expected was [0x10fff5000 - 0x10fff57ff],
so its file offset was [0xe07bf000 - 0xe07bf7ff].

Second, I prepared a patch to make sure whether the fractional page was
mapped with mmap() or not as below:


diff --git a/makedumpfile.c b/makedumpfile.c
index 7536274..b6abd31 100644
--- a/makedumpfile.c
+++ b/makedumpfile.c
@@ -251,11 +251,16 @@ update_mmap_range(off_t offset, int initial) {

        map_size = MIN(max_offset - start_offset, info->mmap_region_size);

+       if (start_offset <= 0xe07bf000 && 0xe07bf000 <= (start_offset + map_size)) {
+               MSG("Try mapping [%llx-%llx] with mmap()\n",
+                   (ulonglong)start_offset,
+                   (ulonglong)(start_offset + map_size));
+       }
+
        info->mmap_buf = mmap(NULL, map_size, PROT_READ, MAP_PRIVATE,
                                     info->fd_memory, start_offset);


Finally, I run makedumpfile_v1.5.5 with only the debug patch above in
2nd kernel (linux-3.12.1):

    # makedumpfile -D -c /proc/vmcore ./dumpfile.c
    ...
    
    mmap() is available on the kernel.
    Copying data                       : [ 92.9 %] -Try mapping [e03f9000-e07f9000] with mmap()
    Copying data                       : [100.0 %] |
    Writing erase info...
    offset_eraseinfo: 12ad1218, size_eraseinfo: 0

    The dumpfile is saved to ./dumpfile.c.

    makedumpfile Completed.
    #


According to this result, mmap() for the fractional page seemed to
succeed even without any fix, so I suspect that I misunderstand
something about the mmap() issue reported by Vivek.
Perhaps, can a fractional page pass that sanity check depending on
the situation ?

At least, I confirmed that the my patch I sent truncates mmap() regions
as I expected with the debug patch above, so I think there is no problem
with it.


Thanks
Atsushi Kumagai

> Also, in early phase, our design didn't care about this kind of fractional pages
> because we don't think there were many such systems on real world. But the
> bug report came earlier than we expected. So, I think we should design
> carefully here around at least as long as they can be done relatively simply.
> # Sorry for delaying my work...
> 
> Of course, I think both kernel and makedumpfile address the issue together
> to reduce potential risk as much as possible.
> 
> -- 
> Thanks.
> HATAYAMA, Daisuke


From vgoyal at redhat.com  Thu Feb  6 09:23:32 2014
From: vgoyal at redhat.com (Vivek Goyal)
Date: Thu, 6 Feb 2014 09:23:32 -0500
Subject: More frequent kexec-tools releases
In-Reply-To: <20140206015513.GX5125@verge.net.au>
References: <52E85B26.2080203@cn.fujitsu.com>
 <20140129142311.GA15077@redhat.com>
 <20140131052304.GC25099@verge.net.au>
 <20140131143047.GA10594@redhat.com>
 <20140204083151.GE30621@verge.net.au>
 <20140204124148.GH17028@verge.net.au>
 <52F18FFA.5060103@cn.fujitsu.com>
 <20140205064906.GB29499@verge.net.au>
 <20140205132015.GA6042@redhat.com>
 <20140206015513.GX5125@verge.net.au>
Message-ID: <20140206142332.GA3674@redhat.com>

On Thu, Feb 06, 2014 at 10:55:13AM +0900, Simon Horman wrote:

[..]
> > Thanks Simon. I did git pull but I don't see new tag in my tree. Not sure
> > why. 
> 
> Could you try again? I messed up the push.

It works now. Thanks.

Vivek



From horms at verge.net.au  Thu Feb  6 18:58:52 2014
From: horms at verge.net.au (Simon Horman)
Date: Fri, 7 Feb 2014 08:58:52 +0900
Subject: More frequent kexec-tools releases
In-Reply-To: <20140206142332.GA3674@redhat.com>
References: <20140129142311.GA15077@redhat.com>
 <20140131052304.GC25099@verge.net.au>
 <20140131143047.GA10594@redhat.com>
 <20140204083151.GE30621@verge.net.au>
 <20140204124148.GH17028@verge.net.au>
 <52F18FFA.5060103@cn.fujitsu.com>
 <20140205064906.GB29499@verge.net.au>
 <20140205132015.GA6042@redhat.com>
 <20140206015513.GX5125@verge.net.au>
 <20140206142332.GA3674@redhat.com>
Message-ID: <20140206235851.GB19799@verge.net.au>

On Thu, Feb 06, 2014 at 09:23:32AM -0500, Vivek Goyal wrote:
> On Thu, Feb 06, 2014 at 10:55:13AM +0900, Simon Horman wrote:
> 
> [..]
> > > Thanks Simon. I did git pull but I don't see new tag in my tree. Not sure
> > > why. 
> > 
> > Could you try again? I messed up the push.
> 
> It works now. Thanks.

It seems that a few bugs showed up in 2.0.5, fixes for which
are now in the git repository. I am thinking it would be a good
idea to release these as 2.0.6 unless people would rather that I held off.


From dyoung at redhat.com  Thu Feb  6 21:20:02 2014
From: dyoung at redhat.com (Dave Young)
Date: Fri, 7 Feb 2014 10:20:02 +0800
Subject: More frequent kexec-tools releases
In-Reply-To: <20140206235851.GB19799@verge.net.au>
References: <20140131052304.GC25099@verge.net.au>
 <20140131143047.GA10594@redhat.com>
 <20140204083151.GE30621@verge.net.au>
 <20140204124148.GH17028@verge.net.au>
 <52F18FFA.5060103@cn.fujitsu.com>
 <20140205064906.GB29499@verge.net.au>
 <20140205132015.GA6042@redhat.com>
 <20140206015513.GX5125@verge.net.au>
 <20140206142332.GA3674@redhat.com>
 <20140206235851.GB19799@verge.net.au>
Message-ID: <20140207022002.GE3718@dhcp-16-126.nay.redhat.com>

On 02/07/14 at 08:58am, Simon Horman wrote:
> On Thu, Feb 06, 2014 at 09:23:32AM -0500, Vivek Goyal wrote:
> > On Thu, Feb 06, 2014 at 10:55:13AM +0900, Simon Horman wrote:
> > 
> > [..]
> > > > Thanks Simon. I did git pull but I don't see new tag in my tree. Not sure
> > > > why. 
> > > 
> > > Could you try again? I messed up the push.
> > 
> > It works now. Thanks.
> 
> It seems that a few bugs showed up in 2.0.5, fixes for which
> are now in the git repository. I am thinking it would be a good
> idea to release these as 2.0.6 unless people would rather that I held off.

I'm fine with a new release, thanks a lot.

Dave


From vgoyal at redhat.com  Fri Feb  7 09:34:09 2014
From: vgoyal at redhat.com (Vivek Goyal)
Date: Fri, 7 Feb 2014 09:34:09 -0500
Subject: More frequent kexec-tools releases
In-Reply-To: <20140206235851.GB19799@verge.net.au>
References: <20140131052304.GC25099@verge.net.au>
 <20140131143047.GA10594@redhat.com>
 <20140204083151.GE30621@verge.net.au>
 <20140204124148.GH17028@verge.net.au>
 <52F18FFA.5060103@cn.fujitsu.com>
 <20140205064906.GB29499@verge.net.au>
 <20140205132015.GA6042@redhat.com>
 <20140206015513.GX5125@verge.net.au>
 <20140206142332.GA3674@redhat.com>
 <20140206235851.GB19799@verge.net.au>
Message-ID: <20140207143409.GA4262@redhat.com>

On Fri, Feb 07, 2014 at 08:58:52AM +0900, Simon Horman wrote:
> On Thu, Feb 06, 2014 at 09:23:32AM -0500, Vivek Goyal wrote:
> > On Thu, Feb 06, 2014 at 10:55:13AM +0900, Simon Horman wrote:
> > 
> > [..]
> > > > Thanks Simon. I did git pull but I don't see new tag in my tree. Not sure
> > > > why. 
> > > 
> > > Could you try again? I messed up the push.
> > 
> > It works now. Thanks.
> 
> It seems that a few bugs showed up in 2.0.5, fixes for which
> are now in the git repository. I am thinking it would be a good
> idea to release these as 2.0.6 unless people would rather that I held off.

I am fine with new release.

In future you might have to come up with a process where you merge
only important fixes so that you can do a stable release.

May be create a development branch 2-3 weeks before final release. Master
branch slowly will get ready for release and will get only important
fixes committed. Devel branch will have everything. And after release,
devel will be rebased on top of master and merged or some other better
process.

Thanks
Vivek



From vgoyal at redhat.com  Fri Feb  7 11:24:09 2014
From: vgoyal at redhat.com (Vivek Goyal)
Date: Fri, 7 Feb 2014 11:24:09 -0500
Subject: [GIT PULL] x86/kaslr for v3.14
In-Reply-To: <52F503FD.8080607@linux.intel.com>
References: <201401201647.s0KGlZdh004167@tazenda.hos.anvin.org>
 <CAFLxGvxO1MPDDjEh3FU5Gv2-eb6zBJxYtTnKdABDTTpbMxxYAw@mail.gmail.com>
 <52E5EFAF.3060609@linux.intel.com>
 <CAFLxGvxJ0A6hZ52RWffkg_zXXScyPn10P4HcKvdAXfE43h32Eg@mail.gmail.com>
 <52E601DA.7010605@zytor.com> <20140130220708.GP9951@redhat.com>
 <CAGXu5jKp0j71ucE7uOWRa+gQM1Wzp=_KdByJK4XnACTwiCW4ow@mail.gmail.com>
 <20140207144914.GA5949@redhat.com>
 <52F503FD.8080607@linux.intel.com>
Message-ID: <20140207162408.GD6967@redhat.com>

On Fri, Feb 07, 2014 at 08:04:13AM -0800, H. Peter Anvin wrote:
> On 02/07/2014 06:49 AM, Vivek Goyal wrote:
> > 
> > Hi Kees,
> > 
> > Dave Young is testing kdump with kaslr enabled. He is facing some issues.
> > 
> > One issue he mentioned is that when second kernel boots, it might be
> > placed in an area which is outside the reserved area for second kernel.
> > 
> > We reserve a certain memory for second kernel. And modify memory map of
> > second kernel using memmap=exactmap parameter. Looks like kernel placement
> > is happening before memmap=exactmap takes effect. And that seems to be
> > the reason that second kernel can be placed outside the reserved memory.
> > 
> > IOW, memmap=exactmap and kaslr don't work together. Is it possible to
> > first let memmap=exactmap take affect and then kaslr does its job. Or it
> > is too late by the time memmap=exactmap is parsed.
> > 
> > As a workaround, Dave is currently using "nokaslr" command line parameter
> > for second kernel. He is still facing issues where makedumpfile segment
> > faults. He is looking into it further.
> > 
> > I thought I will atleast bring up with issue of memmap=exactmap and kaslr
> > being incompatible.
> > 
> 
> Yes, because memmap=exactmap gets parsed too late; kaslr assumes that
> the e820 information passed to it is actually correct.
> 
> Yet another cause of breakage caused by the decision on the part of
> kdump to rely on command-line options.

[CC kexec mailing list]

Ok, I think this is high time we change kexec-tools to not use
memmap=exactmap and start passing modified memory map in bootparams. I
think only concern with that change was backward compatibility of
kexec-tools with older kernels.

IIUC, only thing which will be impacted by this change is users of
saved_max_pfn which determine the highest accessible pfn in first
kernel. Some calgary IOMMU code seems to be the only user of it now.

So may be we can create a new command line option say --pass-memmap-cmdline
to kexec-tools which forces old behavior and by default we pass memmap
in bootparams.

Or create --do-not-pass-memmap-cmdline and new users will use it. Default
will be old behavior.

Thansk
Vivek


From keescook at chromium.org  Fri Feb  7 14:44:47 2014
From: keescook at chromium.org (Kees Cook)
Date: Fri, 7 Feb 2014 11:44:47 -0800
Subject: [GIT PULL] x86/kaslr for v3.14
In-Reply-To: <52F52EDA.4080007@linux.intel.com>
References: <201401201647.s0KGlZdh004167@tazenda.hos.anvin.org>
 <CAFLxGvxO1MPDDjEh3FU5Gv2-eb6zBJxYtTnKdABDTTpbMxxYAw@mail.gmail.com>
 <52E5EFAF.3060609@linux.intel.com>
 <CAFLxGvxJ0A6hZ52RWffkg_zXXScyPn10P4HcKvdAXfE43h32Eg@mail.gmail.com>
 <52E601DA.7010605@zytor.com> <20140130220708.GP9951@redhat.com>
 <CAGXu5jKp0j71ucE7uOWRa+gQM1Wzp=_KdByJK4XnACTwiCW4ow@mail.gmail.com>
 <20140207144914.GA5949@redhat.com>
 <52F52EDA.4080007@linux.intel.com>
Message-ID: <CAGXu5jKTr1udKiD7mhVEkN2W4z0w687DS=jJMORTT+ny+DqGCg@mail.gmail.com>

On Fri, Feb 7, 2014 at 11:07 AM, H. Peter Anvin <hpa at linux.intel.com> wrote:
> On 02/07/2014 06:49 AM, Vivek Goyal wrote:
>>
>> As a workaround, Dave is currently using "nokaslr" command line parameter
>> for second kernel. He is still facing issues where makedumpfile segment
>> faults. He is looking into it further.
>>
>
> Now, let's state this: kaslr for kdump is almost certainly useless (the
> amount of reserved memory is not enough to provide any meaningful
> randomization, so any randomization needs to happen during the memory
> reservation phase.)  So disabling kaslr in the kdump kernel is entirely
> appropriate.

Peter covered everything already, but yeah, kaslr and kdump may not
make a lot of sense together, but regardless, yes, it only examines
e820 for memory space. It has to do all this work before the kernel
decompresses, so it's very early.

-Kees

-- 
Kees Cook
Chrome OS Security


From dyoung at redhat.com  Fri Feb  7 18:16:26 2014
From: dyoung at redhat.com (Dave Young)
Date: Sat, 8 Feb 2014 07:16:26 +0800
Subject: [GIT PULL] x86/kaslr for v3.14
In-Reply-To: <20140207162408.GD6967@redhat.com>
References: <201401201647.s0KGlZdh004167@tazenda.hos.anvin.org>
 <CAFLxGvxO1MPDDjEh3FU5Gv2-eb6zBJxYtTnKdABDTTpbMxxYAw@mail.gmail.com>
 <52E5EFAF.3060609@linux.intel.com>
 <CAFLxGvxJ0A6hZ52RWffkg_zXXScyPn10P4HcKvdAXfE43h32Eg@mail.gmail.com>
 <52E601DA.7010605@zytor.com> <20140130220708.GP9951@redhat.com>
 <CAGXu5jKp0j71ucE7uOWRa+gQM1Wzp=_KdByJK4XnACTwiCW4ow@mail.gmail.com>
 <20140207144914.GA5949@redhat.com>
 <52F503FD.8080607@linux.intel.com>
 <20140207162408.GD6967@redhat.com>
Message-ID: <20140207231626.GA3840@dhcp-16-126.nay.redhat.com>

On 02/07/14 at 11:24am, Vivek Goyal wrote:
> On Fri, Feb 07, 2014 at 08:04:13AM -0800, H. Peter Anvin wrote:
> > On 02/07/2014 06:49 AM, Vivek Goyal wrote:
> > > 
> > > Hi Kees,
> > > 
> > > Dave Young is testing kdump with kaslr enabled. He is facing some issues.
> > > 
> > > One issue he mentioned is that when second kernel boots, it might be
> > > placed in an area which is outside the reserved area for second kernel.
> > > 
> > > We reserve a certain memory for second kernel. And modify memory map of
> > > second kernel using memmap=exactmap parameter. Looks like kernel placement
> > > is happening before memmap=exactmap takes effect. And that seems to be
> > > the reason that second kernel can be placed outside the reserved memory.
> > > 
> > > IOW, memmap=exactmap and kaslr don't work together. Is it possible to
> > > first let memmap=exactmap take affect and then kaslr does its job. Or it
> > > is too late by the time memmap=exactmap is parsed.
> > > 
> > > As a workaround, Dave is currently using "nokaslr" command line parameter
> > > for second kernel. He is still facing issues where makedumpfile segment
> > > faults. He is looking into it further.
> > > 
> > > I thought I will atleast bring up with issue of memmap=exactmap and kaslr
> > > being incompatible.
> > > 
> > 
> > Yes, because memmap=exactmap gets parsed too late; kaslr assumes that
> > the e820 information passed to it is actually correct.
> > 
> > Yet another cause of breakage caused by the decision on the part of
> > kdump to rely on command-line options.
> 
> [CC kexec mailing list]
> 
> Ok, I think this is high time we change kexec-tools to not use
> memmap=exactmap and start passing modified memory map in bootparams. I
> think only concern with that change was backward compatibility of
> kexec-tools with older kernels.
> 
> IIUC, only thing which will be impacted by this change is users of
> saved_max_pfn which determine the highest accessible pfn in first
> kernel. Some calgary IOMMU code seems to be the only user of it now.
> 
> So may be we can create a new command line option say --pass-memmap-cmdline
> to kexec-tools which forces old behavior and by default we pass memmap
> in bootparams.
> 
> Or create --do-not-pass-memmap-cmdline and new users will use it. Default
> will be old behavior.

Hi Vivek,

Chaowang <chaowang at redhat.com> is looking into passing setup_data SETUP_E820_EXT
instead of using exactmap. Previously Thomas Renninger tried passing them in e820.
I did not find the old thread, but I remember it's not enough because of the
128 entries limitation. 

In case for kaslr, I agree that it do not make sense for kdump kernel. IMHO it's
better to disable it automaticlly for kdump kernel but we can use the nokaslr
as workaround for now. 

Thanks
Dave


From hpa at zytor.com  Fri Feb  7 18:20:32 2014
From: hpa at zytor.com (H. Peter Anvin)
Date: Fri, 07 Feb 2014 15:20:32 -0800
Subject: [GIT PULL] x86/kaslr for v3.14
In-Reply-To: <20140207231626.GA3840@dhcp-16-126.nay.redhat.com>
References: <201401201647.s0KGlZdh004167@tazenda.hos.anvin.org>
 <CAFLxGvxO1MPDDjEh3FU5Gv2-eb6zBJxYtTnKdABDTTpbMxxYAw@mail.gmail.com>
 <52E5EFAF.3060609@linux.intel.com>
 <CAFLxGvxJ0A6hZ52RWffkg_zXXScyPn10P4HcKvdAXfE43h32Eg@mail.gmail.com>
 <52E601DA.7010605@zytor.com> <20140130220708.GP9951@redhat.com>
 <CAGXu5jKp0j71ucE7uOWRa+gQM1Wzp=_KdByJK4XnACTwiCW4ow@mail.gmail.com>
 <20140207144914.GA5949@redhat.com> <52F503FD.8080607@linux.intel.com>
 <20140207162408.GD6967@redhat.com>
 <20140207231626.GA3840@dhcp-16-126.nay.redhat.com>
Message-ID: <52F56A40.60707@zytor.com>

On 02/07/2014 03:16 PM, Dave Young wrote:
> 
> Hi Vivek,
> 
> Chaowang <chaowang at redhat.com> is looking into passing setup_data SETUP_E820_EXT
> instead of using exactmap. Previously Thomas Renninger tried passing them in e820.
> I did not find the old thread, but I remember it's not enough because of the
> 128 entries limitation. 
> 

THERE IS NO SUCH LIMITATION.

Only 128 slots fit in struct boot_params, but additional entries can be
added to the setup_data linked list.

	-hpa



From dyoung at redhat.com  Fri Feb  7 18:28:15 2014
From: dyoung at redhat.com (Dave Young)
Date: Sat, 8 Feb 2014 07:28:15 +0800
Subject: [GIT PULL] x86/kaslr for v3.14
In-Reply-To: <52F56A40.60707@zytor.com>
References: <52E5EFAF.3060609@linux.intel.com>
 <CAFLxGvxJ0A6hZ52RWffkg_zXXScyPn10P4HcKvdAXfE43h32Eg@mail.gmail.com>
 <52E601DA.7010605@zytor.com> <20140130220708.GP9951@redhat.com>
 <CAGXu5jKp0j71ucE7uOWRa+gQM1Wzp=_KdByJK4XnACTwiCW4ow@mail.gmail.com>
 <20140207144914.GA5949@redhat.com>
 <52F503FD.8080607@linux.intel.com>
 <20140207162408.GD6967@redhat.com>
 <20140207231626.GA3840@dhcp-16-126.nay.redhat.com>
 <52F56A40.60707@zytor.com>
Message-ID: <20140207232815.GD3840@dhcp-16-126.nay.redhat.com>

On 02/07/14 at 03:20pm, H. Peter Anvin wrote:
> On 02/07/2014 03:16 PM, Dave Young wrote:
> > 
> > Hi Vivek,
> > 
> > Chaowang <chaowang at redhat.com> is looking into passing setup_data SETUP_E820_EXT
> > instead of using exactmap. Previously Thomas Renninger tried passing them in e820.
> > I did not find the old thread, but I remember it's not enough because of the
> > 128 entries limitation. 
> > 
> 
> THERE IS NO SUCH LIMITATION.
> 
> Only 128 slots fit in struct boot_params, but additional entries can be
> added to the setup_data linked list.

Ok, I did not describe it right, I actually means the space limit. Thanks for
clarifying. 


From bhe at redhat.com  Sat Feb  8 04:09:47 2014
From: bhe at redhat.com (Baoquan He)
Date: Sat, 8 Feb 2014 17:09:47 +0800
Subject: [v2 2/3] makedumpfile: use struct cycle to update cyclic region
 and clean up
In-Reply-To: <0910DD04CBD6DE4193FCF86B9C00BE971E376F@BPXM01GP.gisp.nec.co.jp>
References: <1390470454-14272-1-git-send-email-bhe@redhat.com>
 <1390470454-14272-3-git-send-email-bhe@redhat.com>
 <52E5DA76.7070702@jp.fujitsu.com>
 <20140127085526.GB1481@dhcp-16-105.nay.redhat.com>
 <0910DD04CBD6DE4193FCF86B9C00BE971E376F@BPXM01GP.gisp.nec.co.jp>
Message-ID: <20140208090947.GC25133@dhcp-16-105.nay.redhat.com>

 
> > > Removing this check changes behaviour, not just clean up, so should be separated into another patch.
> > > 
> > > Further, this change seems buggy because, in addition to Kumaga-san's comment, memory outside of
> > > cycle region can be passed to here. Please look at the below.
> > 
> > Hi Both,
> > 
> > I understand your finding. How about put the pfn checking back to
> > set_bitmap_cyclic(). Maybe this is simpler and safer. Otherwise each
> > case need be taken care and adding the pfn checking.
> 
> Agreed, and this simple check may have a small influence on the
> performance, so I think it's OK to do it.
> 

Sorry to responsed so late. Will post v3 to adding back the pfn checking
in set_bitmap_cyclic. 

Thanks for your suggestion.

Baoquan
Thanks




From bhe at redhat.com  Sat Feb  8 04:19:28 2014
From: bhe at redhat.com (Baoquan He)
Date: Sat,  8 Feb 2014 17:19:28 +0800
Subject: [v3 3/3] makedumpfile: remove member variables representing cyclic
 pfn region in struct DumpInfo
In-Reply-To: <1391851168-6431-1-git-send-email-bhe@redhat.com>
References: <1391851168-6431-1-git-send-email-bhe@redhat.com>
Message-ID: <1391851168-6431-4-git-send-email-bhe@redhat.com>

Now member variables to store cyclic pfn region in struct DumpInfo
is not needed any more, remove them.

Signed-off-by: Baoquan He <bhe at redhat.com>
---
 makedumpfile.h | 2 --
 1 file changed, 2 deletions(-)

diff --git a/makedumpfile.h b/makedumpfile.h
index 38df2b3..0d5b086 100644
--- a/makedumpfile.h
+++ b/makedumpfile.h
@@ -1056,8 +1056,6 @@ struct DumpInfo {
 	 */
 	char               *partial_bitmap1;
 	char               *partial_bitmap2;
-	unsigned long long cyclic_start_pfn;
-	unsigned long long cyclic_end_pfn;  
 	unsigned long long num_dumpable;
 	unsigned long      bufsize_cyclic;
 	unsigned long      pfn_cyclic;
-- 
1.8.3.1



From bhe at redhat.com  Sat Feb  8 04:19:25 2014
From: bhe at redhat.com (Baoquan He)
Date: Sat,  8 Feb 2014 17:19:25 +0800
Subject: [v3 0/3] Introduce struct cycle to store cyclic region and clean up
Message-ID: <1391851168-6431-1-git-send-email-bhe@redhat.com>

v1->v2:
    In first_cycle(), start_pfn assignation is not aligned to info->pfn_cyclic.
    Now in v2 change this. Accordingly the pfn in write_elf_header() and
    write_elf_pages_cyclic() need be adjusted to the real beginning of a
    load segment, but not the cycle->start_pfn which may be lower after alignment.

v2->v3:
    Astushi and HATAYAMA found removing the pfn check in set_bitmap_cyclic will
introduce bugs. So it's better to add the pfn checking back, though there's
a little influence on perforcemance.

Baoquan He (3):
  makedumpfile: introduce struct cycle to store the cyclic region
  makedumpfile: use struct cycle to update cyclic region and clean up
  makedumpfile: remove member variables representing cyclic pfn region
    in struct DumpInfo

 makedumpfile.c | 498 ++++++++++++++++++++++++++++-----------------------------
 makedumpfile.h |  21 +--
 sadump_info.c  |   4 +-
 3 files changed, 261 insertions(+), 262 deletions(-)

-- 
1.8.3.1



From bhe at redhat.com  Sat Feb  8 04:19:26 2014
From: bhe at redhat.com (Baoquan He)
Date: Sat,  8 Feb 2014 17:19:26 +0800
Subject: [v3 1/3] makedumpfile: introduce struct cycle to store the cyclic
 region
In-Reply-To: <1391851168-6431-1-git-send-email-bhe@redhat.com>
References: <1391851168-6431-1-git-send-email-bhe@redhat.com>
Message-ID: <1391851168-6431-2-git-send-email-bhe@redhat.com>

The cyclic mode uses two member variables in struct DumpInfo to store
the cyclic region each time. Since there's a global instance of struct
DumpInfo, then those two member variables, cyclic_start_pfn and
cyclic_end_pfn would be the same as global variable on behavior. So
with this attribute, the implementation of updating cyclic region
have to be coupled with several other functions. Mainly in function
update_cyclic_region() this happened.

struct DumpInfo {
	...
	unsigned long long cyclic_start_pfn;
	unsigned long long cyclic_end_pfn;
	...
}

Now introduce struct cycle and several helper functions and MACRO
as Hatayama suggested. With these, the pfn region which is contained
in struct cycle can be passed down to inner functions. Then several
actions embedded in update_cyclic_region() can be decoupled.

struct cycle {
	unsigned long long start_pfn;
	unsigned long long end_pfn;
};

Signed-off-by: Baoquan He <bhe at redhat.com>
---
 makedumpfile.c | 27 +++++++++++++++++++++++++++
 makedumpfile.h |  5 +++++
 2 files changed, 32 insertions(+)

diff --git a/makedumpfile.c b/makedumpfile.c
index 7536274..01c6443 100644
--- a/makedumpfile.c
+++ b/makedumpfile.c
@@ -37,6 +37,33 @@ struct DumpInfo		*info = NULL;
 
 char filename_stdout[] = FILENAME_STDOUT;
 
+static void first_cycle(unsigned long long start, unsigned long long max, struct cycle *cycle)
+{
+	cycle->start_pfn = round(start, info->pfn_cyclic);
+	cycle->end_pfn = cycle->start_pfn + info->pfn_cyclic;
+
+	if (cycle->end_pfn > max)
+		cycle->end_pfn = max;
+}
+
+static void update_cycle(unsigned long long max, struct cycle *cycle)
+{
+	cycle->start_pfn= cycle->end_pfn;
+	cycle->end_pfn=  cycle->start_pfn + info->pfn_cyclic;
+
+	if (cycle->end_pfn > max)
+		cycle->end_pfn = max;
+}
+
+static int end_cycle(unsigned long long max, struct cycle *cycle)
+{
+	return (cycle->start_pfn >=  max)?TRUE:FALSE;
+}
+
+#define for_each_cycle(start, max, C) \
+	for (first_cycle(start, max, C); !end_cycle(max, C); \
+	     update_cycle(max, C))
+
 /*
  * The numbers of the excluded pages
  */
diff --git a/makedumpfile.h b/makedumpfile.h
index 3d270c6..4cf8102 100644
--- a/makedumpfile.h
+++ b/makedumpfile.h
@@ -1590,6 +1590,11 @@ int get_xen_info_ia64(void);
 #define get_xen_info_arch(X) FALSE
 #endif	/* s390x */
 
+struct cycle {
+	unsigned long long start_pfn;
+	unsigned long long end_pfn;
+};
+
 static inline int
 is_on(char *bitmap, int i)
 {
-- 
1.8.3.1



From bhe at redhat.com  Sat Feb  8 04:19:27 2014
From: bhe at redhat.com (Baoquan He)
Date: Sat,  8 Feb 2014 17:19:27 +0800
Subject: [v3 2/3] makedumpfile: use struct cycle to update cyclic region and
 clean up
In-Reply-To: <1391851168-6431-1-git-send-email-bhe@redhat.com>
References: <1391851168-6431-1-git-send-email-bhe@redhat.com>
Message-ID: <1391851168-6431-3-git-send-email-bhe@redhat.com>

Per struct cycle and the relevant helper functions, it's simple to
update cyclic region only. update_cyclic_region() is broken and not
needed any more. cycle containing the cyclic region is passed down,
and not global.

Related clean up is also done in this patch.

Signed-off-by: Baoquan He <bhe at redhat.com>
---
 makedumpfile.c | 471 +++++++++++++++++++++++++++------------------------------
 makedumpfile.h |  14 +-
 sadump_info.c  |   4 +-
 3 files changed, 229 insertions(+), 260 deletions(-)

diff --git a/makedumpfile.c b/makedumpfile.c
index 01c6443..daef109 100644
--- a/makedumpfile.c
+++ b/makedumpfile.c
@@ -206,7 +206,7 @@ is_in_same_page(unsigned long vaddr1, unsigned long vaddr2)
 
 #define BITMAP_SECT_LEN 4096
 static inline int is_dumpable(struct dump_bitmap *, unsigned long long);
-static inline int is_dumpable_cyclic(char *bitmap, unsigned long long);
+static inline int is_dumpable_cyclic(char *bitmap, unsigned long long, struct cycle *cycle);
 unsigned long
 pfn_to_pos(unsigned long long pfn)
 {
@@ -3301,18 +3301,18 @@ set_bitmap(struct dump_bitmap *bitmap, unsigned long long pfn,
 }
 
 int
-set_bitmap_cyclic(char *bitmap, unsigned long long pfn, int val)
+set_bitmap_cyclic(char *bitmap, unsigned long long pfn, int val, struct cycle *cycle)
 {
 	int byte, bit;
 
-	if (pfn < info->cyclic_start_pfn || info->cyclic_end_pfn <= pfn)
-		return FALSE;
+        if (pfn < cycle->start_pfn || cycle->end_pfn <= pfn)
+                return FALSE;
 
 	/*
 	 * If val is 0, clear bit on the bitmap.
 	 */
-	byte = (pfn - info->cyclic_start_pfn)>>3;
-	bit  = (pfn - info->cyclic_start_pfn) & 7;
+	byte = (pfn - cycle->start_pfn)>>3;
+	bit  = (pfn - cycle->start_pfn) & 7;
 	if (val)
 		bitmap[byte] |= 1<<bit;
 	else
@@ -3361,37 +3361,37 @@ sync_2nd_bitmap(void)
 }
 
 int
-set_bit_on_1st_bitmap(unsigned long long pfn)
+set_bit_on_1st_bitmap(unsigned long long pfn, struct cycle *cycle)
 {
 	if (info->flag_cyclic) {
-		return set_bitmap_cyclic(info->partial_bitmap1, pfn, 1);
+		return set_bitmap_cyclic(info->partial_bitmap1, pfn, 1, cycle);
 	} else {
 		return set_bitmap(info->bitmap1, pfn, 1);
 	}
 }
 
 int
-clear_bit_on_1st_bitmap(unsigned long long pfn)
+clear_bit_on_1st_bitmap(unsigned long long pfn, struct cycle *cycle)
 {
 	if (info->flag_cyclic) {
-		return set_bitmap_cyclic(info->partial_bitmap1, pfn, 0);
+		return set_bitmap_cyclic(info->partial_bitmap1, pfn, 0, cycle);
 	} else {
 		return set_bitmap(info->bitmap1, pfn, 0);
 	}
 }
 
 int
-clear_bit_on_2nd_bitmap(unsigned long long pfn)
+clear_bit_on_2nd_bitmap(unsigned long long pfn, struct cycle *cycle)
 {
 	if (info->flag_cyclic) {
-		return set_bitmap_cyclic(info->partial_bitmap2, pfn, 0);
+		return set_bitmap_cyclic(info->partial_bitmap2, pfn, 0, cycle);
 	} else {
 		return set_bitmap(info->bitmap2, pfn, 0);
 	}
 }
 
 int
-clear_bit_on_2nd_bitmap_for_kernel(unsigned long long pfn)
+clear_bit_on_2nd_bitmap_for_kernel(unsigned long long pfn, struct cycle *cycle)
 {
 	unsigned long long maddr;
 
@@ -3404,21 +3404,21 @@ clear_bit_on_2nd_bitmap_for_kernel(unsigned long long pfn)
 		}
 		pfn = paddr_to_pfn(maddr);
 	}
-	return clear_bit_on_2nd_bitmap(pfn);
+	return clear_bit_on_2nd_bitmap(pfn, cycle);
 }
 
 int
-set_bit_on_2nd_bitmap(unsigned long long pfn)
+set_bit_on_2nd_bitmap(unsigned long long pfn, struct cycle *cycle)
 {
 	if (info->flag_cyclic) {
-		return set_bitmap_cyclic(info->partial_bitmap2, pfn, 1);
+		return set_bitmap_cyclic(info->partial_bitmap2, pfn, 1, cycle);
 	} else {
 		return set_bitmap(info->bitmap2, pfn, 1);
 	}
 }
 
 int
-set_bit_on_2nd_bitmap_for_kernel(unsigned long long pfn)
+set_bit_on_2nd_bitmap_for_kernel(unsigned long long pfn, struct cycle *cycle)
 {
 	unsigned long long maddr;
 
@@ -3431,7 +3431,7 @@ set_bit_on_2nd_bitmap_for_kernel(unsigned long long pfn)
 		}
 		pfn = paddr_to_pfn(maddr);
 	}
-	return set_bit_on_2nd_bitmap(pfn);
+	return set_bit_on_2nd_bitmap(pfn, cycle);
 }
 
 static inline int
@@ -3757,7 +3757,7 @@ page_to_pfn(unsigned long page)
 }
 
 int
-reset_bitmap_of_free_pages(unsigned long node_zones)
+reset_bitmap_of_free_pages(unsigned long node_zones, struct cycle *cycle)
 {
 
 	int order, i, migrate_type, migrate_types;
@@ -3803,7 +3803,7 @@ reset_bitmap_of_free_pages(unsigned long node_zones)
 				}
 				for (i = 0; i < (1<<order); i++) {
 					pfn = start_pfn + i;
-					if (clear_bit_on_2nd_bitmap_for_kernel(pfn))
+					if (clear_bit_on_2nd_bitmap_for_kernel(pfn, cycle))
 						found_free_pages++;
 				}
 
@@ -4098,7 +4098,7 @@ out:
 
 
 int
-_exclude_free_page(void)
+_exclude_free_page(struct cycle *cycle)
 {
 	int i, nr_zones, num_nodes, node;
 	unsigned long node_zones, zone, spanned_pages, pgdat;
@@ -4139,7 +4139,7 @@ _exclude_free_page(void)
 			}
 			if (!spanned_pages)
 				continue;
-			if (!reset_bitmap_of_free_pages(zone))
+			if (!reset_bitmap_of_free_pages(zone, cycle))
 				return FALSE;
 		}
 		if (num_nodes < vt.numnodes) {
@@ -4164,7 +4164,7 @@ _exclude_free_page(void)
 }
 
 int
-exclude_free_page(void)
+exclude_free_page(struct cycle *cycle)
 {
 	/*
 	 * Check having necessary information.
@@ -4199,7 +4199,7 @@ exclude_free_page(void)
 	/*
 	 * Detect free pages and update 2nd-bitmap.
 	 */
-	if (!_exclude_free_page())
+	if (!_exclude_free_page(cycle))
 		return FALSE;
 
 	return TRUE;
@@ -4404,7 +4404,7 @@ create_1st_bitmap(void)
 		pfn_end   = paddr_to_pfn(phys_end);
 
 		for (pfn = pfn_start; pfn < pfn_end; pfn++) {
-			set_bit_on_1st_bitmap(pfn);
+			set_bit_on_1st_bitmap(pfn, NULL);
 			pfn_bitmap1++;
 		}
 	}
@@ -4422,8 +4422,9 @@ create_1st_bitmap(void)
 	return TRUE;
 }
 
+
 int
-create_1st_bitmap_cyclic()
+create_1st_bitmap_cyclic(struct cycle *cycle)
 {
 	int i;
 	unsigned long long pfn, pfn_bitmap1;
@@ -4443,8 +4444,8 @@ create_1st_bitmap_cyclic()
 	 */
 	pfn_bitmap1 = 0;
 	for (i = 0; get_pt_load(i, &phys_start, &phys_end, NULL, NULL); i++) {
-		pfn_start = MAX(paddr_to_pfn(phys_start), info->cyclic_start_pfn);
-		pfn_end   = MIN(paddr_to_pfn(phys_end), info->cyclic_end_pfn);
+		pfn_start = MAX(paddr_to_pfn(phys_start), cycle->start_pfn);
+		pfn_end   = MIN(paddr_to_pfn(phys_end), cycle->end_pfn);
 
 		if (pfn_start >= pfn_end)
 			continue;
@@ -4453,12 +4454,12 @@ create_1st_bitmap_cyclic()
 		pfn_end_round = round(pfn_end, BITPERBYTE);
 
 		for (pfn = pfn_start; pfn < pfn_start_roundup; pfn++) {
-			if (set_bit_on_1st_bitmap(pfn))
+			if (set_bit_on_1st_bitmap(pfn, cycle))
 				pfn_bitmap1++;
 		}
 
-		pfn_start_byte = (pfn_start_roundup - info->cyclic_start_pfn) >> 3;
-		pfn_end_byte = (pfn_end_round - info->cyclic_start_pfn) >> 3;
+		pfn_start_byte = (pfn_start_roundup - cycle->start_pfn) >> 3;
+		pfn_end_byte = (pfn_end_round - cycle->start_pfn) >> 3;
 
 		if (pfn_start_byte < pfn_end_byte) {
 			memset(info->partial_bitmap1 + pfn_start_byte,
@@ -4469,7 +4470,7 @@ create_1st_bitmap_cyclic()
 		}
 
 		for (pfn = pfn_end_round; pfn < pfn_end; pfn++) {
-			if (set_bit_on_1st_bitmap(pfn))
+			if (set_bit_on_1st_bitmap(pfn, cycle))
 				pfn_bitmap1++;
 		}
 	}
@@ -4518,7 +4519,7 @@ exclude_zero_pages(void)
 			}
 		}
 		if (is_zero_page(buf, info->page_size)) {
-			if (clear_bit_on_2nd_bitmap(pfn))
+			if (clear_bit_on_2nd_bitmap(pfn, NULL))
 				pfn_zero++;
 		}
 	}
@@ -4533,7 +4534,7 @@ exclude_zero_pages(void)
 }
 
 static int
-initialize_2nd_bitmap_cyclic(void)
+initialize_2nd_bitmap_cyclic(struct cycle *cycle)
 {
 	int i;
 	unsigned long long pfn;
@@ -4551,8 +4552,8 @@ initialize_2nd_bitmap_cyclic(void)
 	 * If page is on memory hole, set bit on the 2nd-bitmap.
 	 */
 	for (i = 0; get_pt_load(i, &phys_start, &phys_end, NULL, NULL); i++) {
-		pfn_start = MAX(paddr_to_pfn(phys_start), info->cyclic_start_pfn);
-		pfn_end = MIN(paddr_to_pfn(phys_end), info->cyclic_end_pfn);
+		pfn_start = MAX(paddr_to_pfn(phys_start), cycle->start_pfn);
+		pfn_end = MIN(paddr_to_pfn(phys_end), cycle->end_pfn);
 
 		if (pfn_start >= pfn_end)
 			continue;
@@ -4561,11 +4562,11 @@ initialize_2nd_bitmap_cyclic(void)
 		pfn_end_round = round(pfn_end, BITPERBYTE);
 
 		for (pfn = pfn_start; pfn < pfn_start_roundup; ++pfn)
-			if (!set_bit_on_2nd_bitmap_for_kernel(pfn))
+			if (!set_bit_on_2nd_bitmap_for_kernel(pfn, cycle))
 				return FALSE;
 
-		pfn_start_byte = (pfn_start_roundup - info->cyclic_start_pfn) >> 3;
-		pfn_end_byte = (pfn_end_round - info->cyclic_start_pfn) >> 3;
+		pfn_start_byte = (pfn_start_roundup - cycle->start_pfn) >> 3;
+		pfn_end_byte = (pfn_end_round - cycle->start_pfn) >> 3;
 
 		if (pfn_start_byte < pfn_end_byte) {
 			memset(info->partial_bitmap2 + pfn_start_byte,
@@ -4574,7 +4575,7 @@ initialize_2nd_bitmap_cyclic(void)
 		}
 
 		for (pfn = pfn_end_round; pfn < pfn_end; ++pfn)
-			if (!set_bit_on_2nd_bitmap_for_kernel(pfn))
+			if (!set_bit_on_2nd_bitmap_for_kernel(pfn, cycle))
 				return FALSE;
 	}
 
@@ -4583,7 +4584,7 @@ initialize_2nd_bitmap_cyclic(void)
 
 int
 __exclude_unnecessary_pages(unsigned long mem_map,
-    unsigned long long pfn_start, unsigned long long pfn_end)
+    unsigned long long pfn_start, unsigned long long pfn_end, struct cycle *cycle)
 {
 	unsigned long long pfn, pfn_mm, maddr;
 	unsigned long long pfn_read_start, pfn_read_end, index_pg;
@@ -4603,7 +4604,7 @@ __exclude_unnecessary_pages(unsigned long mem_map,
 		/*
 		 * If this pfn doesn't belong to target region, skip this pfn.
 		 */
-		if (info->flag_cyclic && !is_cyclic_region(pfn))
+		if (info->flag_cyclic && !is_cyclic_region(pfn, cycle))
 			continue;
 
 		/*
@@ -4668,7 +4669,7 @@ __exclude_unnecessary_pages(unsigned long mem_map,
 				 * See check_cyclic_buffer_overrun()
 				 * for the detail.
 				 */
-				if (clear_bit_on_2nd_bitmap_for_kernel(pfn + i))
+				if (clear_bit_on_2nd_bitmap_for_kernel((pfn + i), cycle))
 					pfn_free++;
 			}
 			pfn += nr_pages - 1;
@@ -4680,7 +4681,7 @@ __exclude_unnecessary_pages(unsigned long mem_map,
 		else if ((info->dump_level & DL_EXCLUDE_CACHE)
 		    && (isLRU(flags) || isSwapCache(flags))
 		    && !isPrivate(flags) && !isAnon(mapping)) {
-			if (clear_bit_on_2nd_bitmap_for_kernel(pfn))
+			if (clear_bit_on_2nd_bitmap_for_kernel(pfn, cycle))
 				pfn_cache++;
 		}
 		/*
@@ -4689,7 +4690,7 @@ __exclude_unnecessary_pages(unsigned long mem_map,
 		else if ((info->dump_level & DL_EXCLUDE_CACHE_PRI)
 		    && (isLRU(flags) || isSwapCache(flags))
 		    && !isAnon(mapping)) {
-			if (clear_bit_on_2nd_bitmap_for_kernel(pfn))
+			if (clear_bit_on_2nd_bitmap_for_kernel(pfn, cycle))
 				pfn_cache_private++;
 		}
 		/*
@@ -4697,14 +4698,14 @@ __exclude_unnecessary_pages(unsigned long mem_map,
 		 */
 		else if ((info->dump_level & DL_EXCLUDE_USER_DATA)
 		    && isAnon(mapping)) {
-			if (clear_bit_on_2nd_bitmap_for_kernel(pfn))
+			if (clear_bit_on_2nd_bitmap_for_kernel(pfn, cycle))
 				pfn_user++;
 		}
 		/*
 		 * Exclude the hwpoison page.
 		 */
 		else if (isHWPOISON(flags)) {
-			if (clear_bit_on_2nd_bitmap_for_kernel(pfn))
+			if (clear_bit_on_2nd_bitmap_for_kernel(pfn, cycle))
 				pfn_hwpoison++;
 		}
 	}
@@ -4734,7 +4735,7 @@ exclude_unnecessary_pages(void)
 			continue;
 
 		if (!__exclude_unnecessary_pages(mmd->mem_map,
-						 mmd->pfn_start, mmd->pfn_end))
+						 mmd->pfn_start, mmd->pfn_end, NULL))
 			return FALSE;
 	}
 
@@ -4748,17 +4749,17 @@ exclude_unnecessary_pages(void)
 }
 
 int
-exclude_unnecessary_pages_cyclic(void)
+exclude_unnecessary_pages_cyclic(struct cycle *cycle)
 {
 	unsigned int mm;
 	struct mem_map_data *mmd;
 	struct timeval tv_start;
 
-	if (!initialize_2nd_bitmap_cyclic())
+	if (!initialize_2nd_bitmap_cyclic(cycle))
 		return FALSE;
 
 	if ((info->dump_level & DL_EXCLUDE_FREE) && !info->page_is_buddy)
-		if (!exclude_free_page())
+		if (!exclude_free_page(cycle))
 			return FALSE;
 
 	/*
@@ -4782,10 +4783,10 @@ exclude_unnecessary_pages_cyclic(void)
 			if (mmd->mem_map == NOT_MEMMAP_ADDR)
 				continue;
 
-			if (mmd->pfn_end >= info->cyclic_start_pfn &&
-			    mmd->pfn_start <= info->cyclic_end_pfn) {
+			if (mmd->pfn_end >= cycle->start_pfn &&
+			    mmd->pfn_start <= cycle->end_pfn) {
 				if (!__exclude_unnecessary_pages(mmd->mem_map,
-								 mmd->pfn_start, mmd->pfn_end))
+								 mmd->pfn_start, mmd->pfn_end, cycle))
 					return FALSE;
 			}
 		}
@@ -4801,27 +4802,6 @@ exclude_unnecessary_pages_cyclic(void)
 }
 
 int
-update_cyclic_region(unsigned long long pfn)
-{
-	if (is_cyclic_region(pfn))
-		return TRUE;
-
-	info->cyclic_start_pfn = round(pfn, info->pfn_cyclic);
-	info->cyclic_end_pfn = info->cyclic_start_pfn + info->pfn_cyclic;
-
-	if (info->cyclic_end_pfn > info->max_mapnr)
-		info->cyclic_end_pfn = info->max_mapnr;
-
-	if (info->flag_elf_dumpfile && !create_1st_bitmap_cyclic())
-		return FALSE;
-
-	if (!exclude_unnecessary_pages_cyclic())
-		return FALSE;
-
-	return TRUE;
-}
-
-int
 copy_bitmap(void)
 {
 	off_t offset;
@@ -4887,7 +4867,7 @@ create_2nd_bitmap(void)
 	 * Exclude free pages.
 	 */
 	if ((info->dump_level & DL_EXCLUDE_FREE) && !info->page_is_buddy)
-		if (!exclude_free_page())
+		if (!exclude_free_page(NULL))
 			return FALSE;
 
 	/*
@@ -5576,13 +5556,16 @@ unsigned long long
 get_num_dumpable_cyclic(void)
 {
 	unsigned long long pfn, num_dumpable=0;
+	struct cycle cycle = {0};
 
-	for (pfn = 0; pfn < info->max_mapnr; pfn++) {
-		if (!update_cyclic_region(pfn))
+	for_each_cycle(0, info->max_mapnr, &cycle)
+	{
+		if (!exclude_unnecessary_pages_cyclic(&cycle))
 			return FALSE;
 
-		if (is_dumpable_cyclic(info->partial_bitmap2, pfn))
-			num_dumpable++;
+		for(pfn=cycle.start_pfn; pfn<cycle.end_pfn; pfn++)
+			if (is_dumpable_cyclic(info->partial_bitmap2, pfn, &cycle))
+				num_dumpable++;
 	}
 
 	return num_dumpable;
@@ -5841,16 +5824,7 @@ get_loads_dumpfile_cyclic(void)
 	unsigned long long pfn, pfn_start, pfn_end, num_excluded;
 	unsigned long frac_head, frac_tail;
 	Elf64_Phdr load;
-
-	/*
-	 * Initialize target region and bitmap.
-	 */
-	info->cyclic_start_pfn = 0;
-	info->cyclic_end_pfn = info->pfn_cyclic;
-	if (!create_1st_bitmap_cyclic())
-		return FALSE;
-	if (!exclude_unnecessary_pages_cyclic())
-		return FALSE;
+	struct cycle cycle = {0};
 
 	if (!(phnum = get_phnum_memory()))
 		return FALSE;
@@ -5874,44 +5848,41 @@ get_loads_dumpfile_cyclic(void)
 		if (frac_tail)
 			pfn_end++;
 
-		for (pfn = pfn_start; pfn < pfn_end; pfn++) {
-			/*
-			 * Update target region and bitmap
-			 */
-			if (!is_cyclic_region(pfn)) {
-				if (!update_cyclic_region(pfn))
-					return FALSE;
-			}
-
-			if (!is_dumpable_cyclic(info->partial_bitmap2, pfn)) {
-				num_excluded++;
-				continue;
-			}
-
-			/*
-			 * Exclude zero pages.
-			 */
-			if (info->dump_level & DL_EXCLUDE_ZERO) {
-				if (!read_pfn(pfn, buf))
-					return FALSE;
-				if (is_zero_page(buf, page_size)) {
+		for_each_cycle(pfn_start, pfn_end, &cycle) {
+			if (!exclude_unnecessary_pages_cyclic(&cycle))
+				return FALSE;
+			for (pfn = MAX(pfn_start, cycle.start_pfn); pfn < cycle.end_pfn; pfn++) {
+				if (!is_dumpable_cyclic(info->partial_bitmap2, pfn, &cycle)) {
 					num_excluded++;
 					continue;
 				}
-			}
 
-			info->num_dumpable++;
+				/*
+				 * Exclude zero pages.
+				 */
+				if (info->dump_level & DL_EXCLUDE_ZERO) {
+					if (!read_pfn(pfn, buf))
+						return FALSE;
+					if (is_zero_page(buf, page_size)) {
+						num_excluded++;
+						continue;
+					}
+				}
 
-			/*
-			 * If the number of the contiguous pages to be excluded
-			 * is 256 or more, those pages are excluded really.
-			 * And a new PT_LOAD segment is created.
-			 */
-			if (num_excluded >= PFN_EXCLUDED) {
-				num_new_load++;
+				info->num_dumpable++;
+
+				/*
+				 * If the number of the contiguous pages to be excluded
+				 * is 256 or more, those pages are excluded really.
+				 * And a new PT_LOAD segment is created.
+				 */
+				if (num_excluded >= PFN_EXCLUDED) {
+					num_new_load++;
+				}
+				num_excluded = 0;
 			}
-			num_excluded = 0;
 		}
+
 	}
 	return num_new_load;
 }
@@ -5929,6 +5900,7 @@ write_elf_pages_cyclic(struct cache_data *cd_header, struct cache_data *cd_page)
 	off_t off_seg_load, off_memory;
 	Elf64_Phdr load;
 	struct timeval tv_start;
+	struct cycle cycle = {0};
 
 	if (!info->flag_elf_dumpfile)
 		return FALSE;
@@ -5946,11 +5918,6 @@ write_elf_pages_cyclic(struct cache_data *cd_header, struct cache_data *cd_page)
 	pfn_user = pfn_free = pfn_hwpoison = 0;
 	pfn_memhole = info->max_mapnr;
 
-	info->cyclic_start_pfn = 0;
-	info->cyclic_end_pfn = 0;
-	if (!update_cyclic_region(0))
-		return FALSE;
-
 	if (!(phnum = get_phnum_memory()))
 		return FALSE;
 
@@ -5982,30 +5949,17 @@ write_elf_pages_cyclic(struct cache_data *cd_header, struct cache_data *cd_page)
 		if (frac_tail)
 			pfn_end++;
 
-		for (pfn = pfn_start; pfn < pfn_end; pfn++) {
+		for_each_cycle(pfn_start, pfn_end, &cycle) {
 			/*
 			 * Update target region and partial bitmap if necessary.
 			 */
-			if (!update_cyclic_region(pfn))
+			if (!create_1st_bitmap_cyclic(&cycle))
+				return FALSE;
+			if (!exclude_unnecessary_pages_cyclic(&cycle))
 				return FALSE;
 
-			if (!is_dumpable_cyclic(info->partial_bitmap2, pfn)) {
-				num_excluded++;
-				if ((pfn == pfn_end - 1) && frac_tail)
-					memsz += frac_tail;
-				else
-					memsz += page_size;
-				continue;
-			}
-
-			/*
-			 * Exclude zero pages.
-			 */
-			if (info->dump_level & DL_EXCLUDE_ZERO) {
-				if (!read_pfn(pfn, buf))
-					return FALSE;
-				if (is_zero_page(buf, page_size)) {
-					pfn_zero++;
+			for (pfn = MAX(pfn_start, cycle.start_pfn); pfn < cycle.end_pfn; pfn++) {
+				if (!is_dumpable_cyclic(info->partial_bitmap2, pfn, &cycle)) {
 					num_excluded++;
 					if ((pfn == pfn_end - 1) && frac_tail)
 						memsz += frac_tail;
@@ -6013,93 +5967,111 @@ write_elf_pages_cyclic(struct cache_data *cd_header, struct cache_data *cd_page)
 						memsz += page_size;
 					continue;
 				}
-			}
 
-			if ((num_dumped % per) == 0)
-				print_progress(PROGRESS_COPY, num_dumped, num_dumpable);
+				/*
+				 * Exclude zero pages.
+				 */
+				if (info->dump_level & DL_EXCLUDE_ZERO) {
+					if (!read_pfn(pfn, buf))
+						return FALSE;
+					if (is_zero_page(buf, page_size)) {
+						pfn_zero++;
+						num_excluded++;
+						if ((pfn == pfn_end - 1) && frac_tail)
+							memsz += frac_tail;
+						else
+							memsz += page_size;
+						continue;
+					}
+				}
 
-			num_dumped++;
+				if ((num_dumped % per) == 0)
+					print_progress(PROGRESS_COPY, num_dumped, num_dumpable);
+
+				num_dumped++;
 
-			/*
-			 * The dumpable pages are continuous.
-			 */
-			if (!num_excluded) {
-				if ((pfn == pfn_end - 1) && frac_tail) {
-					memsz  += frac_tail;
-					filesz += frac_tail;
-				} else {
-					memsz  += page_size;
-					filesz += page_size;
-				}
-				continue;
 				/*
-				 * If the number of the contiguous pages to be excluded
-				 * is 255 or less, those pages are not excluded.
+				 * The dumpable pages are continuous.
 				 */
-			} else if (num_excluded < PFN_EXCLUDED) {
-				if ((pfn == pfn_end - 1) && frac_tail) {
-					memsz  += frac_tail;
-					filesz += (page_size*num_excluded
-						   + frac_tail);
-				}else {
-					memsz  += page_size;
-					filesz += (page_size*num_excluded
-						   + page_size);
+				if (!num_excluded) {
+					if ((pfn == pfn_end - 1) && frac_tail) {
+						memsz  += frac_tail;
+						filesz += frac_tail;
+					} else {
+						memsz  += page_size;
+						filesz += page_size;
+					}
+					continue;
+					/*
+					 * If the number of the contiguous pages to be excluded
+					 * is 255 or less, those pages are not excluded.
+					 */
+				} else if (num_excluded < PFN_EXCLUDED) {
+					if ((pfn == pfn_end - 1) && frac_tail) {
+						memsz  += frac_tail;
+						filesz += (page_size*num_excluded
+							   + frac_tail);
+					}else {
+						memsz  += page_size;
+						filesz += (page_size*num_excluded
+							   + page_size);
+					}
+					num_excluded = 0;
+					continue;
 				}
-				num_excluded = 0;
-				continue;
-			}
 
-			/*
-			 * If the number of the contiguous pages to be excluded
-			 * is 256 or more, those pages are excluded really.
-			 * And a new PT_LOAD segment is created.
-			 */
-			load.p_memsz = memsz;
-			load.p_filesz = filesz;
-			if (load.p_filesz)
-				load.p_offset = off_seg_load;
-			else
 				/*
-				 * If PT_LOAD segment does not have real data
-				 * due to the all excluded pages, the file
-				 * offset is not effective and it should be 0.
+				 * If the number of the contiguous pages to be excluded
+				 * is 256 or more, those pages are excluded really.
+				 * And a new PT_LOAD segment is created.
 				 */
-				load.p_offset = 0;
-
-			/*
-			 * Write a PT_LOAD header.
-			 */
-			if (!write_elf_phdr(cd_header, &load))
-				return FALSE;
+				load.p_memsz = memsz;
+				load.p_filesz = filesz;
+				if (load.p_filesz)
+					load.p_offset = off_seg_load;
+				else
+					/*
+					 * If PT_LOAD segment does not have real data
+					 * due to the all excluded pages, the file
+					 * offset is not effective and it should be 0.
+					 */
+					load.p_offset = 0;
 
-			/*
-			 * Write a PT_LOAD segment.
-			 */
-			if (load.p_filesz)
-				if (!write_elf_load_segment(cd_page, paddr,
-							    off_memory, load.p_filesz))
+				/*
+				 * Write a PT_LOAD header.
+				 */
+				if (!write_elf_phdr(cd_header, &load))
 					return FALSE;
 
-			load.p_paddr += load.p_memsz;
+				/*
+				 * Write a PT_LOAD segment.
+				 */
+				if (load.p_filesz)
+					if (!write_elf_load_segment(cd_page, paddr,
+								    off_memory, load.p_filesz))
+						return FALSE;
+
+				load.p_paddr += load.p_memsz;
 #ifdef __x86__
-			/*
-			 * FIXME:
-			 *  (x86) Fill PT_LOAD headers with appropriate
-			 * virtual addresses.
-			 */
-			if (load.p_paddr < MAXMEM)
-				load.p_vaddr += load.p_memsz;
+				/*
+				 * FIXME:
+				 *  (x86) Fill PT_LOAD headers with appropriate
+				 * virtual addresses.
+				 */
+				if (load.p_paddr < MAXMEM)
+					load.p_vaddr += load.p_memsz;
 #else
-			load.p_vaddr += load.p_memsz;
+				load.p_vaddr += load.p_memsz;
 #endif /* x86 */
-			paddr  = load.p_paddr;
-			off_seg_load += load.p_filesz;
+				paddr  = load.p_paddr;
+				off_seg_load += load.p_filesz;
 
-			num_excluded = 0;
-			memsz  = page_size;
-			filesz = page_size;
+				num_excluded = 0;
+				memsz  = page_size;
+				filesz = page_size;
+			}
 		}
+
 		/*
 		 * Write the last PT_LOAD.
 		 */
@@ -6348,7 +6320,7 @@ out:
 
 int
 write_kdump_pages_cyclic(struct cache_data *cd_header, struct cache_data *cd_page,
-			 struct page_desc *pd_zero, off_t *offset_data)
+			 struct page_desc *pd_zero, off_t *offset_data, struct cycle *cycle)
 {
 	unsigned long long pfn, per;
 	unsigned long long start_pfn, end_pfn;
@@ -6406,8 +6378,8 @@ write_kdump_pages_cyclic(struct cache_data *cd_header, struct cache_data *cd_pag
 		goto out;
 	}
 
-	start_pfn = info->cyclic_start_pfn;
-	end_pfn   = info->cyclic_end_pfn;
+	start_pfn = cycle->start_pfn;
+	end_pfn   = cycle->end_pfn;
 
 	if (info->flag_split) {
 		if (start_pfn < info->split_start_pfn)
@@ -6426,7 +6398,7 @@ write_kdump_pages_cyclic(struct cache_data *cd_header, struct cache_data *cd_pag
 		/*
 		 * Check the excluded page.
 		 */
-		if (!is_dumpable_cyclic(info->partial_bitmap2, pfn))
+		if (!is_on(info->partial_bitmap2, pfn - cycle->start_pfn))
 			continue;
 
 		num_dumped++;
@@ -6788,20 +6760,20 @@ out:
 }
 
 int
-write_kdump_bitmap1_cyclic(void)
+write_kdump_bitmap1_cyclic(struct cycle *cycle)
 {
 	off_t offset;
         int increment;
 	int ret = FALSE;
 
-	increment = divideup(info->cyclic_end_pfn - info->cyclic_start_pfn, BITPERBYTE);
+	increment = divideup(cycle->end_pfn - cycle->start_pfn, BITPERBYTE);
 
 	if (info->flag_elf_dumpfile)
 		return FALSE;
 
 	offset = info->offset_bitmap1;
 	if (!write_buffer(info->fd_dumpfile, offset + info->bufsize_cyclic *
-			  (info->cyclic_start_pfn / info->pfn_cyclic),
+			  (cycle->start_pfn / info->pfn_cyclic),
 			  info->partial_bitmap1, increment, info->name_dumpfile))
 		goto out;
 
@@ -6811,13 +6783,13 @@ out:
 }
 
 int
-write_kdump_bitmap2_cyclic(void)
+write_kdump_bitmap2_cyclic(struct cycle *cycle)
 {
 	off_t offset;
 	int increment;
 	int ret = FALSE;
 
-	increment = divideup(info->cyclic_end_pfn - info->cyclic_start_pfn,
+	increment = divideup(cycle->end_pfn - cycle->start_pfn,
 			     BITPERBYTE);
 
 	if (info->flag_elf_dumpfile)
@@ -6844,7 +6816,6 @@ write_kdump_pages_and_bitmap_cyclic(struct cache_data *cd_header, struct cache_d
 	off_t offset_data=0;
 	struct disk_dump_header *dh = info->dump_header;
 	unsigned char buf[info->page_size];
-	unsigned long long pfn;
 	struct timeval tv_start;
 
 	/*
@@ -6880,19 +6851,16 @@ write_kdump_pages_and_bitmap_cyclic(struct cache_data *cd_header, struct cache_d
 	if (!prepare_bitmap1_buffer_cyclic())
 		return FALSE;
 
-	info->cyclic_start_pfn = 0;
-	info->cyclic_end_pfn = 0;
-	for (pfn = 0; pfn < info->max_mapnr; pfn++) {
-		if (is_cyclic_region(pfn))
-			continue;
-		if (!update_cyclic_region(pfn))
-			return FALSE;
-		if (!create_1st_bitmap_cyclic())
+	struct cycle cycle = {0};
+	for_each_cycle(0, info->max_mapnr, &cycle)
+	{
+		if (!create_1st_bitmap_cyclic(&cycle))
 			return FALSE;
-		if (!write_kdump_bitmap1_cyclic())
+		if (!write_kdump_bitmap1_cyclic(&cycle))
 			return FALSE;
 	}
 
+
 	free_bitmap1_buffer();
 
 	if (!prepare_bitmap2_buffer_cyclic())
@@ -6901,21 +6869,22 @@ write_kdump_pages_and_bitmap_cyclic(struct cache_data *cd_header, struct cache_d
 	/*
 	 * Write pages and bitmap cyclically.
 	 */
-	info->cyclic_start_pfn = 0;
-	info->cyclic_end_pfn = 0;
-	for (pfn = 0; pfn < info->max_mapnr; pfn++) {
-		if (is_cyclic_region(pfn))
-			continue;
-
-		if (!update_cyclic_region(pfn))
-                        return FALSE;
+	//cycle = {0, 0};
+	memset(&cycle, 0, sizeof(struct cycle));
+	for_each_cycle(0, info->max_mapnr, &cycle)
+	{
+		if (!exclude_unnecessary_pages_cyclic(&cycle))
+			return FALSE;
 
-		if (!write_kdump_pages_cyclic(cd_header, cd_page, &pd_zero, &offset_data))
+		if (!write_kdump_pages_cyclic(cd_header, cd_page, &pd_zero,
+					&offset_data, &cycle))
 			return FALSE;
 
-		if (!write_kdump_bitmap2_cyclic())
+		if (!write_kdump_bitmap2_cyclic(&cycle))
 			return FALSE;
-        }
+	}
+
+
 
 	gettimeofday(&tv_start, NULL);
 
@@ -7527,7 +7496,7 @@ exclude_xen3_user_domain(void)
 					size * num_pt_loads);
 
 			if (!allocated_in_map(pfn)) {
-				clear_bit_on_2nd_bitmap(pfn);
+				clear_bit_on_2nd_bitmap(pfn, NULL);
 				continue;
 			}
 
@@ -7535,7 +7504,7 @@ exclude_xen3_user_domain(void)
 			if (!readmem(VADDR_XEN,
 			      page_info_addr + OFFSET(page_info.count_info),
 		 	      &count_info, sizeof(count_info))) {
-				clear_bit_on_2nd_bitmap(pfn);
+				clear_bit_on_2nd_bitmap(pfn, NULL);
 				continue;	/* page_info may not exist */
 			}
 			if (!readmem(VADDR_XEN,
@@ -7556,7 +7525,7 @@ exclude_xen3_user_domain(void)
 				continue;
 			if ((count_info & 0xffff) && is_select_domain(_domain))
 				continue;
-			clear_bit_on_2nd_bitmap(pfn);
+			clear_bit_on_2nd_bitmap(pfn, NULL);
 		}
 	}
 
@@ -7594,7 +7563,7 @@ exclude_xen4_user_domain(void)
 			if (!readmem(VADDR_XEN,
 			      page_info_addr + OFFSET(page_info.count_info),
 		 	      &count_info, sizeof(count_info))) {
-				clear_bit_on_2nd_bitmap(pfn);
+				clear_bit_on_2nd_bitmap(pfn, NULL);
 				continue;	/* page_info may not exist */
 			}
 
@@ -7606,7 +7575,7 @@ exclude_xen4_user_domain(void)
 			if (page_state_is(count_info, free) ||
 			    page_state_is(count_info, offlined) ||
 			    count_info & PGC_broken) {
-				clear_bit_on_2nd_bitmap(pfn);
+				clear_bit_on_2nd_bitmap(pfn, NULL);
 				continue;
 			}
 
@@ -7632,7 +7601,7 @@ exclude_xen4_user_domain(void)
 				continue;
 			if (is_select_domain(_domain))
 				continue;
-			clear_bit_on_2nd_bitmap(pfn);
+			clear_bit_on_2nd_bitmap(pfn, NULL);
 		}
 	}
 
diff --git a/makedumpfile.h b/makedumpfile.h
index 4cf8102..38df2b3 100644
--- a/makedumpfile.h
+++ b/makedumpfile.h
@@ -1618,18 +1618,18 @@ is_dumpable(struct dump_bitmap *bitmap, unsigned long long pfn)
 }
 
 static inline int
-is_dumpable_cyclic(char *bitmap, unsigned long long pfn)
+is_dumpable_cyclic(char *bitmap, unsigned long long pfn, struct cycle *cycle)
 {
-	if (pfn < info->cyclic_start_pfn || info->cyclic_end_pfn <= pfn)
+	if (pfn < cycle->start_pfn || cycle->end_pfn <= pfn)
 		return FALSE;
 	else
-		return is_on(bitmap, pfn - info->cyclic_start_pfn);
+		return is_on(bitmap, pfn - cycle->start_pfn);
 }
 
 static inline int
-is_cyclic_region(unsigned long long pfn)
+is_cyclic_region(unsigned long long pfn, struct cycle *cycle)
 {
-	if (pfn < info->cyclic_start_pfn || info->cyclic_end_pfn <= pfn)
+	if (pfn < cycle->start_pfn || cycle->end_pfn <= pfn)
 		return FALSE;
 	else
 		return TRUE;
@@ -1647,8 +1647,8 @@ is_zero_page(unsigned char *buf, long page_size)
 }
 
 void write_vmcoreinfo_data(void);
-int set_bit_on_1st_bitmap(unsigned long long pfn);
-int clear_bit_on_1st_bitmap(unsigned long long pfn);
+int set_bit_on_1st_bitmap(unsigned long long pfn, struct cycle *cycle);
+int clear_bit_on_1st_bitmap(unsigned long long pfn, struct cycle *cycle);
 
 #ifdef __x86__
 
diff --git a/sadump_info.c b/sadump_info.c
index 7822e82..f14ffc9 100644
--- a/sadump_info.c
+++ b/sadump_info.c
@@ -214,9 +214,9 @@ sadump_copy_1st_bitmap_from_memory(void)
 						      si->backup_src_start);
 
 			if (is_dumpable(info->bitmap_memory, backup_src_pfn))
-				set_bit_on_1st_bitmap(pfn);
+				set_bit_on_1st_bitmap(pfn, NULL);
 			else
-				clear_bit_on_1st_bitmap(pfn);
+				clear_bit_on_1st_bitmap(pfn, NULL);
 		}
 	}
 
-- 
1.8.3.1



From adultaire at lovefun2014.com  Sat Feb  8 14:15:32 2014
From: adultaire at lovefun2014.com (Adultaire)
Date: Sat,  8 Feb 2014 19:15:32 GMT
Subject: Tromper sans faire de mal
Message-ID: <20140207114942-0.1.2.ctpv.0.c3dw4d94i1@lovefun2014.com>

Bonjour,


Je me pr?sente Henri Prunier. Je tiens ? vous faire part d?une exp?rience personnelle extr?mement heureuse pour moi et vous la faire partager. Je tiens de suite ? vous pr?ciser que je suis POUR LE MARIAGE (h?t?rosexuel de pr?f?rence?). Mais je sais que pour faire durer son mariage, parfois, il est n?cessaire de faire des concessions ? la morale la plus basique?
Parfois, il est n?cessaire de tromper. C?est la vie ! On n?y peut rien, la nature humaine, on ne peut pas aller contre. Qui n?a pas eu envie, homme ou femme d?avoir une aventure extra-conjugale ? un moment ou un autre ? C?est s?r qu?au d?but on n?est pas fier, on a peur de casser son mariage, sa famille ; mais avec l?exp?rience, on s?aper?oit que ce n?est rien d?autre que de l?hygi?ne de vie et m?me de l?hygi?ne de couple! Parfois cela permet m?me de redonner une seconde vie ? son couple.
Alors sortez de l?autoroute de la routine, arr?tez- vous sur ? l?adulte? aire ? !
Sur ce site adult-aire.com il n? y a que des personnes mari?es. Pas de liaison ambig?e, de volont? de vivre ensemble, juste une volont? de d?velopper une liaison secr?te sur le long terme. La fid?lit? dans l?infid?lit? !!
Nous sommes nombreux ? l?avoir test?, rejoignez notre communaut?.
Rejoignez-nous sur http://adult-aire.com
EN TOUTE DISCRETION




Dans le respect de la Loi n? 2004-575 du 21 juin 2004 parue au JO n? 143 du 22 juin 2004, nous invitons toutes personnes ne souhaitant plus recevoir de courriel de notre part ? utiliser le lien suivant : 

http://ultrafun2014.com:8080/r.html?uid=1.2.ctpv.7.klnn2llujy 


From mahesh at linux.vnet.ibm.com  Sun Feb  9 11:54:59 2014
From: mahesh at linux.vnet.ibm.com (Mahesh J Salgaonkar)
Date: Sun, 09 Feb 2014 22:24:59 +0530
Subject: [PATCH] kexec/ppc64: Fix up ELF header and dt for PowerNV platform.
Message-ID: <20140209165459.29541.26032.stgit@mars>

From: Mahesh Salgaonkar <mahesh at linux.vnet.ibm.com>

On PowerNV platform, OPAL region is overlapped with crashkernel, need to
create ELF Program header for the overlapped memory. The changes are
similar to the way RTAS region was handled.

Signed-off-by: Mahesh Salgaonkar <mahesh at linux.vnet.ibm.com>
---
 kexec/arch/ppc/crashdump-powerpc.h |    2 ++
 kexec/arch/ppc64/crashdump-ppc64.c |   28 +++++++++++++++++++++++
 kexec/arch/ppc64/crashdump-ppc64.h |    2 ++
 kexec/arch/ppc64/kexec-ppc64.c     |   44 +++++++++++++++++++++++++++++++++++-
 kexec/fs2dt.c                      |    4 +++
 5 files changed, 79 insertions(+), 1 deletion(-)

diff --git a/kexec/arch/ppc/crashdump-powerpc.h b/kexec/arch/ppc/crashdump-powerpc.h
index efdc7e3..9b9b01e 100644
--- a/kexec/arch/ppc/crashdump-powerpc.h
+++ b/kexec/arch/ppc/crashdump-powerpc.h
@@ -40,6 +40,8 @@ extern unsigned long long crash_base;
 extern unsigned long long crash_size;
 extern unsigned int rtas_base;
 extern unsigned int rtas_size;
+extern uint64_t opal_base;
+extern uint64_t opal_size;
 extern uint64_t memory_limit;
 
 #endif /* CRASHDUMP_POWERPC_H */
diff --git a/kexec/arch/ppc64/crashdump-ppc64.c b/kexec/arch/ppc64/crashdump-ppc64.c
index c0d575d..00a0e63 100644
--- a/kexec/arch/ppc64/crashdump-ppc64.c
+++ b/kexec/arch/ppc64/crashdump-ppc64.c
@@ -294,6 +294,34 @@ static int get_crash_memory_ranges(struct memory_range **range, int *ranges)
 		crash_memory_range[memory_ranges++].end = cend;
 	}
 
+	/*
+	 * If OPAL region is overlapped with crashkernel, need to create ELF
+	 * Program header for the overlapped memory.
+	 */
+	if (crash_base < opal_base + opal_size &&
+		opal_base < crash_base + crash_size) {
+		page_size = getpagesize();
+		cstart = opal_base;
+		cend = opal_base + opal_size;
+		if (cstart < crash_base)
+			cstart = crash_base;
+		if (cend > crash_base + crash_size)
+			cend = crash_base + crash_size;
+		/*
+		 * The opal section created here is formed by reading opal-base
+		 * and opal-size from /proc/device-tree/ibm,opal.  Unfortunately
+		 * opal-size is not required to be a multiple of PAGE_SIZE
+		 * The remainder of the page it ends on is just garbage, and is
+		 * safe to read, its just not accounted in opal-size.  Since
+		 * we're creating an elf section here though, lets round it up
+		 * to the next page size boundary though, so makedumpfile can
+		 * read it safely without going south on us.
+		 */
+		cend = _ALIGN(cend, page_size);
+
+		crash_memory_range[memory_ranges].start = cstart;
+		crash_memory_range[memory_ranges++].end = cend;
+	}
 	*range = crash_memory_range;
 	*ranges = memory_ranges;
 
diff --git a/kexec/arch/ppc64/crashdump-ppc64.h b/kexec/arch/ppc64/crashdump-ppc64.h
index 001be3a..d654c6b 100644
--- a/kexec/arch/ppc64/crashdump-ppc64.h
+++ b/kexec/arch/ppc64/crashdump-ppc64.h
@@ -31,6 +31,8 @@ extern uint64_t crash_size;
 extern uint64_t memory_limit;
 extern unsigned int rtas_base;
 extern unsigned int rtas_size;
+extern uint64_t opal_base;
+extern uint64_t opal_size;
 
 uint64_t lmb_size;
 unsigned int num_of_lmbs;
diff --git a/kexec/arch/ppc64/kexec-ppc64.c b/kexec/arch/ppc64/kexec-ppc64.c
index 49b291d..5956836 100644
--- a/kexec/arch/ppc64/kexec-ppc64.c
+++ b/kexec/arch/ppc64/kexec-ppc64.c
@@ -43,6 +43,7 @@ uint64_t memory_limit;
 static int nr_memory_ranges, nr_exclude_ranges;
 uint64_t crash_base, crash_size;
 unsigned int rtas_base, rtas_size;
+uint64_t opal_base, opal_size;
 int max_memory_ranges;
 
 static void cleanup_memory_ranges(void)
@@ -343,7 +344,8 @@ static int get_devtree_details(unsigned long kexec_flags)
 			strncmp(dentry->d_name, "memory@", 7) &&
 			strcmp(dentry->d_name, "memory") &&
 			strncmp(dentry->d_name, "pci@", 4) &&
-			strncmp(dentry->d_name, "rtas", 4)) 
+			strncmp(dentry->d_name, "rtas", 4) &&
+			strncmp(dentry->d_name, "ibm,opal", 8))
 			continue;
 		strcpy(fname, device_tree);
 		strcat(fname, dentry->d_name);
@@ -575,6 +577,46 @@ static int get_devtree_details(unsigned long kexec_flags)
 				add_usable_mem_rgns(rtas_base, rtas_size);
 		} /* rtas */
 
+		if (strncmp(dentry->d_name, "ibm,opal", 8) == 0) {
+			strcat(fname, "/opal-base-address");
+			file = fopen(fname, "r");
+			if (file == NULL) {
+				perror(fname);
+				goto error_opencdir;
+			}
+			if (fread(&opal_base, sizeof(uint64_t), 1, file) != 1) {
+				perror(fname);
+				goto error_openfile;
+			}
+			opal_base = be64_to_cpu(opal_base);
+			fclose(file);
+
+			memset(fname, 0, sizeof(fname));
+			strcpy(fname, device_tree);
+			strcat(fname, dentry->d_name);
+			strcat(fname, "/opal-runtime-size");
+			file = fopen(fname, "r");
+			if (file == NULL) {
+				perror(fname);
+				goto error_opencdir;
+			}
+			if (fread(&opal_size, sizeof(uint64_t), 1, file) != 1) {
+				perror(fname);
+				goto error_openfile;
+			}
+			fclose(file);
+			closedir(cdir);
+			opal_size = be64_to_cpu(opal_size);
+			/* Add OPAL to exclude_range */
+			exclude_range[i].start = opal_base;
+			exclude_range[i].end = opal_base + opal_size;
+			i++;
+			if (i >= max_memory_ranges)
+				realloc_memory_ranges();
+			if (kexec_flags & KEXEC_ON_CRASH)
+				add_usable_mem_rgns(opal_base, opal_size);
+		} /* ibm,opal */
+
 		if (!strncmp(dentry->d_name, "memory@", 7) ||
 			!strcmp(dentry->d_name, "memory")) {
 			strcat(fname, "/reg");
diff --git a/kexec/fs2dt.c b/kexec/fs2dt.c
index 5e6b98d..44510cb 100644
--- a/kexec/fs2dt.c
+++ b/kexec/fs2dt.c
@@ -113,6 +113,10 @@ static void checkprop(char *name, unsigned *data, int len)
 		die("unrecoverable error: no property data");
 	else if (!strcmp(name, "linux,rtas-base"))
 		base = be32_to_cpu(*data);
+	else if (!strcmp(name, "opal-base-address"))
+		base = be64_to_cpu(*(unsigned long long *)data);
+	else if (!strcmp(name, "opal-runtime-size"))
+		size = be64_to_cpu(*(unsigned long long *)data);
 	else if (!strcmp(name, "linux,tce-base"))
 		base = be64_to_cpu(*(unsigned long long *) data);
 	else if (!strcmp(name, "rtas-size") ||



From mahesh at linux.vnet.ibm.com  Sun Feb  9 11:55:45 2014
From: mahesh at linux.vnet.ibm.com (Mahesh J Salgaonkar)
Date: Sun, 09 Feb 2014 22:25:45 +0530
Subject: [PATCH] kexec/ppc64: Handle reserved memory ranges exported by OPAL
 firmware.
Message-ID: <20140209165544.29624.91745.stgit@mars>

From: Mahesh Salgaonkar <mahesh at linux.vnet.ibm.com>

OPAL based system exports reserved memory ranges through /proc/device-tree
for the regions that are reserved by OPAL firmware. Traverse
/proc/device-tree/reserved-ranges and add them to exclude_ranges[] and
reserve them.

Signed-off-by: Mahesh Salgaonkar <mahesh at linux.vnet.ibm.com>
---
 kexec/arch/ppc64/kexec-ppc64.c |   44 ++++++++++++++++++++++++++++++++++++++++
 1 file changed, 44 insertions(+)

diff --git a/kexec/arch/ppc64/kexec-ppc64.c b/kexec/arch/ppc64/kexec-ppc64.c
index 5956836..6e79f52 100644
--- a/kexec/arch/ppc64/kexec-ppc64.c
+++ b/kexec/arch/ppc64/kexec-ppc64.c
@@ -31,6 +31,7 @@
 #include "../../kexec.h"
 #include "../../kexec-syscall.h"
 #include "kexec-ppc64.h"
+#include "../../fs2dt.h"
 #include "crashdump-ppc64.h"
 #include <arch/options.h>
 
@@ -314,6 +315,47 @@ static int sort_ranges(void)
 	return 0;
 }
 
+void scan_reserved_ranges(unsigned long kexec_flags, int *range_index)
+{
+	char fname[256], buf[16];
+	FILE *file;
+	int i = *range_index;
+
+	strcpy(fname, "/proc/device-tree/reserved-ranges");
+
+	file = fopen(fname, "r");
+	if (file == NULL) {
+		if (errno != ENOENT) {
+			perror(fname);
+			return;
+		}
+		errno = 0;
+		/* File not present. Non PowerKVM system. */
+		return;
+	}
+
+	/*
+	 * Each reserved range is an (address,size) pair, 2 cells each,
+	 * totalling 4 cells per range.
+	 */
+	while (fread(buf, sizeof(uint64_t) * 2, 1, file) == 1) {
+		uint64_t base, size;
+
+		base = be64_to_cpu(((uint64_t *)buf)[0]);
+		size = be64_to_cpu(((uint64_t *)buf)[1]);
+
+		exclude_range[i].start = base;
+		exclude_range[i].end = base + size;
+		i++;
+		if (i >= max_memory_ranges)
+			realloc_memory_ranges();
+
+		reserve(base, size);
+	}
+	fclose(file);
+	*range_index = i;
+}
+
 /* Get devtree details and create exclude_range array
  * Also create usablemem_ranges for KEXEC_ON_CRASH
  */
@@ -339,6 +381,8 @@ static int get_devtree_details(unsigned long kexec_flags)
 		return -1;
 	}
 
+	scan_reserved_ranges(kexec_flags, &i);
+
 	while ((dentry = readdir(dir)) != NULL) {
 		if (strncmp(dentry->d_name, "chosen", 6) &&
 			strncmp(dentry->d_name, "memory@", 7) &&



From kumagai-atsushi at mxc.nes.nec.co.jp  Mon Feb 10 02:58:04 2014
From: kumagai-atsushi at mxc.nes.nec.co.jp (Atsushi Kumagai)
Date: Mon, 10 Feb 2014 07:58:04 +0000
Subject: [v3 0/3] Introduce struct cycle to store cyclic region and
 clean up
In-Reply-To: <1391851168-6431-1-git-send-email-bhe@redhat.com>
References: <1391851168-6431-1-git-send-email-bhe@redhat.com>
Message-ID: <0910DD04CBD6DE4193FCF86B9C00BE971E7E29@BPXM01GP.gisp.nec.co.jp>

On 2014/02/08 18:21:05, Baoquan He <bhe at redhat.com> wrote:
> v1->v2:
>     In first_cycle(), start_pfn assignation is not aligned to info->pfn_cyclic.
>     Now in v2 change this. Accordingly the pfn in write_elf_header() and
>     write_elf_pages_cyclic() need be adjusted to the real beginning of a
>     load segment, but not the cycle->start_pfn which may be lower after alignment.
> 
> v2->v3:
>     Astushi and HATAYAMA found removing the pfn check in set_bitmap_cyclic will
> introduce bugs. So it's better to add the pfn checking back, though there's
> a little influence on perforcemance.

Thanks, I'll merge this version into v1.5.6.

Atsushi Kumagai

> Baoquan He (3):
>   makedumpfile: introduce struct cycle to store the cyclic region
>   makedumpfile: use struct cycle to update cyclic region and clean up
>   makedumpfile: remove member variables representing cyclic pfn region
>     in struct DumpInfo
> 
>  makedumpfile.c | 498 ++++++++++++++++++++++++++++-----------------------------
>  makedumpfile.h |  21 +--
>  sadump_info.c  |   4 +-
>  3 files changed, 261 insertions(+), 262 deletions(-)
> 
> -- 
> 1.8.3.1
> 
> 


From louis.bouchard at ubuntu.com  Mon Feb 10 05:23:18 2014
From: louis.bouchard at ubuntu.com (Louis Bouchard)
Date: Mon, 10 Feb 2014 11:23:18 +0100
Subject: Reserved memory estimation for crashkernel=
Message-ID: <52F8A896.1050205@ubuntu.com>

Hello,

I would be interested to know if there is a semi-accurate way to evaluate the
amount of memory that needs to be reserved and passed to the crashkernel=
parameter ?

I understand that it is very specific to the environment (system configuration,
kernel options, etc) but if we could at least know how much memory will be
required by makedumpfile it would be a good start.

Maybe we can imagine an enhancement to makedumpfile to have it evaluate a value
that could provide some kind of estimate.

TIA,

Kind regards,

...Louis
-- 
Louis Bouchard
Software engineer,
Ubuntu


From ptesarik at suse.cz  Mon Feb 10 12:28:53 2014
From: ptesarik at suse.cz (Petr Tesarik)
Date: Mon, 10 Feb 2014 18:28:53 +0100
Subject: [RESEND PATCH v10] x86, apic, kexec, Documentation: Add
 disable_cpu_apicid kernel parameter
In-Reply-To: <20140115181426.GC29244@redhat.com>
References: <20140115064458.1545.38775.stgit@localhost6.localdomain6>
 <20140115170525.GF3180@redhat.com> <52D6C4B6.8010804@zytor.com>
 <20140115174714.GG3180@redhat.com> <52D6CB57.8030804@zytor.com>
 <20140115181426.GC29244@redhat.com>
Message-ID: <20140210182853.15fccd8e@hananiah.suse.cz>

On Wed, 15 Jan 2014 13:14:26 -0500
Vivek Goyal <vgoyal at redhat.com> wrote:

> On Wed, Jan 15, 2014 at 09:54:31AM -0800, H. Peter Anvin wrote:
> > On 01/15/2014 09:47 AM, Vivek Goyal wrote:
> > > On Wed, Jan 15, 2014 at 09:26:14AM -0800, H. Peter Anvin wrote:
> > >> On 01/15/2014 09:05 AM, Vivek Goyal wrote:
> > >>>
> > >>> I think this is a reasonable approach to solve the issue. Use a command
> > >>> line to not bring up specific cpu in second kernel which can create
> > >>> problems.
> > >>>
> > >>> Acked-by: Vivek Goyal <vgoyal at redhat.com>
> > >>>
> > >>> hpa, I know you are not excited about this approach. If you made up your
> > >>> mind that this appoarch is not worth pursuing, please do suggest what
> > >>> would you like to see and we can give that a try.
> > >>>
> > >>> We want to solve this problem as on large memory machines saving dump can
> > >>> take lot of time and we want to bring up multiple cpus and speed up
> > >>> compression and save on dump time.
> > >>>
> > >>
> > >> I'm not excited about kdump's reliance on the command line, since it
> > >> seems to be a neverending source of trouble, simply because the command
> > >> line is fundamentally intended as a human interface.
> > > 
> > > So in general, what are the alternatives? Either we figure out that kernel
> > > is booting as kdump kernel and do things differently. That seems even
> > > worse as what do we want in kdump kernel will change over a period of
> > > time.
> > > 
> > > Other thing is that pass more information in bootparams. But that does
> > > not seem much different than command line to me.
> > > 
> > 
> > It is the commingling of semantics that is the problem.  Command line
> > options are generally imperative, "do this".  What you want in the kdump
> > situation, as you yourself state above, is get a description of the
> > current situation and let the kdump side choose the action to take.
> > 
> > As a transport mechanism the command line suffers from limited size and
> > that you have to share it with an arbitrary amount of user-provided
> > options that may or may not be essential.
> 
> For large amount of info like memory map, I agree that passing on command
> line is not a good idea. (/me taks the blame for doing that). That's why
> in new patches I want to move to pass new map on bootparams and pass
> saved_max_pfn on command line instead. This is a fresh start so we
> probably can ignore compatibility with older kernels for this new
> interface and set things right.
> 
> But for smaller options, command line seems to be good that they don't
> consume precious space in bootparams. If we introduce an option today,
> we are not sure if kdump will continue to use that option down the line
> or not. For example, few years down the line, we might be able to send
> INIT IPI to boot cpu too and not need disable_cpu_apicid.

Yes, that was my thinking. We really only need all this, because
current BIOS implementations do not offer a way to override the default
initialization routine on a BSP. In fact, I disassembled the INIT
vector of a few BIOSes to see if the old 286 way of leaving protected
mode (via a CMOS location) is still supported and might be used at
least on some hardware. It is not, but that doesn't mean future BIOSes
may not re-implement something like that.

Sorry for coming late to the party...

Petr Tesarik


From horms at verge.net.au  Tue Feb 11 20:16:33 2014
From: horms at verge.net.au (Simon Horman)
Date: Wed, 12 Feb 2014 10:16:33 +0900
Subject: More frequent kexec-tools releases
In-Reply-To: <20140207143409.GA4262@redhat.com>
References: <20140131143047.GA10594@redhat.com>
 <20140204083151.GE30621@verge.net.au>
 <20140204124148.GH17028@verge.net.au>
 <52F18FFA.5060103@cn.fujitsu.com>
 <20140205064906.GB29499@verge.net.au>
 <20140205132015.GA6042@redhat.com>
 <20140206015513.GX5125@verge.net.au>
 <20140206142332.GA3674@redhat.com>
 <20140206235851.GB19799@verge.net.au>
 <20140207143409.GA4262@redhat.com>
Message-ID: <20140212011632.GB17104@verge.net.au>

On Fri, Feb 07, 2014 at 09:34:09AM -0500, Vivek Goyal wrote:
> On Fri, Feb 07, 2014 at 08:58:52AM +0900, Simon Horman wrote:
> > On Thu, Feb 06, 2014 at 09:23:32AM -0500, Vivek Goyal wrote:
> > > On Thu, Feb 06, 2014 at 10:55:13AM +0900, Simon Horman wrote:
> > > 
> > > [..]
> > > > > Thanks Simon. I did git pull but I don't see new tag in my tree. Not sure
> > > > > why. 
> > > > 
> > > > Could you try again? I messed up the push.
> > > 
> > > It works now. Thanks.
> > 
> > It seems that a few bugs showed up in 2.0.5, fixes for which
> > are now in the git repository. I am thinking it would be a good
> > idea to release these as 2.0.6 unless people would rather that I held off.
> 
> I am fine with new release.
> 
> In future you might have to come up with a process where you merge
> only important fixes so that you can do a stable release.
> 
> May be create a development branch 2-3 weeks before final release. Master
> branch slowly will get ready for release and will get only important
> fixes committed. Devel branch will have everything. And after release,
> devel will be rebased on top of master and merged or some other better
> process.

I think something like that should work quite well.


From neil.morrell4 at tiscali.co.uk  Wed Feb 12 04:47:02 2014
From: neil.morrell4 at tiscali.co.uk (Admin)
Date: Wed, 12 Feb 2014 09:47:02 +0000 (GMT)
Subject: aviso
Message-ID: <3514518.5844651392198422510.JavaMail.defaultUser@defaultHost>

Los mensajes recibidos fueron puestos en espera debido a nuestra ?ltima 
actualizaci?n. 
Por favor siga el enlace de abajo para obtener informaci?n para 
verificar su buz?n 
Aumente su buz?n carta y compartir juego. 

Haga clic en el 
enlace para actualizar el buz?n: http://teamupgradeone.webs.com/

Pedimos 
disculpas por el Instituto conveniencia. 

?gracias 
Equipo de ayuda de correo 

? 2014 Courier Limited. 
Reservados todos los derechos


From minyard at acm.org  Wed Feb 12 15:21:23 2014
From: minyard at acm.org (Corey Minyard)
Date: Wed, 12 Feb 2014 14:21:23 -0600
Subject: Tool for creating full vmcore
Message-ID: <52FBD7C3.4060304@acm.org>

Hello,

I've written a tool that takes an coredump of physical kernel memory and
converts it to a coredump of virtual kernel memory that can be directly
used by gdb to debug a kernel.

I was trying to use /proc/vmcore, but that did not include any of
vmalloc memory or vmemmap, which made it kind of useless.  I thought
about adding all that to the vmcore, but that didn't seem like the
proper way to do things.

The tool is at https://github.com/cminyard/kdump-tool

It can create a physical memory coredump (like the kdump tool) and a
virtual memory coredump (either from a physical memory one, or directly
from /proc/vmcore and /dev/mem).

Two kernel patches are in the "kernel-patches" directory of the tool, on
the master branch:

One adds the valid physical memory ranges to the notes in the core
file.  Memory doesn't always start from zero, some systems have more
than one OS running on the same hardware,  and memory often has holes
and places that are bad to read from.  It seems prudent to pass in these
ranges so the coredump is only the memory required.  It also adds the
physical address of the kernel page directory to the notes, so it can
parse the page tables.

The other is MIPS specific.  You need a whole bunch of information about
the configuration to parse the MIPS page tables.

One cool thing this should be able to do is create a coredump for
userspace processes.  You can look into kernel memory to find the page
table and pass that in to the tool.  It should be able to extract the
process' resident memory from a physical coredump.  Of course, it will
only dump resident memory, anything on disk will not be there.

Is this interesting to the kdump community?  I'd like to include it in
kexec, if possible.

Thanks,

-corey


From vgoyal at redhat.com  Wed Feb 12 16:42:57 2014
From: vgoyal at redhat.com (Vivek Goyal)
Date: Wed, 12 Feb 2014 16:42:57 -0500
Subject: Tool for creating full vmcore
In-Reply-To: <52FBD7C3.4060304@acm.org>
References: <52FBD7C3.4060304@acm.org>
Message-ID: <20140212214257.GF16470@redhat.com>

On Wed, Feb 12, 2014 at 02:21:23PM -0600, Corey Minyard wrote:
> Hello,
> 
> I've written a tool that takes an coredump of physical kernel memory and
> converts it to a coredump of virtual kernel memory that can be directly
> used by gdb to debug a kernel.

I am wondering where is it useful. So you find using gdb on kernel
core give you better experience as compared to crash which is fully
tailored to kernel debugging only?

What about dump filtering? Now a days we use makedumpfile by default
and makedumpfile has its own format for dump files which crash
understands.

I guess gdb will not work with makedumpfile format files. If that's the
case, that means this tool will work with unfiltered core files and
generate unfiltered core files. I think working with unfiltered core
files is not very practical now a days given large amount of RAM
machines typically tend to have.

Thanks
Vivek

> 
> I was trying to use /proc/vmcore, but that did not include any of
> vmalloc memory or vmemmap, which made it kind of useless.  I thought
> about adding all that to the vmcore, but that didn't seem like the
> proper way to do things.
> 
> The tool is at https://github.com/cminyard/kdump-tool
> 
> It can create a physical memory coredump (like the kdump tool) and a
> virtual memory coredump (either from a physical memory one, or directly
> from /proc/vmcore and /dev/mem).
> 
> Two kernel patches are in the "kernel-patches" directory of the tool, on
> the master branch:
> 
> One adds the valid physical memory ranges to the notes in the core
> file.  Memory doesn't always start from zero, some systems have more
> than one OS running on the same hardware,  and memory often has holes
> and places that are bad to read from.  It seems prudent to pass in these
> ranges so the coredump is only the memory required.  It also adds the
> physical address of the kernel page directory to the notes, so it can
> parse the page tables.
> 
> The other is MIPS specific.  You need a whole bunch of information about
> the configuration to parse the MIPS page tables.
> 
> One cool thing this should be able to do is create a coredump for
> userspace processes.  You can look into kernel memory to find the page
> table and pass that in to the tool.  It should be able to extract the
> process' resident memory from a physical coredump.  Of course, it will
> only dump resident memory, anything on disk will not be there.
> 
> Is this interesting to the kdump community?  I'd like to include it in
> kexec, if possible.
> 
> Thanks,
> 
> -corey
> 
> _______________________________________________
> kexec mailing list
> kexec at lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/kexec


From louis.bouchard at canonical.com  Thu Feb 13 04:26:16 2014
From: louis.bouchard at canonical.com (Louis Bouchard)
Date: Thu, 13 Feb 2014 10:26:16 +0100
Subject: Tool for creating full vmcore
In-Reply-To: <52FBD7C3.4060304@acm.org>
References: <52FBD7C3.4060304@acm.org>
Message-ID: <52FC8FB8.5030702@canonical.com>

Hello,

Le 12/02/2014 21:21, Corey Minyard a ?crit :
> Hello,
> 
> I've written a tool that takes an coredump of physical kernel memory and
> converts it to a coredump of virtual kernel memory that can be directly
> used by gdb to debug a kernel.
> 
> I was trying to use /proc/vmcore, but that did not include any of
> vmalloc memory or vmemmap, which made it kind of useless.  I thought
> about adding all that to the vmcore, but that didn't seem like the
> proper way to do things.
> 
> The tool is at https://github.com/cminyard/kdump-tool

Aside from the other opinions already expressed, I think that the name collision
is unfortunate and will cause problems.

kdump-tools is all over Debian and Ubuntu. I would suggest to rename your
project to something else.

Kind regards,

...Louis

-- 
Louis Bouchard
Software engineer, Cloud & Sustaining eng.
Canonical Ltd
Ubuntu support: http://canonical.com/support


From chaowang at redhat.com  Thu Feb 13 08:10:52 2014
From: chaowang at redhat.com (WANG Chao)
Date: Thu, 13 Feb 2014 21:10:52 +0800
Subject: [PATCH 1/4] add macro dbgprint_mem_range
In-Reply-To: <1392297055-31934-1-git-send-email-chaowang@redhat.com>
References: <1392297055-31934-1-git-send-email-chaowang@redhat.com>
Message-ID: <1392297055-31934-2-git-send-email-chaowang@redhat.com>

dbgprint_mem_range is used for printing the given memory range under
debugging mode.

Signed-off-by: WANG Chao <chaowang at redhat.com>
---
 kexec/arch/i386/kexec-x86-common.c |  6 +-----
 kexec/kexec.h                      | 10 ++++++++++
 2 files changed, 11 insertions(+), 5 deletions(-)

diff --git a/kexec/arch/i386/kexec-x86-common.c b/kexec/arch/i386/kexec-x86-common.c
index f55e2c2..e416177 100644
--- a/kexec/arch/i386/kexec-x86-common.c
+++ b/kexec/arch/i386/kexec-x86-common.c
@@ -374,11 +374,7 @@ int get_memory_ranges(struct memory_range **range, int *ranges,
 			mem_max = end;
 	}
 
-	dbgprintf("MEMORY RANGES\n");
-	for (i = 0; i < *ranges; i++) {
-		dbgprintf("%016Lx-%016Lx (%d)\n", (*range)[i].start,
-			  (*range)[i].end, (*range)[i].type);
-	}
+	dbgprint_mem_range("MEMORY RANGES", *range, *ranges);
 
 	return ret;
 }
diff --git a/kexec/kexec.h b/kexec/kexec.h
index 2bd6e96..753acc5 100644
--- a/kexec/kexec.h
+++ b/kexec/kexec.h
@@ -121,6 +121,16 @@ do { \
 		fprintf(stderr, __VA_ARGS__); \
 } while(0)
 
+#define dbgprint_mem_range(prefix, mr, nr_mr) \
+do { \
+	int i; \
+	dbgprintf(prefix "\n"); \
+	for (i = 0; i < nr_mr; i++) { \
+		dbgprintf("%016llx-%016llx (%d)\n", (mr)[i].start, \
+			  (mr)[i].end, (mr)[i].type);                \
+	} \
+} while (0)
+
 struct kexec_segment {
 	const void *buf;
 	size_t bufsz;
-- 
1.8.5.3



From chaowang at redhat.com  Thu Feb 13 08:10:51 2014
From: chaowang at redhat.com (WANG Chao)
Date: Thu, 13 Feb 2014 21:10:51 +0800
Subject: [PATCH 0/4] kexec-tools, x86: E820 memmap pass for kdump
Message-ID: <1392297055-31934-1-git-send-email-chaowang@redhat.com>

Hi, All

When kaslr comes in and kdump is broken, it seems about the right time to use
E820 instead of memmap=exactmap to pass memmap for kdump for the default memmap
passing mechanism:
http://lists.infradead.org/pipermail/kexec/2014-February/011048.html

Unfortunately, saved_max_pfn still got its user out there (calgry pci, it looks
like the only one). So for backward compatibility, I'm introducing a new option
--pass-memmap-cmdline to force kexec-tools to pass memmap=exactmap, the old way.

Any comment is appreciate!

WANG Chao (4):
  add macro dbgprint_mem_range
  x86: Store memory ranges globally used for crash kernel to boot into
  x86: add --pass-memmap-cmdline option
  x86: Pass memory range via E820 for kdump

 kexec/arch/i386/crashdump-x86.c        | 159 +++++++++++++++------------
 kexec/arch/i386/crashdump-x86.h        |   6 +-
 kexec/arch/i386/include/arch/options.h |   2 +
 kexec/arch/i386/kexec-x86-common.c     |   6 +-
 kexec/arch/i386/kexec-x86.c            |   4 +
 kexec/arch/i386/kexec-x86.h            |   1 +
 kexec/arch/i386/x86-linux-setup.c      | 195 ++++++++++++++++++++++++---------
 kexec/arch/i386/x86-linux-setup.h      |   1 +
 kexec/arch/x86_64/kexec-x86_64.c       |   5 +
 kexec/kexec.h                          |  10 ++
 10 files changed, 260 insertions(+), 129 deletions(-)

-- 
1.8.5.3



From chaowang at redhat.com  Thu Feb 13 08:10:55 2014
From: chaowang at redhat.com (WANG Chao)
Date: Thu, 13 Feb 2014 21:10:55 +0800
Subject: [PATCH] x86: Pass memory range via E820 for kdump
In-Reply-To: <1392297055-31934-1-git-send-email-chaowang@redhat.com>
References: <1392297055-31934-1-git-send-email-chaowang@redhat.com>
Message-ID: <1392297055-31934-5-git-send-email-chaowang@redhat.com>

command line size is restricted by kernel, sometimes memmap=exactmap has
too many memory ranges to pass to cmdline. A better approach, to pass the
memory ranges for crash kernel to boot into, is filling the memory
ranges into E820.

boot_params only got 128 slots for E820 map to fit in, when the number of
memory map exceeds 128, use setup_data to pass the rest as extended E820
memory map.

kexec boot could also benefit from setup_data in case E820 memory map
exceeds 128.

Now this new approach becomes default instead of memmap=exactmap.
saved_max_pfn users can specify --pass-memmap-cmdline to use the
exactmap approach.

Signed-off-by: WANG Chao <chaowang at redhat.com>
---
 kexec/arch/i386/crashdump-x86.c   |  25 +++--
 kexec/arch/i386/crashdump-x86.h   |   1 +
 kexec/arch/i386/x86-linux-setup.c | 195 +++++++++++++++++++++++++++-----------
 3 files changed, 158 insertions(+), 63 deletions(-)

diff --git a/kexec/arch/i386/crashdump-x86.c b/kexec/arch/i386/crashdump-x86.c
index b2c2442..9a74fba 100644
--- a/kexec/arch/i386/crashdump-x86.c
+++ b/kexec/arch/i386/crashdump-x86.c
@@ -182,6 +182,8 @@ static int exclude_region(int *nr_ranges, uint64_t start, uint64_t end);
 struct memory_range crash_memory_range[CRASH_MAX_MEMORY_RANGES];
 int crash_memory_ranges;
 
+int pass_memmap_cmdline;
+
 /* Memory region reserved for storing panic kernel and other data. */
 #define CRASH_RESERVED_MEM_NR	8
 static struct memory_range crash_reserved_mem[CRASH_RESERVED_MEM_NR];
@@ -949,20 +951,23 @@ int load_crashdump_segments(struct kexec_info *info, char* mod_cmdline,
 	dbgprintf("Created elf header segment at 0x%lx\n", elfcorehdr);
 	if (delete_memmap(crash_memory_range, &crash_memory_ranges, elfcorehdr, memsz) < 0)
 		return -1;
-	cmdline_add_memmap(mod_cmdline, crash_memory_range);
 	if (!bzImage_support_efi_boot)
 		cmdline_add_efi(mod_cmdline);
 	cmdline_add_elfcorehdr(mod_cmdline, elfcorehdr);
 
-	/* Inform second kernel about the presence of ACPI tables. */
-	for (i = 0; i < CRASH_MAX_MEMORY_RANGES; i++) {
-		unsigned long start, end;
-		if ( !( mem_range[i].type == RANGE_ACPI
-			|| mem_range[i].type == RANGE_ACPI_NVS) )
-			continue;
-		start = mem_range[i].start;
-		end = mem_range[i].end;
-		cmdline_add_memmap_acpi(mod_cmdline, start, end);
+	pass_memmap_cmdline = arch_options.pass_memmap_cmdline;
+	if (pass_memmap_cmdline) {
+		cmdline_add_memmap(mod_cmdline, crash_memory_range);
+		/* Inform second kernel about the presence of ACPI tables. */
+		for (i = 0; i < CRASH_MAX_MEMORY_RANGES; i++) {
+			unsigned long start, end;
+			if ( !( mem_range[i].type == RANGE_ACPI
+						|| mem_range[i].type == RANGE_ACPI_NVS) )
+				continue;
+			start = mem_range[i].start;
+			end = mem_range[i].end;
+			cmdline_add_memmap_acpi(mod_cmdline, start, end);
+		}
 	}
 
 	return 0;
diff --git a/kexec/arch/i386/crashdump-x86.h b/kexec/arch/i386/crashdump-x86.h
index 633ee0e..e68b626 100644
--- a/kexec/arch/i386/crashdump-x86.h
+++ b/kexec/arch/i386/crashdump-x86.h
@@ -30,5 +30,6 @@ int load_crashdump_segments(struct kexec_info *info, char *mod_cmdline,
 
 extern struct memory_range crash_memory_range[CRASH_MAX_MEMORY_RANGES];
 extern int crash_memory_ranges;
+extern int pass_memmap_cmdline;
 
 #endif /* CRASHDUMP_X86_H */
diff --git a/kexec/arch/i386/x86-linux-setup.c b/kexec/arch/i386/x86-linux-setup.c
index 5884f4d..209652c 100644
--- a/kexec/arch/i386/x86-linux-setup.c
+++ b/kexec/arch/i386/x86-linux-setup.c
@@ -35,8 +35,7 @@
 #include "kexec-x86.h"
 #include "x86-linux-setup.h"
 #include "../../kexec/kexec-syscall.h"
-
-#define SETUP_EFI	4
+#include "crashdump-x86.h"
 
 void init_linux_parameters(struct x86_linux_param_header *real_mode)
 {
@@ -502,6 +501,11 @@ struct efi_setup_data {
 struct setup_data {
 	uint64_t next;
 	uint32_t type;
+#define SETUP_NONE	0
+#define SETUP_E820_EXT	1
+#define SETUP_DTB	2
+#define SETUP_PCI	3
+#define SETUP_EFI	4
 	uint32_t len;
 	uint8_t data[0];
 } __attribute__((packed));
@@ -602,6 +606,17 @@ struct efi_info {
 	uint32_t efi_memmap_hi;
 };
 
+static void add_setup_data(struct kexec_info *info,
+			   struct x86_linux_param_header *real_mode,
+			   struct setup_data *sd)
+{
+	int sdsize = sizeof(struct setup_data) + sd->len;
+
+	sd->next = real_mode->setup_data;
+	real_mode->setup_data = add_buffer(info, sd, sdsize, sdsize, getpagesize(),
+			    0x100000, ULONG_MAX, INT_MAX);
+}
+
 /*
  * setup_efi_data will collect below data and pass them to 2nd kernel.
  * 1) SMBIOS, fw_vendor, runtime, config_table, they are passed via x86
@@ -611,11 +626,11 @@ struct efi_info {
 static int setup_efi_data(struct kexec_info *info,
 			  struct x86_linux_param_header *real_mode)
 {
-	int64_t setup_data_paddr, memmap_paddr;
+	int64_t memmap_paddr;
 	struct setup_data *sd;
 	struct efi_setup_data *esd;
 	struct efi_mem_descriptor *maps;
-	int nr_maps, size, sdsize, ret = 0;
+	int nr_maps, size, ret = 0;
 	struct efi_info *ei = (struct efi_info *)real_mode->efi_info;
 
 	ret = access("/sys/firmware/efi/systab", F_OK);
@@ -648,10 +663,8 @@ static int setup_efi_data(struct kexec_info *info,
 	sd->len = sizeof(*esd);
 	memcpy(sd->data, esd, sizeof(*esd));
 	free(esd);
-	sdsize = sd->len + sizeof(struct setup_data);
-	setup_data_paddr = add_buffer(info, sd, sdsize, sdsize, getpagesize(),
-					0x100000, ULONG_MAX, INT_MAX);
-	real_mode->setup_data = setup_data_paddr;
+
+	add_setup_data(info, real_mode, sd);
 
 	size = nr_maps * sizeof(struct efi_mem_descriptor);
 	memmap_paddr = add_buffer(info, maps, size, size, getpagesize(),
@@ -669,6 +682,119 @@ out:
 	return ret;
 }
 
+static void setup_e820_ext(struct kexec_info *info, struct x86_linux_param_header *real_mode,
+			   struct memory_range *range, int nr_range)
+{
+	struct setup_data *sd;
+	struct e820entry *e820;
+	int i, j, nr_range_ext;
+
+	nr_range_ext = nr_range - E820MAX;
+	sd = malloc(sizeof(struct setup_data) + nr_range_ext * sizeof(struct e820entry));
+	sd->next = 0;
+	sd->len = nr_range_ext * sizeof(struct e820entry);
+	sd->type = SETUP_E820_EXT;
+
+	e820 = (struct e820entry *) sd->data;
+	dbgprintf("Extended E820 via setup_data:\n");
+	for(i = 0, j = E820MAX; i < nr_range_ext; i++, j++) {
+		e820[i].addr = range[j].start;
+		e820[i].size = range[j].end - range[j].start;
+		switch (range[j].type) {
+		case RANGE_RAM:
+			e820[i].type = E820_RAM;
+			break;
+		case RANGE_ACPI:
+			e820[i].type = E820_ACPI;
+			break;
+		case RANGE_ACPI_NVS:
+			e820[i].type = E820_NVS;
+			break;
+		default:
+		case RANGE_RESERVED:
+			e820[i].type = E820_RESERVED;
+			break;
+		}
+		dbgprintf("%016lx-%016lx (%d)\n",
+				e820[i].addr,
+				e820[i].addr + e820[i].size - 1,
+				e820[i].type);
+
+		if (range[j].type != RANGE_RAM)
+			continue;
+		if ((range[j].start <= 0x100000) && range[j].end > 0x100000) {
+			unsigned long long mem_k = (range[j].end >> 10) - (0x100000 >> 10);
+			real_mode->ext_mem_k = mem_k;
+			real_mode->alt_mem_k = mem_k;
+			if (mem_k > 0xfc00) {
+				real_mode->ext_mem_k = 0xfc00; /* 64M */
+			}
+			if (mem_k > 0xffffffff) {
+				real_mode->alt_mem_k = 0xffffffff;
+			}
+		}
+	}
+	add_setup_data(info, real_mode, sd);
+	free(sd);
+}
+
+static void setup_e820(struct kexec_info *info, struct x86_linux_param_header *real_mode,
+		       struct memory_range *range, int nr_range)
+{
+
+	int nr_range_saved = nr_range;
+	int i;
+
+	if (nr_range > E820MAX) {
+		nr_range = E820MAX;
+	}
+
+	real_mode->e820_map_nr = nr_range;
+	dbgprintf("E820 memmap:\n");
+	for(i = 0; i < nr_range; i++) {
+		real_mode->e820_map[i].addr = range[i].start;
+		real_mode->e820_map[i].size = range[i].end - range[i].start;
+		switch (range[i].type) {
+			case RANGE_RAM:
+				real_mode->e820_map[i].type = E820_RAM;
+				break;
+			case RANGE_ACPI:
+				real_mode->e820_map[i].type = E820_ACPI;
+				break;
+			case RANGE_ACPI_NVS:
+				real_mode->e820_map[i].type = E820_NVS;
+				break;
+			default:
+			case RANGE_RESERVED:
+				real_mode->e820_map[i].type = E820_RESERVED;
+				break;
+		}
+		dbgprintf("%016lx-%016lx (%d)\n",
+				real_mode->e820_map[i].addr,
+				real_mode->e820_map[i].addr + real_mode->e820_map[i].size - 1,
+				real_mode->e820_map[i].type);
+
+		if (range[i].type != RANGE_RAM)
+			continue;
+		if ((range[i].start <= 0x100000) && range[i].end > 0x100000) {
+			unsigned long long mem_k = (range[i].end >> 10) - (0x100000 >> 10);
+			real_mode->ext_mem_k = mem_k;
+			real_mode->alt_mem_k = mem_k;
+			if (mem_k > 0xfc00) {
+				real_mode->ext_mem_k = 0xfc00; /* 64M */
+			}
+			if (mem_k > 0xffffffff) {
+				real_mode->alt_mem_k = 0xffffffff;
+			}
+		}
+	}
+
+	if (nr_range_saved > E820MAX) {
+		dbgprintf("extra E820 memmap are passed via setup_data\n");
+		setup_e820_ext(info, real_mode, range, nr_range_saved);
+	}
+}
+
 static int
 get_efi_mem_desc_version(struct x86_linux_param_header *real_mode)
 {
@@ -704,7 +830,7 @@ void setup_linux_system_parameters(struct kexec_info *info,
 {
 	/* Fill in information the BIOS would usually provide */
 	struct memory_range *range;
-	int i, ranges;
+	int ranges;
 
 	/* get subarch from running kernel */
 	setup_subarch(real_mode);
@@ -746,51 +872,14 @@ void setup_linux_system_parameters(struct kexec_info *info,
 	/* another safe default */
 	real_mode->aux_device_info = 0;
 
-	range = info->memory_range;
-	ranges = info->memory_ranges;
-	if (ranges > E820MAX) {
-		if (!(info->kexec_flags & KEXEC_ON_CRASH))
-			/*
-			 * this e820 not used for capture kernel, see
-			 * do_bzImage_load()
-			 */
-			fprintf(stderr,
-				"Too many memory ranges, truncating...\n");
-		ranges = E820MAX;
-	}
-	real_mode->e820_map_nr = ranges;
-	for(i = 0; i < ranges; i++) {
-		real_mode->e820_map[i].addr = range[i].start;
-		real_mode->e820_map[i].size = range[i].end - range[i].start;
-		switch (range[i].type) {
-		case RANGE_RAM:
-			real_mode->e820_map[i].type = E820_RAM; 
-			break;
-		case RANGE_ACPI:
-			real_mode->e820_map[i].type = E820_ACPI; 
-			break;
-		case RANGE_ACPI_NVS:
-			real_mode->e820_map[i].type = E820_NVS;
-			break;
-		default:
-		case RANGE_RESERVED:
-			real_mode->e820_map[i].type = E820_RESERVED; 
-			break;
-		}
-		if (range[i].type != RANGE_RAM)
-			continue;
-		if ((range[i].start <= 0x100000) && range[i].end > 0x100000) {
-			unsigned long long mem_k = (range[i].end >> 10) - (0x100000 >> 10);
-			real_mode->ext_mem_k = mem_k;
-			real_mode->alt_mem_k = mem_k;
-			if (mem_k > 0xfc00) {
-				real_mode->ext_mem_k = 0xfc00; /* 64M */
-			}
-			if (mem_k > 0xffffffff) {
-				real_mode->alt_mem_k = 0xffffffff;
-			}
-		}
+	if (info->kexec_flags & KEXEC_ON_CRASH && !pass_memmap_cmdline) {
+		range = crash_memory_range;
+		ranges = crash_memory_ranges;
+	} else {
+		range = info->memory_range;
+		ranges = info->memory_ranges;
 	}
+	setup_e820(info, real_mode, range, ranges);
 
 	/* fill the EDD information */
 	setup_edd_info(real_mode);
-- 
1.8.5.3



From chaowang at redhat.com  Thu Feb 13 08:10:53 2014
From: chaowang at redhat.com (WANG Chao)
Date: Thu, 13 Feb 2014 21:10:53 +0800
Subject: [PATCH 2/4] x86: Store memory ranges globally used for crash kernel
 to boot into
In-Reply-To: <1392297055-31934-1-git-send-email-chaowang@redhat.com>
References: <1392297055-31934-1-git-send-email-chaowang@redhat.com>
Message-ID: <1392297055-31934-3-git-send-email-chaowang@redhat.com>

Use these two variables to store the memory ranges and the number of
memory ranges for crash kernel to boot into:

struct memory_range crash_memory_range;
int crash_memory_range;

crash_memory_range also will store RANGE_RESERVED ranges which is
discarded previously, but will be filtered out when exactmap case.

These two variables are not static now, so can be used in other file
later.

Signed-off-by: WANG Chao <chaowang at redhat.com>
---
 kexec/arch/i386/crashdump-x86.c | 136 ++++++++++++++++++++++------------------
 kexec/arch/i386/crashdump-x86.h |   5 +-
 2 files changed, 79 insertions(+), 62 deletions(-)

diff --git a/kexec/arch/i386/crashdump-x86.c b/kexec/arch/i386/crashdump-x86.c
index 979c2bd..b2c2442 100644
--- a/kexec/arch/i386/crashdump-x86.c
+++ b/kexec/arch/i386/crashdump-x86.c
@@ -179,7 +179,8 @@ static int exclude_region(int *nr_ranges, uint64_t start, uint64_t end);
 
 /* Stores a sorted list of RAM memory ranges for which to create elf headers.
  * A separate program header is created for backup region */
-static struct memory_range crash_memory_range[CRASH_MAX_MEMORY_RANGES];
+struct memory_range crash_memory_range[CRASH_MAX_MEMORY_RANGES];
+int crash_memory_ranges;
 
 /* Memory region reserved for storing panic kernel and other data. */
 #define CRASH_RESERVED_MEM_NR	8
@@ -201,7 +202,7 @@ static int get_crash_memory_ranges(struct memory_range **range, int *ranges,
 				   int kexec_flags, unsigned long lowmem_limit)
 {
 	const char *iomem = proc_iomem();
-	int memory_ranges = 0, gart = 0, i;
+	int gart = 0, i;
 	char line[MAX_LINE];
 	FILE *fp;
 	unsigned long long start, end;
@@ -218,7 +219,7 @@ static int get_crash_memory_ranges(struct memory_range **range, int *ranges,
 		char *str;
 		int type, consumed, count;
 
-		if (memory_ranges >= CRASH_MAX_MEMORY_RANGES)
+		if (crash_memory_ranges >= CRASH_MAX_MEMORY_RANGES)
 			break;
 		count = sscanf(line, "%Lx-%Lx : %n",
 			&start, &end, &consumed);
@@ -230,6 +231,8 @@ static int get_crash_memory_ranges(struct memory_range **range, int *ranges,
 		/* Only Dumping memory of type System RAM. */
 		if (memcmp(str, "System RAM\n", 11) == 0) {
 			type = RANGE_RAM;
+		} else if (memcmp(str, "reserved\n", 9) == 0) {
+			type = RANGE_RESERVED;
 		} else if (memcmp(str, "ACPI Tables\n", 12) == 0) {
 			/*
 			 * ACPI Tables area need to be passed to new
@@ -250,17 +253,17 @@ static int get_crash_memory_ranges(struct memory_range **range, int *ranges,
 			continue;
 		}
 
-		crash_memory_range[memory_ranges].start = start;
-		crash_memory_range[memory_ranges].end = end;
-		crash_memory_range[memory_ranges].type = type;
+		crash_memory_range[crash_memory_ranges].start = start;
+		crash_memory_range[crash_memory_ranges].end = end;
+		crash_memory_range[crash_memory_ranges].type = type;
 
-		segregate_lowmem_region(&memory_ranges, lowmem_limit);
+		segregate_lowmem_region(&crash_memory_ranges, lowmem_limit);
 
-		memory_ranges++;
+		crash_memory_ranges++;
 	}
 	fclose(fp);
 	if (kexec_flags & KEXEC_PRESERVE_CONTEXT) {
-		for (i = 0; i < memory_ranges; i++) {
+		for (i = 0; i < crash_memory_ranges; i++) {
 			if (crash_memory_range[i].end > 0x0009ffff) {
 				crash_reserved_mem[0].start = \
 					crash_memory_range[i].start;
@@ -278,17 +281,17 @@ static int get_crash_memory_ranges(struct memory_range **range, int *ranges,
 	}
 
 	for (i = 0; i < crash_reserved_mem_nr; i++)
-		if (exclude_region(&memory_ranges, crash_reserved_mem[i].start,
+		if (exclude_region(&crash_memory_ranges, crash_reserved_mem[i].start,
 				crash_reserved_mem[i].end) < 0)
 			return -1;
 
 	if (gart) {
 		/* exclude GART region if the system has one */
-		if (exclude_region(&memory_ranges, gart_start, gart_end) < 0)
+		if (exclude_region(&crash_memory_ranges, gart_start, gart_end) < 0)
 			return -1;
 	}
 	*range = crash_memory_range;
-	*ranges = memory_ranges;
+	*ranges = crash_memory_ranges;
 
 	return 0;
 }
@@ -324,7 +327,7 @@ static int get_crash_memory_ranges_xen(struct memory_range **range,
 	}
 
 	*range = crash_memory_range;
-	*ranges = j;
+	*ranges = crash_memory_ranges = j;
 
 	qsort(*range, *ranges, sizeof(struct memory_range), compare_ranges);
 
@@ -417,8 +420,8 @@ static int exclude_region(int *nr_ranges, uint64_t start, uint64_t end)
 
 /* Adds a segment from list of memory regions which new kernel can use to
  * boot. Segment start and end should be aligned to 1K boundary. */
-static int add_memmap(struct memory_range *memmap_p, unsigned long long addr,
-								size_t size)
+static int add_memmap(struct memory_range *memmap_p, int *nr_range,
+					unsigned long long addr, size_t size)
 {
 	int i, j, nr_entries = 0, tidx = 0, align = 1024;
 	unsigned long long mstart, mend;
@@ -450,29 +453,23 @@ static int add_memmap(struct memory_range *memmap_p, unsigned long long addr,
 		else if (addr > mend)
 			tidx = i+1;
 	}
-		/* Insert the memory region. */
-		for (j = nr_entries-1; j >= tidx; j--)
-			memmap_p[j+1] = memmap_p[j];
-		memmap_p[tidx].start = addr;
-		memmap_p[tidx].end = addr + size - 1;
+	/* Insert the memory region. */
+	for (j = nr_entries-1; j >= tidx; j--)
+		memmap_p[j+1] = memmap_p[j];
+	memmap_p[tidx].start = addr;
+	memmap_p[tidx].end = addr + size - 1;
+	memmap_p[tidx].type = RANGE_RAM;
+	*nr_range = nr_entries + 1;
 
-	dbgprintf("Memmap after adding segment\n");
-	for (i = 0; i < CRASH_MAX_MEMMAP_NR;  i++) {
-		mstart = memmap_p[i].start;
-		mend = memmap_p[i].end;
-		if (mstart == 0 && mend == 0)
-			break;
-		dbgprintf("%016llx - %016llx\n",
-			mstart, mend);
-	}
+	dbgprint_mem_range("Memmap after adding segment", memmap_p, *nr_range);
 
 	return 0;
 }
 
 /* Removes a segment from list of memory regions which new kernel can use to
  * boot. Segment start and end should be aligned to 1K boundary. */
-static int delete_memmap(struct memory_range *memmap_p, unsigned long long addr,
-								size_t size)
+static int delete_memmap(struct memory_range *memmap_p, int *nr_range,
+					unsigned long long addr, size_t size)
 {
 	int i, j, nr_entries = 0, tidx = -1, operation = 0, align = 1024;
 	unsigned long long mstart, mend;
@@ -534,24 +531,17 @@ static int delete_memmap(struct memory_range *memmap_p, unsigned long long addr,
 		for (j = nr_entries-1; j > tidx; j--)
 			memmap_p[j+1] = memmap_p[j];
 		memmap_p[tidx+1] = temp_region;
+		*nr_range = nr_entries + 1;
 	}
 	if ((operation == -1) && tidx >=0) {
 		/* Delete the exact match memory region. */
 		for (j = i+1; j < CRASH_MAX_MEMMAP_NR; j++)
 			memmap_p[j-1] = memmap_p[j];
 		memmap_p[j-1].start = memmap_p[j-1].end = 0;
+		*nr_range = nr_entries - 1;
 	}
 
-	dbgprintf("Memmap after deleting segment\n");
-	for (i = 0; i < CRASH_MAX_MEMMAP_NR;  i++) {
-		mstart = memmap_p[i].start;
-		mend = memmap_p[i].end;
-		if (mstart == 0 && mend == 0) {
-			break;
-		}
-		dbgprintf("%016llx - %016llx\n",
-			mstart, mend);
-	}
+	dbgprint_mem_range("Memmap after deleting segment", memmap_p, *nr_range);
 
 	return 0;
 }
@@ -626,6 +616,9 @@ static int cmdline_add_memmap(char *cmdline, struct memory_range *memmap_p)
 			/* All regions traversed. */
 			break;
 
+		if (memmap_p[i].type != RANGE_RAM)
+			continue;
+
 		/* A region is not worth adding if region size < 100K. It eats
 		 * up precious command line length. */
 		if ((endk - startk) < min_sizek)
@@ -797,6 +790,25 @@ static void get_backup_area(struct kexec_info *info,
 	info->backup_src_size = BACKUP_SRC_END - BACKUP_SRC_START + 1;
 }
 
+static void exclude_ram(struct memory_range *mr, int *nr_mr)
+{
+	int ranges, i, j, m;
+
+	ranges = *nr_mr;
+	for (i = 0, j = 0; i < ranges; i++) {
+		if (mr[j].type == RANGE_RAM) {
+			dbgprintf("Remove RAM %016llx-%016llxx: (%d)\n", mr[j].start, mr[j].end, mr[j].type);
+			for (m = j; m < *nr_mr; m++)
+				mr[m] = mr[m+1];
+			(*nr_mr)--;
+		} else {
+			j++;
+		}
+	}
+
+	dbgprint_mem_range("After remove RAM", mr, *nr_mr);
+}
+
 /* Loads additional segments in case of a panic kernel is being loaded.
  * One segment for backup region, another segment for storing elf headers
  * for crash memory image.
@@ -807,7 +819,7 @@ int load_crashdump_segments(struct kexec_info *info, char* mod_cmdline,
 	void *tmp;
 	unsigned long sz, bufsz, memsz, elfcorehdr;
 	int nr_ranges = 0, align = 1024, i;
-	struct memory_range *mem_range, *memmap_p;
+	struct memory_range *mem_range;
 	struct crash_elf_info elf_info;
 	unsigned kexec_arch;
 
@@ -850,10 +862,7 @@ int load_crashdump_segments(struct kexec_info *info, char* mod_cmdline,
 
 	get_backup_area(info, mem_range, nr_ranges);
 
-	dbgprintf("CRASH MEMORY RANGES\n");
-
-	for(i = 0; i < nr_ranges; ++i)
-		dbgprintf("%016Lx-%016Lx\n", mem_range[i].start, mem_range[i].end);
+	dbgprint_mem_range("CRASH MEMORY RANGES", mem_range, nr_ranges);
 
 	/*
 	 * if the core type has not been set on command line, set it here
@@ -878,17 +887,6 @@ int load_crashdump_segments(struct kexec_info *info, char* mod_cmdline,
 	if (get_kernel_vaddr_and_size(info, &elf_info))
 		return -1;
 
-	/* Memory regions which panic kernel can safely use to boot into */
-	sz = (sizeof(struct memory_range) * CRASH_MAX_MEMMAP_NR);
-	memmap_p = xmalloc(sz);
-	memset(memmap_p, 0, sz);
-	add_memmap(memmap_p, info->backup_src_start, info->backup_src_size);
-	for (i = 0; i < crash_reserved_mem_nr; i++) {
-		sz = crash_reserved_mem[i].end - crash_reserved_mem[i].start +1;
-		if (add_memmap(memmap_p, crash_reserved_mem[i].start, sz) < 0)
-			return ENOCRASHKERNEL;
-	}
-
 	/* Create a backup region segment to store backup data*/
 	if (!(info->kexec_flags & KEXEC_PRESERVE_CONTEXT)) {
 		sz = _ALIGN(info->backup_src_size, align);
@@ -898,8 +896,6 @@ int load_crashdump_segments(struct kexec_info *info, char* mod_cmdline,
 						0, max_addr, -1);
 		dbgprintf("Created backup segment at 0x%lx\n",
 			  info->backup_start);
-		if (delete_memmap(memmap_p, info->backup_start, sz) < 0)
-			return EFAILED;
 	}
 
 	/* Create elf header segment and store crash image data. */
@@ -915,6 +911,23 @@ int load_crashdump_segments(struct kexec_info *info, char* mod_cmdline,
 						ELF_CORE_HEADER_ALIGN) < 0)
 			return EFAILED;
 	}
+
+	/* Memory regions which panic kernel can safely use to boot into */
+	exclude_ram(crash_memory_range, &crash_memory_ranges);
+
+	add_memmap(crash_memory_range, &crash_memory_ranges, info->backup_src_start, info->backup_src_size);
+	for (i = 0; i < crash_reserved_mem_nr; i++) {
+		sz = crash_reserved_mem[i].end - crash_reserved_mem[i].start +1;
+		if (add_memmap(crash_memory_range, &crash_memory_ranges, crash_reserved_mem[i].start, sz) < 0)
+			return ENOCRASHKERNEL;
+	}
+
+	/* exclude backup region from crash dump memory range */
+	sz = _ALIGN(info->backup_src_size, align);
+	if (delete_memmap(crash_memory_range, &crash_memory_ranges, info->backup_start, sz) < 0) {
+		return EFAILED;
+	}
+
 	/* the size of the elf headers allocated is returned in 'bufsz' */
 
 	/* Hack: With some ld versions (GNU ld version 2.14.90.0.4 20030523),
@@ -934,9 +947,9 @@ int load_crashdump_segments(struct kexec_info *info, char* mod_cmdline,
 	elfcorehdr = add_buffer(info, tmp, bufsz, memsz, align, min_base,
 							max_addr, -1);
 	dbgprintf("Created elf header segment at 0x%lx\n", elfcorehdr);
-	if (delete_memmap(memmap_p, elfcorehdr, memsz) < 0)
+	if (delete_memmap(crash_memory_range, &crash_memory_ranges, elfcorehdr, memsz) < 0)
 		return -1;
-	cmdline_add_memmap(mod_cmdline, memmap_p);
+	cmdline_add_memmap(mod_cmdline, crash_memory_range);
 	if (!bzImage_support_efi_boot)
 		cmdline_add_efi(mod_cmdline);
 	cmdline_add_elfcorehdr(mod_cmdline, elfcorehdr);
@@ -951,6 +964,7 @@ int load_crashdump_segments(struct kexec_info *info, char* mod_cmdline,
 		end = mem_range[i].end;
 		cmdline_add_memmap_acpi(mod_cmdline, start, end);
 	}
+
 	return 0;
 }
 
diff --git a/kexec/arch/i386/crashdump-x86.h b/kexec/arch/i386/crashdump-x86.h
index b61cf0a..633ee0e 100644
--- a/kexec/arch/i386/crashdump-x86.h
+++ b/kexec/arch/i386/crashdump-x86.h
@@ -20,7 +20,7 @@ int load_crashdump_segments(struct kexec_info *info, char *mod_cmdline,
 /* Kernel text size */
 #define X86_64_KERNEL_TEXT_SIZE  (512UL*1024*1024)
 
-#define CRASH_MAX_MEMMAP_NR	(KEXEC_MAX_SEGMENTS + 1)
+#define CRASH_MAX_MEMMAP_NR	CRASH_MAX_MEMORY_RANGES
 #define CRASH_MAX_MEMORY_RANGES	(MAX_MEMORY_RANGES + 2)
 
 /* Backup Region, First 640K of System RAM. */
@@ -28,4 +28,7 @@ int load_crashdump_segments(struct kexec_info *info, char *mod_cmdline,
 #define BACKUP_SRC_END		0x0009ffff
 #define BACKUP_SRC_SIZE	(BACKUP_SRC_END - BACKUP_SRC_START + 1)
 
+extern struct memory_range crash_memory_range[CRASH_MAX_MEMORY_RANGES];
+extern int crash_memory_ranges;
+
 #endif /* CRASHDUMP_X86_H */
-- 
1.8.5.3



From chaowang at redhat.com  Thu Feb 13 08:10:54 2014
From: chaowang at redhat.com (WANG Chao)
Date: Thu, 13 Feb 2014 21:10:54 +0800
Subject: [PATCH 3/4] x86: add --pass-memmap-cmdline option
In-Reply-To: <1392297055-31934-1-git-send-email-chaowang@redhat.com>
References: <1392297055-31934-1-git-send-email-chaowang@redhat.com>
Message-ID: <1392297055-31934-4-git-send-email-chaowang@redhat.com>

--pass-memmap-cmdline is used for pass memmap=exactmap cmdline for 2nd
kernel. Later we will use this option to disable passing E820 memmap
method but use the old exactmap method.

Signed-off-by: WANG Chao <chaowang at redhat.com>
---
 kexec/arch/i386/include/arch/options.h | 2 ++
 kexec/arch/i386/kexec-x86.c            | 4 ++++
 kexec/arch/i386/kexec-x86.h            | 1 +
 kexec/arch/i386/x86-linux-setup.h      | 1 +
 kexec/arch/x86_64/kexec-x86_64.c       | 5 +++++
 5 files changed, 13 insertions(+)

diff --git a/kexec/arch/i386/include/arch/options.h b/kexec/arch/i386/include/arch/options.h
index aaac731..e5300b5 100644
--- a/kexec/arch/i386/include/arch/options.h
+++ b/kexec/arch/i386/include/arch/options.h
@@ -30,6 +30,7 @@
 #define OPT_VGA 		(OPT_ARCH_MAX+8)
 #define OPT_REAL_MODE		(OPT_ARCH_MAX+9)
 #define OPT_ENTRY_32BIT		(OPT_ARCH_MAX+10)
+#define OPT_PASS_MEMMAP_CMDLINE	(OPT_ARCH_MAX+11)
 
 /* Options relevant to the architecture (excluding loader-specific ones): */
 #define KEXEC_ARCH_OPTIONS \
@@ -41,6 +42,7 @@
 	{ "console-serial", 0, 0, OPT_CONSOLE_SERIAL }, \
 	{ "elf32-core-headers", 0, 0, OPT_ELF32_CORE }, \
 	{ "elf64-core-headers", 0, 0, OPT_ELF64_CORE }, \
+	{ "pass-memmap-cmdline", 0, 0, OPT_PASS_MEMMAP_CMDLINE }, \
 
 #define KEXEC_ARCH_OPT_STR KEXEC_OPT_STR ""
 
diff --git a/kexec/arch/i386/kexec-x86.c b/kexec/arch/i386/kexec-x86.c
index 014ecd5..0b58dff 100644
--- a/kexec/arch/i386/kexec-x86.c
+++ b/kexec/arch/i386/kexec-x86.c
@@ -54,6 +54,7 @@ void arch_usage(void)
 		"     --console-serial          Enable the serial console\n"
 		"     --elf32-core-headers      Prepare core headers in ELF32 format\n"
 		"     --elf64-core-headers      Prepare core headers in ELF64 format\n"
+		"     --pass--memmap-cmdline    Pass memory map via command line in kexec on panic case\n"
 		);
 }
 
@@ -64,6 +65,7 @@ struct arch_options_t arch_options = {
 	.console_vga = 0,
 	.console_serial = 0,
 	.core_header_type = CORE_TYPE_UNDEF,
+	.pass_memmap_cmdline = 0,
 };
 
 int arch_process_options(int argc, char **argv)
@@ -133,6 +135,8 @@ int arch_process_options(int argc, char **argv)
 		case OPT_ELF64_CORE:
 			arch_options.core_header_type = CORE_TYPE_ELF64;
 			break;
+		case OPT_PASS_MEMMAP_CMDLINE:
+			arch_options.pass_memmap_cmdline = 1;
 		}
 	}
 	/* Reset getopt for the next pass; called in other source modules */
diff --git a/kexec/arch/i386/kexec-x86.h b/kexec/arch/i386/kexec-x86.h
index 5aa2a46..e8c9188 100644
--- a/kexec/arch/i386/kexec-x86.h
+++ b/kexec/arch/i386/kexec-x86.h
@@ -50,6 +50,7 @@ struct arch_options_t {
 	uint8_t  	console_vga;
 	uint8_t  	console_serial;
 	enum coretype	core_header_type;
+	uint8_t  	pass_memmap_cmdline;
 };
 
 int multiboot_x86_probe(const char *buf, off_t len);
diff --git a/kexec/arch/i386/x86-linux-setup.h b/kexec/arch/i386/x86-linux-setup.h
index 6fb84b4..b0ccd26 100644
--- a/kexec/arch/i386/x86-linux-setup.h
+++ b/kexec/arch/i386/x86-linux-setup.h
@@ -30,5 +30,6 @@ void setup_linux_system_parameters(struct kexec_info *info,
 /* command line parameter may be appended by purgatory */
 #define PURGATORY_CMDLINE_SIZE 64
 extern int bzImage_support_efi_boot;
+extern int pass_memmap_cmdline;
 
 #endif /* X86_LINUX_SETUP_H */
diff --git a/kexec/arch/x86_64/kexec-x86_64.c b/kexec/arch/x86_64/kexec-x86_64.c
index 5c23e01..f70851d 100644
--- a/kexec/arch/x86_64/kexec-x86_64.c
+++ b/kexec/arch/x86_64/kexec-x86_64.c
@@ -53,6 +53,7 @@ void arch_usage(void)
 		"     --serial-baud=<baud_rate> Specify the serial port baud rate\n"
 		"     --console-vga             Enable the vga console\n"
 		"     --console-serial          Enable the serial console\n"
+		"     --pass-memmap-cmdline     Pass memory map via command line in kexec on panic case\n"
 		);
 }
 
@@ -63,6 +64,7 @@ struct arch_options_t arch_options = {
 	.console_vga = 0,
 	.console_serial = 0,
 	.core_header_type = CORE_TYPE_ELF64,
+	.pass_memmap_cmdline = 0,
 };
 
 int arch_process_options(int argc, char **argv)
@@ -126,6 +128,9 @@ int arch_process_options(int argc, char **argv)
 			}
 			arch_options.serial_baud = value;
 			break;
+		case OPT_PASS_MEMMAP_CMDLINE:
+			arch_options.pass_memmap_cmdline = 1;
+			break;
 		}
 	}
 	/* Reset getopt for the next pass; called in other source modules */
-- 
1.8.5.3



From vgoyal at redhat.com  Thu Feb 13 08:52:29 2014
From: vgoyal at redhat.com (Vivek Goyal)
Date: Thu, 13 Feb 2014 08:52:29 -0500
Subject: Tool for creating full vmcore
In-Reply-To: <20140213135153.GB30844@redhat.com>
References: <52FBD7C3.4060304@acm.org> <20140212214257.GF16470@redhat.com>
 <CADq4U7+K-Zi2Ckb-mfDWFf50Oq7hbTWR6H92=Jx=STqWSJu89g@mail.gmail.com>
 <20140213135153.GB30844@redhat.com>
Message-ID: <20140213135229.GC30844@redhat.com>

Oops, forgot to cc kexec list. Doing it now.

On Thu, Feb 13, 2014 at 08:51:53AM -0500, Vivek Goyal wrote:
> CCing kexec list. Please don't drop the list from the conversation.
> 
> On Wed, Feb 12, 2014 at 04:51:07PM -0600, Corey Minyard wrote:
> > Well, I would like to use crash, but it does not support cross debugging
> > and everything we do is cross development.
> 
> Hmm.., I will let Dave Anderson comment on that.
> 
> > 
> > I'm not familiar with filtered core files, but it would be easy enough to
> > just dump kernel memory.  It's not a big deal for what I do, we don't deal
> > with huge machines.  I suppose that's coming, though.
> 
> Well, makedumpfile utility does the kernel filtering and that utility has
> been growing over time. So for a specific use case it might be trivial but
> when you try to make it generic, we end up the size of makedumpfile.
> 
> So this is like trying to regenerate kcore file out of vmcore where
> there are ELF headers for vmalloc and vmemmap areas?
> 
> Given the fact that this tool is specifically generating kcore, I guess
> one possile name for the tool could be vmcore-kcore.
> 
> I saw some references to /dev/oldmem in git. /dev/oldmem has been
> deprecated, so you can remove all the code dealing with that and
> just rely on /proc/vmcore being there.
> 
> I guess if code is small enough, then it might be useful to 
> keep it in a direcotry say kexec-tools/vmcore-kcore. But if it turns
> out to be big, it might be better to maintain it as a separate project
> (like makedumpfile).
> 
> Thanks
> Vivek
> 
> > 
> > -corey
> > On Feb 12, 2014 3:43 PM, "Vivek Goyal" <vgoyal at redhat.com> wrote:
> > 
> > > On Wed, Feb 12, 2014 at 02:21:23PM -0600, Corey Minyard wrote:
> > > > Hello,
> > > >
> > > > I've written a tool that takes an coredump of physical kernel memory and
> > > > converts it to a coredump of virtual kernel memory that can be directly
> > > > used by gdb to debug a kernel.
> > >
> > > I am wondering where is it useful. So you find using gdb on kernel
> > > core give you better experience as compared to crash which is fully
> > > tailored to kernel debugging only?
> > >
> > > What about dump filtering? Now a days we use makedumpfile by default
> > > and makedumpfile has its own format for dump files which crash
> > > understands.
> > >
> > > I guess gdb will not work with makedumpfile format files. If that's the
> > > case, that means this tool will work with unfiltered core files and
> > > generate unfiltered core files. I think working with unfiltered core
> > > files is not very practical now a days given large amount of RAM
> > > machines typically tend to have.
> > >
> > > Thanks
> > > Vivek
> > >
> > > >
> > > > I was trying to use /proc/vmcore, but that did not include any of
> > > > vmalloc memory or vmemmap, which made it kind of useless.  I thought
> > > > about adding all that to the vmcore, but that didn't seem like the
> > > > proper way to do things.
> > > >
> > > > The tool is at https://github.com/cminyard/kdump-tool
> > > >
> > > > It can create a physical memory coredump (like the kdump tool) and a
> > > > virtual memory coredump (either from a physical memory one, or directly
> > > > from /proc/vmcore and /dev/mem).
> > > >
> > > > Two kernel patches are in the "kernel-patches" directory of the tool, on
> > > > the master branch:
> > > >
> > > > One adds the valid physical memory ranges to the notes in the core
> > > > file.  Memory doesn't always start from zero, some systems have more
> > > > than one OS running on the same hardware,  and memory often has holes
> > > > and places that are bad to read from.  It seems prudent to pass in these
> > > > ranges so the coredump is only the memory required.  It also adds the
> > > > physical address of the kernel page directory to the notes, so it can
> > > > parse the page tables.
> > > >
> > > > The other is MIPS specific.  You need a whole bunch of information about
> > > > the configuration to parse the MIPS page tables.
> > > >
> > > > One cool thing this should be able to do is create a coredump for
> > > > userspace processes.  You can look into kernel memory to find the page
> > > > table and pass that in to the tool.  It should be able to extract the
> > > > process' resident memory from a physical coredump.  Of course, it will
> > > > only dump resident memory, anything on disk will not be there.
> > > >
> > > > Is this interesting to the kdump community?  I'd like to include it in
> > > > kexec, if possible.
> > > >
> > > > Thanks,
> > > >
> > > > -corey
> > > >
> > > > _______________________________________________
> > > > kexec mailing list
> > > > kexec at lists.infradead.org
> > > > http://lists.infradead.org/mailman/listinfo/kexec
> > >


From minyard at acm.org  Thu Feb 13 11:45:16 2014
From: minyard at acm.org (Corey Minyard)
Date: Thu, 13 Feb 2014 10:45:16 -0600
Subject: Tool for creating full vmcore
In-Reply-To: <20140213135229.GC30844@redhat.com>
References: <52FBD7C3.4060304@acm.org> <20140212214257.GF16470@redhat.com>
 <CADq4U7+K-Zi2Ckb-mfDWFf50Oq7hbTWR6H92=Jx=STqWSJu89g@mail.gmail.com>
 <20140213135153.GB30844@redhat.com> <20140213135229.GC30844@redhat.com>
Message-ID: <52FCF69C.2080108@acm.org>

On 02/13/2014 07:52 AM, Vivek Goyal wrote:
> Oops, forgot to cc kexec list. Doing it now.
Yeah, I forgot that, too.

>
> On Thu, Feb 13, 2014 at 08:51:53AM -0500, Vivek Goyal wrote:
>> CCing kexec list. Please don't drop the list from the conversation.
>>
>> On Wed, Feb 12, 2014 at 04:51:07PM -0600, Corey Minyard wrote:
>>> Well, I would like to use crash, but it does not support cross debugging
>>> and everything we do is cross development.
>> Hmm.., I will let Dave Anderson comment on that.

Dave has already commented on it several times.  It's not going to happen.

>>
>>> I'm not familiar with filtered core files, but it would be easy enough to
>>> just dump kernel memory.  It's not a big deal for what I do, we don't deal
>>> with huge machines.  I suppose that's coming, though.
>> Well, makedumpfile utility does the kernel filtering and that utility has
>> been growing over time. So for a specific use case it might be trivial but
>> when you try to make it generic, we end up the size of makedumpfile.
>>
>> So this is like trying to regenerate kcore file out of vmcore where
>> there are ELF headers for vmalloc and vmemmap areas?

Basically, that's it.  It walks the page tables and generates an ELF
file from that, so it will pick up anything in the page tables.  It's
theoretically possible to walk user page tables, too.  That means
there's arch-specific code.  It's pretty trivial for everything but
MIPS, which implements page tables in software and has too many options.

Oh, I forgot to mention earlier that i386 is not tested yet.  x86_64,
ARM, and MIPS are tested.  I need to get to i386 soon.

>>
>> Given the fact that this tool is specifically generating kcore, I guess
>> one possile name for the tool could be vmcore-kcore.

Yeah, I've been leaning somewhere in that direction for the name.

>>
>> I saw some references to /dev/oldmem in git. /dev/oldmem has been
>> deprecated, so you can remove all the code dealing with that and
>> just rely on /proc/vmcore being there.

Yes, I found that out and removed it a while ago.  Makes sense.

>>
>> I guess if code is small enough, then it might be useful to 
>> keep it in a direcotry say kexec-tools/vmcore-kcore. But if it turns
>> out to be big, it might be better to maintain it as a separate project
>> (like makedumpfile).

Yeah, it's a little big, but not huge.  Most of the code is the elf
part, which is in it's own file and could be a separate library.  I'm
fine either way.  It will get bigger as new arch-specific code is added.

Thanks,

-corey

>> Thanks
>> Vivek
>>
>>> -corey
>>> On Feb 12, 2014 3:43 PM, "Vivek Goyal" <vgoyal at redhat.com> wrote:
>>>
>>>> On Wed, Feb 12, 2014 at 02:21:23PM -0600, Corey Minyard wrote:
>>>>> Hello,
>>>>>
>>>>> I've written a tool that takes an coredump of physical kernel memory and
>>>>> converts it to a coredump of virtual kernel memory that can be directly
>>>>> used by gdb to debug a kernel.
>>>> I am wondering where is it useful. So you find using gdb on kernel
>>>> core give you better experience as compared to crash which is fully
>>>> tailored to kernel debugging only?
>>>>
>>>> What about dump filtering? Now a days we use makedumpfile by default
>>>> and makedumpfile has its own format for dump files which crash
>>>> understands.
>>>>
>>>> I guess gdb will not work with makedumpfile format files. If that's the
>>>> case, that means this tool will work with unfiltered core files and
>>>> generate unfiltered core files. I think working with unfiltered core
>>>> files is not very practical now a days given large amount of RAM
>>>> machines typically tend to have.
>>>>
>>>> Thanks
>>>> Vivek
>>>>
>>>>> I was trying to use /proc/vmcore, but that did not include any of
>>>>> vmalloc memory or vmemmap, which made it kind of useless.  I thought
>>>>> about adding all that to the vmcore, but that didn't seem like the
>>>>> proper way to do things.
>>>>>
>>>>> The tool is at https://github.com/cminyard/kdump-tool
>>>>>
>>>>> It can create a physical memory coredump (like the kdump tool) and a
>>>>> virtual memory coredump (either from a physical memory one, or directly
>>>>> from /proc/vmcore and /dev/mem).
>>>>>
>>>>> Two kernel patches are in the "kernel-patches" directory of the tool, on
>>>>> the master branch:
>>>>>
>>>>> One adds the valid physical memory ranges to the notes in the core
>>>>> file.  Memory doesn't always start from zero, some systems have more
>>>>> than one OS running on the same hardware,  and memory often has holes
>>>>> and places that are bad to read from.  It seems prudent to pass in these
>>>>> ranges so the coredump is only the memory required.  It also adds the
>>>>> physical address of the kernel page directory to the notes, so it can
>>>>> parse the page tables.
>>>>>
>>>>> The other is MIPS specific.  You need a whole bunch of information about
>>>>> the configuration to parse the MIPS page tables.
>>>>>
>>>>> One cool thing this should be able to do is create a coredump for
>>>>> userspace processes.  You can look into kernel memory to find the page
>>>>> table and pass that in to the tool.  It should be able to extract the
>>>>> process' resident memory from a physical coredump.  Of course, it will
>>>>> only dump resident memory, anything on disk will not be there.
>>>>>
>>>>> Is this interesting to the kdump community?  I'd like to include it in
>>>>> kexec, if possible.
>>>>>
>>>>> Thanks,
>>>>>
>>>>> -corey
>>>>>
>>>>> _______________________________________________
>>>>> kexec mailing list
>>>>> kexec at lists.infradead.org
>>>>> http://lists.infradead.org/mailman/listinfo/kexec



From vgoyal at redhat.com  Thu Feb 13 12:07:47 2014
From: vgoyal at redhat.com (Vivek Goyal)
Date: Thu, 13 Feb 2014 12:07:47 -0500
Subject: Tool for creating full vmcore
In-Reply-To: <52FCF69C.2080108@acm.org>
References: <52FBD7C3.4060304@acm.org> <20140212214257.GF16470@redhat.com>
 <CADq4U7+K-Zi2Ckb-mfDWFf50Oq7hbTWR6H92=Jx=STqWSJu89g@mail.gmail.com>
 <20140213135153.GB30844@redhat.com>
 <20140213135229.GC30844@redhat.com> <52FCF69C.2080108@acm.org>
Message-ID: <20140213170747.GJ30844@redhat.com>

On Thu, Feb 13, 2014 at 10:45:16AM -0600, Corey Minyard wrote:

[..]
> >>
> >> I guess if code is small enough, then it might be useful to 
> >> keep it in a direcotry say kexec-tools/vmcore-kcore. But if it turns
> >> out to be big, it might be better to maintain it as a separate project
> >> (like makedumpfile).
> 
> Yeah, it's a little big, but not huge.  Most of the code is the elf
> part, which is in it's own file and could be a separate library.  I'm
> fine either way.  It will get bigger as new arch-specific code is added.

This does sound like significant code when other arch support is added.
I am beginning to think if it better to manage it as a separate project
in separate git tree.

Thanks
Vivek


From vgoyal at redhat.com  Thu Feb 13 15:35:05 2014
From: vgoyal at redhat.com (Vivek Goyal)
Date: Thu, 13 Feb 2014 15:35:05 -0500
Subject: [PATCH 1/4] add macro dbgprint_mem_range
In-Reply-To: <1392297055-31934-2-git-send-email-chaowang@redhat.com>
References: <1392297055-31934-1-git-send-email-chaowang@redhat.com>
 <1392297055-31934-2-git-send-email-chaowang@redhat.com>
Message-ID: <20140213203505.GK30844@redhat.com>

On Thu, Feb 13, 2014 at 09:10:52PM +0800, WANG Chao wrote:

[..]
> diff --git a/kexec/kexec.h b/kexec/kexec.h
> index 2bd6e96..753acc5 100644
> --- a/kexec/kexec.h
> +++ b/kexec/kexec.h
> @@ -121,6 +121,16 @@ do { \
>  		fprintf(stderr, __VA_ARGS__); \
>  } while(0)
>  
> +#define dbgprint_mem_range(prefix, mr, nr_mr) \
> +do { \
> +	int i; \
> +	dbgprintf(prefix "\n"); \
> +	for (i = 0; i < nr_mr; i++) { \
> +		dbgprintf("%016llx-%016llx (%d)\n", (mr)[i].start, \
> +			  (mr)[i].end, (mr)[i].type);                \
> +	} \
> +} while (0)
> +

Can we make it a function instead of macro? 

Vivek


From vgoyal at redhat.com  Thu Feb 13 16:46:19 2014
From: vgoyal at redhat.com (Vivek Goyal)
Date: Thu, 13 Feb 2014 16:46:19 -0500
Subject: [PATCH 2/4] x86: Store memory ranges globally used for crash
 kernel to boot into
In-Reply-To: <1392297055-31934-3-git-send-email-chaowang@redhat.com>
References: <1392297055-31934-1-git-send-email-chaowang@redhat.com>
 <1392297055-31934-3-git-send-email-chaowang@redhat.com>
Message-ID: <20140213214619.GL30844@redhat.com>

On Thu, Feb 13, 2014 at 09:10:53PM +0800, WANG Chao wrote:

[..]
> @@ -230,6 +231,8 @@ static int get_crash_memory_ranges(struct memory_range **range, int *ranges,
>  		/* Only Dumping memory of type System RAM. */
>  		if (memcmp(str, "System RAM\n", 11) == 0) {
>  			type = RANGE_RAM;
> +		} else if (memcmp(str, "reserved\n", 9) == 0) {
> +			type = RANGE_RESERVED;

Hi Chao,

Can we take up the issue of passing reserved ranges to second kernel in
a separate patchset. I had noticed higher memory usage due to that and
it might have been something else.

It might be easier to handle one thing at a time. Let us first start
passing the memory range we pass on command line through bootparams and
once that gets merged and stablizes, write a patchset to start passing
reserved memory ranges if need be.

Thanks
Vivek


From chaowang at redhat.com  Fri Feb 14 01:30:57 2014
From: chaowang at redhat.com (WANG Chao)
Date: Fri, 14 Feb 2014 14:30:57 +0800
Subject: [PATCH 2/4] x86: Store memory ranges globally used for crash
 kernel to boot into
In-Reply-To: <20140213214619.GL30844@redhat.com>
References: <1392297055-31934-1-git-send-email-chaowang@redhat.com>
 <1392297055-31934-3-git-send-email-chaowang@redhat.com>
 <20140213214619.GL30844@redhat.com>
Message-ID: <20140214063057.GC18964@dhcp-17-89.nay.redhat.com>

On 02/13/14 at 04:46pm, Vivek Goyal wrote:
> On Thu, Feb 13, 2014 at 09:10:53PM +0800, WANG Chao wrote:
> 
> [..]
> > @@ -230,6 +231,8 @@ static int get_crash_memory_ranges(struct memory_range **range, int *ranges,
> >  		/* Only Dumping memory of type System RAM. */
> >  		if (memcmp(str, "System RAM\n", 11) == 0) {
> >  			type = RANGE_RAM;
> > +		} else if (memcmp(str, "reserved\n", 9) == 0) {
> > +			type = RANGE_RESERVED;
> 
> Hi Chao,
> 
> Can we take up the issue of passing reserved ranges to second kernel in
> a separate patchset. I had noticed higher memory usage due to that and
> it might have been something else.

OK. That can be done later.

> 
> It might be easier to handle one thing at a time. Let us first start
> passing the memory range we pass on command line through bootparams and
> once that gets merged and stablizes, write a patchset to start passing
> reserved memory ranges if need be.

Cliff once sent a patch to pass reserved range to 2nd kernel (reverted
eventually due to its dependency on another patch which needed to
revert). In the patch he mentioned that some devices (PCI>0) on UV2
would fail without passing reserved range:
http://lists.infradead.org/pipermail/kexec/2013-February/007924.html

I don't dive into this issue. However I think as long as these reserved
ranges are provided by the firmware, it could be useful in 2nd kernel,
at least potentially.

Anyway this reserved ranges issue could be addressed later. I'll cut it
out in next update.

Thanks
WANG Chao


From chaowang at redhat.com  Fri Feb 14 01:31:58 2014
From: chaowang at redhat.com (WANG Chao)
Date: Fri, 14 Feb 2014 14:31:58 +0800
Subject: [PATCH 1/4] add macro dbgprint_mem_range
In-Reply-To: <20140213203505.GK30844@redhat.com>
References: <1392297055-31934-1-git-send-email-chaowang@redhat.com>
 <1392297055-31934-2-git-send-email-chaowang@redhat.com>
 <20140213203505.GK30844@redhat.com>
Message-ID: <20140214063158.GD18964@dhcp-17-89.nay.redhat.com>

On 02/13/14 at 03:35pm, Vivek Goyal wrote:
> On Thu, Feb 13, 2014 at 09:10:52PM +0800, WANG Chao wrote:
> 
> [..]
> > diff --git a/kexec/kexec.h b/kexec/kexec.h
> > index 2bd6e96..753acc5 100644
> > --- a/kexec/kexec.h
> > +++ b/kexec/kexec.h
> > @@ -121,6 +121,16 @@ do { \
> >  		fprintf(stderr, __VA_ARGS__); \
> >  } while(0)
> >  
> > +#define dbgprint_mem_range(prefix, mr, nr_mr) \
> > +do { \
> > +	int i; \
> > +	dbgprintf(prefix "\n"); \
> > +	for (i = 0; i < nr_mr; i++) { \
> > +		dbgprintf("%016llx-%016llx (%d)\n", (mr)[i].start, \
> > +			  (mr)[i].end, (mr)[i].type);                \
> > +	} \
> > +} while (0)
> > +
> 
> Can we make it a function instead of macro? 

Sure. Will put it in kexec.c

Thanks
WANG Chao


From kumagai-atsushi at mxc.nes.nec.co.jp  Fri Feb 14 02:21:52 2014
From: kumagai-atsushi at mxc.nes.nec.co.jp (Atsushi Kumagai)
Date: Fri, 14 Feb 2014 07:21:52 +0000
Subject: Reserved memory estimation for crashkernel=
In-Reply-To: <52F8A896.1050205@ubuntu.com>
References: <52F8A896.1050205@ubuntu.com>
Message-ID: <0910DD04CBD6DE4193FCF86B9C00BE971E9670@BPXM01GP.gisp.nec.co.jp>

Hello Louis,

On 2014/02/10 19:24:05, kexec <kexec-bounces at lists.infradead.org> wrote:
> Hello,
>
> I would be interested to know if there is a semi-accurate way to evaluate the
> amount of memory that needs to be reserved and passed to the crashkernel=
> parameter ?
>
> I understand that it is very specific to the environment (system configuration,
> kernel options, etc) but if we could at least know how much memory will be
> required by makedumpfile it would be a good start.

Almost all the memory required by makedumpfile is used for the bitmap,
and its maximum size can be calculated as:

  ((system memory size / page size) / 8) * 2 [byte]

Additional requirement size will be a few MByte at most, so estimating
for makedumpfile is easy.

Moreover, makedumpfile can work even with lower memory since the cyclic mode
was introduced. Then, the performance degradation caused by multi-cycle
processing is very small according to the report below:

  https://lkml.org/lkml/2013/3/26/914
  (Please see the "Performance degradation in cyclic mode" paragraph.)


Thanks
Atsushi Kumagai

> 
> Maybe we can imagine an enhancement to makedumpfile to have it evaluate a value
> that could provide some kind of estimate.
> 
> TIA,
> 
> Kind regards,
> 
> ...Louis
> -- 
> Louis Bouchard
> Software engineer,
> Ubuntu
> 
> _______________________________________________
> kexec mailing list
> kexec at lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/kexec
> 


From d.hatayama at jp.fujitsu.com  Fri Feb 14 07:18:05 2014
From: d.hatayama at jp.fujitsu.com (HATAYAMA Daisuke)
Date: Fri, 14 Feb 2014 21:18:05 +0900
Subject: [PATCH v2] vmcore: copy fractional pages into buffers in the
 kdump 2nd kernel
In-Reply-To: <0910DD04CBD6DE4193FCF86B9C00BE971E6D19@BPXM01GP.gisp.nec.co.jp>
References: <52A579EE.6090107@jp.fujitsu.com>
 <0910DD04CBD6DE4193FCF86B9C00BE971E47E1@BPXM01GP.gisp.nec.co.jp>
 <52EB73A1.3080409@jp.fujitsu.com>
 <0910DD04CBD6DE4193FCF86B9C00BE971E6D19@BPXM01GP.gisp.nec.co.jp>
Message-ID: <52FE097D.1070408@jp.fujitsu.com>

(2014/02/06 18:38), Atsushi Kumagai wrote:
> On 2014/01/31 18:58:08, HATAYAMA Daisuke <d.hatayama at jp.fujitsu.com> wrote:
>> (2014/01/31 11:36), Atsushi Kumagai wrote:
>>> Hello HATAYAMA-san,
>>>
>>> On 2013/12/09 17:06:18, HATAYAMA Daisuke <d.hatayama at jp.fujitsu.com> wrote:
>>>> This is a patch for fixing mmap failure due to fractional page issue.
>>>>
>>>> This patch might be still a bit too large as a single patch and might need to split.
>>>> If you think patch refactoring is needed, please suggest.
>>>>
>>>> Change Log:
>>>>
>>>> v1 => v2)
>>>>
>>>> - Copy fractional pages from 1st kernel to 2nd kernel to reduce read
>>>>     to the fractional pages for reliability.
>>>>
>>>> - Deal with the case where multiple System RAM areas are contained in
>>>>     a single fractional page.
>>>>
>>>> Test:
>>>>
>>>> Tested on X86_64. Fractional pages are created using memmap= kernel
>>>> parameter on the kdump 1st kernel.
>>>
>>> Could you tell me more details about how to reproduce this ?
>>> I tried to create such fractional pages to test the patch at
>>> the end of this mail, by using memmap= kernel parameter as you said
>>> like below:
>>>
>>>     # cat /proc/iomem
>>>     ...
>>>     100000000-10fff57ff : System RAM
>>>     10fff5800-1100057ff : reserved
>>>     110005800-11fffffff : System RAM
>>>
>>> However, I couldn't face the mmap() failure and makedumpfile worked
>>> normally even using mmap() on linux-3.12.1. What am I missing here ?
>>>
>>
>> This patch set tries to reduce potential risk on accessing i.e. creating
>> page tables reading memory outside System RAM regions. The potential risk
>> I intend here is for example effect of accessing mmio region.
>>
>> If you didn't see any failure except for mmap() failure on fractional pages,
>> there's no potential risk on your system in the sense of what I mean above.
>> Or you could probably see different behavior by choosing other System RAM
>> region that resides in the memory that is used for something special.
>
> Thanks for your response, but I couldn't see even the mmap() failure caused
> by a sanity check in remap_pfn_range().
> I'll describe what I did for debugging as below.
>
> First, the 1st kernel's memory map I prepared and its PT_LOAD are here.
>
>     # cat /proc/iomem
>
>     ...
>     100000000-10fff57ff : System RAM
>     10fff5800-1100057ff : ACPI Tables
>     110005800-11fffffff : System RAM
>
>     ...
>
>     Type           Offset             VirtAddr           PhysAddr
>                    FileSiz            MemSiz              Flags  Align
>     LOAD           0x00000000d07ca000 0xffff880100000000 0x0000000100000000
>                    0x000000000fff5800 0x000000000fff5800  RWE    0
>     LOAD           0x00000000e07c0800 0xffff880110005800 0x0000000110005800
>                    0x000000000fffa800 0x000000000fffa800  RWE    0
>
>
> The fractional page I expected was [0x10fff5000 - 0x10fff57ff],
> so its file offset was [0xe07bf000 - 0xe07bf7ff].
>
> Second, I prepared a patch to make sure whether the fractional page was
> mapped with mmap() or not as below:
>
>
> diff --git a/makedumpfile.c b/makedumpfile.c
> index 7536274..b6abd31 100644
> --- a/makedumpfile.c
> +++ b/makedumpfile.c
> @@ -251,11 +251,16 @@ update_mmap_range(off_t offset, int initial) {
>
>          map_size = MIN(max_offset - start_offset, info->mmap_region_size);
>
> +       if (start_offset <= 0xe07bf000 && 0xe07bf000 <= (start_offset + map_size)) {
> +               MSG("Try mapping [%llx-%llx] with mmap()\n",
> +                   (ulonglong)start_offset,
> +                   (ulonglong)(start_offset + map_size));
> +       }
> +
>          info->mmap_buf = mmap(NULL, map_size, PROT_READ, MAP_PRIVATE,
>                                       info->fd_memory, start_offset);
>
>
> Finally, I run makedumpfile_v1.5.5 with only the debug patch above in
> 2nd kernel (linux-3.12.1):
>
>      # makedumpfile -D -c /proc/vmcore ./dumpfile.c
>      ...
>
>      mmap() is available on the kernel.
>      Copying data                       : [ 92.9 %] -Try mapping [e03f9000-e07f9000] with mmap()
>      Copying data                       : [100.0 %] |
>      Writing erase info...
>      offset_eraseinfo: 12ad1218, size_eraseinfo: 0
>
>      The dumpfile is saved to ./dumpfile.c.
>
>      makedumpfile Completed.
>      #
>
>
> According to this result, mmap() for the fractional page seemed to
> succeed even without any fix, so I suspect that I misunderstand
> something about the mmap() issue reported by Vivek.
> Perhaps, can a fractional page pass that sanity check depending on
> the situation ?
>

mmap fails if target region contains two or more different memory types,
and on Vivek's environment, some ACPI region was mapped as UC.
Because you didn't see this failure, ACPI Tables on your environment
would have the same memory type as System RAM.

-- 
Thanks.
HATAYAMA, Daisuke



From bill.sumner at hp.com  Fri Feb 14 22:04:26 2014
From: bill.sumner at hp.com (Bill Sumner)
Date: Fri, 14 Feb 2014 20:04:26 -0700
Subject: [PATCH 0/1] Fix Crashdump failure caused by leftover DMA through a
 hardware IOMMU
Message-ID: <1392433467-62357-1-git-send-email-bill.sumner@hp.com>

Renamed from previous email thread: Crashdump Accepting Active IOMMU

This patch implements a fix for:
A kdump problem about DMA that has been discussed for a long time. That is,
when a kernel panics and boots into the kdump kernel, DMA started by the 
panicked kernel is not stopped before the kdump kernel is booted and the 
kdump kernel disables the IOMMU while this DMA continues.  This causes the
IOMMU to stop translating the DMA addresses as IOVAs and begin to treat them 
as physical memory addresses -- which causes the DMA to either:
(1) generate DMAR errors or (2) generate PCI SERR errors or (3) transfer  
data to or from incorrect areas of memory. Often this causes the dump to fail.

This patch modifies the behavior of the Intel iommu in the crashdump kernel: 
1. to skip disabling the iommu hardware translations
2. to leave the current translations in-place so that legacy DMA will continue
   using its current buffers until the device drivers in the crashdump kernel
   initialize and initialize their devices,
3. to use different portions of the iova address ranges for the device drivers
   in the crashdump kernel than the iova ranges that were in-use at the time
   of the panic.  

Advantages of this approach:
1. All manipulation of the IO-device is done by the Linux device-driver
   for that device.
2. This approach behaves in a manner very similar to operation when the
   panicked kernel was not using a hardware IOMMU.
3. Any activity between the IO-device and its RMRR areas is handled by the
   device-driver in the same manner as during a non-kdump boot.
4. If an IO-device has no driver in the kdump kernel, it is simply left alone.
   This supports the practice of creating a special kdump kernel without
   drivers for any devices that are not required for taking a crashdump. 

Bill Sumner (1):
  Fix Crashdump failure caused by leftover DMA through a hardware IOMMU

 drivers/iommu/intel-iommu.c | 1233 ++++++++++++++++++++++++++++++++++++++++---
 1 file changed, 1172 insertions(+), 61 deletions(-)

-- 
Bill Sumner <bill.sumner at hp.com>



From bill.sumner at hp.com  Fri Feb 14 22:04:27 2014
From: bill.sumner at hp.com (Bill Sumner)
Date: Fri, 14 Feb 2014 20:04:27 -0700
Subject: [PATCH] Fix dump failure caused by DMA through an IOMMU
In-Reply-To: <1392433467-62357-1-git-send-email-bill.sumner@hp.com>
References: <1392433467-62357-1-git-send-email-bill.sumner@hp.com>
Message-ID: <1392433467-62357-2-git-send-email-bill.sumner@hp.com>

Renamed from "Crashdump Accepting Active IOMMU" to better communicate
the purpose of this patch.

This patch implements a fix for:
A kdump problem about DMA that has been discussed for a long time. That is,
when a kernel panics and boots into the kdump kernel, DMA started by the 
panicked kernel is not stopped before the kdump kernel is booted and the 
kdump kernel disables the IOMMU while this DMA continues.  This causes the
IOMMU to stop translating the DMA addresses as IOVAs and begin to treat them 
as physical memory addresses -- which causes the DMA to either:
(1) generate DMAR errors or (2) generate PCI SERR errors or (3) transfer  
data to or from incorrect areas of memory. Often this causes the dump to fail.

This patch modifies the behavior of the Intel iommu in the crashdump kernel:
1. to skip disabling the IOMMU translation of IO Virtual Addresses (IOVA),
2. to leave the current translations in-place so that legacy DMA will continue
   using its current buffers until the device drivers in the crashdump kernel
   initialize and initialize their devices,
3. to use different portions of the iova address ranges for the device drivers
   in the crashdump kernel than the iova ranges that were in-use at the time
   of the panic.  

Advantages of this approach:
1. All manipulation of the IO-device is done by the Linux device-driver
   for that device.
2. This approach behaves in a manner very similar to operation without an
   active iommu.
3. Any activity between the IO-device and its RMRR areas is handled by the
   device-driver in the same manner as during a non-kdump boot.
4. If an IO-device has no driver in the kdump kernel, it is simply left alone.
   This supports the practice of creating a special kdump kernel without
   drivers for any devices that are not required for taking a crashdump. 

High-level overview:
During a crashdump, this code operates primarily during iommu initialization
and device-driver initialization -- in essentially the following order:

During intel-iommu hardware initialization:
In intel_iommu_init(void)
* If (This is the crash kernel)
  .  Set flag: crashdump_with_iommu (all changes below check this)
  .  Skip disabling the iommu hardware translations

In init_dmars()
* Duplicate the intel iommu translation tables from the old kernel
  into the new kernel
  . The root-entry table, all context-entry tables,
    and all page-translation-entry tables
  . The duplicate tables contain updated physical addresses to link them together.
  . The duplicate tables are mapped into kernel virtual addresses
    in the new kernel which allows most of the existing iommu code
    to operate without change.
  . Do some minimal sanity-checks during the copy
  . Place the address of the new root-entry structure into "struct intel_iommu"

* Skip setting-up new domains for 'si', 'rmrr', 'isa' 
  . Translations for 'rmrr' and 'isa' ranges have been copied from the old kernel
  . This patch has not yet been tested with iommu pass-through enabled

* Existing (unchanged) code near the end of dmar_init:
  . Loads the address of the duplicated root-entry structure from
    "struct intel_iommu" into the iommu hardware and does the hardware flushes.
    This changes the active translation tables from the ones in the old kernel
    to the copies in the new kernel.
  . This is legal because the translations in the two sets of tables are
    currently identical:
      Virtualization Technology for Directed I/O. Architecture Specification,
      February 2011, Rev. 1.3  (section 11.2, paragraph 2) 

In iommu_init_domains()
* Mark as in-use all domain-id's from the old kernel
  . In case the new kernel contains a device that was not in the old kernel
    and a new, unused domain-id is actually needed, the bitmap will give us one.

During Device Driver Initialization:
When a new domain is created for a device:
* If (this device has a context in the old kernel)
  . Get domain-id, address-width, and IOVA ranges from the old kernel context;
  . Get address(page-entry-tables) from the copy in the new kernel;
  . And apply all of the above values to the new domain structure.
* Else
  . Create a new domain as normal


Changes from: [PATCHv3 0/6] Crashdump Accepting Active IOMMU
1. Rearranged the patch cover-letter to provide a clearer and shorter
   explanation of the problem, how the problem is being solved, and
   the advantages of this approach.
2. Combined the multiple patches of the previous patch-set into this
   single patch.
3. Deleted two purely diagnostic print functions that were unnecessary 
   to the primary purpose of this fix.  These could be submitted later
   as separate, independent patches.
4. Changed the patch subject to more accurately reflect its purpose.
5. Made a few changes to better match the style of the mainline code.
6. Added comments at the front of several of the new functions.  
7. Re-edited this patch log 


Signed-off-by: Bill Sumner <bill.sumner at hp.com>
---
 drivers/iommu/intel-iommu.c | 1233 ++++++++++++++++++++++++++++++++++++++++---
 1 file changed, 1172 insertions(+), 61 deletions(-)

diff --git a/drivers/iommu/intel-iommu.c b/drivers/iommu/intel-iommu.c
index a22c86c..69b48e9 100644
--- a/drivers/iommu/intel-iommu.c
+++ b/drivers/iommu/intel-iommu.c
@@ -21,6 +21,8 @@
  * Author: Fenghua Yu <fenghua.yu at intel.com>
  */
 
+/* #define DEBUG 1 */	/* Enable/Disable debug print in this source file */
+
 #include <linux/init.h>
 #include <linux/bitmap.h>
 #include <linux/debugfs.h>
@@ -48,6 +50,7 @@
 
 #include "irq_remapping.h"
 #include "pci.h"
+#include <linux/crash_dump.h>
 
 #define ROOT_SIZE		VTD_PAGE_SIZE
 #define CONTEXT_SIZE		VTD_PAGE_SIZE
@@ -165,6 +168,78 @@ static inline unsigned long virt_to_dma_pfn(void *p)
 	return page_to_dma_pfn(virt_to_page(p));
 }
 
+#ifdef CONFIG_CRASH_DUMP
+/*
+ * Fix Crashdump failure caused by leftover DMA through a hardware IOMMU
+ *
+ * Fixes the crashdump kernel to deal with an active iommu and legacy
+ * DMA from the (old) panicked kernel in a manner similar to how legacy
+ * DMA is handled when no hardware iommu was in use by the old kernel --
+ * allow the legacy DMA to continue into its current buffers.
+ *
+ * In the crashdump kernel, this code:
+ * 1. skips disabling the IOMMU's translating of IO Virtual Addresses (IOVA)
+ * 2. leaves the current translations in-place so that legacy DMA will
+ *    continue to use its current buffers,
+ * 3. allocates to the device drivers in the crashdump kernel
+ *    portions of the iova address ranges that are different
+ *    from the iova address ranges that were being used by the old kernel
+ *    at the time of the panic.
+ *
+ */
+
+static int crashdump_with_iommu;	/* activate this feature */
+static int iova_translation_tables_are_mapped;	/* table copy done */
+
+static struct {				/* run-time pr_debug() flags */
+	unsigned in_crashdump:1;	/* if crashdump_with_iommu */
+	unsigned domain_get:1;		/* pr_debug in domain_get* functions */
+	unsigned copy_page_table:1;	/* enter/leave copy_page_table() */
+	unsigned copy_page_addr:1;	/* enter/leave copy_page_addr() */
+	unsigned addr_ranges:1;		/* accumulated addr ranges */
+	unsigned reserved_ranges:1;	/* accumulated addr ranges reserved */
+	unsigned page_addr:1;		/* adr(each page table) */
+	unsigned enter_oldcopy:1;	/* enter oldcopy() parameters */
+	unsigned leave_oldcopy:1;	/* leave oldcopy() parameters */
+} pr_dbg  = {				/* Enable flags below here */
+	.in_crashdump = 1,
+	.domain_get = 1,
+	.copy_page_table = 1,
+	.copy_page_addr = 0,
+	.addr_ranges = 0,
+	.reserved_ranges = 0,
+	.page_addr = 0,
+	.enter_oldcopy = 0,
+	.leave_oldcopy = 0,
+};
+
+
+/*
+ * Prototypes of interface functions for:
+ * Fix Crashdump failure caused by leftover DMA through a hardware IOMMU
+ */
+
+static int
+copy_intel_iommu_translation_tables(struct dmar_drhd_unit *drhd,
+	struct root_entry **root_old_p, struct root_entry **root_new_p);
+
+static int
+domain_get_did_from_old_kernel(struct intel_iommu *iommu, struct pci_dev *pdev);
+
+static int
+domain_get_gaw_from_old_kernel(struct intel_iommu *iommu, struct pci_dev *pdev);
+
+static u64
+domain_get_pgd_from_old_kernel(struct intel_iommu *iommu, struct pci_dev *pdev);
+
+static void
+domain_get_ranges_from_old_kernel(struct dmar_domain *domain,
+		  struct intel_iommu *iommu, struct pci_dev *pdev);
+static int
+intel_iommu_get_dids_from_old_kernel(struct intel_iommu *iommu);
+#endif	/* CONFIG_CRASH_DUMP */
+
+
 /* global iommu list, set NULL for ignored DMAR units */
 static struct intel_iommu **g_iommus;
 
@@ -1258,6 +1333,12 @@ static int iommu_init_domains(struct intel_iommu *iommu)
 	 */
 	if (cap_caching_mode(iommu->cap))
 		set_bit(0, iommu->domain_ids);
+
+#ifdef CONFIG_CRASH_DUMP
+	if (crashdump_with_iommu)
+		intel_iommu_get_dids_from_old_kernel(iommu);
+#endif /* CONFIG_CRASH_DUMP */
+
 	return 0;
 }
 
@@ -1327,7 +1408,8 @@ static struct dmar_domain *alloc_domain(void)
 }
 
 static int iommu_attach_domain(struct dmar_domain *domain,
-			       struct intel_iommu *iommu)
+			       struct intel_iommu *iommu,
+			       int domain_number)
 {
 	int num;
 	unsigned long ndomains;
@@ -1337,12 +1419,15 @@ static int iommu_attach_domain(struct dmar_domain *domain,
 
 	spin_lock_irqsave(&iommu->lock, flags);
 
-	num = find_first_zero_bit(iommu->domain_ids, ndomains);
-	if (num >= ndomains) {
-		spin_unlock_irqrestore(&iommu->lock, flags);
-		printk(KERN_ERR "IOMMU: no free domain ids\n");
-		return -ENOMEM;
-	}
+	if (domain_number < 0) {
+		num = find_first_zero_bit(iommu->domain_ids, ndomains);
+		if (num >= ndomains) {
+			spin_unlock_irqrestore(&iommu->lock, flags);
+			printk(KERN_ERR "IOMMU: no free domain ids\n");
+			return -ENOMEM;
+		}
+	} else
+		num = domain_number;
 
 	domain->id = num;
 	set_bit(num, iommu->domain_ids);
@@ -1953,8 +2038,17 @@ static struct dmar_domain *get_domain_for_dev(struct pci_dev *pdev, int gaw)
 	int bus = 0, devfn = 0;
 	int segment;
 	int ret;
+	int did = -1;	/* Default to "no domain_id supplied" */
 
 	domain = find_domain(pdev);
+
+#ifdef CONFIG_CRASH_DUMP
+	if (domain)
+		if (pr_dbg.in_crashdump && crashdump_with_iommu)
+			pr_debug("IOMMU: Found domain (%d) for device %s\n",
+				domain->id, pci_name(pdev));
+#endif /* CONFIG_CRASH_DUMP */
+
 	if (domain)
 		return domain;
 
@@ -1985,6 +2079,12 @@ static struct dmar_domain *get_domain_for_dev(struct pci_dev *pdev, int gaw)
 		}
 	}
 
+#ifdef CONFIG_CRASH_DUMP
+	if (pr_dbg.in_crashdump && crashdump_with_iommu)
+		pr_debug("IOMMU: Allocating new domain for device %s\n",
+			pci_name(pdev));
+#endif /* CONFIG_CRASH_DUMP */
+
 	domain = alloc_domain();
 	if (!domain)
 		goto error;
@@ -1999,7 +2099,29 @@ static struct dmar_domain *get_domain_for_dev(struct pci_dev *pdev, int gaw)
 	}
 	iommu = drhd->iommu;
 
-	ret = iommu_attach_domain(domain, iommu);
+#ifdef CONFIG_CRASH_DUMP
+	if (crashdump_with_iommu) {
+		/*
+		 * if this device had a did & gaw in the old kernel
+		 * use them instead of generating new ones
+		 */
+		did = domain_get_did_from_old_kernel(iommu, pdev);
+		if (did > 0 || (did == 0 && !cap_caching_mode(iommu->cap))) {
+			ret = domain_get_gaw_from_old_kernel(iommu, pdev);
+			if (ret > 0)
+				gaw = ret;
+			else
+				did = -1;
+		} else
+			did = -1;
+	}
+
+	if (pr_dbg.in_crashdump && crashdump_with_iommu)
+		pr_debug("IOMMU: new domain for device %s: gaw(%d) did(%d)\n",
+			pci_name(pdev), gaw, did);
+#endif /* CONFIG_CRASH_DUMP */
+
+	ret = iommu_attach_domain(domain, iommu, did);
 	if (ret) {
 		free_domain_mem(domain);
 		goto error;
@@ -2010,6 +2132,23 @@ static struct dmar_domain *get_domain_for_dev(struct pci_dev *pdev, int gaw)
 		goto error;
 	}
 
+#ifdef CONFIG_CRASH_DUMP
+	if (crashdump_with_iommu && did >= 0) {
+		u64 temp_pgd;	/* Top page-translation-table */
+
+		domain_get_ranges_from_old_kernel(domain, iommu, pdev);
+
+		temp_pgd = domain_get_pgd_from_old_kernel(iommu, pdev);
+		if (temp_pgd) {
+			if (domain->pgd)
+				free_pgtable_page(domain->pgd);
+			domain->pgd = (struct dma_pte *)temp_pgd;
+		}
+		pr_debug("IOMMU: New Domain for device %s Did:%d Pgd: 0x%12.12llx\n",
+			pci_name(pdev), did, temp_pgd);
+	}
+#endif /* CONFIG_CRASH_DUMP */
+
 	/* register pcie-to-pci device */
 	if (dev_tmp) {
 		info = alloc_devinfo_mem();
@@ -2218,7 +2357,7 @@ static int __init si_domain_init(int hw)
 		return -EFAULT;
 
 	for_each_active_iommu(iommu, drhd) {
-		ret = iommu_attach_domain(si_domain, iommu);
+		ret = iommu_attach_domain(si_domain, iommu, (int) -1);
 		if (ret) {
 			domain_exit(si_domain);
 			return -EFAULT;
@@ -2428,6 +2567,10 @@ static int __init init_dmars(void)
 	struct pci_dev *pdev;
 	struct intel_iommu *iommu;
 	int i, ret;
+#ifdef CONFIG_CRASH_DUMP
+	struct root_entry *root_old_phys;
+	struct root_entry *root_new_virt;
+#endif /* CONFIG_CRASH_DUMP */
 
 	/*
 	 * for each drhd
@@ -2471,16 +2614,39 @@ static int __init init_dmars(void)
 		if (ret)
 			goto error;
 
-		/*
-		 * TBD:
-		 * we could share the same root & context tables
-		 * among all IOMMU's. Need to Split it later.
-		 */
-		ret = iommu_alloc_root_entry(iommu);
-		if (ret) {
-			printk(KERN_ERR "IOMMU: allocate root entry failed\n");
-			goto error;
+#ifdef CONFIG_CRASH_DUMP
+		if (crashdump_with_iommu) {
+			pr_debug("Calling copy_intel_iommu_translation_tables\n");
+			pr_debug("(lists tables in OLD KERNEL during copy)\n");
+			ret = copy_intel_iommu_translation_tables(drhd,
+					&root_old_phys, &root_new_virt);
+			if (ret) {
+				pr_err("IOMMU: Copy translate tables failed\n");
+
+				/* Best to stop trying */
+				crashdump_with_iommu = false;
+				goto error;
+			}
+			iommu->root_entry = root_new_virt;
+			pr_debug("IOMMU: root_new_virt:0x%12.12llx phys:0x%12.12llx\n",
+				(u64)root_new_virt,
+				virt_to_phys(root_new_virt));
+		} else {
+#endif /* CONFIG_CRASH_DUMP */
+			/*
+			 * TBD:
+			 * we could share the same root & context tables
+			 * among all IOMMU's. Need to Split it later.
+			 */
+			ret = iommu_alloc_root_entry(iommu);
+			if (ret) {
+				printk(KERN_ERR "IOMMU: allocate root entry failed\n");
+				goto error;
+			}
+#ifdef CONFIG_CRASH_DUMP
 		}
+#endif /* CONFIG_CRASH_DUMP */
+
 		if (!ecap_pass_through(iommu->ecap))
 			hw_pass_through = 0;
 	}
@@ -2539,50 +2705,64 @@ static int __init init_dmars(void)
 
 	check_tylersburg_isoch();
 
+#ifdef CONFIG_CRASH_DUMP
 	/*
-	 * If pass through is not set or not enabled, setup context entries for
-	 * identity mappings for rmrr, gfx, and isa and may fall back to static
-	 * identity mapping if iommu_identity_mapping is set.
+	 * In the crashdump kernel: Skip setting-up new domains for
+	 * si, rmrr, and the isa bus on the expectation that these
+	 * translations were copied from the old kernel.
 	 */
-	if (iommu_identity_mapping) {
-		ret = iommu_prepare_static_identity_mapping(hw_pass_through);
-		if (ret) {
-			printk(KERN_CRIT "Failed to setup IOMMU pass-through\n");
-			goto error;
+	if (!crashdump_with_iommu) {
+#endif /* CONFIG_CRASH_DUMP */
+		/*
+		 * If pass through is not set or not enabled, setup context
+		 * entries for identity mappings for rmrr, gfx, and isa and
+		 * may fall back to static identity mapping if
+		 * iommu_identity_mapping is set.
+		 */
+		if (iommu_identity_mapping) {
+			ret = iommu_prepare_static_identity_mapping(hw_pass_through);
+			if (ret) {
+				printk(KERN_CRIT "Failed to setup IOMMU pass-through\n");
+				goto error;
+			}
 		}
-	}
-	/*
-	 * For each rmrr
-	 *   for each dev attached to rmrr
-	 *   do
-	 *     locate drhd for dev, alloc domain for dev
-	 *     allocate free domain
-	 *     allocate page table entries for rmrr
-	 *     if context not allocated for bus
-	 *           allocate and init context
-	 *           set present in root table for this bus
-	 *     init context with domain, translation etc
-	 *    endfor
-	 * endfor
-	 */
-	printk(KERN_INFO "IOMMU: Setting RMRR:\n");
-	for_each_rmrr_units(rmrr) {
-		for (i = 0; i < rmrr->devices_cnt; i++) {
-			pdev = rmrr->devices[i];
-			/*
-			 * some BIOS lists non-exist devices in DMAR
-			 * table.
-			 */
-			if (!pdev)
-				continue;
-			ret = iommu_prepare_rmrr_dev(rmrr, pdev);
-			if (ret)
-				printk(KERN_ERR
-				       "IOMMU: mapping reserved region failed\n");
+		/*
+		 * For each rmrr
+		 *   for each dev attached to rmrr
+		 *   do
+		 *     locate drhd for dev, alloc domain for dev
+		 *     allocate free domain
+		 *     allocate page table entries for rmrr
+		 *     if context not allocated for bus
+		 *           allocate and init context
+		 *           set present in root table for this bus
+		 *     init context with domain, translation etc
+		 *    endfor
+		 * endfor
+		 */
+		printk(KERN_INFO "IOMMU: Setting RMRR:\n");
+		for_each_rmrr_units(rmrr) {
+			for (i = 0; i < rmrr->devices_cnt; i++) {
+				pdev = rmrr->devices[i];
+				/*
+				 * some BIOS lists non-exist devices in DMAR
+				 * table.
+				 */
+				if (!pdev)
+					continue;
+				ret = iommu_prepare_rmrr_dev(rmrr, pdev);
+				if (ret)
+					printk(KERN_ERR "IOMMU: mapping reserved region failed\n");
+			}
 		}
-	}
 
-	iommu_prepare_isa();
+		iommu_prepare_isa();
+#ifdef CONFIG_CRASH_DUMP
+	} else {
+		iova_translation_tables_are_mapped = true;
+		pr_debug("iova_translation_tables_are_mapped = true\n");
+	}
+#endif /* CONFIG_CRASH_DUMP */
 
 	/*
 	 * for each drhd
@@ -2772,6 +2952,12 @@ static dma_addr_t __intel_map_single(struct device *hwdev, phys_addr_t paddr,
 
 	BUG_ON(dir == DMA_NONE);
 
+#ifdef CONFIG_CRASH_DUMP
+	if (pr_dbg.in_crashdump && crashdump_with_iommu)
+		pr_debug("ENTER %s paddr(0x%12.12llx) size(0x%12.12lx)\n",
+			 __func__, paddr, size);
+#endif /* CONFIG_CRASH_DUMP */
+
 	if (iommu_no_mapping(hwdev))
 		return paddr;
 
@@ -2814,6 +3000,12 @@ static dma_addr_t __intel_map_single(struct device *hwdev, phys_addr_t paddr,
 
 	start_paddr = (phys_addr_t)iova->pfn_lo << PAGE_SHIFT;
 	start_paddr += paddr & ~PAGE_MASK;
+
+#ifdef CONFIG_CRASH_DUMP
+	if (pr_dbg.in_crashdump && crashdump_with_iommu)
+		pr_debug("LEAVE %s dma_addr_t(0x%16.16llx)\n",
+			 __func__, start_paddr);
+#endif /* CONFIG_CRASH_DUMP */
 	return start_paddr;
 
 error:
@@ -3644,12 +3836,24 @@ int __init intel_iommu_init(void)
 		goto out_free_dmar;
 	}
 
+#ifdef CONFIG_CRASH_DUMP
 	/*
-	 * Disable translation if already enabled prior to OS handover.
+	 * If (This is the crash kernel)
+	 *    Set: copy iommu translate tables from old kernel
+	 *    Skip disabling the iommu hardware translations
 	 */
-	for_each_active_iommu(iommu, drhd)
-		if (iommu->gcmd & DMA_GCMD_TE)
-			iommu_disable_translation(iommu);
+	if (is_kdump_kernel()) {
+		crashdump_with_iommu = true;
+		pr_info("IOMMU crashdump_with_iommu = true\n");
+		pr_info("IOMMU Skip disabling iommu hardware translations\n");
+	} else
+#endif /* CONFIG_CRASH_DUMP */
+		/*
+		 * Disable translation if already enabled prior to OS handover.
+		 */
+		for_each_active_iommu(iommu, drhd)
+			if (iommu->gcmd & DMA_GCMD_TE)
+				iommu_disable_translation(iommu);
 
 	if (dmar_dev_scope_init() < 0) {
 		if (force_on)
@@ -4340,3 +4544,910 @@ static void __init check_tylersburg_isoch(void)
 	printk(KERN_WARNING "DMAR: Recommended TLB entries for ISOCH unit is 16; your BIOS set %d\n",
 	       vtisochctrl);
 }
+
+#ifdef CONFIG_CRASH_DUMP
+/* ------------------------------------------------------------------------
+ * Utility functions for accessing the iommu Translation Tables
+ * ------------------------------------------------------------------------
+ */
+
+static inline struct context_entry *
+get_context_phys_from_root(struct root_entry *root)
+{
+	return (struct context_entry *)
+		(root_present(root) ? (void *) (root->val & VTD_PAGE_MASK)
+				    : NULL);
+}
+
+static int
+context_get_p(struct context_entry *c)    {return((c->lo >> 0) & 0x1); }
+
+static int
+context_get_fpdi(struct context_entry *c) {return((c->lo >> 1) & 0x1); }
+
+static int
+context_get_t(struct context_entry *c)    {return((c->lo >> 2) & 0x3); }
+
+static u64
+context_get_asr(struct context_entry *c)  {return((c->lo >> 12));      }
+
+static int
+context_get_aw(struct context_entry *c)   {return((c->hi >> 0) & 0x7); }
+
+static int
+context_get_aval(struct context_entry *c) {return((c->hi >> 3) & 0xf); }
+
+static int
+context_get_did(struct context_entry *c)  {return((c->hi >> 8) & 0xffff); }
+
+static void context_put_asr(struct context_entry *c, unsigned long asr)
+{
+	c->lo &= (~VTD_PAGE_MASK);
+	c->lo |= (asr << VTD_PAGE_SHIFT);
+}
+
+
+/*
+ * Copy memory from a physically-addressed area into a virtually-addressed area
+ */
+static int oldcopy(void *to, void *from, int size)
+{
+	size_t ret = 0;			/* Length copied */
+	unsigned long pfn;		/* Page Frame Number */
+	char *buf = to;			/* Adr(Output buffer) */
+	size_t csize = (size_t)size;	/* Num(bytes to copy) */
+	unsigned long offset;		/* Lower 12 bits of from */
+	int userbuf = 0;		/* to is in kernel space */
+
+	if (pr_dbg.enter_oldcopy)
+		pr_debug("ENTER %s to=%16.16llx, from = %16.16llx, size = %d\n",
+			__func__,
+			(unsigned long long) to,
+			(unsigned long long) from, size);
+
+	if (iova_translation_tables_are_mapped)
+		memcpy(to, phys_to_virt((phys_addr_t)from), csize);
+	else {
+		pfn = ((unsigned long) from) >> VTD_PAGE_SHIFT;
+		offset = ((unsigned long) from) & (~VTD_PAGE_MASK);
+		ret = copy_oldmem_page(pfn, buf, csize, offset, userbuf);
+	}
+
+	if (pr_dbg.leave_oldcopy)
+		pr_debug("LEAVE %s ret=%d\n", __func__, (int) ret);
+
+	return (int) ret;
+}
+
+
+
+/* ------------------------------------------------------------------------
+ * Interfaces for when a new domain in the crashdump kernel needs some
+ * values from the panicked kernel's context entries
+ * ------------------------------------------------------------------------
+ */
+
+/* List to hold domain values found during the copy operation */
+static struct list_head *device_domain_values_list;
+
+
+/*
+ * Utility function for interface functions that follow.
+ */
+static int
+context_get_entry(struct context_entry *context_addr,
+			struct intel_iommu *iommu, u32 bus, int devfn)
+{
+	unsigned long long q;		/* quadword scratch */
+	struct root_entry *root_phys;	/* Phys adr (root table entry) */
+	struct root_entry  root_temp;	/* Local copy of root_entry */
+	struct context_entry *context_phys;	/* Phys adr */
+
+	if (pr_dbg.domain_get)
+		pr_debug("ENTER %s B:D:F=%2.2x:%2.2x:%1.1x &context_entry:0x%llx &intel_iommu:0x%llx\n",
+			__func__, bus, devfn>>3, devfn&7,
+			(u64)context_addr, (u64)iommu);
+
+	if (bus > 255)				/* Sanity check */
+		return -5;
+	if (devfn > 255 || devfn < 0)		/* Sanity check */
+		return -6;
+
+	q = readq(iommu->reg + DMAR_RTADDR_REG);
+	pr_debug("IOMMU %d: DMAR_RTADDR_REG:0x%16.16llx\n", iommu->seq_id, q);
+	if (!q)
+		return -1;
+
+	root_phys = (struct root_entry *) q;	/* Adr(base of vector) */
+	root_phys += bus;			/* Adr(entry we want) */
+
+	oldcopy(&root_temp, root_phys, sizeof(root_temp));
+
+	pr_debug("root_temp.val:0x%llx .rsvd1:0x%llx root_phys:0x%llx\n",
+		root_temp.val, root_temp.rsvd1, (u64)root_phys);
+
+	if (!root_present(&root_temp))
+		return -2;
+
+	pr_debug("B:D:F=%2.2x:%2.2x:%1.1x root_temp.val: %llx .rsvd1: %llx\n",
+		bus, devfn >> 3, devfn & 7, root_temp.val, root_temp.rsvd1);
+
+	if (root_temp.rsvd1)			/* If (root_entry is bad) */
+		return -3;
+
+	context_phys = get_context_phys_from_root(&root_temp);
+	if (!context_phys)
+		return -4;
+
+	context_phys += devfn;			/* Adr(context_entry we want) */
+
+
+	oldcopy(context_addr, context_phys, sizeof(*context_addr));
+
+	if (pr_dbg.domain_get)
+		pr_debug("LEAVE %s returning: phys:0x%12.12llx hi:0x%16.16llx lo:0x%16.16llx\n",
+			__func__, (u64) context_phys,
+			context_addr->hi, context_addr->lo);
+	return 0;
+}
+
+
+/*
+ * Get address_width of iova for a device from old kernel (if device existed)
+ */
+static int
+domain_get_gaw_from_old_kernel(struct intel_iommu *iommu, struct pci_dev *pdev)
+{
+	int ret;
+	struct context_entry context_temp;
+
+	if (pr_dbg.domain_get)
+		pr_debug("ENTER %s B:D:F=%2.2x:%2.2x:%1.1x iommu:%d\n",
+			__func__, pdev->bus->number,
+			pdev->devfn >> 3, pdev->devfn & 7,
+			iommu->seq_id);
+
+	ret = context_get_entry(&context_temp, iommu,
+				pdev->bus->number, pdev->devfn);
+	if (ret < 0)
+		return ret;
+
+	return (int) agaw_to_width(context_get_aw(&context_temp));
+}
+
+
+/*
+ * Get domain_id for a device from old kernel (if device existed)
+ */
+static int
+domain_get_did_from_old_kernel(struct intel_iommu *iommu, struct pci_dev *pdev)
+{
+	int ret;
+	struct context_entry context_temp;
+
+	if (pr_dbg.domain_get)
+		pr_debug("ENTER %s B:D:F=%2.2x:%2.2x:%1.1x iommu:%d\n",
+			__func__, pdev->bus->number,
+			pdev->devfn >> 3, pdev->devfn & 7,
+			iommu->seq_id);
+
+	ret = context_get_entry(&context_temp, iommu,
+				pdev->bus->number, pdev->devfn);
+	if (ret < 0)
+		return ret;
+
+	return (int) context_get_did(&context_temp);
+}
+
+
+/*
+ * Get adr(top page_table) for a device from old kernel (if device exists)
+ */
+static u64
+domain_get_pgd_from_old_kernel(struct intel_iommu *iommu, struct pci_dev *pdev)
+{
+	int ret;
+	struct context_entry context_temp;
+	u64 phys;
+	u64 virt;
+
+	if (pr_dbg.domain_get)
+		pr_debug("ENTER %s B:D:F=%2.2x:%2.2x:%1.1x iommu:%d\n",
+			__func__, pdev->bus->number,
+			pdev->devfn >> 3, pdev->devfn & 7,
+			iommu->seq_id);
+
+	ret = context_get_entry(&context_temp, iommu,
+				pdev->bus->number, pdev->devfn);
+	if (ret < 0)
+		return 0;
+	if (!context_get_p(&context_temp))
+		return 0;
+
+	phys = context_get_asr(&context_temp) << VTD_PAGE_SHIFT;
+	if (pr_dbg.domain_get)
+		pr_debug("%s, phys: 0x%16.16llx\n", __func__, (u64) phys);
+
+	if (!phys)
+		return 0;
+
+	virt = (u64) phys_to_virt(phys);
+	if (pr_dbg.domain_get)
+		pr_debug("%s, virt: 0x%16.16llx\n", __func__, (u64) virt);
+
+	return virt;
+}
+
+
+/* Mark IOVAs that are in-use at time of panic by a device of the old kernel.
+ * Mark IOVAs in the domain for that device in the new kernel
+ * so that all new requests from the device driver for an IOVA will avoid
+ * re-using any IOVA that was in-use by the old kernel.
+ */
+static void
+domain_get_ranges_from_old_kernel(struct dmar_domain *domain,
+				  struct intel_iommu *iommu,
+				  struct pci_dev *pdev)
+{
+	u32 bus = pdev->bus->number;
+	int devfn = pdev->devfn;
+	struct device_domain_info *i = NULL;    /* iterator for foreach */
+
+	pr_debug("ENTER %s, iommu=%d, B:D:F=%2.2x:%2.2x:%1.1x\n",
+			__func__, iommu->seq_id,
+			bus, devfn >> 3, devfn & 0x3);
+
+	list_for_each_entry(i, &device_domain_values_list[iommu->seq_id],
+				global) {
+		if (i->bus == bus && i->devfn == devfn) {
+			if (i->domain == NULL) {
+				pr_err("ERROR %s, iommu=%d, B:D:F=%2.2x:%2.2x:%1.1x\n",
+					__func__, iommu->seq_id,
+					bus, devfn >> 3, devfn & 0x3);
+
+				pr_err("FOUND B:D:F=%2.2x:%2.2x:%1.1x INFO domain-pointer is NULL\n",
+					bus, devfn >> 3, devfn & 0x3);
+				break;
+			}
+			pr_debug("FOUND B:D:F=%2.2x:%2.2x:%1.1x did:%4.4x\n",
+				bus, devfn >> 3, devfn & 0x3, i->domain->id);
+
+			copy_reserved_iova(&i->domain->iovad, &domain->iovad);
+			break;
+		}
+	}
+
+	pr_debug("LEAVE %s\n", __func__);
+}
+
+
+/* Mark domain-id's from old kernel as in-use on this iommu so that a new
+ * domain-id is allocated in the case where there is a device in the new kernel
+ * that was not in the old kernel -- and therefore a new domain-id is needed.
+ */
+static int intel_iommu_get_dids_from_old_kernel(struct intel_iommu *iommu)
+{
+	unsigned long long q;		/* quadword scratch */
+	struct root_entry *root_phys;	/* Phys(in old kernel) */
+	struct root_entry *root_temp;	/* Virt(Local copy) */
+	struct root_entry *re;		/* Loop index */
+	struct context_entry *context_phys;	/* Phys(in old kernel) */
+	struct context_entry *context_temp;	/* Virt(Local copy) */
+	struct context_entry *ce;	/* Loop index */
+	int did;			/* Each domain-id found */
+	u32 bus;			/* Index into root-entry-table */
+	u32 devfn;			/* Index into context-entry-table */
+
+	pr_debug("ENTER %s iommu:%d\n", __func__, iommu->seq_id);
+
+	q = readq(iommu->reg + DMAR_RTADDR_REG);
+	pr_debug("IOMMU %d: DMAR_RTADDR_REG:0x%16.16llx\n", iommu->seq_id, q);
+	if (!q)
+		return -ENOMEM;
+
+	root_phys = (void *)q;
+	root_temp = (struct root_entry *)alloc_pgtable_page(iommu->node);
+	if (!root_temp)
+		return -ENOMEM;
+	oldcopy(root_temp, root_phys, PAGE_SIZE);
+
+	context_temp = (struct context_entry *)alloc_pgtable_page(iommu->node);
+	if (!context_temp) {
+		free_pgtable_page(root_temp);
+		return -ENOMEM;
+	}
+
+	for (bus = 0, re = root_temp; bus < 256; bus += 1, re += 1) {
+
+		if (!root_present(re))
+			continue;
+
+		pr_debug("ROOT B:%2.2x val: %16.16llx rsvd1: %16.16llx\n",
+			bus, re->val, re->rsvd1);
+
+		if (re->rsvd1)			/* If (root_entry is bad) */
+			continue;
+
+		context_phys = get_context_phys_from_root(re);
+		if (!context_phys)
+			continue;
+
+		oldcopy(context_temp, context_phys, PAGE_SIZE);
+
+		for (devfn = 0, ce = context_temp; devfn < 512; devfn++, ce++) {
+			if (!context_get_p(ce))
+				continue;
+
+			did = context_get_did(ce);
+			set_bit(did, iommu->domain_ids);
+			pr_debug("DID B:D:F:%2.2x:%2.2x:%1.1x did:%d(0x%4.4x)\n",
+				bus, devfn >> 3, devfn & 0x7, did, did);
+		}
+
+	}
+	free_pgtable_page(root_temp);
+	free_pgtable_page(context_temp);
+	pr_debug("LEAVE %s iommu:%d\n", __func__, iommu->seq_id);
+	return 0;
+}
+
+
+
+/* ========================================================================
+ * Copy iommu translation tables from old kernel into new  kernel.
+ * Entry to this set of functions is: copy_intel_iommu_translation_tables()
+ * ------------------------------------------------------------------------
+ */
+
+/*
+ * Struct copy_page_addr_parms is used to allow copy_page_addr()
+ * to accumulate values across multiple calls and returns.
+ */
+struct copy_page_addr_parms {
+	u32 first;	/* flag: first-time  */
+	u32 last;	/* flag: last-time */
+	u32 bus;	/* last bus number we saw */
+	u32 devfn;	/* last devfn we saw */
+	u32 shift;	/* last shift we saw */
+	u64 pte;	/* Page Table Entry */
+	u64 next_addr;	/* next-expected page_addr */
+
+	u64 page_addr;	/* page_addr accumulating size */
+	u64 page_size;	/* page_size accumulated */
+
+	struct dmar_domain *domain;	/* to accumulate iova ranges */
+};
+
+/*
+ * constant for initializing instances of copy_page_addr_parms properly.
+ */
+static struct copy_page_addr_parms copy_page_addr_parms_init = {1, 0};
+
+
+
+/*
+ * Lowest-level function in the 'Copy Page Tables' set
+ * Called once for each page_addr present in an iommu page-address table.
+ *
+ * Because of the depth-first traversal of the page-tables by the
+ * higher-level functions that call 'copy_page_addr', all pages
+ * of a domain will be presented in ascending order of IO Virtual Address.
+ *
+ * This function accumulates each contiguous range of these IOVAs and
+ * reserves it within the proper domain in the crashdump kernel when a
+ * non-contiguous range is detected, as determined by any of the following:
+ * 1. a change in the bus or device owning the presented page
+ * 2. a change in the page-size (parameter shift) of the presented page
+ * 3. a change in the page-table entry of the presented page
+ * 4. a presented IOVA that does not match the expected next-page address
+ * 5. the 'last' flag is set, indicating that all IOVAs have been seen.
+ */
+static int copy_page_addr(u64 page_addr, u32 shift, u32 bus, u32 devfn,
+				u64 pte, struct dmar_domain *domain,
+				void *parms)
+{
+	struct copy_page_addr_parms *ppap = parms;
+
+	u64 page_size = ((u64)1 << shift);	/* page_size */
+	u64 pfn_lo;				/* For reserving IOVA range */
+	u64 pfn_hi;				/* For reserving IOVA range */
+	struct iova *iova_p;			/* For reserving IOVA range */
+
+	if (!ppap) {
+		pr_err("ERROR: ppap is NULL: 0x%3.3x(%3.3d) DevFn: 0x%3.3x(%3.3d) Page: 0x%16.16llx Size: 0x%16.16llx(%lld)\n",
+			bus, bus, devfn, devfn,  page_addr,
+			page_size, page_size);
+		return 0;
+	}
+
+	if (!ppap->last) {			/* If (Not last time) */
+		if (pr_dbg.copy_page_addr)
+			pr_debug("ADDR::B:D:F=%2.2x:%2.2x:%1.1x Addr:0x%12.12llx Size:0x%12.12llx(%lld) Pte:0x%16.16llx\n",
+			bus, devfn >> 3, devfn & 0x7,
+			page_addr, page_size, page_size, pte);
+
+		/* If (only extending current addr range) */
+		if (ppap->first     == 0      &&
+		    ppap->bus       == bus    &&
+		    ppap->devfn     == devfn  &&
+		    ppap->shift     == shift  &&
+		    (ppap->pte & ~VTD_PAGE_MASK) == (pte & ~VTD_PAGE_MASK) &&
+		    ppap->next_addr == page_addr) {
+
+			/* Update page size and next-expected address */
+			ppap->next_addr += page_size;
+			ppap->page_size += page_size;
+			return 0;
+		}
+	}
+
+	if (!ppap->first) {
+		/* Print out the accumulated address range */
+
+		if (pr_dbg.addr_ranges)
+			pr_debug("DATA B:D:F=%2.2x:%2.2x:%1.1x Addr:0x%12.12llx Size:0x%12.12llx(%lld) Pte:0x%16.16llx\n",
+			ppap->bus, ppap->devfn >> 3, ppap->devfn & 0x7,
+			ppap->page_addr,
+			ppap->page_size, ppap->page_size, ppap->pte);
+
+		if (!ppap->domain) {
+			pr_err("%s ERROR: Domain is NULL -- needed to reserve range for B:D:F=%2.2x:%2.2x:%1.1x\n",
+				__func__,
+				ppap->bus, ppap->devfn >> 3, ppap->devfn & 0x7);
+			return 0;
+		}
+		pfn_lo = IOVA_PFN(ppap->page_addr);
+		pfn_hi = IOVA_PFN(ppap->page_addr + ppap->page_size);
+		iova_p = reserve_iova(&ppap->domain->iovad, pfn_lo, pfn_hi);
+
+		if (iova_p)
+			if (pr_dbg.reserved_ranges)
+				pr_debug("RSVD B:D:F=%2.2x:%2.2x:%1.1x (0x%16.16lx, 0x%16.16lx) did=0x%4.4x\n",
+					ppap->bus,
+					ppap->devfn >> 3, ppap->devfn & 0x7,
+					iova_p->pfn_lo, iova_p->pfn_hi,
+					ppap->domain->id);
+	}
+
+	/* Prepare for a new page */
+	ppap->first     = 0;		/* Not first-time anymore */
+	ppap->bus       = bus;
+	ppap->devfn     = devfn;
+	ppap->shift     = shift;
+	ppap->pte       = pte;
+	ppap->next_addr = page_addr + page_size; /* Next-expected page_addr */
+
+	ppap->page_addr = page_addr;	/* Addr(new page) */
+	ppap->page_size = page_size;	/* Size(new page) */
+
+	ppap->domain    = domain;	/* adr(domain for the new range) */
+
+	return 0;
+}
+
+/*
+ * Recursive function to copy the tree of page tables (max 6 recursions)
+ * Parameter 'shift' controls the recursion
+ */
+static int copy_page_table(struct dma_pte **dma_pte_new_p,
+			   struct dma_pte *dma_pte_phys,
+			   u32 shift, u64 page_addr,
+			   struct intel_iommu *iommu,
+			   u32 bus, u32 devfn,
+			   struct dmar_domain *domain, void *ppap)
+{
+	int ret;			/* Integer return code */
+	struct dma_pte *p;		/* Physical adr(each entry) iterator */
+	struct dma_pte *pgt_new_virt;	/* Adr(dma_pte in new kernel) */
+	struct dma_pte *dma_pte_next;	/* Adr(next table down)  */
+	u64 u;				/* index(each entry in page_table) */
+
+	if (pr_dbg.copy_page_table)
+		pr_debug("ENTER %s B:D:F:%2.2x:%2.2x:%1.1x phys:%16.16llx shift:%d addr:%16.16llx\n",
+			__func__, bus, devfn >> 3, devfn & 0x7,
+			(u64)dma_pte_phys, shift, page_addr);
+
+	/* If (already done all levels -- problem) */
+	if (shift < 12) {
+		pr_err("ERROR %s shift < 12 %p\n", __func__, dma_pte_phys);
+		pr_err("shift %d, page_addr %16.16llu bus %3.3u devfn %3.3u\n",
+			shift, page_addr, bus, devfn);
+		return 2;
+	}
+
+	/* allocate a page table in the new kernel
+	 * copy contents from old kernel
+	 * then update each entry in the table in the new kernel
+	 */
+
+	pgt_new_virt = (struct dma_pte *)alloc_pgtable_page(iommu->node);
+	if (!pgt_new_virt)
+		return -ENOMEM;
+
+	ret = oldcopy(pgt_new_virt, dma_pte_phys, VTD_PAGE_SIZE);
+	if (ret <= 0)
+		return ret;
+
+	for (u = 0, p = pgt_new_virt; u < 512; u++, p++) {
+
+		if (((p->val & DMA_PTE_READ) == 0) &&
+		    ((p->val & DMA_PTE_WRITE) == 0))
+			continue;
+
+		if (dma_pte_superpage(p) || (shift == 12)) {
+
+			ret = copy_page_addr(page_addr | (u << shift),
+				shift, bus, devfn, p->val, domain, ppap);
+			if (ret)
+				return ret;
+			continue;
+		}
+
+		ret = copy_page_table(&dma_pte_next,
+				(struct dma_pte *)(p->val & VTD_PAGE_MASK),
+				shift-9, page_addr | (u << shift),
+				iommu, bus, devfn, domain, ppap);
+		if (ret)
+			return ret;
+
+		p->val &= ~VTD_PAGE_MASK;	/* Clear old and set new pgd */
+		p->val |= ((u64)dma_pte_next & VTD_PAGE_MASK);
+	}
+
+	*dma_pte_new_p = (struct dma_pte *)virt_to_phys(pgt_new_virt);
+	__iommu_flush_cache(iommu, pgt_new_virt, VTD_PAGE_SIZE);
+
+	if (pr_dbg.copy_page_table)
+		pr_debug("LEAVE %s new page:%16.16llx(phys) %16.16llx(virt)\n",
+			__func__, (u64)(*dma_pte_new_p), (u64)pgt_new_virt);
+
+	return 0;
+}
+
+
+/*
+ * Called once for each context_entry found in a copied context_entry_table
+ * Each context_entry represents one PCIe device handled by the IOMMU.
+ *
+ * Creates a 'struct device_domain_info' for this device and adds it to
+ * the 'device_domain_values_list'.
+ *
+ * The Intel-iommu spec. requires that every context_entry that contains
+ * the same domain-id point to the same set of page translation tables.
+ * The hardware uses this to improve the use of its translation cache.
+ * In order to make the software internal management structures match the
+ * existing context_entries in the translation tables, this function
+ * checks each previous entry on the list for a domain-id that matches the
+ * domain-id in this context_entry.  If found, it attaches the device to
+ * the existing domain structure and places the address of the previous
+ * domain's page translation table tree into this context_entry.
+ * If a matching previous entry is not found, a new 'dmar_domain'
+ * structure is created for the domain-id in this context_entry and
+ * copy_page_table is called to duplicate its tree of page tables.
+ *
+ * Note: although the 'device_domain_values_list' contains structures
+ * identical to those used by the mainline code to manage domains and
+ * devices, the structures in 'device_domain_values_list' are used only
+ * for the purpose of pointing the duplicated context_entry at the proper
+ * set of page translation tables.  At this point, it would be possible
+ * to create the actual structures used by mainline code; however, this was
+ * not done in order to minimize the changes to the mainline code.
+ */
+static int copy_context_entry(struct intel_iommu *iommu, u32 bus, u32 devfn,
+			      void *ppap, struct context_entry *ce)
+{
+	int ret = 0;			/* Integer Return Code */
+	u32 shift = 0;			/* bits to shift page_addr  */
+	u64 page_addr = 0;		/* Address of translated page */
+	struct dma_pte *pgt_old_phys;	/* Adr(page_table in the old kernel) */
+	struct dma_pte *pgt_new_phys;	/* Adr(page_table in the new kernel) */
+	unsigned long asr;		/* New asr value for new context */
+	u8  t;				/* Translation-type from context */
+	u8  aw;				/* Address-width from context */
+	u32 aw_shift[8] = {
+		12+9+9,		/* [000b] 30-bit AGAW (2-level page table) */
+		12+9+9+9,	/* [001b] 39-bit AGAW (3-level page table) */
+		12+9+9+9+9,	/* [010b] 48-bit AGAW (4-level page table) */
+		12+9+9+9+9+9,	/* [011b] 57-bit AGAW (5-level page table) */
+		12+9+9+9+9+9+9,	/* [100b] 64-bit AGAW (6-level page table) */
+		0,		/* [111b] Reserved */
+		0,		/* [110b] Reserved */
+		0,		/* [111b] Reserved */
+	};
+
+	struct dmar_domain *domain = NULL;	/* To hold domain & device */
+						/*    values from old kernel */
+	struct device_domain_info *info = NULL;	/* adr(new for this device) */
+	struct device_domain_info *i = NULL;	/* iterator for foreach */
+
+
+	pr_debug("CTXT B:D:F:%2.2x:%2.2x:%1.1x at virt: 0x%16.16llx  hi:%16.16llx lo:%16.16llx\n",
+		bus, devfn >> 3, devfn & 0x7,
+		(u64) ce, ce->hi, ce->lo);
+
+	if (!context_get_p(ce)) {	/* If (context not present) */
+		ret = 0;		/* Skip it */
+		goto exit;
+	}
+
+	pr_debug("CTXT B:D:F:%2.2x:%2.2x:%1.1x p=%d fpd=%d t=%d asr=%16.16llx aw=%d aval=%d did=0x%4.4x\n",
+		bus, devfn >> 3, devfn & 0x7,
+		(int) context_get_p(ce),
+		(int) context_get_fpdi(ce),
+		(int) context_get_t(ce),
+		(u64) context_get_asr(ce),
+		(int) context_get_aw(ce),
+		(int) context_get_aval(ce),
+		(u32) context_get_did(ce));
+
+	info = alloc_devinfo_mem();
+	if (!info) {
+		ret = -ENOMEM;
+		goto exit;
+	}
+	/* info->segment = segment;	 May need this later */
+	info->bus = bus;
+	info->devfn = devfn;
+	info->iommu = iommu;
+
+	list_for_each_entry(i, &device_domain_values_list[iommu->seq_id],
+				global) {
+		if (i->domain->id == (int) context_get_did(ce)) {
+			domain = i->domain;
+			pr_debug("CTXT B:D:F:%2.2x:%2.2x:%1.1x Found did=0x%4.4x\n",
+				bus, devfn >> 3, devfn & 0x7, i->domain->id);
+			break;
+		}
+	}
+
+	if (!domain) {
+		domain = alloc_domain();
+		if (!domain) {
+			ret = -ENOMEM;
+			goto exit;
+		}
+		INIT_LIST_HEAD(&domain->devices);
+		domain->id = (int) context_get_did(ce);
+		domain->agaw = (int) context_get_aw(ce);
+		domain->pgd = NULL;
+		init_iova_domain(&domain->iovad, DMA_32BIT_PFN);
+
+		pr_debug("CTXT Allocated new list entry, did:%d\n",
+			domain->id);
+	}
+
+	info->domain = domain;
+	list_add(&info->link, &domain->devices);
+	list_add(&info->global, &device_domain_values_list[iommu->seq_id]);
+
+	if (domain->pgd) {
+		asr = virt_to_phys(domain->pgd) >> VTD_PAGE_SHIFT;
+		context_put_asr(ce, asr);
+		ret = 4;
+		goto exit;
+	}
+
+	t = context_get_t(ce);
+
+	if (t == 0 || t == 1) {		/* If (context has page tables) */
+		aw = context_get_aw(ce);
+		shift = aw_shift[aw];
+
+		pgt_old_phys = (struct dma_pte *)(context_get_asr(ce) << 12);
+
+		ret = copy_page_table(&pgt_new_phys, pgt_old_phys,
+			shift-9, page_addr, iommu, bus, devfn, domain, ppap);
+
+		if (ret)		/* if (problem) bail out */
+			goto exit;
+
+		asr = ((unsigned long)(pgt_new_phys)) >> VTD_PAGE_SHIFT;
+		context_put_asr(ce, asr);
+		domain->pgd = phys_to_virt((unsigned long)pgt_new_phys);
+		ret = 1;
+		goto exit;
+	}
+
+	if (t == 2) {		/* If (Identity mapped pass-through) */
+		ret = 2;	/*	REVISIT: Skip for now */
+		goto exit;
+	}
+
+	ret = 3;		/* Else ce->t is a Reserved value */
+
+exit:	/* all returns come through here to insure good clean-up */
+
+	if (ret < 0) {
+		if (info)
+			free_devinfo_mem(info);
+		if (domain)
+			free_domain_mem(domain);
+	}
+	return ret;
+}
+
+
+/*
+ * Called once for each context_entry_table found in the root_entry_table
+ */
+static int copy_context_entry_table(struct intel_iommu *iommu,
+				    u32 bus, void *ppap,
+				    struct context_entry **context_new_p,
+				    struct context_entry *context_old_phys)
+{
+	int ret = 0;				/* Integer return code */
+	struct context_entry *ce;		/* Iterator */
+	struct context_entry *context_new_phys;	/* adr(table in new kernel) */
+	struct context_entry *context_new_virt;	/* adr(table in new kernel) */
+	u32 devfn = 0;				/* PCI Device & function */
+
+	/* allocate a context-entry table in the new kernel
+	 * copy contents from old kernel
+	 * then update each entry in the table in the new kernel
+	 */
+	context_new_virt =
+		(struct context_entry *)alloc_pgtable_page(iommu->node);
+	if (!context_new_virt)
+		return -ENOMEM;
+
+	context_new_phys =
+		(struct context_entry *)virt_to_phys(context_new_virt);
+
+	oldcopy(context_new_virt, context_old_phys, VTD_PAGE_SIZE);
+
+	for (devfn = 0, ce = context_new_virt; devfn < 256; devfn++, ce++) {
+
+		if (!context_get_p(ce))		/* If (context not present) */
+			continue;		/* Skip it */
+
+		ret = copy_context_entry(iommu, bus, devfn, ppap, ce);
+		if (ret == 0)		/* if (Entry not present) */
+			continue;
+		if (ret == 1)		/* If (Identity mapped pass-through) */
+			continue;	/*    REVISIT -- Skip for now */
+		if (ret == 2)		/* If (ce->t was reserved value) */
+			continue;	/*    REVISIT -- Skip for now */
+		if (ret < 0)		/* if (problem) */
+			return ret;
+	}
+
+	*context_new_p = context_new_phys;
+	__iommu_flush_cache(iommu, context_new_virt, VTD_PAGE_SIZE);
+	return 0;
+}
+
+
+/*
+ * Highest-level function in the 'copy translation tables' set of functions
+ */
+static int copy_root_entry_table(struct intel_iommu *iommu, void *ppap,
+				 struct root_entry  **root_new_virt_p,
+				 struct root_entry  *root_old_phys)
+{
+	int ret = 0;				/* Integer return code */
+	u32 bus;				/* Index: root-entry-table */
+	struct root_entry  *re;			/* Virt(iterator: new table) */
+	struct root_entry  *root_new_virt;	/* Virt(table in new kernel) */
+	struct context_entry *context_old_phys;	/* Phys(context table entry) */
+	struct context_entry *context_new_phys;	/* Phys(new context_entry) */
+
+	/*
+	 * allocate a root-entry table in the new kernel
+	 * copy contents from old kernel
+	 * then update each entry in the table in the new kernel
+	 */
+
+	root_new_virt = (struct root_entry *)alloc_pgtable_page(iommu->node);
+	if (!root_new_virt)
+		return -ENOMEM;
+
+	oldcopy(root_new_virt, root_old_phys, VTD_PAGE_SIZE);
+
+	for (bus = 0, re = root_new_virt; bus < 256; bus += 1, re += 1) {
+
+		if (!root_present(re))
+			continue;
+
+		pr_debug("ROOT Bus: %2.2x re->val: %llx rsvd1: %llx\n",
+			bus, re->val, re->rsvd1);
+
+		context_old_phys = get_context_phys_from_root(re);
+
+		if (!context_old_phys)
+			continue;
+
+		ret = copy_context_entry_table(iommu, bus, ppap,
+						&context_new_phys,
+						context_old_phys);
+		if (ret)
+			return ret;
+
+		re->val &= ~VTD_PAGE_MASK;
+		set_root_value(re, (unsigned long)context_new_phys);
+	}
+
+	*root_new_virt_p = root_new_virt;
+	__iommu_flush_cache(iommu, root_new_virt, VTD_PAGE_SIZE);
+	return 0;
+}
+
+/*
+ * Interface to the "copy translation tables" set of functions
+ * from mainline code.
+ */
+static int copy_intel_iommu_translation_tables(struct dmar_drhd_unit *drhd,
+		struct root_entry **root_old_phys_p,
+		struct root_entry **root_new_virt_p)
+{
+	struct intel_iommu *iommu;	/* Virt(iommu hardware registers) */
+	unsigned long long q;		/* quadword scratch */
+	struct root_entry *root_phys;	/* Phys(table in old kernel) */
+	struct root_entry *root_new;	/* Virt(table in new kernel) */
+	int ret = 0;			/* Integer return code */
+	int i = 0;			/* Loop index */
+
+	/* Structure so copy_page_addr() can accumulate things
+	 * over multiple calls and returns
+	 */
+	struct copy_page_addr_parms ppa_parms = copy_page_addr_parms_init;
+	struct copy_page_addr_parms *ppap = &ppa_parms;
+
+
+	pr_debug("ENTER %s\n", __func__);
+
+	iommu = drhd->iommu;
+	q = readq(iommu->reg + DMAR_RTADDR_REG);
+	pr_debug("IOMMU %d: DMAR_RTADDR_REG:0x%16.16llx\n", iommu->seq_id, q);
+
+	if (!q)
+		return -1;
+
+	*root_old_phys_p = (struct root_entry *)q;	/* Returned to caller */
+
+	/* If (list needs initializing) do it here */
+	if (!device_domain_values_list) {
+		device_domain_values_list =
+			 kcalloc(g_num_of_iommus, sizeof(struct list_head),
+					GFP_KERNEL);
+
+		if (!device_domain_values_list) {
+			pr_err("Allocation failed for device_domain_values_list array\n");
+			return -ENOMEM;
+		}
+		for (i = 0; i < g_num_of_iommus; i++)
+			INIT_LIST_HEAD(&device_domain_values_list[i]);
+	}
+
+	/* Copy the root-entry table from the old kernel
+	 * foreach context_entry_table in root_entry
+	 *    foreach context_entry in context_entry_table
+	 *       foreach level-1 page_table_entry in context_entry
+	 *          foreach level-2 page_table_entry in level 1 page_table_entry
+	 *             Above pattern continues up to 6 levels of page tables
+	 *                Sanity-check the entry
+	 *                Process the bus, devfn, page_address, page_size
+	 */
+
+	root_phys = (struct root_entry *)q;
+	ret = copy_root_entry_table(iommu, ppap, &root_new, root_phys);
+	if (ret)
+		return ret;
+
+
+	ppa_parms.last = 1;
+	copy_page_addr(0, 0, 0, 0, 0, NULL, ppap);
+	*root_new_virt_p = root_new;			/* Returned to caller */
+
+	/* The translation tables in the new kernel should now contain
+	 * the same translations as the tables in the old kernel.
+	 * This will allow us to update the iommu hdw to use the new tables.
+	 *
+	 * NOTE: Neither the iommu hardware nor the iommu->root_entry
+	 *       struct-value is updated herein.
+	 *       These are left for the caller to do.
+	 */
+
+	pr_debug("LEAVE %s\n", __func__);
+	return 0;
+}
+#endif /* CONFIG_CRASH_DUMP */
-- 
Bill Sumner <bill.sumner at hp.com>
************************************************************************



From mdf356 at gmail.com  Tue Feb 18 20:41:09 2014
From: mdf356 at gmail.com (Matthew Fleming)
Date: Tue, 18 Feb 2014 17:41:09 -0800
Subject: Kexec on mips64
Message-ID: <CAMBSHm9PtrthK+VvddYenWVgWmE00cQUkROAVPxsKkMnYs_KMw@mail.gmail.com>

I've been working on kexec into a kdump kernel on mips64 for work.
Since kexec isn't supported by Cavium on the 2.3 SDK, I'm a bit on my
own.  Based on patches from Cavium, I can get the system to crash and
boot into the kdump kernel, and come up to a shell on the console.
However, gdb on /proc/vmcore basically doesn't work for me.

One issue is that x/w on various kernel addresses doesn't work.  I
traced it to what looks like a bug in the kexec binary when it sets up
the elf notes.  The below patch seems to fix the issue, but I wonder
why this has not been seen by others.

I'm still using the kexec-tools-2.0.4 sources, but the is no
difference between 2.0.4 and 2.0.5 in this file.  2.0.5 threw an error
when trying to load the kernel and I haven't had time to debug that
yet, so I've been proceeding with 2.0.4.

Thanks,
matthew



diff -r -U8 --show-c-func
/tmp/kexec-tools-2.0.4/kexec/arch/mips/crashdump-mips.h
/home/sciadmin/workspace/ws_mdf_kdump/target/cavium/SDK/2.3/linux/embedded_rootfs/build/kexec-tools-2.0.4/kexec/arch/mips/crashdump-mips.h
--- /tmp/kexec-tools-2.0.4/kexec/arch/mips/crashdump-mips.h 2011-10-02
15:56:38.000000000 -0700
+++ /home/sciadmin/workspace/ws_mdf_kdump/target/cavium/SDK/2.3/linux/embedded_rootfs/build/kexec-tools-2.0.4/kexec/arch/mips/crashdump-mips.h
2014-02-18 17:00:27.848982998 -0800
@@ -1,23 +1,23 @@
 #ifndef CRASHDUMP_MIPS_H
 #define CRASHDUMP_MIPS_H

 struct kexec_info;
 int load_crashdump_segments(struct kexec_info *info, char *mod_cmdline,
  unsigned long max_addr, unsigned long min_base);
 #ifdef __mips64
 #define PAGE_OFFSET 0xa800000000000000ULL
+#define MAXMEM 0
 #else
 #define PAGE_OFFSET 0x80000000
+#define MAXMEM 0x80000000
 #endif
 #define __pa(x) ((unsigned long)(X) & 0x7fffffff)

-#define MAXMEM 0x80000000
-
 #define CRASH_MAX_MEMMAP_NR (KEXEC_MAX_SEGMENTS + 1)
 #define CRASH_MAX_MEMORY_RANGES (MAX_MEMORY_RANGES + 2)

 #define COMMAND_LINE_SIZE 512

 /* Backup Region, First 1M of System RAM. */
 #define BACKUP_SRC_START 0x00000000
 #define BACKUP_SRC_END 0x000fffff


From kumagai-atsushi at mxc.nes.nec.co.jp  Wed Feb 19 01:01:29 2014
From: kumagai-atsushi at mxc.nes.nec.co.jp (Atsushi Kumagai)
Date: Wed, 19 Feb 2014 06:01:29 +0000
Subject: crash: struct command can read irrelevant pages.
Message-ID: <0910DD04CBD6DE4193FCF86B9C00BE971EAF68@BPXM01GP.gisp.nec.co.jp>

Hello,

Finally, I've found the cause of the issue I mentioned as below
when makedumpfile v1.5.5 was released:

> 2. At first, the supported kernel will be updated to 3.12, but I
> found an issue while testing for v1.5.5, which seems that the page
> filtering works wrongly on kernel 3.12. I couldn't investigate this
> yet and it will take some time to finish it.
> Therefore, the latest supported kernel version is 3.11 in v1.5.5.

This is neither a kernel issue nor a makedumpfile issue, it's a crash's bug.
It can happen when a slab cache is stored at almost end of a page.

== Description ==

At the beginning, I found the error message below when I used crash for
a dumpfile generated by makedumpfile -d2:

    please wait... (gathering kmem slab cache data)
    crash: page excluded: kernel virtual address: f4e87000  type: "kmem_cache buffer"

    crash: unable to initialize kmem slab cache subsystem

This message indicated that crash failed to get a slab cache during
kmem_cache_init(), and according to the below, crash failed to get
the slab cache stored at f4e86f40:

    crash> p kmem_cache
    kmem_cache = $1 = (struct kmem_cache *) 0xc0b1cbc0 <kmem_cache_boot>
    crash>
    crash> list kmem_cache.list -s kmem_cache.name -h 0xc0b1cbc0
    ...
    f4d37840
      name = 0xf4edf540 "uid_cache"
    f4e86f40
    list: page excluded: kernel virtual address: f4e87000  type: "gdb_readmem_callback"

It seems that the slab cache covered two pages, [f4e86000- f4e87000] and
[f4e87000- f4e88000]. Well, let's confirm the *real* size of it.

Since slab caches except kmem_cache_boot are allocated as slab objects,
we can confirm the size like below:

  crash> p kmem_cache
  kmem_cache = $2 = (struct kmem_cache *) 0xc0b1cbc0 <kmem_cache_boot>
  crash> struct kmem_cache.object_size 0xc0b1cbc0
    object_size = 104
  crash>

In my environment, the size was 104 bytes. Therefore, the slab cache
stored at f4e86f40 fits in the single page([f4e86000- f4e87000]) and
the excluded page([f4e87000- f4e88000]) isn't a related page.

On the other hand, crash get the size from vmlinux by using gdb,
it was 216 bytes:

    crash> struct kmem_cache
    struct kmem_cache {
        unsigned int batchcount;
        unsigned int limit;
        ...
        struct kmem_cache_node **node;
        struct array_cache *array[33];
    }
    SIZE: 216
    crash>

So crash mistook the correlative pages of the slab cache as
[f4e86000- f4e87000] and [f4e87000- f4e88000] even though the latter
was a irrelevant page.

This gap came from the fact that the size of slab cache is variable.

    struct kmem_cache {
    ...
            struct kmem_cache_node **node;
            struct array_cache *array[NR_CPUS + MAX_NUMNODES];
            /*
             * Do not add fields after array[]
             */
    };

The size of "array" is the variable factor of kmem_cache.
When building vmlinux, the size of kmem_cache will be calculated with
NR_CPUS and MAX_NUMNODES, and put it into vmlinux as a debug information.
(Sorry, I don't know gcc well. I may misunderstand this.)
However, the actual size will be smaller than the defined size because
the actual size will be decided based on the actual number of CPUs and NODEs.

void __init kmem_cache_init(void)::
...
        /*
         * struct kmem_cache size depends on nr_node_ids & nr_cpu_ids
         */
        create_boot_cache(kmem_cache, "kmem_cache",
                offsetof(struct kmem_cache, array[nr_cpu_ids]) +
                                  nr_node_ids * sizeof(struct kmem_cache_node *),  // object_size
                                  SLAB_HWCACHE_ALIGN);
        list_add(&kmem_cache->list, &slab_caches);


As for kmem_cache, we can get the actual size of it from kmem_cache_boot,
but I suppose that kmem_cache is not the only struct in kernel whose size
is variable. So I think we should discuss how to address such issues like this.

By the way, I mentioned the case of *SLAB* in this mail,
but SLUB seems have the same issue.


Thanks
Atsushi Kumagai


From chaowang at redhat.com  Wed Feb 19 01:18:24 2014
From: chaowang at redhat.com (WANG Chao)
Date: Wed, 19 Feb 2014 14:18:24 +0800
Subject: How could we get rid of saved_max_pfn for calgary iommu?
Message-ID: <20140219061824.GA29703@dhcp-17-89.nay.redhat.com>

Hi, All

arch/x86/kernel/pci-calgary.c is the only user of saved_max_pfn today:

int __init detect_calgary(void)
{
	[..]
	specified_table_size = determine_tce_table_size((is_kdump_kernel() ?
					saved_max_pfn : max_pfn) * PAGE_SIZE);
	[..]
}

saved_max_pfn is the real mem size and is calculated by 1st kernel E820
memmap which is passed in by 2nd kernel's boot_params (done by kexec):

	saved_max_pfn = e820_end_of_ram_pfn();

After saved_max_pfn has been set, memmap=exactmap will reset the E820
provided by boot_params and use the user defined E820 instead.

Now we want to get rid of memmap=exactmap and directly pass the E820
memmap by boot_params for some reason (eg. exactmap may exceed the cmdline
size and also isn't compatible with kaslr).

However saved_max_pfn becomes the obstacle for obsoleting exactmap.
Because it needs two conditions: first kernel's E820 map and
memmap=exactmap cmdline.

So I'm wondering if it's possible to get rid of saved_max_pfn totally in
calgary code. Or we can get saved_max_pfn using a different way, for
example calculated in 1st kernel and passed in to 2nd kernel by cmdline.

Thanks
WANG Chao


From Paul.Caswell at viasat.uk.com  Wed Feb 19 07:46:16 2014
From: Paul.Caswell at viasat.uk.com (Caswell, Paul)
Date: Wed, 19 Feb 2014 12:46:16 +0000
Subject: Kexec question
Message-ID: <55CE1574BF3FA346B57696AC64BF23611703DE95@VS-WHM-S04.Stonewood.local>

Hello List,

I have a project requirement and I was wondering whether it would be possible to solve it using kexec.
I want to run a minimalist Linux OS on a x86 processor based system, I will supply a fixed memory range to
the kernel on boot to limit the physical RAM used.
On shutdown I want to completely overwrite all RAM used by the previously running image.
I thought I could use kexec to load a REALLY simple image whose sole purpose is to overwrite the RAM
used by the previous kernel and then shut the system down.
We have a number of 16bit real mode applications (they utilise flat real mode) that could possibly be
used to realise this feature.  They are normally loaded to 09E0:0000.
Can kexec load non-linux images? Do you think it could load one of our applications and execute it?
I see there's a kexec_test program in the 2.0.5 tarball but was wondering what that does?
Can kexec load and execute that?

Any help really appreciated.

Regards,
Paul



This email and any files transmitted with it may be confidential, legally privileged and protected in law and are intended solely for the use of the individual to whom it is addressed. Any view or opinions presented are solely those of the author and do not necessarily represent those of ViaSat.   If you have received this Email in error please contact the sender by return and confirm that its contents have been destroyed without further distribution or disclosure. Please email admin at viasat.uk.com<mailto:admin at viasat.uk.com> with any questions relating to this disclaimer.

ViaSat has Registered Offices at Sandford Lane, Wareham, Dorset BH20 4DY. The company is registered in England and Wales under no: 3007498.


From bp at alien8.de  Wed Feb 19 09:21:35 2014
From: bp at alien8.de (Borislav Petkov)
Date: Wed, 19 Feb 2014 15:21:35 +0100
Subject: [PATCH] kexec: Fix ->unuseable_pages typo
Message-ID: <1392819695-24116-1-git-send-email-bp@alien8.de>

From: Borislav Petkov <bp at suse.de>

Let's use the more common "unusable".

Cc: Eric Biederman <ebiederm at xmission.com>
Cc: kexec at lists.infradead.org
Signed-off-by: Borislav Petkov <bp at suse.de>
---
 include/linux/kexec.h | 2 +-
 kernel/kexec.c        | 6 +++---
 2 files changed, 4 insertions(+), 4 deletions(-)

diff --git a/include/linux/kexec.h b/include/linux/kexec.h
index 6d4066cdb5b5..969237e338d1 100644
--- a/include/linux/kexec.h
+++ b/include/linux/kexec.h
@@ -100,7 +100,7 @@ struct kimage {
 
 	struct list_head control_pages;
 	struct list_head dest_pages;
-	struct list_head unuseable_pages;
+	struct list_head unusable_pages;
 
 	/* Address of next control page to allocate for crash kernels. */
 	unsigned long control_page;
diff --git a/kernel/kexec.c b/kernel/kexec.c
index 60bafbed06ab..a2d0c5f80bf2 100644
--- a/kernel/kexec.c
+++ b/kernel/kexec.c
@@ -152,7 +152,7 @@ static int do_kimage_alloc(struct kimage **rimage, unsigned long entry,
 	INIT_LIST_HEAD(&image->dest_pages);
 
 	/* Initialize the list of unusable pages */
-	INIT_LIST_HEAD(&image->unuseable_pages);
+	INIT_LIST_HEAD(&image->unusable_pages);
 
 	/* Read in the segments */
 	image->nr_segments = nr_segments;
@@ -607,7 +607,7 @@ static void kimage_free_extra_pages(struct kimage *image)
 	kimage_free_page_list(&image->dest_pages);
 
 	/* Walk through and free any unusable pages I have cached */
-	kimage_free_page_list(&image->unuseable_pages);
+	kimage_free_page_list(&image->unusable_pages);
 
 }
 static void kimage_terminate(struct kimage *image)
@@ -731,7 +731,7 @@ static struct page *kimage_alloc_page(struct kimage *image,
 		/* If the page cannot be used file it away */
 		if (page_to_pfn(page) >
 				(KEXEC_SOURCE_MEMORY_LIMIT >> PAGE_SHIFT)) {
-			list_add(&page->lru, &image->unuseable_pages);
+			list_add(&page->lru, &image->unusable_pages);
 			continue;
 		}
 		addr = page_to_pfn(page) << PAGE_SHIFT;
-- 
1.8.5.rc3



From anderson at redhat.com  Wed Feb 19 09:50:15 2014
From: anderson at redhat.com (Dave Anderson)
Date: Wed, 19 Feb 2014 09:50:15 -0500 (EST)
Subject: [Crash-utility] crash: struct command can read irrelevant pages.
In-Reply-To: <0910DD04CBD6DE4193FCF86B9C00BE971EAF68@BPXM01GP.gisp.nec.co.jp>
References: <0910DD04CBD6DE4193FCF86B9C00BE971EAF68@BPXM01GP.gisp.nec.co.jp>
Message-ID: <1347294540.11438228.1392821415316.JavaMail.zimbra@redhat.com>



----- Original Message -----
> Hello,
> 
> Finally, I've found the cause of the issue I mentioned as below
> when makedumpfile v1.5.5 was released:
> 
> > 2. At first, the supported kernel will be updated to 3.12, but I
> > found an issue while testing for v1.5.5, which seems that the page
> > filtering works wrongly on kernel 3.12. I couldn't investigate this
> > yet and it will take some time to finish it.
> > Therefore, the latest supported kernel version is 3.11 in v1.5.5.
> 
> This is neither a kernel issue nor a makedumpfile issue, it's a crash's bug.
> It can happen when a slab cache is stored at almost end of a page.
> 
> == Description ==
> 
> At the beginning, I found the error message below when I used crash for
> a dumpfile generated by makedumpfile -d2:
> 
>     please wait... (gathering kmem slab cache data)
>     crash: page excluded: kernel virtual address: f4e87000  type: "kmem_cache
>     buffer"
> 
>     crash: unable to initialize kmem slab cache subsystem
> 
> This message indicated that crash failed to get a slab cache during
> kmem_cache_init(), and according to the below, crash failed to get
> the slab cache stored at f4e86f40:
> 
>     crash> p kmem_cache
>     kmem_cache = $1 = (struct kmem_cache *) 0xc0b1cbc0 <kmem_cache_boot>
>     crash>
>     crash> list kmem_cache.list -s kmem_cache.name -h 0xc0b1cbc0
>     ...
>     f4d37840
>       name = 0xf4edf540 "uid_cache"
>     f4e86f40
>     list: page excluded: kernel virtual address: f4e87000  type:
>     "gdb_readmem_callback"
> 
> It seems that the slab cache covered two pages, [f4e86000- f4e87000] and
> [f4e87000- f4e88000]. Well, let's confirm the *real* size of it.
> 
> Since slab caches except kmem_cache_boot are allocated as slab objects,
> we can confirm the size like below:
> 
>   crash> p kmem_cache
>   kmem_cache = $2 = (struct kmem_cache *) 0xc0b1cbc0 <kmem_cache_boot>
>   crash> struct kmem_cache.object_size 0xc0b1cbc0
>     object_size = 104
>   crash>
> 
> In my environment, the size was 104 bytes. Therefore, the slab cache
> stored at f4e86f40 fits in the single page([f4e86000- f4e87000]) and
> the excluded page([f4e87000- f4e88000]) isn't a related page.
> 
> On the other hand, crash get the size from vmlinux by using gdb,
> it was 216 bytes:
> 
>     crash> struct kmem_cache
>     struct kmem_cache {
>         unsigned int batchcount;
>         unsigned int limit;
>         ...
>         struct kmem_cache_node **node;
>         struct array_cache *array[33];
>     }
>     SIZE: 216
>     crash>
> 
> So crash mistook the correlative pages of the slab cache as
> [f4e86000- f4e87000] and [f4e87000- f4e88000] even though the latter
> was a irrelevant page.
> 
> This gap came from the fact that the size of slab cache is variable.
> 
>     struct kmem_cache {
>     ...
>             struct kmem_cache_node **node;
>             struct array_cache *array[NR_CPUS + MAX_NUMNODES];
>             /*
>              * Do not add fields after array[]
>              */
>     };
> 
> The size of "array" is the variable factor of kmem_cache.
> When building vmlinux, the size of kmem_cache will be calculated with
> NR_CPUS and MAX_NUMNODES, and put it into vmlinux as a debug information.
> (Sorry, I don't know gcc well. I may misunderstand this.)
> However, the actual size will be smaller than the defined size because
> the actual size will be decided based on the actual number of CPUs and NODEs.
> 
> void __init kmem_cache_init(void)::
> ...
>         /*
>          * struct kmem_cache size depends on nr_node_ids & nr_cpu_ids
>          */
>         create_boot_cache(kmem_cache, "kmem_cache",
>                 offsetof(struct kmem_cache, array[nr_cpu_ids]) +
>                                   nr_node_ids * sizeof(struct kmem_cache_node
>                                   *),  // object_size
>                                   SLAB_HWCACHE_ALIGN);
>         list_add(&kmem_cache->list, &slab_caches);
> 
> 
> As for kmem_cache, we can get the actual size of it from kmem_cache_boot,
> but I suppose that kmem_cache is not the only struct in kernel whose size
> is variable. So I think we should discuss how to address such issues like
> this.
> 
> By the way, I mentioned the case of *SLAB* in this mail,
> but SLUB seems have the same issue.
> 
> 
> Thanks
> Atsushi Kumagai


This is a "known" issue has been discussed on the crash-utility list in the past,
at least with respect to the kmem_cache data structure.  But for any random data
structure that has such a construct, I'm not sure what can be done.

In the case of the CONFIG_SLAB kmem_cache data structure, there is a function
that is supposed to "downsize" the size value of the kmem_cache data structure
that is returned by gdb.  It is called here in kmem_cache_init(), just
prior to cycling through all of the kmem_cache structures, where the
page excluded error shown above occurred:

   8561         if (!(pc->flags & RUNTIME))
   8562                 kmem_cache_downsize();
   8563 
   8564         cache_buf = GETBUF(SIZE(kmem_cache_s));
   8565         hq_open();
   8566 
   8567         do {
   8568                 cache_count++;
   8569 
   8570                 if (!readmem(cache, KVADDR, cache_buf, SIZE(kmem_cache_s),
   8571                         "kmem_cache buffer", RETURN_ON_ERROR)) {
   8572                         FREEBUF(cache_buf);
   8573                         vt->flags |= KMEM_CACHE_UNAVAIL;
   8574                         error(INFO,
   8575                           "%sunable to initialize kmem slab cache subsystem\n\n",
   8576                                 DUMPFILE() ? "\n" : "");
   8577                         hq_close();
   8578                         return;
   8579                 }

The SIZE(kmem_cache_s) value should have been downsized by that function,
but presumably it did not work.  If CRASHDEBUG(1) was turned on during initialization, 
you would have seen either of these two messages from kmem_cache_downsize():
 
                if (CRASHDEBUG(1))
                        fprintf(fp, "kmem_cache_downsize: %ld to %ld\n",
                                STRUCT_SIZE("kmem_cache"), SIZE(kmem_cache_s));

or:

                if (CRASHDEBUG(1)) {
                        fprintf(fp,
                            "\nkmem_cache_downsize: SIZE(kmem_cache_s): %ld "
                            "cache_cache.buffer_size: %d\n",
                                STRUCT_SIZE("kmem_cache"), buffer_size);
                        fprintf(fp,
                            "kmem_cache_downsize: nr_node_ids: %ld\n",
                                vt->kmem_cache_len_nodes);
                }

The function failed probably failed due to some kernel change.  In fact, 
I just checked a 3.13 CONFIG_SLAB kernel, and I see that kmem_cache_downsize()
no longer works for that kernel.

I see that kmem_cache_boot would be a good alternative for determining
the size on CONFIG_SLAB kernels, at least on 3.7 and later kernels where
it was introduced.  And for CONFIG_SLUB, which doesn't currently have a
"downsize" function, it looks like its "kmem_cache" cache also has size
fields that could be used.

By any chance can you make the 32-bit vmlinux/vmcore pair available for
me to download?  Reply to me off-list if you can.

Thanks,
  Dave



 








From jdmason at kudzu.us  Wed Feb 19 19:04:22 2014
From: jdmason at kudzu.us (Jon Mason)
Date: Wed, 19 Feb 2014 17:04:22 -0700
Subject: How could we get rid of saved_max_pfn for calgary iommu?
In-Reply-To: <20140219061824.GA29703@dhcp-17-89.nay.redhat.com>
References: <20140219061824.GA29703@dhcp-17-89.nay.redhat.com>
Message-ID: <CAPoiz9yuLg4exX58bh5=XumgAmYNq-9kPjc+f1wa8kMU3-dBbg@mail.gmail.com>

On Tue, Feb 18, 2014 at 11:18 PM, WANG Chao <chaowang at redhat.com> wrote:
> Hi, All
>
> arch/x86/kernel/pci-calgary.c is the only user of saved_max_pfn today:
>
> int __init detect_calgary(void)
> {
>         [..]
>         specified_table_size = determine_tce_table_size((is_kdump_kernel() ?
>                                         saved_max_pfn : max_pfn) * PAGE_SIZE);
>         [..]
> }

IIUC, the purpose of this code is to reuse the TCE table from the
previous kernel.  Thus, it needs to be of the same size as the
pre-kdump kernel.  It is using the max_pfn to determine the TCE table
size in the non-kdump case.  If there is another way to determine the
size it used before, then I am fine making the change to use that way.

Thanks,
Jon

> saved_max_pfn is the real mem size and is calculated by 1st kernel E820
> memmap which is passed in by 2nd kernel's boot_params (done by kexec):
>
>         saved_max_pfn = e820_end_of_ram_pfn();
>
> After saved_max_pfn has been set, memmap=exactmap will reset the E820
> provided by boot_params and use the user defined E820 instead.
>
> Now we want to get rid of memmap=exactmap and directly pass the E820
> memmap by boot_params for some reason (eg. exactmap may exceed the cmdline
> size and also isn't compatible with kaslr).
>
> However saved_max_pfn becomes the obstacle for obsoleting exactmap.
> Because it needs two conditions: first kernel's E820 map and
> memmap=exactmap cmdline.
>
> So I'm wondering if it's possible to get rid of saved_max_pfn totally in
> calgary code. Or we can get saved_max_pfn using a different way, for
> example calculated in 1st kernel and passed in to 2nd kernel by cmdline.
>
> Thanks
> WANG Chao


From vgoyal at redhat.com  Wed Feb 19 21:36:22 2014
From: vgoyal at redhat.com (Vivek Goyal)
Date: Wed, 19 Feb 2014 21:36:22 -0500
Subject: How could we get rid of saved_max_pfn for calgary iommu?
In-Reply-To: <CAPoiz9yuLg4exX58bh5=XumgAmYNq-9kPjc+f1wa8kMU3-dBbg@mail.gmail.com>
References: <20140219061824.GA29703@dhcp-17-89.nay.redhat.com>
 <CAPoiz9yuLg4exX58bh5=XumgAmYNq-9kPjc+f1wa8kMU3-dBbg@mail.gmail.com>
Message-ID: <20140220023622.GD2970@redhat.com>

On Wed, Feb 19, 2014 at 05:04:22PM -0700, Jon Mason wrote:
> On Tue, Feb 18, 2014 at 11:18 PM, WANG Chao <chaowang at redhat.com> wrote:
> > Hi, All
> >
> > arch/x86/kernel/pci-calgary.c is the only user of saved_max_pfn today:
> >
> > int __init detect_calgary(void)
> > {
> >         [..]
> >         specified_table_size = determine_tce_table_size((is_kdump_kernel() ?
> >                                         saved_max_pfn : max_pfn) * PAGE_SIZE);
> >         [..]
> > }
> 
> IIUC, the purpose of this code is to reuse the TCE table from the
> previous kernel.  Thus, it needs to be of the same size as the
> pre-kdump kernel.  It is using the max_pfn to determine the TCE table
> size in the non-kdump case.  If there is another way to determine the
> size it used before, then I am fine making the change to use that way.

How about passing old tce table size on command line to second kernel.
Given the fact that it is specific to calgary only, we can it very
specific. Say calgary_iommu_old_tce_table_sz=<size>.

But we will then need to know the size of TCE table in first kernel. Is
this information exported to user space somewhere?

Thanks
Vivek


From chaowang at redhat.com  Thu Feb 20 04:28:29 2014
From: chaowang at redhat.com (WANG Chao)
Date: Thu, 20 Feb 2014 17:28:29 +0800
Subject: [PATCH v2 1/4] cleanup: add dbgprint_mem_range function
In-Reply-To: <1392888512-4473-1-git-send-email-chaowang@redhat.com>
References: <1392888512-4473-1-git-send-email-chaowang@redhat.com>
Message-ID: <1392888512-4473-2-git-send-email-chaowang@redhat.com>

dbgprint_mem_range is used for printing the given memory range under
debugging mode.

Signed-off-by: WANG Chao <chaowang at redhat.com>
---
 kexec/arch/i386/kexec-x86-common.c |  6 +-----
 kexec/kexec.c                      | 10 ++++++++++
 kexec/kexec.h                      |  1 +
 3 files changed, 12 insertions(+), 5 deletions(-)

diff --git a/kexec/arch/i386/kexec-x86-common.c b/kexec/arch/i386/kexec-x86-common.c
index f55e2c2..e416177 100644
--- a/kexec/arch/i386/kexec-x86-common.c
+++ b/kexec/arch/i386/kexec-x86-common.c
@@ -374,11 +374,7 @@ int get_memory_ranges(struct memory_range **range, int *ranges,
 			mem_max = end;
 	}
 
-	dbgprintf("MEMORY RANGES\n");
-	for (i = 0; i < *ranges; i++) {
-		dbgprintf("%016Lx-%016Lx (%d)\n", (*range)[i].start,
-			  (*range)[i].end, (*range)[i].type);
-	}
+	dbgprint_mem_range("MEMORY RANGES", *range, *ranges);
 
 	return ret;
 }
diff --git a/kexec/kexec.c b/kexec/kexec.c
index 703d524..2d5a2e1 100644
--- a/kexec/kexec.c
+++ b/kexec/kexec.c
@@ -53,6 +53,16 @@ unsigned long long mem_max = ULONG_MAX;
 static unsigned long kexec_flags = 0;
 int kexec_debug = 0;
 
+void dbgprint_mem_range(const char *prefix, struct memory_range *mr, int nr_mr)
+{
+	int i;
+	dbgprintf(prefix, "\n");
+	for (i = 0; i < nr_mr; i++) {
+		dbgprintf("%016llx-%016llx (%d)\n", mr[i].start,
+			  mr[i].end, mr[i].type);
+	}
+}
+
 void die(const char *fmt, ...)
 {
 	va_list args;
diff --git a/kexec/kexec.h b/kexec/kexec.h
index 2bd6e96..d69bba2 100644
--- a/kexec/kexec.h
+++ b/kexec/kexec.h
@@ -232,6 +232,7 @@ extern int file_types;
 
 #define KEXEC_OPT_STR "h?vdfxluet:p"
 
+extern void dbgprint_mem_range(const char *prefix, struct memory_range *mr, int nr_mr);
 extern void die(const char *fmt, ...)
 	__attribute__ ((format (printf, 1, 2)));
 extern void *xmalloc(size_t size);
-- 
1.8.5.3



From chaowang at redhat.com  Thu Feb 20 04:28:30 2014
From: chaowang at redhat.com (WANG Chao)
Date: Thu, 20 Feb 2014 17:28:30 +0800
Subject: [PATCH v2 2/4] x86: Store memory ranges globally used for crash
 kernel to boot into
In-Reply-To: <1392888512-4473-1-git-send-email-chaowang@redhat.com>
References: <1392888512-4473-1-git-send-email-chaowang@redhat.com>
Message-ID: <1392888512-4473-3-git-send-email-chaowang@redhat.com>

Use these two variables to store the memory ranges and the number of
memory ranges for crash kernel to boot into:

struct memory_range crash_memory_range;
int crash_memory_range;

These two variables are not static now, so can be used in other file
later.

Signed-off-by: WANG Chao <chaowang at redhat.com>
---
 kexec/arch/i386/crashdump-x86.c | 134 ++++++++++++++++++++++------------------
 kexec/arch/i386/crashdump-x86.h |   5 +-
 2 files changed, 77 insertions(+), 62 deletions(-)

diff --git a/kexec/arch/i386/crashdump-x86.c b/kexec/arch/i386/crashdump-x86.c
index 979c2bd..c55a6b1 100644
--- a/kexec/arch/i386/crashdump-x86.c
+++ b/kexec/arch/i386/crashdump-x86.c
@@ -179,7 +179,8 @@ static int exclude_region(int *nr_ranges, uint64_t start, uint64_t end);
 
 /* Stores a sorted list of RAM memory ranges for which to create elf headers.
  * A separate program header is created for backup region */
-static struct memory_range crash_memory_range[CRASH_MAX_MEMORY_RANGES];
+struct memory_range crash_memory_range[CRASH_MAX_MEMORY_RANGES];
+int crash_memory_ranges;
 
 /* Memory region reserved for storing panic kernel and other data. */
 #define CRASH_RESERVED_MEM_NR	8
@@ -201,7 +202,7 @@ static int get_crash_memory_ranges(struct memory_range **range, int *ranges,
 				   int kexec_flags, unsigned long lowmem_limit)
 {
 	const char *iomem = proc_iomem();
-	int memory_ranges = 0, gart = 0, i;
+	int gart = 0, i;
 	char line[MAX_LINE];
 	FILE *fp;
 	unsigned long long start, end;
@@ -218,7 +219,7 @@ static int get_crash_memory_ranges(struct memory_range **range, int *ranges,
 		char *str;
 		int type, consumed, count;
 
-		if (memory_ranges >= CRASH_MAX_MEMORY_RANGES)
+		if (crash_memory_ranges >= CRASH_MAX_MEMORY_RANGES)
 			break;
 		count = sscanf(line, "%Lx-%Lx : %n",
 			&start, &end, &consumed);
@@ -250,17 +251,17 @@ static int get_crash_memory_ranges(struct memory_range **range, int *ranges,
 			continue;
 		}
 
-		crash_memory_range[memory_ranges].start = start;
-		crash_memory_range[memory_ranges].end = end;
-		crash_memory_range[memory_ranges].type = type;
+		crash_memory_range[crash_memory_ranges].start = start;
+		crash_memory_range[crash_memory_ranges].end = end;
+		crash_memory_range[crash_memory_ranges].type = type;
 
-		segregate_lowmem_region(&memory_ranges, lowmem_limit);
+		segregate_lowmem_region(&crash_memory_ranges, lowmem_limit);
 
-		memory_ranges++;
+		crash_memory_ranges++;
 	}
 	fclose(fp);
 	if (kexec_flags & KEXEC_PRESERVE_CONTEXT) {
-		for (i = 0; i < memory_ranges; i++) {
+		for (i = 0; i < crash_memory_ranges; i++) {
 			if (crash_memory_range[i].end > 0x0009ffff) {
 				crash_reserved_mem[0].start = \
 					crash_memory_range[i].start;
@@ -278,17 +279,17 @@ static int get_crash_memory_ranges(struct memory_range **range, int *ranges,
 	}
 
 	for (i = 0; i < crash_reserved_mem_nr; i++)
-		if (exclude_region(&memory_ranges, crash_reserved_mem[i].start,
+		if (exclude_region(&crash_memory_ranges, crash_reserved_mem[i].start,
 				crash_reserved_mem[i].end) < 0)
 			return -1;
 
 	if (gart) {
 		/* exclude GART region if the system has one */
-		if (exclude_region(&memory_ranges, gart_start, gart_end) < 0)
+		if (exclude_region(&crash_memory_ranges, gart_start, gart_end) < 0)
 			return -1;
 	}
 	*range = crash_memory_range;
-	*ranges = memory_ranges;
+	*ranges = crash_memory_ranges;
 
 	return 0;
 }
@@ -324,7 +325,7 @@ static int get_crash_memory_ranges_xen(struct memory_range **range,
 	}
 
 	*range = crash_memory_range;
-	*ranges = j;
+	*ranges = crash_memory_ranges = j;
 
 	qsort(*range, *ranges, sizeof(struct memory_range), compare_ranges);
 
@@ -417,8 +418,8 @@ static int exclude_region(int *nr_ranges, uint64_t start, uint64_t end)
 
 /* Adds a segment from list of memory regions which new kernel can use to
  * boot. Segment start and end should be aligned to 1K boundary. */
-static int add_memmap(struct memory_range *memmap_p, unsigned long long addr,
-								size_t size)
+static int add_memmap(struct memory_range *memmap_p, int *nr_range,
+					unsigned long long addr, size_t size)
 {
 	int i, j, nr_entries = 0, tidx = 0, align = 1024;
 	unsigned long long mstart, mend;
@@ -450,29 +451,23 @@ static int add_memmap(struct memory_range *memmap_p, unsigned long long addr,
 		else if (addr > mend)
 			tidx = i+1;
 	}
-		/* Insert the memory region. */
-		for (j = nr_entries-1; j >= tidx; j--)
-			memmap_p[j+1] = memmap_p[j];
-		memmap_p[tidx].start = addr;
-		memmap_p[tidx].end = addr + size - 1;
+	/* Insert the memory region. */
+	for (j = nr_entries-1; j >= tidx; j--)
+		memmap_p[j+1] = memmap_p[j];
+	memmap_p[tidx].start = addr;
+	memmap_p[tidx].end = addr + size - 1;
+	memmap_p[tidx].type = RANGE_RAM;
+	*nr_range = nr_entries + 1;
 
-	dbgprintf("Memmap after adding segment\n");
-	for (i = 0; i < CRASH_MAX_MEMMAP_NR;  i++) {
-		mstart = memmap_p[i].start;
-		mend = memmap_p[i].end;
-		if (mstart == 0 && mend == 0)
-			break;
-		dbgprintf("%016llx - %016llx\n",
-			mstart, mend);
-	}
+	dbgprint_mem_range("Memmap after adding segment", memmap_p, *nr_range);
 
 	return 0;
 }
 
 /* Removes a segment from list of memory regions which new kernel can use to
  * boot. Segment start and end should be aligned to 1K boundary. */
-static int delete_memmap(struct memory_range *memmap_p, unsigned long long addr,
-								size_t size)
+static int delete_memmap(struct memory_range *memmap_p, int *nr_range,
+					unsigned long long addr, size_t size)
 {
 	int i, j, nr_entries = 0, tidx = -1, operation = 0, align = 1024;
 	unsigned long long mstart, mend;
@@ -534,24 +529,17 @@ static int delete_memmap(struct memory_range *memmap_p, unsigned long long addr,
 		for (j = nr_entries-1; j > tidx; j--)
 			memmap_p[j+1] = memmap_p[j];
 		memmap_p[tidx+1] = temp_region;
+		*nr_range = nr_entries + 1;
 	}
 	if ((operation == -1) && tidx >=0) {
 		/* Delete the exact match memory region. */
 		for (j = i+1; j < CRASH_MAX_MEMMAP_NR; j++)
 			memmap_p[j-1] = memmap_p[j];
 		memmap_p[j-1].start = memmap_p[j-1].end = 0;
+		*nr_range = nr_entries - 1;
 	}
 
-	dbgprintf("Memmap after deleting segment\n");
-	for (i = 0; i < CRASH_MAX_MEMMAP_NR;  i++) {
-		mstart = memmap_p[i].start;
-		mend = memmap_p[i].end;
-		if (mstart == 0 && mend == 0) {
-			break;
-		}
-		dbgprintf("%016llx - %016llx\n",
-			mstart, mend);
-	}
+	dbgprint_mem_range("Memmap after deleting segment", memmap_p, *nr_range);
 
 	return 0;
 }
@@ -626,6 +614,9 @@ static int cmdline_add_memmap(char *cmdline, struct memory_range *memmap_p)
 			/* All regions traversed. */
 			break;
 
+		if (memmap_p[i].type != RANGE_RAM)
+			continue;
+
 		/* A region is not worth adding if region size < 100K. It eats
 		 * up precious command line length. */
 		if ((endk - startk) < min_sizek)
@@ -797,6 +788,25 @@ static void get_backup_area(struct kexec_info *info,
 	info->backup_src_size = BACKUP_SRC_END - BACKUP_SRC_START + 1;
 }
 
+static void exclude_ram(struct memory_range *mr, int *nr_mr)
+{
+	int ranges, i, j, m;
+
+	ranges = *nr_mr;
+	for (i = 0, j = 0; i < ranges; i++) {
+		if (mr[j].type == RANGE_RAM) {
+			dbgprintf("Remove RAM %016llx-%016llxx: (%d)\n", mr[j].start, mr[j].end, mr[j].type);
+			for (m = j; m < *nr_mr; m++)
+				mr[m] = mr[m+1];
+			(*nr_mr)--;
+		} else {
+			j++;
+		}
+	}
+
+	dbgprint_mem_range("After remove RAM", mr, *nr_mr);
+}
+
 /* Loads additional segments in case of a panic kernel is being loaded.
  * One segment for backup region, another segment for storing elf headers
  * for crash memory image.
@@ -807,7 +817,7 @@ int load_crashdump_segments(struct kexec_info *info, char* mod_cmdline,
 	void *tmp;
 	unsigned long sz, bufsz, memsz, elfcorehdr;
 	int nr_ranges = 0, align = 1024, i;
-	struct memory_range *mem_range, *memmap_p;
+	struct memory_range *mem_range;
 	struct crash_elf_info elf_info;
 	unsigned kexec_arch;
 
@@ -850,10 +860,7 @@ int load_crashdump_segments(struct kexec_info *info, char* mod_cmdline,
 
 	get_backup_area(info, mem_range, nr_ranges);
 
-	dbgprintf("CRASH MEMORY RANGES\n");
-
-	for(i = 0; i < nr_ranges; ++i)
-		dbgprintf("%016Lx-%016Lx\n", mem_range[i].start, mem_range[i].end);
+	dbgprint_mem_range("CRASH MEMORY RANGES", mem_range, nr_ranges);
 
 	/*
 	 * if the core type has not been set on command line, set it here
@@ -878,17 +885,6 @@ int load_crashdump_segments(struct kexec_info *info, char* mod_cmdline,
 	if (get_kernel_vaddr_and_size(info, &elf_info))
 		return -1;
 
-	/* Memory regions which panic kernel can safely use to boot into */
-	sz = (sizeof(struct memory_range) * CRASH_MAX_MEMMAP_NR);
-	memmap_p = xmalloc(sz);
-	memset(memmap_p, 0, sz);
-	add_memmap(memmap_p, info->backup_src_start, info->backup_src_size);
-	for (i = 0; i < crash_reserved_mem_nr; i++) {
-		sz = crash_reserved_mem[i].end - crash_reserved_mem[i].start +1;
-		if (add_memmap(memmap_p, crash_reserved_mem[i].start, sz) < 0)
-			return ENOCRASHKERNEL;
-	}
-
 	/* Create a backup region segment to store backup data*/
 	if (!(info->kexec_flags & KEXEC_PRESERVE_CONTEXT)) {
 		sz = _ALIGN(info->backup_src_size, align);
@@ -898,8 +894,6 @@ int load_crashdump_segments(struct kexec_info *info, char* mod_cmdline,
 						0, max_addr, -1);
 		dbgprintf("Created backup segment at 0x%lx\n",
 			  info->backup_start);
-		if (delete_memmap(memmap_p, info->backup_start, sz) < 0)
-			return EFAILED;
 	}
 
 	/* Create elf header segment and store crash image data. */
@@ -915,6 +909,23 @@ int load_crashdump_segments(struct kexec_info *info, char* mod_cmdline,
 						ELF_CORE_HEADER_ALIGN) < 0)
 			return EFAILED;
 	}
+
+	/* Memory regions which panic kernel can safely use to boot into */
+	exclude_ram(crash_memory_range, &crash_memory_ranges);
+
+	add_memmap(crash_memory_range, &crash_memory_ranges, info->backup_src_start, info->backup_src_size);
+	for (i = 0; i < crash_reserved_mem_nr; i++) {
+		sz = crash_reserved_mem[i].end - crash_reserved_mem[i].start +1;
+		if (add_memmap(crash_memory_range, &crash_memory_ranges, crash_reserved_mem[i].start, sz) < 0)
+			return ENOCRASHKERNEL;
+	}
+
+	/* exclude backup region from crash dump memory range */
+	sz = _ALIGN(info->backup_src_size, align);
+	if (delete_memmap(crash_memory_range, &crash_memory_ranges, info->backup_start, sz) < 0) {
+		return EFAILED;
+	}
+
 	/* the size of the elf headers allocated is returned in 'bufsz' */
 
 	/* Hack: With some ld versions (GNU ld version 2.14.90.0.4 20030523),
@@ -934,9 +945,9 @@ int load_crashdump_segments(struct kexec_info *info, char* mod_cmdline,
 	elfcorehdr = add_buffer(info, tmp, bufsz, memsz, align, min_base,
 							max_addr, -1);
 	dbgprintf("Created elf header segment at 0x%lx\n", elfcorehdr);
-	if (delete_memmap(memmap_p, elfcorehdr, memsz) < 0)
+	if (delete_memmap(crash_memory_range, &crash_memory_ranges, elfcorehdr, memsz) < 0)
 		return -1;
-	cmdline_add_memmap(mod_cmdline, memmap_p);
+	cmdline_add_memmap(mod_cmdline, crash_memory_range);
 	if (!bzImage_support_efi_boot)
 		cmdline_add_efi(mod_cmdline);
 	cmdline_add_elfcorehdr(mod_cmdline, elfcorehdr);
@@ -951,6 +962,7 @@ int load_crashdump_segments(struct kexec_info *info, char* mod_cmdline,
 		end = mem_range[i].end;
 		cmdline_add_memmap_acpi(mod_cmdline, start, end);
 	}
+
 	return 0;
 }
 
diff --git a/kexec/arch/i386/crashdump-x86.h b/kexec/arch/i386/crashdump-x86.h
index b61cf0a..633ee0e 100644
--- a/kexec/arch/i386/crashdump-x86.h
+++ b/kexec/arch/i386/crashdump-x86.h
@@ -20,7 +20,7 @@ int load_crashdump_segments(struct kexec_info *info, char *mod_cmdline,
 /* Kernel text size */
 #define X86_64_KERNEL_TEXT_SIZE  (512UL*1024*1024)
 
-#define CRASH_MAX_MEMMAP_NR	(KEXEC_MAX_SEGMENTS + 1)
+#define CRASH_MAX_MEMMAP_NR	CRASH_MAX_MEMORY_RANGES
 #define CRASH_MAX_MEMORY_RANGES	(MAX_MEMORY_RANGES + 2)
 
 /* Backup Region, First 640K of System RAM. */
@@ -28,4 +28,7 @@ int load_crashdump_segments(struct kexec_info *info, char *mod_cmdline,
 #define BACKUP_SRC_END		0x0009ffff
 #define BACKUP_SRC_SIZE	(BACKUP_SRC_END - BACKUP_SRC_START + 1)
 
+extern struct memory_range crash_memory_range[CRASH_MAX_MEMORY_RANGES];
+extern int crash_memory_ranges;
+
 #endif /* CRASHDUMP_X86_H */
-- 
1.8.5.3



From chaowang at redhat.com  Thu Feb 20 04:28:31 2014
From: chaowang at redhat.com (WANG Chao)
Date: Thu, 20 Feb 2014 17:28:31 +0800
Subject: [PATCH v2 3/4] x86: add --pass-memmap-cmdline option
In-Reply-To: <1392888512-4473-1-git-send-email-chaowang@redhat.com>
References: <1392888512-4473-1-git-send-email-chaowang@redhat.com>
Message-ID: <1392888512-4473-4-git-send-email-chaowang@redhat.com>

--pass-memmap-cmdline is used for pass memmap=exactmap cmdline for 2nd
kernel. Later we will use this option to disable passing E820 memmap
method but use the old exactmap method.

Signed-off-by: WANG Chao <chaowang at redhat.com>
---
 kexec/arch/i386/include/arch/options.h | 2 ++
 kexec/arch/i386/kexec-x86.c            | 4 ++++
 kexec/arch/i386/kexec-x86.h            | 1 +
 kexec/arch/i386/x86-linux-setup.h      | 1 +
 kexec/arch/x86_64/kexec-x86_64.c       | 5 +++++
 5 files changed, 13 insertions(+)

diff --git a/kexec/arch/i386/include/arch/options.h b/kexec/arch/i386/include/arch/options.h
index aaac731..e5300b5 100644
--- a/kexec/arch/i386/include/arch/options.h
+++ b/kexec/arch/i386/include/arch/options.h
@@ -30,6 +30,7 @@
 #define OPT_VGA 		(OPT_ARCH_MAX+8)
 #define OPT_REAL_MODE		(OPT_ARCH_MAX+9)
 #define OPT_ENTRY_32BIT		(OPT_ARCH_MAX+10)
+#define OPT_PASS_MEMMAP_CMDLINE	(OPT_ARCH_MAX+11)
 
 /* Options relevant to the architecture (excluding loader-specific ones): */
 #define KEXEC_ARCH_OPTIONS \
@@ -41,6 +42,7 @@
 	{ "console-serial", 0, 0, OPT_CONSOLE_SERIAL }, \
 	{ "elf32-core-headers", 0, 0, OPT_ELF32_CORE }, \
 	{ "elf64-core-headers", 0, 0, OPT_ELF64_CORE }, \
+	{ "pass-memmap-cmdline", 0, 0, OPT_PASS_MEMMAP_CMDLINE }, \
 
 #define KEXEC_ARCH_OPT_STR KEXEC_OPT_STR ""
 
diff --git a/kexec/arch/i386/kexec-x86.c b/kexec/arch/i386/kexec-x86.c
index 014ecd5..0b58dff 100644
--- a/kexec/arch/i386/kexec-x86.c
+++ b/kexec/arch/i386/kexec-x86.c
@@ -54,6 +54,7 @@ void arch_usage(void)
 		"     --console-serial          Enable the serial console\n"
 		"     --elf32-core-headers      Prepare core headers in ELF32 format\n"
 		"     --elf64-core-headers      Prepare core headers in ELF64 format\n"
+		"     --pass--memmap-cmdline    Pass memory map via command line in kexec on panic case\n"
 		);
 }
 
@@ -64,6 +65,7 @@ struct arch_options_t arch_options = {
 	.console_vga = 0,
 	.console_serial = 0,
 	.core_header_type = CORE_TYPE_UNDEF,
+	.pass_memmap_cmdline = 0,
 };
 
 int arch_process_options(int argc, char **argv)
@@ -133,6 +135,8 @@ int arch_process_options(int argc, char **argv)
 		case OPT_ELF64_CORE:
 			arch_options.core_header_type = CORE_TYPE_ELF64;
 			break;
+		case OPT_PASS_MEMMAP_CMDLINE:
+			arch_options.pass_memmap_cmdline = 1;
 		}
 	}
 	/* Reset getopt for the next pass; called in other source modules */
diff --git a/kexec/arch/i386/kexec-x86.h b/kexec/arch/i386/kexec-x86.h
index 5aa2a46..e8c9188 100644
--- a/kexec/arch/i386/kexec-x86.h
+++ b/kexec/arch/i386/kexec-x86.h
@@ -50,6 +50,7 @@ struct arch_options_t {
 	uint8_t  	console_vga;
 	uint8_t  	console_serial;
 	enum coretype	core_header_type;
+	uint8_t  	pass_memmap_cmdline;
 };
 
 int multiboot_x86_probe(const char *buf, off_t len);
diff --git a/kexec/arch/i386/x86-linux-setup.h b/kexec/arch/i386/x86-linux-setup.h
index 6fb84b4..b0ccd26 100644
--- a/kexec/arch/i386/x86-linux-setup.h
+++ b/kexec/arch/i386/x86-linux-setup.h
@@ -30,5 +30,6 @@ void setup_linux_system_parameters(struct kexec_info *info,
 /* command line parameter may be appended by purgatory */
 #define PURGATORY_CMDLINE_SIZE 64
 extern int bzImage_support_efi_boot;
+extern int pass_memmap_cmdline;
 
 #endif /* X86_LINUX_SETUP_H */
diff --git a/kexec/arch/x86_64/kexec-x86_64.c b/kexec/arch/x86_64/kexec-x86_64.c
index 5c23e01..f70851d 100644
--- a/kexec/arch/x86_64/kexec-x86_64.c
+++ b/kexec/arch/x86_64/kexec-x86_64.c
@@ -53,6 +53,7 @@ void arch_usage(void)
 		"     --serial-baud=<baud_rate> Specify the serial port baud rate\n"
 		"     --console-vga             Enable the vga console\n"
 		"     --console-serial          Enable the serial console\n"
+		"     --pass-memmap-cmdline     Pass memory map via command line in kexec on panic case\n"
 		);
 }
 
@@ -63,6 +64,7 @@ struct arch_options_t arch_options = {
 	.console_vga = 0,
 	.console_serial = 0,
 	.core_header_type = CORE_TYPE_ELF64,
+	.pass_memmap_cmdline = 0,
 };
 
 int arch_process_options(int argc, char **argv)
@@ -126,6 +128,9 @@ int arch_process_options(int argc, char **argv)
 			}
 			arch_options.serial_baud = value;
 			break;
+		case OPT_PASS_MEMMAP_CMDLINE:
+			arch_options.pass_memmap_cmdline = 1;
+			break;
 		}
 	}
 	/* Reset getopt for the next pass; called in other source modules */
-- 
1.8.5.3



From chaowang at redhat.com  Thu Feb 20 04:28:32 2014
From: chaowang at redhat.com (WANG Chao)
Date: Thu, 20 Feb 2014 17:28:32 +0800
Subject: [PATCH v2 4/4] x86: Pass memory range via E820 for kdump
In-Reply-To: <1392888512-4473-1-git-send-email-chaowang@redhat.com>
References: <1392888512-4473-1-git-send-email-chaowang@redhat.com>
Message-ID: <1392888512-4473-5-git-send-email-chaowang@redhat.com>

command line size is restricted by kernel, sometimes memmap=exactmap has
too many memory ranges to pass to cmdline. A better approach, to pass the
memory ranges for crash kernel to boot into, is filling the memory
ranges into E820.

boot_params only got 128 slots for E820 map to fit in, when the number of
memory map exceeds 128, use setup_data to pass the rest as extended E820
memory map.

kexec boot could also benefit from setup_data in case E820 memory map
exceeds 128.

Now this new approach becomes default instead of memmap=exactmap.
saved_max_pfn users can specify --pass-memmap-cmdline to use the
exactmap approach.

Signed-off-by: WANG Chao <chaowang at redhat.com>
---
 kexec/arch/i386/crashdump-x86.c   |  25 +++--
 kexec/arch/i386/crashdump-x86.h   |   1 +
 kexec/arch/i386/x86-linux-setup.c | 195 +++++++++++++++++++++++++++-----------
 3 files changed, 158 insertions(+), 63 deletions(-)

diff --git a/kexec/arch/i386/crashdump-x86.c b/kexec/arch/i386/crashdump-x86.c
index c55a6b1..cb19e7d 100644
--- a/kexec/arch/i386/crashdump-x86.c
+++ b/kexec/arch/i386/crashdump-x86.c
@@ -182,6 +182,8 @@ static int exclude_region(int *nr_ranges, uint64_t start, uint64_t end);
 struct memory_range crash_memory_range[CRASH_MAX_MEMORY_RANGES];
 int crash_memory_ranges;
 
+int pass_memmap_cmdline;
+
 /* Memory region reserved for storing panic kernel and other data. */
 #define CRASH_RESERVED_MEM_NR	8
 static struct memory_range crash_reserved_mem[CRASH_RESERVED_MEM_NR];
@@ -947,20 +949,23 @@ int load_crashdump_segments(struct kexec_info *info, char* mod_cmdline,
 	dbgprintf("Created elf header segment at 0x%lx\n", elfcorehdr);
 	if (delete_memmap(crash_memory_range, &crash_memory_ranges, elfcorehdr, memsz) < 0)
 		return -1;
-	cmdline_add_memmap(mod_cmdline, crash_memory_range);
 	if (!bzImage_support_efi_boot)
 		cmdline_add_efi(mod_cmdline);
 	cmdline_add_elfcorehdr(mod_cmdline, elfcorehdr);
 
-	/* Inform second kernel about the presence of ACPI tables. */
-	for (i = 0; i < CRASH_MAX_MEMORY_RANGES; i++) {
-		unsigned long start, end;
-		if ( !( mem_range[i].type == RANGE_ACPI
-			|| mem_range[i].type == RANGE_ACPI_NVS) )
-			continue;
-		start = mem_range[i].start;
-		end = mem_range[i].end;
-		cmdline_add_memmap_acpi(mod_cmdline, start, end);
+	pass_memmap_cmdline = arch_options.pass_memmap_cmdline;
+	if (pass_memmap_cmdline) {
+		cmdline_add_memmap(mod_cmdline, crash_memory_range);
+		/* Inform second kernel about the presence of ACPI tables. */
+		for (i = 0; i < CRASH_MAX_MEMORY_RANGES; i++) {
+			unsigned long start, end;
+			if ( !( mem_range[i].type == RANGE_ACPI
+						|| mem_range[i].type == RANGE_ACPI_NVS) )
+				continue;
+			start = mem_range[i].start;
+			end = mem_range[i].end;
+			cmdline_add_memmap_acpi(mod_cmdline, start, end);
+		}
 	}
 
 	return 0;
diff --git a/kexec/arch/i386/crashdump-x86.h b/kexec/arch/i386/crashdump-x86.h
index 633ee0e..e68b626 100644
--- a/kexec/arch/i386/crashdump-x86.h
+++ b/kexec/arch/i386/crashdump-x86.h
@@ -30,5 +30,6 @@ int load_crashdump_segments(struct kexec_info *info, char *mod_cmdline,
 
 extern struct memory_range crash_memory_range[CRASH_MAX_MEMORY_RANGES];
 extern int crash_memory_ranges;
+extern int pass_memmap_cmdline;
 
 #endif /* CRASHDUMP_X86_H */
diff --git a/kexec/arch/i386/x86-linux-setup.c b/kexec/arch/i386/x86-linux-setup.c
index 5884f4d..209652c 100644
--- a/kexec/arch/i386/x86-linux-setup.c
+++ b/kexec/arch/i386/x86-linux-setup.c
@@ -35,8 +35,7 @@
 #include "kexec-x86.h"
 #include "x86-linux-setup.h"
 #include "../../kexec/kexec-syscall.h"
-
-#define SETUP_EFI	4
+#include "crashdump-x86.h"
 
 void init_linux_parameters(struct x86_linux_param_header *real_mode)
 {
@@ -502,6 +501,11 @@ struct efi_setup_data {
 struct setup_data {
 	uint64_t next;
 	uint32_t type;
+#define SETUP_NONE	0
+#define SETUP_E820_EXT	1
+#define SETUP_DTB	2
+#define SETUP_PCI	3
+#define SETUP_EFI	4
 	uint32_t len;
 	uint8_t data[0];
 } __attribute__((packed));
@@ -602,6 +606,17 @@ struct efi_info {
 	uint32_t efi_memmap_hi;
 };
 
+static void add_setup_data(struct kexec_info *info,
+			   struct x86_linux_param_header *real_mode,
+			   struct setup_data *sd)
+{
+	int sdsize = sizeof(struct setup_data) + sd->len;
+
+	sd->next = real_mode->setup_data;
+	real_mode->setup_data = add_buffer(info, sd, sdsize, sdsize, getpagesize(),
+			    0x100000, ULONG_MAX, INT_MAX);
+}
+
 /*
  * setup_efi_data will collect below data and pass them to 2nd kernel.
  * 1) SMBIOS, fw_vendor, runtime, config_table, they are passed via x86
@@ -611,11 +626,11 @@ struct efi_info {
 static int setup_efi_data(struct kexec_info *info,
 			  struct x86_linux_param_header *real_mode)
 {
-	int64_t setup_data_paddr, memmap_paddr;
+	int64_t memmap_paddr;
 	struct setup_data *sd;
 	struct efi_setup_data *esd;
 	struct efi_mem_descriptor *maps;
-	int nr_maps, size, sdsize, ret = 0;
+	int nr_maps, size, ret = 0;
 	struct efi_info *ei = (struct efi_info *)real_mode->efi_info;
 
 	ret = access("/sys/firmware/efi/systab", F_OK);
@@ -648,10 +663,8 @@ static int setup_efi_data(struct kexec_info *info,
 	sd->len = sizeof(*esd);
 	memcpy(sd->data, esd, sizeof(*esd));
 	free(esd);
-	sdsize = sd->len + sizeof(struct setup_data);
-	setup_data_paddr = add_buffer(info, sd, sdsize, sdsize, getpagesize(),
-					0x100000, ULONG_MAX, INT_MAX);
-	real_mode->setup_data = setup_data_paddr;
+
+	add_setup_data(info, real_mode, sd);
 
 	size = nr_maps * sizeof(struct efi_mem_descriptor);
 	memmap_paddr = add_buffer(info, maps, size, size, getpagesize(),
@@ -669,6 +682,119 @@ out:
 	return ret;
 }
 
+static void setup_e820_ext(struct kexec_info *info, struct x86_linux_param_header *real_mode,
+			   struct memory_range *range, int nr_range)
+{
+	struct setup_data *sd;
+	struct e820entry *e820;
+	int i, j, nr_range_ext;
+
+	nr_range_ext = nr_range - E820MAX;
+	sd = malloc(sizeof(struct setup_data) + nr_range_ext * sizeof(struct e820entry));
+	sd->next = 0;
+	sd->len = nr_range_ext * sizeof(struct e820entry);
+	sd->type = SETUP_E820_EXT;
+
+	e820 = (struct e820entry *) sd->data;
+	dbgprintf("Extended E820 via setup_data:\n");
+	for(i = 0, j = E820MAX; i < nr_range_ext; i++, j++) {
+		e820[i].addr = range[j].start;
+		e820[i].size = range[j].end - range[j].start;
+		switch (range[j].type) {
+		case RANGE_RAM:
+			e820[i].type = E820_RAM;
+			break;
+		case RANGE_ACPI:
+			e820[i].type = E820_ACPI;
+			break;
+		case RANGE_ACPI_NVS:
+			e820[i].type = E820_NVS;
+			break;
+		default:
+		case RANGE_RESERVED:
+			e820[i].type = E820_RESERVED;
+			break;
+		}
+		dbgprintf("%016lx-%016lx (%d)\n",
+				e820[i].addr,
+				e820[i].addr + e820[i].size - 1,
+				e820[i].type);
+
+		if (range[j].type != RANGE_RAM)
+			continue;
+		if ((range[j].start <= 0x100000) && range[j].end > 0x100000) {
+			unsigned long long mem_k = (range[j].end >> 10) - (0x100000 >> 10);
+			real_mode->ext_mem_k = mem_k;
+			real_mode->alt_mem_k = mem_k;
+			if (mem_k > 0xfc00) {
+				real_mode->ext_mem_k = 0xfc00; /* 64M */
+			}
+			if (mem_k > 0xffffffff) {
+				real_mode->alt_mem_k = 0xffffffff;
+			}
+		}
+	}
+	add_setup_data(info, real_mode, sd);
+	free(sd);
+}
+
+static void setup_e820(struct kexec_info *info, struct x86_linux_param_header *real_mode,
+		       struct memory_range *range, int nr_range)
+{
+
+	int nr_range_saved = nr_range;
+	int i;
+
+	if (nr_range > E820MAX) {
+		nr_range = E820MAX;
+	}
+
+	real_mode->e820_map_nr = nr_range;
+	dbgprintf("E820 memmap:\n");
+	for(i = 0; i < nr_range; i++) {
+		real_mode->e820_map[i].addr = range[i].start;
+		real_mode->e820_map[i].size = range[i].end - range[i].start;
+		switch (range[i].type) {
+			case RANGE_RAM:
+				real_mode->e820_map[i].type = E820_RAM;
+				break;
+			case RANGE_ACPI:
+				real_mode->e820_map[i].type = E820_ACPI;
+				break;
+			case RANGE_ACPI_NVS:
+				real_mode->e820_map[i].type = E820_NVS;
+				break;
+			default:
+			case RANGE_RESERVED:
+				real_mode->e820_map[i].type = E820_RESERVED;
+				break;
+		}
+		dbgprintf("%016lx-%016lx (%d)\n",
+				real_mode->e820_map[i].addr,
+				real_mode->e820_map[i].addr + real_mode->e820_map[i].size - 1,
+				real_mode->e820_map[i].type);
+
+		if (range[i].type != RANGE_RAM)
+			continue;
+		if ((range[i].start <= 0x100000) && range[i].end > 0x100000) {
+			unsigned long long mem_k = (range[i].end >> 10) - (0x100000 >> 10);
+			real_mode->ext_mem_k = mem_k;
+			real_mode->alt_mem_k = mem_k;
+			if (mem_k > 0xfc00) {
+				real_mode->ext_mem_k = 0xfc00; /* 64M */
+			}
+			if (mem_k > 0xffffffff) {
+				real_mode->alt_mem_k = 0xffffffff;
+			}
+		}
+	}
+
+	if (nr_range_saved > E820MAX) {
+		dbgprintf("extra E820 memmap are passed via setup_data\n");
+		setup_e820_ext(info, real_mode, range, nr_range_saved);
+	}
+}
+
 static int
 get_efi_mem_desc_version(struct x86_linux_param_header *real_mode)
 {
@@ -704,7 +830,7 @@ void setup_linux_system_parameters(struct kexec_info *info,
 {
 	/* Fill in information the BIOS would usually provide */
 	struct memory_range *range;
-	int i, ranges;
+	int ranges;
 
 	/* get subarch from running kernel */
 	setup_subarch(real_mode);
@@ -746,51 +872,14 @@ void setup_linux_system_parameters(struct kexec_info *info,
 	/* another safe default */
 	real_mode->aux_device_info = 0;
 
-	range = info->memory_range;
-	ranges = info->memory_ranges;
-	if (ranges > E820MAX) {
-		if (!(info->kexec_flags & KEXEC_ON_CRASH))
-			/*
-			 * this e820 not used for capture kernel, see
-			 * do_bzImage_load()
-			 */
-			fprintf(stderr,
-				"Too many memory ranges, truncating...\n");
-		ranges = E820MAX;
-	}
-	real_mode->e820_map_nr = ranges;
-	for(i = 0; i < ranges; i++) {
-		real_mode->e820_map[i].addr = range[i].start;
-		real_mode->e820_map[i].size = range[i].end - range[i].start;
-		switch (range[i].type) {
-		case RANGE_RAM:
-			real_mode->e820_map[i].type = E820_RAM; 
-			break;
-		case RANGE_ACPI:
-			real_mode->e820_map[i].type = E820_ACPI; 
-			break;
-		case RANGE_ACPI_NVS:
-			real_mode->e820_map[i].type = E820_NVS;
-			break;
-		default:
-		case RANGE_RESERVED:
-			real_mode->e820_map[i].type = E820_RESERVED; 
-			break;
-		}
-		if (range[i].type != RANGE_RAM)
-			continue;
-		if ((range[i].start <= 0x100000) && range[i].end > 0x100000) {
-			unsigned long long mem_k = (range[i].end >> 10) - (0x100000 >> 10);
-			real_mode->ext_mem_k = mem_k;
-			real_mode->alt_mem_k = mem_k;
-			if (mem_k > 0xfc00) {
-				real_mode->ext_mem_k = 0xfc00; /* 64M */
-			}
-			if (mem_k > 0xffffffff) {
-				real_mode->alt_mem_k = 0xffffffff;
-			}
-		}
+	if (info->kexec_flags & KEXEC_ON_CRASH && !pass_memmap_cmdline) {
+		range = crash_memory_range;
+		ranges = crash_memory_ranges;
+	} else {
+		range = info->memory_range;
+		ranges = info->memory_ranges;
 	}
+	setup_e820(info, real_mode, range, ranges);
 
 	/* fill the EDD information */
 	setup_edd_info(real_mode);
-- 
1.8.5.3



From chaowang at redhat.com  Thu Feb 20 04:28:28 2014
From: chaowang at redhat.com (WANG Chao)
Date: Thu, 20 Feb 2014 17:28:28 +0800
Subject: [PATCH v2 0/4] kexec-tools, x86: E820 memmap pass for kdump
Message-ID: <1392888512-4473-1-git-send-email-chaowang@redhat.com>

Hi, All

When kaslr comes in and kdump is broken, it seems about the right time to use
E820 instead of memmap=exactmap to pass memmap for kdump for the default memmap
passing mechanism:
http://lists.infradead.org/pipermail/kexec/2014-February/011048.html

Unfortunately, saved_max_pfn still got its user out there (calgry pci, it looks
like the only one). So for backward compatibility, I'm introducing a new option
--pass-memmap-cmdline to force kexec-tools to pass memmap=exactmap, the old way.

Any comment is appreciate!

v1->v2:

Vivek:
 - Use function instead of macro for dbgprint_mem_range
 - Do not pass reserved memory range for kdump. It could addressed later
   separately.

WANG Chao (4):
  cleanup: add dbgprint_mem_range function
  x86: Store memory ranges globally used for crash kernel to boot into
  x86: add --pass-memmap-cmdline option
  x86: Pass memory range via E820 for kdump

 kexec/arch/i386/crashdump-x86.c        | 157 ++++++++++++++------------
 kexec/arch/i386/crashdump-x86.h        |   6 +-
 kexec/arch/i386/include/arch/options.h |   2 +
 kexec/arch/i386/kexec-x86-common.c     |   6 +-
 kexec/arch/i386/kexec-x86.c            |   4 +
 kexec/arch/i386/kexec-x86.h            |   1 +
 kexec/arch/i386/x86-linux-setup.c      | 195 ++++++++++++++++++++++++---------
 kexec/arch/i386/x86-linux-setup.h      |   1 +
 kexec/arch/x86_64/kexec-x86_64.c       |   5 +
 kexec/kexec.c                          |  10 ++
 kexec/kexec.h                          |   1 +
 11 files changed, 259 insertions(+), 129 deletions(-)

-- 
1.8.5.3



From anderson at redhat.com  Thu Feb 20 15:45:50 2014
From: anderson at redhat.com (Dave Anderson)
Date: Thu, 20 Feb 2014 15:45:50 -0500 (EST)
Subject: [Crash-utility] crash: struct command can read irrelevant pages.
In-Reply-To: <1347294540.11438228.1392821415316.JavaMail.zimbra@redhat.com>
References: <0910DD04CBD6DE4193FCF86B9C00BE971EAF68@BPXM01GP.gisp.nec.co.jp>
 <1347294540.11438228.1392821415316.JavaMail.zimbra@redhat.com>
Message-ID: <1598236100.13279715.1392929150735.JavaMail.zimbra@redhat.com>


Hello Atsushi,
 
I've committed a SLAB/SLUB kmem_cache-specific fix for this issue:

  https://github.com/crash-utility/crash/commit/c0b7a74fc13121203810d06d163550436b2d5476

which is queued for crash-7.0.6.

Thanks,
  Dave


----- Original Message -----
> 
> 
> ----- Original Message -----
> > Hello,
> > 
> > Finally, I've found the cause of the issue I mentioned as below
> > when makedumpfile v1.5.5 was released:
> > 
> > > 2. At first, the supported kernel will be updated to 3.12, but I
> > > found an issue while testing for v1.5.5, which seems that the page
> > > filtering works wrongly on kernel 3.12. I couldn't investigate this
> > > yet and it will take some time to finish it.
> > > Therefore, the latest supported kernel version is 3.11 in v1.5.5.
> > 
> > This is neither a kernel issue nor a makedumpfile issue, it's a crash's bug.
> > It can happen when a slab cache is stored at almost end of a page.
> > 
> > == Description ==
> > 
> > At the beginning, I found the error message below when I used crash for
> > a dumpfile generated by makedumpfile -d2:
> > 
> >     please wait... (gathering kmem slab cache data)
> >     crash: page excluded: kernel virtual address: f4e87000  type:
> >     "kmem_cache
> >     buffer"
> > 
> >     crash: unable to initialize kmem slab cache subsystem
> > 
> > This message indicated that crash failed to get a slab cache during
> > kmem_cache_init(), and according to the below, crash failed to get
> > the slab cache stored at f4e86f40:
> > 
> >     crash> p kmem_cache
> >     kmem_cache = $1 = (struct kmem_cache *) 0xc0b1cbc0 <kmem_cache_boot>
> >     crash>
> >     crash> list kmem_cache.list -s kmem_cache.name -h 0xc0b1cbc0
> >     ...
> >     f4d37840
> >       name = 0xf4edf540 "uid_cache"
> >     f4e86f40
> >     list: page excluded: kernel virtual address: f4e87000  type:
> >     "gdb_readmem_callback"
> > 
> > It seems that the slab cache covered two pages, [f4e86000- f4e87000] and
> > [f4e87000- f4e88000]. Well, let's confirm the *real* size of it.
> > 
> > Since slab caches except kmem_cache_boot are allocated as slab objects,
> > we can confirm the size like below:
> > 
> >   crash> p kmem_cache
> >   kmem_cache = $2 = (struct kmem_cache *) 0xc0b1cbc0 <kmem_cache_boot>
> >   crash> struct kmem_cache.object_size 0xc0b1cbc0
> >     object_size = 104
> >   crash>
> > 
> > In my environment, the size was 104 bytes. Therefore, the slab cache
> > stored at f4e86f40 fits in the single page([f4e86000- f4e87000]) and
> > the excluded page([f4e87000- f4e88000]) isn't a related page.
> > 
> > On the other hand, crash get the size from vmlinux by using gdb,
> > it was 216 bytes:
> > 
> >     crash> struct kmem_cache
> >     struct kmem_cache {
> >         unsigned int batchcount;
> >         unsigned int limit;
> >         ...
> >         struct kmem_cache_node **node;
> >         struct array_cache *array[33];
> >     }
> >     SIZE: 216
> >     crash>
> > 
> > So crash mistook the correlative pages of the slab cache as
> > [f4e86000- f4e87000] and [f4e87000- f4e88000] even though the latter
> > was a irrelevant page.
> > 
> > This gap came from the fact that the size of slab cache is variable.
> > 
> >     struct kmem_cache {
> >     ...
> >             struct kmem_cache_node **node;
> >             struct array_cache *array[NR_CPUS + MAX_NUMNODES];
> >             /*
> >              * Do not add fields after array[]
> >              */
> >     };
> > 
> > The size of "array" is the variable factor of kmem_cache.
> > When building vmlinux, the size of kmem_cache will be calculated with
> > NR_CPUS and MAX_NUMNODES, and put it into vmlinux as a debug information.
> > (Sorry, I don't know gcc well. I may misunderstand this.)
> > However, the actual size will be smaller than the defined size because
> > the actual size will be decided based on the actual number of CPUs and
> > NODEs.
> > 
> > void __init kmem_cache_init(void)::
> > ...
> >         /*
> >          * struct kmem_cache size depends on nr_node_ids & nr_cpu_ids
> >          */
> >         create_boot_cache(kmem_cache, "kmem_cache",
> >                 offsetof(struct kmem_cache, array[nr_cpu_ids]) +
> >                                   nr_node_ids * sizeof(struct
> >                                   kmem_cache_node
> >                                   *),  // object_size
> >                                   SLAB_HWCACHE_ALIGN);
> >         list_add(&kmem_cache->list, &slab_caches);
> > 
> > 
> > As for kmem_cache, we can get the actual size of it from kmem_cache_boot,
> > but I suppose that kmem_cache is not the only struct in kernel whose size
> > is variable. So I think we should discuss how to address such issues like
> > this.
> > 
> > By the way, I mentioned the case of *SLAB* in this mail,
> > but SLUB seems have the same issue.
> > 
> > 
> > Thanks
> > Atsushi Kumagai
> 
> 
> This is a "known" issue has been discussed on the crash-utility list in the
> past,
> at least with respect to the kmem_cache data structure.  But for any random
> data
> structure that has such a construct, I'm not sure what can be done.
> 
> In the case of the CONFIG_SLAB kmem_cache data structure, there is a function
> that is supposed to "downsize" the size value of the kmem_cache data
> structure
> that is returned by gdb.  It is called here in kmem_cache_init(), just
> prior to cycling through all of the kmem_cache structures, where the
> page excluded error shown above occurred:
> 
>    8561         if (!(pc->flags & RUNTIME))
>    8562                 kmem_cache_downsize();
>    8563
>    8564         cache_buf = GETBUF(SIZE(kmem_cache_s));
>    8565         hq_open();
>    8566
>    8567         do {
>    8568                 cache_count++;
>    8569
>    8570                 if (!readmem(cache, KVADDR, cache_buf,
>    SIZE(kmem_cache_s),
>    8571                         "kmem_cache buffer", RETURN_ON_ERROR)) {
>    8572                         FREEBUF(cache_buf);
>    8573                         vt->flags |= KMEM_CACHE_UNAVAIL;
>    8574                         error(INFO,
>    8575                           "%sunable to initialize kmem slab cache
>    subsystem\n\n",
>    8576                                 DUMPFILE() ? "\n" : "");
>    8577                         hq_close();
>    8578                         return;
>    8579                 }
> 
> The SIZE(kmem_cache_s) value should have been downsized by that function,
> but presumably it did not work.  If CRASHDEBUG(1) was turned on during
> initialization,
> you would have seen either of these two messages from kmem_cache_downsize():
>  
>                 if (CRASHDEBUG(1))
>                         fprintf(fp, "kmem_cache_downsize: %ld to %ld\n",
>                                 STRUCT_SIZE("kmem_cache"),
>                                 SIZE(kmem_cache_s));
> 
> or:
> 
>                 if (CRASHDEBUG(1)) {
>                         fprintf(fp,
>                             "\nkmem_cache_downsize: SIZE(kmem_cache_s): %ld "
>                             "cache_cache.buffer_size: %d\n",
>                                 STRUCT_SIZE("kmem_cache"), buffer_size);
>                         fprintf(fp,
>                             "kmem_cache_downsize: nr_node_ids: %ld\n",
>                                 vt->kmem_cache_len_nodes);
>                 }
> 
> The function failed probably failed due to some kernel change.  In fact,
> I just checked a 3.13 CONFIG_SLAB kernel, and I see that
> kmem_cache_downsize()
> no longer works for that kernel.
> 
> I see that kmem_cache_boot would be a good alternative for determining
> the size on CONFIG_SLAB kernels, at least on 3.7 and later kernels where
> it was introduced.  And for CONFIG_SLUB, which doesn't currently have a
> "downsize" function, it looks like its "kmem_cache" cache also has size
> fields that could be used.
> 
> By any chance can you make the 32-bit vmlinux/vmcore pair available for
> me to download?  Reply to me off-list if you can.
> 
> Thanks,
>   Dave
> 
> 
> 
>  
> 
> 
> 
> 
> 
> 
> 


From v.tolstov at selfip.ru  Fri Feb 21 00:23:45 2014
From: v.tolstov at selfip.ru (Vasiliy Tolstov)
Date: Fri, 21 Feb 2014 09:23:45 +0400
Subject: kexec with unpacked initrd to memory
Message-ID: <CACaajQtDmtz4MoAk8FWwue2reUgb2nRGdNgh6+fFOwXV2=n5jg@mail.gmail.com>

Hello all. I'm try to use kexec in unusual space - i want to kexec new
kernel with new initrd already unpacked at some place in memory.
For example  i have pxe booted server, that need about 5 minutes to
boot and configured via chef.
I want to minimize this time creating ramdisk , setup new system on it
in chroot and after all ok kexec new kernel.
Does this possible ? Or i must cpio | gzip this dir to initrd file and
kexec with it?
I want to avoid unneeded steps with cpio because kernel must do
uncompress after kexec ...
Sorry for bad english.

-- 
Vasiliy Tolstov,
e-mail: v.tolstov at selfip.ru
jabber: vase at selfip.ru


From chaowang at redhat.com  Fri Feb 21 02:47:14 2014
From: chaowang at redhat.com (WANG Chao)
Date: Fri, 21 Feb 2014 15:47:14 +0800
Subject: How could we get rid of saved_max_pfn for calgary iommu?
In-Reply-To: <20140220023622.GD2970@redhat.com>
References: <20140219061824.GA29703@dhcp-17-89.nay.redhat.com>
 <CAPoiz9yuLg4exX58bh5=XumgAmYNq-9kPjc+f1wa8kMU3-dBbg@mail.gmail.com>
 <20140220023622.GD2970@redhat.com>
Message-ID: <20140221074714.GB1262@dhcp-17-89.nay.redhat.com>

Remove muli at il.ibm.com from CC, this email isn't valid now.

On 02/19/14 at 09:36pm, Vivek Goyal wrote:
> On Wed, Feb 19, 2014 at 05:04:22PM -0700, Jon Mason wrote:
> > On Tue, Feb 18, 2014 at 11:18 PM, WANG Chao <chaowang at redhat.com> wrote:
> > > Hi, All
> > >
> > > arch/x86/kernel/pci-calgary.c is the only user of saved_max_pfn today:
> > >
> > > int __init detect_calgary(void)
> > > {
> > >         [..]
> > >         specified_table_size = determine_tce_table_size((is_kdump_kernel() ?
> > >                                         saved_max_pfn : max_pfn) * PAGE_SIZE);
> > >         [..]
> > > }
> > 
> > IIUC, the purpose of this code is to reuse the TCE table from the
> > previous kernel.  Thus, it needs to be of the same size as the
> > pre-kdump kernel.  It is using the max_pfn to determine the TCE table
> > size in the non-kdump case.  If there is another way to determine the
> > size it used before, then I am fine making the change to use that way.
> 
> How about passing old tce table size on command line to second kernel.
> Given the fact that it is specific to calgary only, we can it very
> specific. Say calgary_iommu_old_tce_table_sz=<size>.

Don't need to introduce a new parameter, this is already there:
calgary=[64k,128k,256k,512k,1M,2M,4M,8M]

> 
> But we will then need to know the size of TCE table in first kernel. Is
> this information exported to user space somewhere?

If this value isn't exported to userspace or even won't in the future, I think
the table size also can be determined by userspace. We can implement something like the
kernel does in kexec.

The calgary code:

static inline int __init determine_tce_table_size(u64 ram)
{
	int ret;

	if (specified_table_size != TCE_TABLE_SIZE_UNSPECIFIED)
		return specified_table_size;

	/*
	 * Table sizes are from 0 to 7 (TCE_TABLE_SIZE_64K to
	 * TCE_TABLE_SIZE_8M). Table size 0 has 8K entries and each
	 * larger table size has twice as many entries, so shift the
	 * max ram address by 13 to divide by 8K and then look at the
	 * order of the result to choose between 0-7.
	 */
	ret = get_order(ram >> 13);
	if (ret > TCE_TABLE_SIZE_8M)
		ret = TCE_TABLE_SIZE_8M;

	return ret;
}

But it still no clear to me how I can determine calgary iommu is in use in 1st kernel.

Thanks
WANG Chao


From bhe at redhat.com  Fri Feb 21 03:18:06 2014
From: bhe at redhat.com (Baoquan He)
Date: Fri, 21 Feb 2014 16:18:06 +0800
Subject: How could we get rid of saved_max_pfn for calgary iommu?
In-Reply-To: <CAPoiz9yuLg4exX58bh5=XumgAmYNq-9kPjc+f1wa8kMU3-dBbg@mail.gmail.com>
References: <20140219061824.GA29703@dhcp-17-89.nay.redhat.com>
 <CAPoiz9yuLg4exX58bh5=XumgAmYNq-9kPjc+f1wa8kMU3-dBbg@mail.gmail.com>
Message-ID: <20140221081806.GB1635@dhcp-16-105.nay.redhat.com>

On 02/19/14 at 05:04pm, Jon Mason wrote:
> On Tue, Feb 18, 2014 at 11:18 PM, WANG Chao <chaowang at redhat.com> wrote:
> > Hi, All
> >
> > arch/x86/kernel/pci-calgary.c is the only user of saved_max_pfn today:
> >
> > int __init detect_calgary(void)
> > {
> >         [..]
> >         specified_table_size = determine_tce_table_size((is_kdump_kernel() ?
> >                                         saved_max_pfn : max_pfn) * PAGE_SIZE);
> >         [..]
> > }
> 
> IIUC, the purpose of this code is to reuse the TCE table from the
> previous kernel.  Thus, it needs to be of the same size as the
> pre-kdump kernel.  It is using the max_pfn to determine the TCE table
> size in the non-kdump case.  If there is another way to determine the
> size it used before, then I am fine making the change to use that way.

>From code the size is from 64K to 8M, saved_max_pfn is needed to get
this. Could it be a fixed size for TCE table? If this can be a fixed
value, E.g 8M,  saved_max_pfn will be not needed any more though a
little memory may be wasted if total ram is smaller than 4G.

Baoquan
Thanks
> 


From bp at alien8.de  Fri Feb 21 09:59:10 2014
From: bp at alien8.de (Borislav Petkov)
Date: Fri, 21 Feb 2014 15:59:10 +0100
Subject: [PATCH 06/11] kexec: A new system call, kexec_file_load, for in
 kernel kexec
In-Reply-To: <1390849071-21989-7-git-send-email-vgoyal@redhat.com>
References: <1390849071-21989-1-git-send-email-vgoyal@redhat.com>
 <1390849071-21989-7-git-send-email-vgoyal@redhat.com>
Message-ID: <20140221145910.GE11531@pd.tnic>

On Mon, Jan 27, 2014 at 01:57:46PM -0500, Vivek Goyal wrote:
> This patch implements the in kernel kexec functionality. It implements a
> new system call kexec_file_load. I think parameter list of this system
> call will change as I have not done the kernel image signature handling
> yet. I have been told that I might have to pass the detached signature
> and size as part of system call.
> 
> Previously segment list was prepared in user space. Now user space just
> passes kernel fd, initrd fd and command line and kernel will create a
> segment list internally.
> 
> This patch contains generic part of the code. Actual segment preparation
> and loading is done by arch and image specific loader. Which comes in
> next patch.
> 
> Signed-off-by: Vivek Goyal <vgoyal at redhat.com>

You might want to run it through checkpatch - some of them are actually,
to my surprise, legitimate :)

Just some minor nitpicks below...

> ---
>  arch/x86/kernel/machine_kexec_64.c |  50 ++++
>  arch/x86/syscalls/syscall_64.tbl   |   1 +
>  include/linux/kexec.h              |  55 +++++
>  include/linux/syscalls.h           |   3 +
>  include/uapi/linux/kexec.h         |   4 +
>  kernel/kexec.c                     | 495 ++++++++++++++++++++++++++++++++++++-
>  kernel/sys_ni.c                    |   1 +
>  7 files changed, 605 insertions(+), 4 deletions(-)

...

> diff --git a/include/linux/kexec.h b/include/linux/kexec.h
> index d8188b3..51b56cd 100644
> --- a/include/linux/kexec.h
> +++ b/include/linux/kexec.h
> @@ -121,13 +121,58 @@ struct kimage {
>  #define KEXEC_TYPE_DEFAULT 0
>  #define KEXEC_TYPE_CRASH   1
>  	unsigned int preserve_context : 1;
> +	/* If set, we are using file mode kexec syscall */
> +	unsigned int file_mode : 1;
>  
>  #ifdef ARCH_HAS_KIMAGE_ARCH
>  	struct kimage_arch arch;
>  #endif
> +
> +	/* Additional Fields for file based kexec syscall */
> +	void *kernel_buf;
> +	unsigned long kernel_buf_len;
> +
> +	void *initrd_buf;
> +	unsigned long initrd_buf_len;
> +
> +	char *cmdline_buf;
> +	unsigned long cmdline_buf_len;
> +
> +	/* index of file handler in array */
> +	int file_handler_idx;
> +
> +	/* Image loader handling the kernel can store a pointer here */
> +	void * image_loader_data;
>  };
>  
> +/*
> + * Keeps a track of buffer parameters as provided by caller for requesting
> + * memory placement of buffer.
> + */
> +struct kexec_buf {
> +	struct kimage *image;
> +	char *buffer;
> +	unsigned long bufsz;
> +	unsigned long memsz;
> +	unsigned long buf_align;
> +	unsigned long buf_min;
> +	unsigned long buf_max;
> +	int top_down;		/* allocate from top of memory hole */

Looks like this wants to be a bool.

...

> diff --git a/include/uapi/linux/kexec.h b/include/uapi/linux/kexec.h
> index d6629d4..5fddb1b 100644
> --- a/include/uapi/linux/kexec.h
> +++ b/include/uapi/linux/kexec.h
> @@ -13,6 +13,10 @@
>  #define KEXEC_PRESERVE_CONTEXT	0x00000002
>  #define KEXEC_ARCH_MASK		0xffff0000
>  
> +/* Kexec file load interface flags */
> +#define KEXEC_FILE_UNLOAD	0x00000001
> +#define KEXEC_FILE_ON_CRASH	0x00000002

BIT()

> +
>  /* These values match the ELF architecture values.
>   * Unless there is a good reason that should continue to be the case.
>   */
> diff --git a/kernel/kexec.c b/kernel/kexec.c
> index c0944b2..b28578a 100644
> --- a/kernel/kexec.c
> +++ b/kernel/kexec.c
> @@ -123,6 +123,11 @@ static struct page *kimage_alloc_page(struct kimage *image,
>  				       gfp_t gfp_mask,
>  				       unsigned long dest);
>  
> +void kimage_set_start_addr(struct kimage *image, unsigned long start)
> +{
> +	image->start = start;
> +}

Why a separate function? It is used only once in the next patch.

...

> +static int kimage_file_prepare_segments(struct kimage *image, int kernel_fd,
> +		int initrd_fd, const char __user *cmdline_ptr,
> +		unsigned long cmdline_len)
> +{
> +	int ret = 0;
> +	void *ldata;
> +
> +	ret = copy_file_from_fd(kernel_fd, &image->kernel_buf,
> +					&image->kernel_buf_len);
> +	if (ret)
> +		goto out;
> +
> +	/* Call arch image probe handlers */
> +	ret = arch_kexec_kernel_image_probe(image, image->kernel_buf,
> +						image->kernel_buf_len);
> +
> +	if (ret)
> +		goto out;
> +
> +	ret = copy_file_from_fd(initrd_fd, &image->initrd_buf,
> +					&image->initrd_buf_len);
> +	if (ret)
> +		goto out;
> +
> +	image->cmdline_buf = vzalloc(cmdline_len);
> +	if (!image->cmdline_buf)
> +		goto out;
> +
> +	ret = copy_from_user(image->cmdline_buf, cmdline_ptr, cmdline_len);
> +	if (ret) {
> +		ret = -EFAULT;
> +		goto out;
> +	}
> +
> +	image->cmdline_buf_len = cmdline_len;
> +
> +	/* command line should be a string with last byte null */
> +	if (image->cmdline_buf[cmdline_len - 1] != '\0') {
> +		ret = -EINVAL;
> +		goto out;
> +	}
> +
> +	/* Call arch image load handlers */
> +	ldata = arch_kexec_kernel_image_load(image,
> +			image->kernel_buf, image->kernel_buf_len,
> +			image->initrd_buf, image->initrd_buf_len,
> +			image->cmdline_buf, image->cmdline_buf_len);
> +
> +	if (IS_ERR(ldata)) {
> +		ret = PTR_ERR(ldata);
> +		goto out;
> +	}
> +
> +	image->image_loader_data = ldata;
> +out:
> +	return ret;

You probably want to drop this "out:" label and simply return the error
value directly in each error path above for simplicity.

> +static int kimage_file_normal_alloc(struct kimage **rimage, int kernel_fd,
> +		int initrd_fd, const char __user *cmdline_ptr,
> +		unsigned long cmdline_len)
> +{
> +	int result;
> +	struct kimage *image;
> +
> +	/* Allocate and initialize a controlling structure */
> +	image = do_kimage_alloc_init();
> +	if (!image)
> +		return -ENOMEM;
> +
> +	image->file_mode = 1;
> +	image->file_handler_idx = -1;
> +
> +	result = kimage_file_prepare_segments(image, kernel_fd, initrd_fd,
> +			cmdline_ptr, cmdline_len);
> +	if (result)
> +		goto out_free_image;
> +
> +	result = sanity_check_segment_list(image);
> +	if (result)
> +		goto out_free_post_load_bufs;

Dunno, it could probably be a larger restructuring effort but if you
do load a segment and sanity-check it right after loading, instead of
loading all of them first and then iterating over them, you could save
yourself some work in the error case when a segment fails the check.

...

> +int kexec_add_buffer(struct kimage *image, char *buffer,
> +		unsigned long bufsz, unsigned long memsz,
> +		unsigned long buf_align, unsigned long buf_min,
> +		unsigned long buf_max, int top_down, unsigned long *load_addr)
> +{
> +
> +	unsigned long nr_segments = image->nr_segments, new_nr_segments;
> +	struct kexec_segment *ksegment;
> +	struct kexec_buf *kbuf;
> +
> +	/* Currently adding segment this way is allowed only in file mode */
> +	if (!image->file_mode)
> +		return -EINVAL;
> +
> +	if (nr_segments >= KEXEC_SEGMENT_MAX)
> +		return -EINVAL;
> +
> +	/*
> +	 * Make sure we are not trying to add buffer after allocating
> +	 * control pages. All segments need to be placed first before
> +	 * any control pages are allocated. As control page allocation
> +	 * logic goes through list of segments to make sure there are
> +	 * no destination overlaps.
> +	 */
> +	WARN_ONCE(!list_empty(&image->control_pages), "Adding kexec buffer"
> +			" after allocating control pages\n");
> +
> +	kbuf = kzalloc(sizeof(struct kexec_buf), GFP_KERNEL);
> +	if (!kbuf)
> +		return -ENOMEM;
> +
> +	kbuf->image = image;
> +	kbuf->buffer = buffer;
> +	kbuf->bufsz = bufsz;
> +	/* Align memsz to next page boundary */
> +	kbuf->memsz = ALIGN(memsz, PAGE_SIZE);
> +
> +	/* Align to atleast page size boundary */
> +	kbuf->buf_align = max(buf_align, PAGE_SIZE);
> +	kbuf->buf_min = buf_min;
> +	kbuf->buf_max = buf_max;
> +	kbuf->top_down = top_down;
> +
> +	/* Walk the RAM ranges and allocate a suitable range for the buffer */
> +	walk_system_ram_res(0, -1, kbuf, walk_ram_range_callback);
> +
> +	kbuf->image = NULL;
> +	kfree(kbuf);

This is freed after kzalloc'ing it a bit earlier, why not make it a
stack variable for simplicity? struct kexec_buf doesn't seem that
large...

-- 
Regards/Gruss,
    Boris.

Sent from a fat crate under my desk. Formatting is fine.
--


From dyoung at redhat.com  Sun Feb 23 22:22:05 2014
From: dyoung at redhat.com (Dave Young)
Date: Mon, 24 Feb 2014 11:22:05 +0800
Subject: [PATCH] kexec: Fix ->unuseable_pages typo
In-Reply-To: <1392819695-24116-1-git-send-email-bp@alien8.de>
References: <1392819695-24116-1-git-send-email-bp@alien8.de>
Message-ID: <20140224032204.GC4043@dhcp-16-126.nay.redhat.com>

On 02/19/14 at 03:21pm, Borislav Petkov wrote:
> From: Borislav Petkov <bp at suse.de>
> 
> Let's use the more common "unusable".
> 
> Cc: Eric Biederman <ebiederm at xmission.com>
> Cc: kexec at lists.infradead.org
> Signed-off-by: Borislav Petkov <bp at suse.de>
> ---
>  include/linux/kexec.h | 2 +-
>  kernel/kexec.c        | 6 +++---
>  2 files changed, 4 insertions(+), 4 deletions(-)
> 
> diff --git a/include/linux/kexec.h b/include/linux/kexec.h
> index 6d4066cdb5b5..969237e338d1 100644
> --- a/include/linux/kexec.h
> +++ b/include/linux/kexec.h
> @@ -100,7 +100,7 @@ struct kimage {
>  
>  	struct list_head control_pages;
>  	struct list_head dest_pages;
> -	struct list_head unuseable_pages;
> +	struct list_head unusable_pages;
>  
>  	/* Address of next control page to allocate for crash kernels. */
>  	unsigned long control_page;
> diff --git a/kernel/kexec.c b/kernel/kexec.c
> index 60bafbed06ab..a2d0c5f80bf2 100644
> --- a/kernel/kexec.c
> +++ b/kernel/kexec.c
> @@ -152,7 +152,7 @@ static int do_kimage_alloc(struct kimage **rimage, unsigned long entry,
>  	INIT_LIST_HEAD(&image->dest_pages);
>  
>  	/* Initialize the list of unusable pages */
> -	INIT_LIST_HEAD(&image->unuseable_pages);
> +	INIT_LIST_HEAD(&image->unusable_pages);
>  
>  	/* Read in the segments */
>  	image->nr_segments = nr_segments;
> @@ -607,7 +607,7 @@ static void kimage_free_extra_pages(struct kimage *image)
>  	kimage_free_page_list(&image->dest_pages);
>  
>  	/* Walk through and free any unusable pages I have cached */
> -	kimage_free_page_list(&image->unuseable_pages);
> +	kimage_free_page_list(&image->unusable_pages);
>  
>  }
>  static void kimage_terminate(struct kimage *image)
> @@ -731,7 +731,7 @@ static struct page *kimage_alloc_page(struct kimage *image,
>  		/* If the page cannot be used file it away */
>  		if (page_to_pfn(page) >
>  				(KEXEC_SOURCE_MEMORY_LIMIT >> PAGE_SHIFT)) {
> -			list_add(&page->lru, &image->unuseable_pages);
> +			list_add(&page->lru, &image->unusable_pages);
>  			continue;
>  		}
>  		addr = page_to_pfn(page) << PAGE_SHIFT;

Acked-by: Dave Young <dyoung at redhat.com>

--
Thanks
Dave


From kumagai-atsushi at mxc.nes.nec.co.jp  Mon Feb 24 00:00:56 2014
From: kumagai-atsushi at mxc.nes.nec.co.jp (Atsushi Kumagai)
Date: Mon, 24 Feb 2014 05:00:56 +0000
Subject: crash: struct command can read irrelevant pages.
In-Reply-To: <1598236100.13279715.1392929150735.JavaMail.zimbra@redhat.com>
References: <0910DD04CBD6DE4193FCF86B9C00BE971EAF68@BPXM01GP.gisp.nec.co.jp>
 <1347294540.11438228.1392821415316.JavaMail.zimbra@redhat.com>
 <1598236100.13279715.1392929150735.JavaMail.zimbra@redhat.com>
Message-ID: <0910DD04CBD6DE4193FCF86B9C00BE971EC432@BPXM01GP.gisp.nec.co.jp>

>Hello Atsushi,
>
>I've committed a SLAB/SLUB kmem_cache-specific fix for this issue:
>
>  https://github.com/crash-utility/crash/commit/c0b7a74fc13121203810d06d163550436b2d5476
>
>which is queued for crash-7.0.6.

Thanks Dave, I made sure that this patch solved my problem.

>> This is a "known" issue has been discussed on the crash-utility list in the
>> past, at least with respect to the kmem_cache data structure.  But for any random
>> data structure that has such a construct, I'm not sure what can be done.

I also have no ideas how to solve it, but it seems that it hasn't been a
practical problem yet. So I think your patch is enough for now.

>> By any chance can you make the 32-bit vmlinux/vmcore pair available for
>> me to download?  Reply to me off-list if you can.

Sure, I'll send another mail.


Thanks
Atsushi Kumagai

>>
>>
>> ----- Original Message -----
>> > Hello,
>> >
>> > Finally, I've found the cause of the issue I mentioned as below
>> > when makedumpfile v1.5.5 was released:
>> >
>> > > 2. At first, the supported kernel will be updated to 3.12, but I
>> > > found an issue while testing for v1.5.5, which seems that the page
>> > > filtering works wrongly on kernel 3.12. I couldn't investigate this
>> > > yet and it will take some time to finish it.
>> > > Therefore, the latest supported kernel version is 3.11 in v1.5.5.
>> >
>> > This is neither a kernel issue nor a makedumpfile issue, it's a crash's bug.
>> > It can happen when a slab cache is stored at almost end of a page.
>> >
>> > == Description ==
>> >
>> > At the beginning, I found the error message below when I used crash for
>> > a dumpfile generated by makedumpfile -d2:
>> >
>> >     please wait... (gathering kmem slab cache data)
>> >     crash: page excluded: kernel virtual address: f4e87000  type:
>> >     "kmem_cache
>> >     buffer"
>> >
>> >     crash: unable to initialize kmem slab cache subsystem
>> >
>> > This message indicated that crash failed to get a slab cache during
>> > kmem_cache_init(), and according to the below, crash failed to get
>> > the slab cache stored at f4e86f40:
>> >
>> >     crash> p kmem_cache
>> >     kmem_cache = $1 = (struct kmem_cache *) 0xc0b1cbc0 <kmem_cache_boot>
>> >     crash>
>> >     crash> list kmem_cache.list -s kmem_cache.name -h 0xc0b1cbc0
>> >     ...
>> >     f4d37840
>> >       name = 0xf4edf540 "uid_cache"
>> >     f4e86f40
>> >     list: page excluded: kernel virtual address: f4e87000  type:
>> >     "gdb_readmem_callback"
>> >
>> > It seems that the slab cache covered two pages, [f4e86000- f4e87000] and
>> > [f4e87000- f4e88000]. Well, let's confirm the *real* size of it.
>> >
>> > Since slab caches except kmem_cache_boot are allocated as slab objects,
>> > we can confirm the size like below:
>> >
>> >   crash> p kmem_cache
>> >   kmem_cache = $2 = (struct kmem_cache *) 0xc0b1cbc0 <kmem_cache_boot>
>> >   crash> struct kmem_cache.object_size 0xc0b1cbc0
>> >     object_size = 104
>> >   crash>
>> >
>> > In my environment, the size was 104 bytes. Therefore, the slab cache
>> > stored at f4e86f40 fits in the single page([f4e86000- f4e87000]) and
>> > the excluded page([f4e87000- f4e88000]) isn't a related page.
>> >
>> > On the other hand, crash get the size from vmlinux by using gdb,
>> > it was 216 bytes:
>> >
>> >     crash> struct kmem_cache
>> >     struct kmem_cache {
>> >         unsigned int batchcount;
>> >         unsigned int limit;
>> >         ...
>> >         struct kmem_cache_node **node;
>> >         struct array_cache *array[33];
>> >     }
>> >     SIZE: 216
>> >     crash>
>> >
>> > So crash mistook the correlative pages of the slab cache as
>> > [f4e86000- f4e87000] and [f4e87000- f4e88000] even though the latter
>> > was a irrelevant page.
>> >
>> > This gap came from the fact that the size of slab cache is variable.
>> >
>> >     struct kmem_cache {
>> >     ...
>> >             struct kmem_cache_node **node;
>> >             struct array_cache *array[NR_CPUS + MAX_NUMNODES];
>> >             /*
>> >              * Do not add fields after array[]
>> >              */
>> >     };
>> >
>> > The size of "array" is the variable factor of kmem_cache.
>> > When building vmlinux, the size of kmem_cache will be calculated with
>> > NR_CPUS and MAX_NUMNODES, and put it into vmlinux as a debug information.
>> > (Sorry, I don't know gcc well. I may misunderstand this.)
>> > However, the actual size will be smaller than the defined size because
>> > the actual size will be decided based on the actual number of CPUs and
>> > NODEs.
>> >
>> > void __init kmem_cache_init(void)::
>> > ...
>> >         /*
>> >          * struct kmem_cache size depends on nr_node_ids & nr_cpu_ids
>> >          */
>> >         create_boot_cache(kmem_cache, "kmem_cache",
>> >                 offsetof(struct kmem_cache, array[nr_cpu_ids]) +
>> >                                   nr_node_ids * sizeof(struct
>> >                                   kmem_cache_node
>> >                                   *),  // object_size
>> >                                   SLAB_HWCACHE_ALIGN);
>> >         list_add(&kmem_cache->list, &slab_caches);
>> >
>> >
>> > As for kmem_cache, we can get the actual size of it from kmem_cache_boot,
>> > but I suppose that kmem_cache is not the only struct in kernel whose size
>> > is variable. So I think we should discuss how to address such issues like
>> > this.
>> >
>> > By the way, I mentioned the case of *SLAB* in this mail,
>> > but SLUB seems have the same issue.
>> >
>> >
>> > Thanks
>> > Atsushi Kumagai
>>
>>
>> This is a "known" issue has been discussed on the crash-utility list in the
>> past,
>> at least with respect to the kmem_cache data structure.  But for any random
>> data
>> structure that has such a construct, I'm not sure what can be done.
>>
>> In the case of the CONFIG_SLAB kmem_cache data structure, there is a function
>> that is supposed to "downsize" the size value of the kmem_cache data
>> structure
>> that is returned by gdb.  It is called here in kmem_cache_init(), just
>> prior to cycling through all of the kmem_cache structures, where the
>> page excluded error shown above occurred:
>>
>>    8561         if (!(pc->flags & RUNTIME))
>>    8562                 kmem_cache_downsize();
>>    8563
>>    8564         cache_buf = GETBUF(SIZE(kmem_cache_s));
>>    8565         hq_open();
>>    8566
>>    8567         do {
>>    8568                 cache_count++;
>>    8569
>>    8570                 if (!readmem(cache, KVADDR, cache_buf,
>>    SIZE(kmem_cache_s),
>>    8571                         "kmem_cache buffer", RETURN_ON_ERROR)) {
>>    8572                         FREEBUF(cache_buf);
>>    8573                         vt->flags |= KMEM_CACHE_UNAVAIL;
>>    8574                         error(INFO,
>>    8575                           "%sunable to initialize kmem slab cache
>>    subsystem\n\n",
>>    8576                                 DUMPFILE() ? "\n" : "");
>>    8577                         hq_close();
>>    8578                         return;
>>    8579                 }
>>
>> The SIZE(kmem_cache_s) value should have been downsized by that function,
>> but presumably it did not work.  If CRASHDEBUG(1) was turned on during
>> initialization,
>> you would have seen either of these two messages from kmem_cache_downsize():
>>
>>                 if (CRASHDEBUG(1))
>>                         fprintf(fp, "kmem_cache_downsize: %ld to %ld\n",
>>                                 STRUCT_SIZE("kmem_cache"),
>>                                 SIZE(kmem_cache_s));
>>
>> or:
>>
>>                 if (CRASHDEBUG(1)) {
>>                         fprintf(fp,
>>                             "\nkmem_cache_downsize: SIZE(kmem_cache_s): %ld "
>>                             "cache_cache.buffer_size: %d\n",
>>                                 STRUCT_SIZE("kmem_cache"), buffer_size);
>>                         fprintf(fp,
>>                             "kmem_cache_downsize: nr_node_ids: %ld\n",
>>                                 vt->kmem_cache_len_nodes);
>>                 }
>>
>> The function failed probably failed due to some kernel change.  In fact,
>> I just checked a 3.13 CONFIG_SLAB kernel, and I see that
>> kmem_cache_downsize()
>> no longer works for that kernel.
>>
>> I see that kmem_cache_boot would be a good alternative for determining
>> the size on CONFIG_SLAB kernels, at least on 3.7 and later kernels where
>> it was introduced.  And for CONFIG_SLUB, which doesn't currently have a
>> "downsize" function, it looks like its "kmem_cache" cache also has size
>> fields that could be used.
>>
>> By any chance can you make the 32-bit vmlinux/vmcore pair available for
>> me to download?  Reply to me off-list if you can.
>>
>> Thanks,
>>   Dave


From trenn at suse.de  Mon Feb 24 05:38:38 2014
From: trenn at suse.de (Thomas Renninger)
Date: Mon, 24 Feb 2014 11:38:38 +0100
Subject: [PATCH v2 0/4] kexec-tools, x86: E820 memmap pass for kdump
In-Reply-To: <1392888512-4473-1-git-send-email-chaowang@redhat.com>
References: <1392888512-4473-1-git-send-email-chaowang@redhat.com>
Message-ID: <2680313.u921kQOFS9@skinner>

On Thursday, February 20, 2014 05:28:28 PM WANG Chao wrote:
> Hi, All
> 
> When kaslr comes in and kdump is broken, it seems about the right time to
> use E820 instead of memmap=exactmap to pass memmap for kdump for the
> default memmap passing mechanism:
> http://lists.infradead.org/pipermail/kexec/2014-February/011048.html
> 
> Unfortunately, saved_max_pfn still got its user out there (calgry pci, it
> looks like the only one). So for backward compatibility, I'm introducing a
> new option --pass-memmap-cmdline to force kexec-tools to pass
> memmap=exactmap, the old way.
The saved_max_pfn usage is calgary pci looks bad/wrong and I wonder:
  - whether this is still worth touching, so that the old mechanism:
    --pass-memmap-cmdline could vanish in the one or other year and need
    not to be carried forever
I tried to find such a machine, but couldn't find anything mentioning calgary
in quite some machines' dmesg.

Approaches to avoid saved_max_pfn in calgary case:
  1) If done correctly from the beginning, the TCE table size would have
     been exposed via /sys and kexec-tools could simply add:
     calgary="128k|512K...|8M" which is already caught by pci-calgary and
     saved_max_pfn is not needed/touched anymore.
     -> Disadvantage: needs a new sysfs entry
  2) When finding max_pfn for calgary table size usage, we could try in 
     kdump case to use the highest memory (RAM or RESERVED) showing up
     in e820 map.

Please find below a patch which would eleminate the last saved_max_pfn
user. Unfortunately I could not find a calgary system to test this on.

Be aware: I could not test this.
If someone tells me for what kind of machine (and BIOS stuff enabled?)
I should look for, I can try to search for such a platform.

Something else: There is quite some duplicate code in kexec-tools when it
is about retrieving the e820 table info (normal kexec vs kdump).
Did you see my cleanups I posted long ago? Do you plan to still clean up
a bit after this series?

        Thomas



X86: Eliminate saved_max_pfn user in pci-calgary and remove the unused variable

Searching for the highest value of RAM and RESERVED memory in kdump case
should be the same as max_pfn of the original kernel.
At least this is always the case as long as type usable RAM is the highest
entry in original e820 map.

Signed-off-by: Thomas Renninger <trenn at suse.de>

diff --git a/arch/x86/include/asm/e820.h b/arch/x86/include/asm/e820.h
index 779c2ef..712173e 100644
--- a/arch/x86/include/asm/e820.h
+++ b/arch/x86/include/asm/e820.h
@@ -49,6 +49,7 @@ static inline void early_memtest(unsigned long start, unsigned long end)
 #endif
 
 extern unsigned long e820_end_of_ram_pfn(void);
+extern unsigned long e820_end_of_e820_pfn(void);
 extern unsigned long e820_end_of_low_ram_pfn(void);
 extern u64 early_reserve_e820(u64 sizet, u64 align);
 
diff --git a/arch/x86/kernel/e820.c b/arch/x86/kernel/e820.c
index 988c00a..699e8fe 100644
--- a/arch/x86/kernel/e820.c
+++ b/arch/x86/kernel/e820.c
@@ -757,7 +757,7 @@ u64 __init early_reserve_e820(u64 size, u64 align)
 /*
  * Find the highest page frame number we have available
  */
-static unsigned long __init e820_end_pfn(unsigned long limit_pfn, unsigned type)
+unsigned long __init e820_end_pfn(unsigned long limit_pfn, unsigned type)
 {
 	int i;
 	unsigned long last_pfn = 0;
@@ -796,6 +796,12 @@ unsigned long __init e820_end_of_ram_pfn(void)
 	return e820_end_pfn(MAX_ARCH_PFN, E820_RAM);
 }
 
+unsigned long __init e820_end_of_e820_pfn(void)
+{
+	return max(e820_end_pfn(MAX_ARCH_PFN, E820_RAM),
+		   e820_end_pfn(MAX_ARCH_PFN, E820_RESERVED);
+}
+
 unsigned long __init e820_end_of_low_ram_pfn(void)
 {
 	return e820_end_pfn(1UL<<(32 - PAGE_SHIFT), E820_RAM);
@@ -847,14 +853,6 @@ static int __init parse_memmap_one(char *p)
 		return -EINVAL;
 
 	if (!strncmp(p, "exactmap", 8)) {
-#ifdef CONFIG_CRASH_DUMP
-		/*
-		 * If we are doing a crash dump, we still need to know
-		 * the real mem size before original memory map is
-		 * reset.
-		 */
-		saved_max_pfn = e820_end_of_ram_pfn();
-#endif
 		e820.nr_map = 0;
 		userdef = 1;
 		return 0;
diff --git a/arch/x86/kernel/pci-calgary_64.c b/arch/x86/kernel/pci-calgary_64.c
index 299d493..89ae766 100644
--- a/arch/x86/kernel/pci-calgary_64.c
+++ b/arch/x86/kernel/pci-calgary_64.c
@@ -1371,6 +1371,7 @@ int __init detect_calgary(void)
 	unsigned long ptr;
 	unsigned int offset, prev_offset;
 	int ret;
+	unsigned long orig_max_pfn = max_pfn;
 
 	/*
 	 * if the user specified iommu=off or iommu=soft or we found
@@ -1418,8 +1419,10 @@ int __init detect_calgary(void)
 		return -ENOMEM;
 	}
 
-	specified_table_size = determine_tce_table_size((is_kdump_kernel() ?
-					saved_max_pfn : max_pfn) * PAGE_SIZE);
+	if (is_kdump_kernel())
+		orig_max_pfn = e820_end_of_e820_pfn();
+	specified_table_size = determine_tce_table_size(orig_max_pfn
+							* PAGE_SIZE);
 
 	for (bus = 0; bus < MAX_PHB_BUS_NUM; bus++) {
 		struct calgary_bus_info *info = &bus_info[bus];
diff --git a/include/linux/crash_dump.h b/include/linux/crash_dump.h
index 7032518..bce4d97 100644
--- a/include/linux/crash_dump.h
+++ b/include/linux/crash_dump.h
@@ -87,5 +87,4 @@ extern void unregister_oldmem_pfn_is_ram(void);
 static inline int is_kdump_kernel(void) { return 0; }
 #endif /* CONFIG_CRASH_DUMP */
 
-extern unsigned long saved_max_pfn;
 #endif /* LINUX_CRASHDUMP_H */
diff --git a/kernel/crash_dump.c b/kernel/crash_dump.c
index c766ee5..9d50486 100644
--- a/kernel/crash_dump.c
+++ b/kernel/crash_dump.c
@@ -5,12 +5,6 @@
 #include <linux/export.h>
 
 /*
- * If we have booted due to a crash, max_pfn will be a very low value. We need
- * to know the amount of memory that the previous kernel used.
- */
-unsigned long saved_max_pfn;
-
-/*
  * stores the physical address of elf header of crash image
  *
  * Note: elfcorehdr_addr is not just limited to vmcore. It is also used by



From chaowang at redhat.com  Mon Feb 24 09:58:41 2014
From: chaowang at redhat.com (WANG Chao)
Date: Mon, 24 Feb 2014 22:58:41 +0800
Subject: [PATCH v2 0/4] kexec-tools, x86: E820 memmap pass for kdump
In-Reply-To: <2680313.u921kQOFS9@skinner>
References: <1392888512-4473-1-git-send-email-chaowang@redhat.com>
 <2680313.u921kQOFS9@skinner>
Message-ID: <20140224145841.GE1262@dhcp-17-89.nay.redhat.com>

On 02/24/14 at 11:38am, Thomas Renninger wrote:
> On Thursday, February 20, 2014 05:28:28 PM WANG Chao wrote:
> > Hi, All
> > 
> > When kaslr comes in and kdump is broken, it seems about the right time to
> > use E820 instead of memmap=exactmap to pass memmap for kdump for the
> > default memmap passing mechanism:
> > http://lists.infradead.org/pipermail/kexec/2014-February/011048.html
> > 
> > Unfortunately, saved_max_pfn still got its user out there (calgry pci, it
> > looks like the only one). So for backward compatibility, I'm introducing a
> > new option --pass-memmap-cmdline to force kexec-tools to pass
> > memmap=exactmap, the old way.
> The saved_max_pfn usage is calgary pci looks bad/wrong and I wonder:
>   - whether this is still worth touching, so that the old mechanism:
>     --pass-memmap-cmdline could vanish in the one or other year and need
>     not to be carried forever
> I tried to find such a machine, but couldn't find anything mentioning calgary
> in quite some machines' dmesg.
> 
> Approaches to avoid saved_max_pfn in calgary case:
>   1) If done correctly from the beginning, the TCE table size would have
>      been exposed via /sys and kexec-tools could simply add:
>      calgary="128k|512K...|8M" which is already caught by pci-calgary and
>      saved_max_pfn is not needed/touched anymore.
>      -> Disadvantage: needs a new sysfs entry
>   2) When finding max_pfn for calgary table size usage, we could try in 
>      kdump case to use the highest memory (RAM or RESERVED) showing up
>      in e820 map.

How could this replace saved_max_pfn? The highest memory in kdump can't
necessarily be the real ram size. In kdump, RAM range is just part of the real
ram, not mentioning we don't pass RESERVED range to kdump E820.

Thanks
WANG Chao

> 
> Please find below a patch which would eleminate the last saved_max_pfn
> user. Unfortunately I could not find a calgary system to test this on.
> 
> Be aware: I could not test this.
> If someone tells me for what kind of machine (and BIOS stuff enabled?)
> I should look for, I can try to search for such a platform.
> 
> Something else: There is quite some duplicate code in kexec-tools when it
> is about retrieving the e820 table info (normal kexec vs kdump).
> Did you see my cleanups I posted long ago? Do you plan to still clean up
> a bit after this series?

Yes, I saw them and find some of them are pretty useful for this
patchset. I suppose some cleanups can be done later. Feel free to clean
up after this patchset is settled.

> 
>         Thomas
> 
> 
> 
> X86: Eliminate saved_max_pfn user in pci-calgary and remove the unused variable
> 
> Searching for the highest value of RAM and RESERVED memory in kdump case
> should be the same as max_pfn of the original kernel.
> At least this is always the case as long as type usable RAM is the highest
> entry in original e820 map.
> 
> Signed-off-by: Thomas Renninger <trenn at suse.de>
> 
> diff --git a/arch/x86/include/asm/e820.h b/arch/x86/include/asm/e820.h
> index 779c2ef..712173e 100644
> --- a/arch/x86/include/asm/e820.h
> +++ b/arch/x86/include/asm/e820.h
> @@ -49,6 +49,7 @@ static inline void early_memtest(unsigned long start, unsigned long end)
>  #endif
>  
>  extern unsigned long e820_end_of_ram_pfn(void);
> +extern unsigned long e820_end_of_e820_pfn(void);
>  extern unsigned long e820_end_of_low_ram_pfn(void);
>  extern u64 early_reserve_e820(u64 sizet, u64 align);
>  
> diff --git a/arch/x86/kernel/e820.c b/arch/x86/kernel/e820.c
> index 988c00a..699e8fe 100644
> --- a/arch/x86/kernel/e820.c
> +++ b/arch/x86/kernel/e820.c
> @@ -757,7 +757,7 @@ u64 __init early_reserve_e820(u64 size, u64 align)
>  /*
>   * Find the highest page frame number we have available
>   */
> -static unsigned long __init e820_end_pfn(unsigned long limit_pfn, unsigned type)
> +unsigned long __init e820_end_pfn(unsigned long limit_pfn, unsigned type)
>  {
>  	int i;
>  	unsigned long last_pfn = 0;
> @@ -796,6 +796,12 @@ unsigned long __init e820_end_of_ram_pfn(void)
>  	return e820_end_pfn(MAX_ARCH_PFN, E820_RAM);
>  }
>  
> +unsigned long __init e820_end_of_e820_pfn(void)
> +{
> +	return max(e820_end_pfn(MAX_ARCH_PFN, E820_RAM),
> +		   e820_end_pfn(MAX_ARCH_PFN, E820_RESERVED);
> +}
> +
>  unsigned long __init e820_end_of_low_ram_pfn(void)
>  {
>  	return e820_end_pfn(1UL<<(32 - PAGE_SHIFT), E820_RAM);
> @@ -847,14 +853,6 @@ static int __init parse_memmap_one(char *p)
>  		return -EINVAL;
>  
>  	if (!strncmp(p, "exactmap", 8)) {
> -#ifdef CONFIG_CRASH_DUMP
> -		/*
> -		 * If we are doing a crash dump, we still need to know
> -		 * the real mem size before original memory map is
> -		 * reset.
> -		 */
> -		saved_max_pfn = e820_end_of_ram_pfn();
> -#endif
>  		e820.nr_map = 0;
>  		userdef = 1;
>  		return 0;
> diff --git a/arch/x86/kernel/pci-calgary_64.c b/arch/x86/kernel/pci-calgary_64.c
> index 299d493..89ae766 100644
> --- a/arch/x86/kernel/pci-calgary_64.c
> +++ b/arch/x86/kernel/pci-calgary_64.c
> @@ -1371,6 +1371,7 @@ int __init detect_calgary(void)
>  	unsigned long ptr;
>  	unsigned int offset, prev_offset;
>  	int ret;
> +	unsigned long orig_max_pfn = max_pfn;
>  
>  	/*
>  	 * if the user specified iommu=off or iommu=soft or we found
> @@ -1418,8 +1419,10 @@ int __init detect_calgary(void)
>  		return -ENOMEM;
>  	}
>  
> -	specified_table_size = determine_tce_table_size((is_kdump_kernel() ?
> -					saved_max_pfn : max_pfn) * PAGE_SIZE);
> +	if (is_kdump_kernel())
> +		orig_max_pfn = e820_end_of_e820_pfn();
> +	specified_table_size = determine_tce_table_size(orig_max_pfn
> +							* PAGE_SIZE);
>  
>  	for (bus = 0; bus < MAX_PHB_BUS_NUM; bus++) {
>  		struct calgary_bus_info *info = &bus_info[bus];
> diff --git a/include/linux/crash_dump.h b/include/linux/crash_dump.h
> index 7032518..bce4d97 100644
> --- a/include/linux/crash_dump.h
> +++ b/include/linux/crash_dump.h
> @@ -87,5 +87,4 @@ extern void unregister_oldmem_pfn_is_ram(void);
>  static inline int is_kdump_kernel(void) { return 0; }
>  #endif /* CONFIG_CRASH_DUMP */
>  
> -extern unsigned long saved_max_pfn;
>  #endif /* LINUX_CRASHDUMP_H */
> diff --git a/kernel/crash_dump.c b/kernel/crash_dump.c
> index c766ee5..9d50486 100644
> --- a/kernel/crash_dump.c
> +++ b/kernel/crash_dump.c
> @@ -5,12 +5,6 @@
>  #include <linux/export.h>
>  
>  /*
> - * If we have booted due to a crash, max_pfn will be a very low value. We need
> - * to know the amount of memory that the previous kernel used.
> - */
> -unsigned long saved_max_pfn;
> -
> -/*
>   * stores the physical address of elf header of crash image
>   *
>   * Note: elfcorehdr_addr is not just limited to vmcore. It is also used by
> 


From anderson at redhat.com  Mon Feb 24 09:59:17 2014
From: anderson at redhat.com (Dave Anderson)
Date: Mon, 24 Feb 2014 09:59:17 -0500 (EST)
Subject: [Crash-utility] crash: struct command can read irrelevant pages.
In-Reply-To: <0910DD04CBD6DE4193FCF86B9C00BE971EC432@BPXM01GP.gisp.nec.co.jp>
References: <0910DD04CBD6DE4193FCF86B9C00BE971EAF68@BPXM01GP.gisp.nec.co.jp>
 <1347294540.11438228.1392821415316.JavaMail.zimbra@redhat.com>
 <1598236100.13279715.1392929150735.JavaMail.zimbra@redhat.com>
 <0910DD04CBD6DE4193FCF86B9C00BE971EC432@BPXM01GP.gisp.nec.co.jp>
Message-ID: <1890371822.15122719.1393253957343.JavaMail.zimbra@redhat.com>



----- Original Message -----
> >Hello Atsushi,
> >
> >I've committed a SLAB/SLUB kmem_cache-specific fix for this issue:
> >
> >  https://github.com/crash-utility/crash/commit/c0b7a74fc13121203810d06d163550436b2d5476
> >
> >which is queued for crash-7.0.6.
> 
> Thanks Dave, I made sure that this patch solved my problem.

OK good, thanks.
 
> >> This is a "known" issue has been discussed on the crash-utility list in the
> >> past, at least with respect to the kmem_cache data structure.  But for any random
> >> data structure that has such a construct, I'm not sure what can be done.
> 
> I also have no ideas how to solve it, but it seems that it hasn't been a
> practical problem yet. So I think your patch is enough for now.

At least with compressed kdumps, the "crash --zero_excluded" command line option,
or "set zero_excluded on" during runtime, should handle 99% of the cases.

Dave
 
 


From hpa at zytor.com  Mon Feb 24 10:03:07 2014
From: hpa at zytor.com (H. Peter Anvin)
Date: Mon, 24 Feb 2014 07:03:07 -0800
Subject: [PATCH v2 0/4] kexec-tools, x86: E820 memmap pass for kdump
In-Reply-To: <20140224145841.GE1262@dhcp-17-89.nay.redhat.com>
References: <1392888512-4473-1-git-send-email-chaowang@redhat.com>
 <2680313.u921kQOFS9@skinner>
 <20140224145841.GE1262@dhcp-17-89.nay.redhat.com>
Message-ID: <7125bd4c-b394-4180-b564-f2002c9d9a2e@email.android.com>

First question is if Calgary even exists anymore and if so if someone actually cares about it enough to maintain it.

On February 24, 2014 6:58:41 AM PST, WANG Chao <chaowang at redhat.com> wrote:
>On 02/24/14 at 11:38am, Thomas Renninger wrote:
>> On Thursday, February 20, 2014 05:28:28 PM WANG Chao wrote:
>> > Hi, All
>> > 
>> > When kaslr comes in and kdump is broken, it seems about the right
>time to
>> > use E820 instead of memmap=exactmap to pass memmap for kdump for
>the
>> > default memmap passing mechanism:
>> >
>http://lists.infradead.org/pipermail/kexec/2014-February/011048.html
>> > 
>> > Unfortunately, saved_max_pfn still got its user out there (calgry
>pci, it
>> > looks like the only one). So for backward compatibility, I'm
>introducing a
>> > new option --pass-memmap-cmdline to force kexec-tools to pass
>> > memmap=exactmap, the old way.
>> The saved_max_pfn usage is calgary pci looks bad/wrong and I wonder:
>>   - whether this is still worth touching, so that the old mechanism:
>>     --pass-memmap-cmdline could vanish in the one or other year and
>need
>>     not to be carried forever
>> I tried to find such a machine, but couldn't find anything mentioning
>calgary
>> in quite some machines' dmesg.
>> 
>> Approaches to avoid saved_max_pfn in calgary case:
>>   1) If done correctly from the beginning, the TCE table size would
>have
>>      been exposed via /sys and kexec-tools could simply add:
>>      calgary="128k|512K...|8M" which is already caught by pci-calgary
>and
>>      saved_max_pfn is not needed/touched anymore.
>>      -> Disadvantage: needs a new sysfs entry
>>   2) When finding max_pfn for calgary table size usage, we could try
>in 
>>      kdump case to use the highest memory (RAM or RESERVED) showing
>up
>>      in e820 map.
>
>How could this replace saved_max_pfn? The highest memory in kdump can't
>necessarily be the real ram size. In kdump, RAM range is just part of
>the real
>ram, not mentioning we don't pass RESERVED range to kdump E820.
>
>Thanks
>WANG Chao
>
>> 
>> Please find below a patch which would eleminate the last
>saved_max_pfn
>> user. Unfortunately I could not find a calgary system to test this
>on.
>> 
>> Be aware: I could not test this.
>> If someone tells me for what kind of machine (and BIOS stuff
>enabled?)
>> I should look for, I can try to search for such a platform.
>> 
>> Something else: There is quite some duplicate code in kexec-tools
>when it
>> is about retrieving the e820 table info (normal kexec vs kdump).
>> Did you see my cleanups I posted long ago? Do you plan to still clean
>up
>> a bit after this series?
>
>Yes, I saw them and find some of them are pretty useful for this
>patchset. I suppose some cleanups can be done later. Feel free to clean
>up after this patchset is settled.
>
>> 
>>         Thomas
>> 
>> 
>> 
>> X86: Eliminate saved_max_pfn user in pci-calgary and remove the
>unused variable
>> 
>> Searching for the highest value of RAM and RESERVED memory in kdump
>case
>> should be the same as max_pfn of the original kernel.
>> At least this is always the case as long as type usable RAM is the
>highest
>> entry in original e820 map.
>> 
>> Signed-off-by: Thomas Renninger <trenn at suse.de>
>> 
>> diff --git a/arch/x86/include/asm/e820.h
>b/arch/x86/include/asm/e820.h
>> index 779c2ef..712173e 100644
>> --- a/arch/x86/include/asm/e820.h
>> +++ b/arch/x86/include/asm/e820.h
>> @@ -49,6 +49,7 @@ static inline void early_memtest(unsigned long
>start, unsigned long end)
>>  #endif
>>  
>>  extern unsigned long e820_end_of_ram_pfn(void);
>> +extern unsigned long e820_end_of_e820_pfn(void);
>>  extern unsigned long e820_end_of_low_ram_pfn(void);
>>  extern u64 early_reserve_e820(u64 sizet, u64 align);
>>  
>> diff --git a/arch/x86/kernel/e820.c b/arch/x86/kernel/e820.c
>> index 988c00a..699e8fe 100644
>> --- a/arch/x86/kernel/e820.c
>> +++ b/arch/x86/kernel/e820.c
>> @@ -757,7 +757,7 @@ u64 __init early_reserve_e820(u64 size, u64
>align)
>>  /*
>>   * Find the highest page frame number we have available
>>   */
>> -static unsigned long __init e820_end_pfn(unsigned long limit_pfn,
>unsigned type)
>> +unsigned long __init e820_end_pfn(unsigned long limit_pfn, unsigned
>type)
>>  {
>>  	int i;
>>  	unsigned long last_pfn = 0;
>> @@ -796,6 +796,12 @@ unsigned long __init e820_end_of_ram_pfn(void)
>>  	return e820_end_pfn(MAX_ARCH_PFN, E820_RAM);
>>  }
>>  
>> +unsigned long __init e820_end_of_e820_pfn(void)
>> +{
>> +	return max(e820_end_pfn(MAX_ARCH_PFN, E820_RAM),
>> +		   e820_end_pfn(MAX_ARCH_PFN, E820_RESERVED);
>> +}
>> +
>>  unsigned long __init e820_end_of_low_ram_pfn(void)
>>  {
>>  	return e820_end_pfn(1UL<<(32 - PAGE_SHIFT), E820_RAM);
>> @@ -847,14 +853,6 @@ static int __init parse_memmap_one(char *p)
>>  		return -EINVAL;
>>  
>>  	if (!strncmp(p, "exactmap", 8)) {
>> -#ifdef CONFIG_CRASH_DUMP
>> -		/*
>> -		 * If we are doing a crash dump, we still need to know
>> -		 * the real mem size before original memory map is
>> -		 * reset.
>> -		 */
>> -		saved_max_pfn = e820_end_of_ram_pfn();
>> -#endif
>>  		e820.nr_map = 0;
>>  		userdef = 1;
>>  		return 0;
>> diff --git a/arch/x86/kernel/pci-calgary_64.c
>b/arch/x86/kernel/pci-calgary_64.c
>> index 299d493..89ae766 100644
>> --- a/arch/x86/kernel/pci-calgary_64.c
>> +++ b/arch/x86/kernel/pci-calgary_64.c
>> @@ -1371,6 +1371,7 @@ int __init detect_calgary(void)
>>  	unsigned long ptr;
>>  	unsigned int offset, prev_offset;
>>  	int ret;
>> +	unsigned long orig_max_pfn = max_pfn;
>>  
>>  	/*
>>  	 * if the user specified iommu=off or iommu=soft or we found
>> @@ -1418,8 +1419,10 @@ int __init detect_calgary(void)
>>  		return -ENOMEM;
>>  	}
>>  
>> -	specified_table_size = determine_tce_table_size((is_kdump_kernel()
>?
>> -					saved_max_pfn : max_pfn) * PAGE_SIZE);
>> +	if (is_kdump_kernel())
>> +		orig_max_pfn = e820_end_of_e820_pfn();
>> +	specified_table_size = determine_tce_table_size(orig_max_pfn
>> +							* PAGE_SIZE);
>>  
>>  	for (bus = 0; bus < MAX_PHB_BUS_NUM; bus++) {
>>  		struct calgary_bus_info *info = &bus_info[bus];
>> diff --git a/include/linux/crash_dump.h b/include/linux/crash_dump.h
>> index 7032518..bce4d97 100644
>> --- a/include/linux/crash_dump.h
>> +++ b/include/linux/crash_dump.h
>> @@ -87,5 +87,4 @@ extern void unregister_oldmem_pfn_is_ram(void);
>>  static inline int is_kdump_kernel(void) { return 0; }
>>  #endif /* CONFIG_CRASH_DUMP */
>>  
>> -extern unsigned long saved_max_pfn;
>>  #endif /* LINUX_CRASHDUMP_H */
>> diff --git a/kernel/crash_dump.c b/kernel/crash_dump.c
>> index c766ee5..9d50486 100644
>> --- a/kernel/crash_dump.c
>> +++ b/kernel/crash_dump.c
>> @@ -5,12 +5,6 @@
>>  #include <linux/export.h>
>>  
>>  /*
>> - * If we have booted due to a crash, max_pfn will be a very low
>value. We need
>> - * to know the amount of memory that the previous kernel used.
>> - */
>> -unsigned long saved_max_pfn;
>> -
>> -/*
>>   * stores the physical address of elf header of crash image
>>   *
>>   * Note: elfcorehdr_addr is not just limited to vmcore. It is also
>used by
>> 

-- 
Sent from my mobile phone.  Please pardon brevity and lack of formatting.


From vgoyal at redhat.com  Mon Feb 24 10:11:03 2014
From: vgoyal at redhat.com (Vivek Goyal)
Date: Mon, 24 Feb 2014 10:11:03 -0500
Subject: [PATCH v2 0/4] kexec-tools, x86: E820 memmap pass for kdump
In-Reply-To: <7125bd4c-b394-4180-b564-f2002c9d9a2e@email.android.com>
References: <1392888512-4473-1-git-send-email-chaowang@redhat.com>
 <2680313.u921kQOFS9@skinner>
 <20140224145841.GE1262@dhcp-17-89.nay.redhat.com>
 <7125bd4c-b394-4180-b564-f2002c9d9a2e@email.android.com>
Message-ID: <20140224151103.GB4631@redhat.com>

On Mon, Feb 24, 2014 at 07:03:07AM -0800, H. Peter Anvin wrote:
> First question is if Calgary even exists anymore and if so if someone actually cares about it enough to maintain it.

Atleast MAINTAINERS file says it is maintained.

CALGARY x86-64 IOMMU
M:      Muli Ben-Yehuda <muli at il.ibm.com>
M:      "Jon D. Mason" <jdmason at kudzu.us>
L:      discuss at x86-64.org
S:      Maintained
F:      arch/x86/kernel/pci-calgary_64.c
F:      arch/x86/kernel/tce_64.c
F:      arch/x86/include/asm/calgary.h
F:      arch/x86/include/asm/tce.h


I am add maintainers to CC list and they can shed more light on if
calgary still exists and if somebody actually cares about it.

Thanks
Vivek
> 
> On February 24, 2014 6:58:41 AM PST, WANG Chao <chaowang at redhat.com> wrote:
> >On 02/24/14 at 11:38am, Thomas Renninger wrote:
> >> On Thursday, February 20, 2014 05:28:28 PM WANG Chao wrote:
> >> > Hi, All
> >> > 
> >> > When kaslr comes in and kdump is broken, it seems about the right
> >time to
> >> > use E820 instead of memmap=exactmap to pass memmap for kdump for
> >the
> >> > default memmap passing mechanism:
> >> >
> >http://lists.infradead.org/pipermail/kexec/2014-February/011048.html
> >> > 
> >> > Unfortunately, saved_max_pfn still got its user out there (calgry
> >pci, it
> >> > looks like the only one). So for backward compatibility, I'm
> >introducing a
> >> > new option --pass-memmap-cmdline to force kexec-tools to pass
> >> > memmap=exactmap, the old way.
> >> The saved_max_pfn usage is calgary pci looks bad/wrong and I wonder:
> >>   - whether this is still worth touching, so that the old mechanism:
> >>     --pass-memmap-cmdline could vanish in the one or other year and
> >need
> >>     not to be carried forever
> >> I tried to find such a machine, but couldn't find anything mentioning
> >calgary
> >> in quite some machines' dmesg.
> >> 
> >> Approaches to avoid saved_max_pfn in calgary case:
> >>   1) If done correctly from the beginning, the TCE table size would
> >have
> >>      been exposed via /sys and kexec-tools could simply add:
> >>      calgary="128k|512K...|8M" which is already caught by pci-calgary
> >and
> >>      saved_max_pfn is not needed/touched anymore.
> >>      -> Disadvantage: needs a new sysfs entry
> >>   2) When finding max_pfn for calgary table size usage, we could try
> >in 
> >>      kdump case to use the highest memory (RAM or RESERVED) showing
> >up
> >>      in e820 map.
> >
> >How could this replace saved_max_pfn? The highest memory in kdump can't
> >necessarily be the real ram size. In kdump, RAM range is just part of
> >the real
> >ram, not mentioning we don't pass RESERVED range to kdump E820.
> >
> >Thanks
> >WANG Chao
> >
> >> 
> >> Please find below a patch which would eleminate the last
> >saved_max_pfn
> >> user. Unfortunately I could not find a calgary system to test this
> >on.
> >> 
> >> Be aware: I could not test this.
> >> If someone tells me for what kind of machine (and BIOS stuff
> >enabled?)
> >> I should look for, I can try to search for such a platform.
> >> 
> >> Something else: There is quite some duplicate code in kexec-tools
> >when it
> >> is about retrieving the e820 table info (normal kexec vs kdump).
> >> Did you see my cleanups I posted long ago? Do you plan to still clean
> >up
> >> a bit after this series?
> >
> >Yes, I saw them and find some of them are pretty useful for this
> >patchset. I suppose some cleanups can be done later. Feel free to clean
> >up after this patchset is settled.
> >
> >> 
> >>         Thomas
> >> 
> >> 
> >> 
> >> X86: Eliminate saved_max_pfn user in pci-calgary and remove the
> >unused variable
> >> 
> >> Searching for the highest value of RAM and RESERVED memory in kdump
> >case
> >> should be the same as max_pfn of the original kernel.
> >> At least this is always the case as long as type usable RAM is the
> >highest
> >> entry in original e820 map.
> >> 
> >> Signed-off-by: Thomas Renninger <trenn at suse.de>
> >> 
> >> diff --git a/arch/x86/include/asm/e820.h
> >b/arch/x86/include/asm/e820.h
> >> index 779c2ef..712173e 100644
> >> --- a/arch/x86/include/asm/e820.h
> >> +++ b/arch/x86/include/asm/e820.h
> >> @@ -49,6 +49,7 @@ static inline void early_memtest(unsigned long
> >start, unsigned long end)
> >>  #endif
> >>  
> >>  extern unsigned long e820_end_of_ram_pfn(void);
> >> +extern unsigned long e820_end_of_e820_pfn(void);
> >>  extern unsigned long e820_end_of_low_ram_pfn(void);
> >>  extern u64 early_reserve_e820(u64 sizet, u64 align);
> >>  
> >> diff --git a/arch/x86/kernel/e820.c b/arch/x86/kernel/e820.c
> >> index 988c00a..699e8fe 100644
> >> --- a/arch/x86/kernel/e820.c
> >> +++ b/arch/x86/kernel/e820.c
> >> @@ -757,7 +757,7 @@ u64 __init early_reserve_e820(u64 size, u64
> >align)
> >>  /*
> >>   * Find the highest page frame number we have available
> >>   */
> >> -static unsigned long __init e820_end_pfn(unsigned long limit_pfn,
> >unsigned type)
> >> +unsigned long __init e820_end_pfn(unsigned long limit_pfn, unsigned
> >type)
> >>  {
> >>  	int i;
> >>  	unsigned long last_pfn = 0;
> >> @@ -796,6 +796,12 @@ unsigned long __init e820_end_of_ram_pfn(void)
> >>  	return e820_end_pfn(MAX_ARCH_PFN, E820_RAM);
> >>  }
> >>  
> >> +unsigned long __init e820_end_of_e820_pfn(void)
> >> +{
> >> +	return max(e820_end_pfn(MAX_ARCH_PFN, E820_RAM),
> >> +		   e820_end_pfn(MAX_ARCH_PFN, E820_RESERVED);
> >> +}
> >> +
> >>  unsigned long __init e820_end_of_low_ram_pfn(void)
> >>  {
> >>  	return e820_end_pfn(1UL<<(32 - PAGE_SHIFT), E820_RAM);
> >> @@ -847,14 +853,6 @@ static int __init parse_memmap_one(char *p)
> >>  		return -EINVAL;
> >>  
> >>  	if (!strncmp(p, "exactmap", 8)) {
> >> -#ifdef CONFIG_CRASH_DUMP
> >> -		/*
> >> -		 * If we are doing a crash dump, we still need to know
> >> -		 * the real mem size before original memory map is
> >> -		 * reset.
> >> -		 */
> >> -		saved_max_pfn = e820_end_of_ram_pfn();
> >> -#endif
> >>  		e820.nr_map = 0;
> >>  		userdef = 1;
> >>  		return 0;
> >> diff --git a/arch/x86/kernel/pci-calgary_64.c
> >b/arch/x86/kernel/pci-calgary_64.c
> >> index 299d493..89ae766 100644
> >> --- a/arch/x86/kernel/pci-calgary_64.c
> >> +++ b/arch/x86/kernel/pci-calgary_64.c
> >> @@ -1371,6 +1371,7 @@ int __init detect_calgary(void)
> >>  	unsigned long ptr;
> >>  	unsigned int offset, prev_offset;
> >>  	int ret;
> >> +	unsigned long orig_max_pfn = max_pfn;
> >>  
> >>  	/*
> >>  	 * if the user specified iommu=off or iommu=soft or we found
> >> @@ -1418,8 +1419,10 @@ int __init detect_calgary(void)
> >>  		return -ENOMEM;
> >>  	}
> >>  
> >> -	specified_table_size = determine_tce_table_size((is_kdump_kernel()
> >?
> >> -					saved_max_pfn : max_pfn) * PAGE_SIZE);
> >> +	if (is_kdump_kernel())
> >> +		orig_max_pfn = e820_end_of_e820_pfn();
> >> +	specified_table_size = determine_tce_table_size(orig_max_pfn
> >> +							* PAGE_SIZE);
> >>  
> >>  	for (bus = 0; bus < MAX_PHB_BUS_NUM; bus++) {
> >>  		struct calgary_bus_info *info = &bus_info[bus];
> >> diff --git a/include/linux/crash_dump.h b/include/linux/crash_dump.h
> >> index 7032518..bce4d97 100644
> >> --- a/include/linux/crash_dump.h
> >> +++ b/include/linux/crash_dump.h
> >> @@ -87,5 +87,4 @@ extern void unregister_oldmem_pfn_is_ram(void);
> >>  static inline int is_kdump_kernel(void) { return 0; }
> >>  #endif /* CONFIG_CRASH_DUMP */
> >>  
> >> -extern unsigned long saved_max_pfn;
> >>  #endif /* LINUX_CRASHDUMP_H */
> >> diff --git a/kernel/crash_dump.c b/kernel/crash_dump.c
> >> index c766ee5..9d50486 100644
> >> --- a/kernel/crash_dump.c
> >> +++ b/kernel/crash_dump.c
> >> @@ -5,12 +5,6 @@
> >>  #include <linux/export.h>
> >>  
> >>  /*
> >> - * If we have booted due to a crash, max_pfn will be a very low
> >value. We need
> >> - * to know the amount of memory that the previous kernel used.
> >> - */
> >> -unsigned long saved_max_pfn;
> >> -
> >> -/*
> >>   * stores the physical address of elf header of crash image
> >>   *
> >>   * Note: elfcorehdr_addr is not just limited to vmcore. It is also
> >used by
> >> 
> 
> -- 
> Sent from my mobile phone.  Please pardon brevity and lack of formatting.


From vgoyal at redhat.com  Mon Feb 24 10:22:05 2014
From: vgoyal at redhat.com (Vivek Goyal)
Date: Mon, 24 Feb 2014 10:22:05 -0500
Subject: [PATCH v2 0/4] kexec-tools, x86: E820 memmap pass for kdump
In-Reply-To: <20140224145841.GE1262@dhcp-17-89.nay.redhat.com>
References: <1392888512-4473-1-git-send-email-chaowang@redhat.com>
 <2680313.u921kQOFS9@skinner>
 <20140224145841.GE1262@dhcp-17-89.nay.redhat.com>
Message-ID: <20140224152205.GC4631@redhat.com>

On Mon, Feb 24, 2014 at 10:58:41PM +0800, WANG Chao wrote:
[..]
> > Approaches to avoid saved_max_pfn in calgary case:
> >   1) If done correctly from the beginning, the TCE table size would have
> >      been exposed via /sys and kexec-tools could simply add:
> >      calgary="128k|512K...|8M" which is already caught by pci-calgary and
> >      saved_max_pfn is not needed/touched anymore.
> >      -> Disadvantage: needs a new sysfs entry
> >   2) When finding max_pfn for calgary table size usage, we could try in 
> >      kdump case to use the highest memory (RAM or RESERVED) showing up
> >      in e820 map.
> 
> How could this replace saved_max_pfn? The highest memory in kdump can't
> necessarily be the real ram size. In kdump, RAM range is just part of the real
> ram, not mentioning we don't pass RESERVED range to kdump E820.

I vaguely remember there was some discussion about passing first kerne's
RAM as special reserved ranges. Say E820_RESERVED_KDUMP. And use that
to figure out saved_max_pfn.

I personally feel that just create a new command line parameter
"saved_max_pfn" and pass it to second kernel and be done with it. Modify
calgary code to first look for saved_max_pfn and if not present, calculate
saved_max_pfn from e820.

saved_max_pfn command line option is pretty ugly, not sure what are the
better options here.

Thanks
Vivek


From vgoyal at redhat.com  Mon Feb 24 10:24:27 2014
From: vgoyal at redhat.com (Vivek Goyal)
Date: Mon, 24 Feb 2014 10:24:27 -0500
Subject: [PATCH v2 0/4] kexec-tools, x86: E820 memmap pass for kdump
In-Reply-To: <20140224151103.GB4631@redhat.com>
References: <1392888512-4473-1-git-send-email-chaowang@redhat.com>
 <2680313.u921kQOFS9@skinner>
 <20140224145841.GE1262@dhcp-17-89.nay.redhat.com>
 <7125bd4c-b394-4180-b564-f2002c9d9a2e@email.android.com>
 <20140224151103.GB4631@redhat.com>
Message-ID: <20140224152427.GD4631@redhat.com>

On Mon, Feb 24, 2014 at 10:11:03AM -0500, Vivek Goyal wrote:
> On Mon, Feb 24, 2014 at 07:03:07AM -0800, H. Peter Anvin wrote:
> > First question is if Calgary even exists anymore and if so if someone actually cares about it enough to maintain it.
> 
> Atleast MAINTAINERS file says it is maintained.
> 
> CALGARY x86-64 IOMMU
> M:      Muli Ben-Yehuda <muli at il.ibm.com>
> M:      "Jon D. Mason" <jdmason at kudzu.us>
> L:      discuss at x86-64.org
> S:      Maintained
> F:      arch/x86/kernel/pci-calgary_64.c
> F:      arch/x86/kernel/tce_64.c
> F:      arch/x86/include/asm/calgary.h
> F:      arch/x86/include/asm/tce.h
> 
> 
> I am add maintainers to CC list and they can shed more light on if
> calgary still exists and if somebody actually cares about it.

Jon,

Muli's mail is bouncing. Is he still maintaining calgary and is his
mail id still valid as mentioned in MAINTAINERS entry above.

Thanks
Vivek


From hpa at zytor.com  Mon Feb 24 10:27:15 2014
From: hpa at zytor.com (H. Peter Anvin)
Date: Mon, 24 Feb 2014 07:27:15 -0800
Subject: [PATCH v2 0/4] kexec-tools, x86: E820 memmap pass for kdump
In-Reply-To: <20140224152205.GC4631@redhat.com>
References: <1392888512-4473-1-git-send-email-chaowang@redhat.com>
 <2680313.u921kQOFS9@skinner>
 <20140224145841.GE1262@dhcp-17-89.nay.redhat.com>
 <20140224152205.GC4631@redhat.com>
Message-ID: <5458fa7d-ca13-4c2a-bd76-344ceb7679cb@email.android.com>

I would like to see if there is any actual use for it before doing anything else.  The Calgary code may just be off.

On February 24, 2014 7:22:05 AM PST, Vivek Goyal <vgoyal at redhat.com> wrote:
>On Mon, Feb 24, 2014 at 10:58:41PM +0800, WANG Chao wrote:
>[..]
>> > Approaches to avoid saved_max_pfn in calgary case:
>> >   1) If done correctly from the beginning, the TCE table size would
>have
>> >      been exposed via /sys and kexec-tools could simply add:
>> >      calgary="128k|512K...|8M" which is already caught by
>pci-calgary and
>> >      saved_max_pfn is not needed/touched anymore.
>> >      -> Disadvantage: needs a new sysfs entry
>> >   2) When finding max_pfn for calgary table size usage, we could
>try in 
>> >      kdump case to use the highest memory (RAM or RESERVED) showing
>up
>> >      in e820 map.
>> 
>> How could this replace saved_max_pfn? The highest memory in kdump
>can't
>> necessarily be the real ram size. In kdump, RAM range is just part of
>the real
>> ram, not mentioning we don't pass RESERVED range to kdump E820.
>
>I vaguely remember there was some discussion about passing first
>kerne's
>RAM as special reserved ranges. Say E820_RESERVED_KDUMP. And use that
>to figure out saved_max_pfn.
>
>I personally feel that just create a new command line parameter
>"saved_max_pfn" and pass it to second kernel and be done with it.
>Modify
>calgary code to first look for saved_max_pfn and if not present,
>calculate
>saved_max_pfn from e820.
>
>saved_max_pfn command line option is pretty ugly, not sure what are the
>better options here.
>
>Thanks
>Vivek

-- 
Sent from my mobile phone.  Please pardon brevity and lack of formatting.


From hpa at zytor.com  Mon Feb 24 10:28:02 2014
From: hpa at zytor.com (H. Peter Anvin)
Date: Mon, 24 Feb 2014 07:28:02 -0800
Subject: [PATCH v2 0/4] kexec-tools, x86: E820 memmap pass for kdump
In-Reply-To: <20140224152427.GD4631@redhat.com>
References: <1392888512-4473-1-git-send-email-chaowang@redhat.com>
 <2680313.u921kQOFS9@skinner>
 <20140224145841.GE1262@dhcp-17-89.nay.redhat.com>
 <7125bd4c-b394-4180-b564-f2002c9d9a2e@email.android.com>
 <20140224151103.GB4631@redhat.com> <20140224152427.GD4631@redhat.com>
Message-ID: <c264cd10-2c97-4f03-bb8d-c6ba018ecc03@email.android.com>

I think Muli had moved on a while ago.

On February 24, 2014 7:24:27 AM PST, Vivek Goyal <vgoyal at redhat.com> wrote:
>On Mon, Feb 24, 2014 at 10:11:03AM -0500, Vivek Goyal wrote:
>> On Mon, Feb 24, 2014 at 07:03:07AM -0800, H. Peter Anvin wrote:
>> > First question is if Calgary even exists anymore and if so if
>someone actually cares about it enough to maintain it.
>> 
>> Atleast MAINTAINERS file says it is maintained.
>> 
>> CALGARY x86-64 IOMMU
>> M:      Muli Ben-Yehuda <muli at il.ibm.com>
>> M:      "Jon D. Mason" <jdmason at kudzu.us>
>> L:      discuss at x86-64.org
>> S:      Maintained
>> F:      arch/x86/kernel/pci-calgary_64.c
>> F:      arch/x86/kernel/tce_64.c
>> F:      arch/x86/include/asm/calgary.h
>> F:      arch/x86/include/asm/tce.h
>> 
>> 
>> I am add maintainers to CC list and they can shed more light on if
>> calgary still exists and if somebody actually cares about it.
>
>Jon,
>
>Muli's mail is bouncing. Is he still maintaining calgary and is his
>mail id still valid as mentioned in MAINTAINERS entry above.
>
>Thanks
>Vivek

-- 
Sent from my mobile phone.  Please pardon brevity and lack of formatting.


From trenn at suse.de  Mon Feb 24 10:34:26 2014
From: trenn at suse.de (Thomas Renninger)
Date: Mon, 24 Feb 2014 16:34:26 +0100
Subject: [PATCH v2 0/4] kexec-tools, x86: E820 memmap pass for kdump
In-Reply-To: <20140224152205.GC4631@redhat.com>
References: <1392888512-4473-1-git-send-email-chaowang@redhat.com>
 <20140224145841.GE1262@dhcp-17-89.nay.redhat.com>
 <20140224152205.GC4631@redhat.com>
Message-ID: <1972414.2B2S29ZK0k@skinner>

On Monday, February 24, 2014 10:22:05 AM Vivek Goyal wrote:
> On Mon, Feb 24, 2014 at 10:58:41PM +0800, WANG Chao wrote:
> [..]
> 
> > > Approaches to avoid saved_max_pfn in calgary case:
> > >   1) If done correctly from the beginning, the TCE table size would have
> > >   
> > >      been exposed via /sys and kexec-tools could simply add:
> > >      calgary="128k|512K...|8M" which is already caught by pci-calgary
> > >      and
> > >      saved_max_pfn is not needed/touched anymore.
> > >      -> Disadvantage: needs a new sysfs entry
> > >   
> > >   2) When finding max_pfn for calgary table size usage, we could try in
> > >   
> > >      kdump case to use the highest memory (RAM or RESERVED) showing up
> > >      in e820 map.
> > 
> > How could this replace saved_max_pfn? The highest memory in kdump can't
> > necessarily be the real ram size. In kdump, RAM range is just part of the
> > real ram, not mentioning we don't pass RESERVED range to kdump E820.
I expected you pass RAM that must not be used as RESERVED. Then, still 
depending on which mem type is the last one, it might have worked.
 
> I vaguely remember there was some discussion about passing first kerne's
> RAM as special reserved ranges. Say E820_RESERVED_KDUMP. And use that
> to figure out saved_max_pfn.
> 
> I personally feel that just create a new command line parameter
> "saved_max_pfn" and pass it to second kernel and be done with it. Modify
> calgary code to first look for saved_max_pfn and if not present, calculate
> saved_max_pfn from e820.
> 
> saved_max_pfn command line option is pretty ugly, not sure what are the
> better options here.

It should be done like that:

The specified_table_size variable must be exported via sysfs.
If kexec-tools finds it existing it can pass in the table size via
boot param:
calgary=
(compare with calgary_parse_options() in arch/x86/kernel/pci-calgary_64.c).

Then the table size detection (for which saved_max_pfn is needed) would
fall off in kdump case.

If this really is supported/relevant, I can send something, but it
would need kexec-tools code as well.

          Thomas


From vgoyal at redhat.com  Mon Feb 24 10:45:19 2014
From: vgoyal at redhat.com (Vivek Goyal)
Date: Mon, 24 Feb 2014 10:45:19 -0500
Subject: [PATCH v2 0/4] kexec-tools, x86: E820 memmap pass for kdump
In-Reply-To: <1972414.2B2S29ZK0k@skinner>
References: <1392888512-4473-1-git-send-email-chaowang@redhat.com>
 <20140224145841.GE1262@dhcp-17-89.nay.redhat.com>
 <20140224152205.GC4631@redhat.com> <1972414.2B2S29ZK0k@skinner>
Message-ID: <20140224154518.GE4631@redhat.com>

On Mon, Feb 24, 2014 at 04:34:26PM +0100, Thomas Renninger wrote:

[..]
> > > How could this replace saved_max_pfn? The highest memory in kdump can't
> > > necessarily be the real ram size. In kdump, RAM range is just part of the
> > > real ram, not mentioning we don't pass RESERVED range to kdump E820.
> I expected you pass RAM that must not be used as RESERVED. Then, still 
> depending on which mem type is the last one, it might have worked.

No we don't. There is a proposal though to pass first kernel's reserved
ranges to second kernel as SGI folks need that somehow.

Thanks
Vivek


From hpa at zytor.com  Mon Feb 24 10:50:19 2014
From: hpa at zytor.com (H. Peter Anvin)
Date: Mon, 24 Feb 2014 07:50:19 -0800
Subject: [PATCH v2 0/4] kexec-tools, x86: E820 memmap pass for kdump
In-Reply-To: <20140224154518.GE4631@redhat.com>
References: <1392888512-4473-1-git-send-email-chaowang@redhat.com>
 <20140224145841.GE1262@dhcp-17-89.nay.redhat.com>
 <20140224152205.GC4631@redhat.com> <1972414.2B2S29ZK0k@skinner>
 <20140224154518.GE4631@redhat.com>
Message-ID: <f0e5bc8f-8771-4faa-86a1-a46120a9aa1f@email.android.com>

Not just SGI, I don't think. You definitely need to do this.

On February 24, 2014 7:45:19 AM PST, Vivek Goyal <vgoyal at redhat.com> wrote:
>On Mon, Feb 24, 2014 at 04:34:26PM +0100, Thomas Renninger wrote:
>
>[..]
>> > > How could this replace saved_max_pfn? The highest memory in kdump
>can't
>> > > necessarily be the real ram size. In kdump, RAM range is just
>part of the
>> > > real ram, not mentioning we don't pass RESERVED range to kdump
>E820.
>> I expected you pass RAM that must not be used as RESERVED. Then,
>still 
>> depending on which mem type is the last one, it might have worked.
>
>No we don't. There is a proposal though to pass first kernel's reserved
>ranges to second kernel as SGI folks need that somehow.
>
>Thanks
>Vivek

-- 
Sent from my mobile phone.  Please pardon brevity and lack of formatting.


From vgoyal at redhat.com  Mon Feb 24 10:59:02 2014
From: vgoyal at redhat.com (Vivek Goyal)
Date: Mon, 24 Feb 2014 10:59:02 -0500
Subject: [PATCH v2 0/4] kexec-tools, x86: E820 memmap pass for kdump
In-Reply-To: <f0e5bc8f-8771-4faa-86a1-a46120a9aa1f@email.android.com>
References: <1392888512-4473-1-git-send-email-chaowang@redhat.com>
 <20140224145841.GE1262@dhcp-17-89.nay.redhat.com>
 <20140224152205.GC4631@redhat.com> <1972414.2B2S29ZK0k@skinner>
 <20140224154518.GE4631@redhat.com>
 <f0e5bc8f-8771-4faa-86a1-a46120a9aa1f@email.android.com>
Message-ID: <20140224155902.GG4631@redhat.com>

On Mon, Feb 24, 2014 at 07:50:19AM -0800, H. Peter Anvin wrote:
> Not just SGI, I don't think. You definitely need to do this.

Ok. Once we have resolved the calgary issue and merged the patches
where kdump memory ranges are passed in bootparams, we can take care
of passing reserved ranges too. One thing at a time.

Solving calgary issue is important though as this has been blocking
new patches for quite some time now.

Thanks
Vivek


From vgoyal at redhat.com  Mon Feb 24 11:41:31 2014
From: vgoyal at redhat.com (Vivek Goyal)
Date: Mon, 24 Feb 2014 11:41:31 -0500
Subject: [PATCH 06/11] kexec: A new system call, kexec_file_load, for in
 kernel kexec
In-Reply-To: <20140221145910.GE11531@pd.tnic>
References: <1390849071-21989-1-git-send-email-vgoyal@redhat.com>
 <1390849071-21989-7-git-send-email-vgoyal@redhat.com>
 <20140221145910.GE11531@pd.tnic>
Message-ID: <20140224164131.GJ4631@redhat.com>

On Fri, Feb 21, 2014 at 03:59:10PM +0100, Borislav Petkov wrote:

[..]
> You might want to run it through checkpatch - some of them are actually,
> to my surprise, legitimate :)

Thanks for having a look at the patches. I will run patches through
checkpatch before next posting.

[..]
> > +struct kexec_buf {
> > +	struct kimage *image;
> > +	char *buffer;
> > +	unsigned long bufsz;
> > +	unsigned long memsz;
> > +	unsigned long buf_align;
> > +	unsigned long buf_min;
> > +	unsigned long buf_max;
> > +	int top_down;		/* allocate from top of memory hole */
> 
> Looks like this wants to be a bool.

Will change.

> 
> ...
> 
> > diff --git a/include/uapi/linux/kexec.h b/include/uapi/linux/kexec.h
> > index d6629d4..5fddb1b 100644
> > --- a/include/uapi/linux/kexec.h
> > +++ b/include/uapi/linux/kexec.h
> > @@ -13,6 +13,10 @@
> >  #define KEXEC_PRESERVE_CONTEXT	0x00000002
> >  #define KEXEC_ARCH_MASK		0xffff0000
> >  
> > +/* Kexec file load interface flags */
> > +#define KEXEC_FILE_UNLOAD	0x00000001
> > +#define KEXEC_FILE_ON_CRASH	0x00000002
> 
> BIT()

What's that?

> 
> > +
> >  /* These values match the ELF architecture values.
> >   * Unless there is a good reason that should continue to be the case.
> >   */
> > diff --git a/kernel/kexec.c b/kernel/kexec.c
> > index c0944b2..b28578a 100644
> > --- a/kernel/kexec.c
> > +++ b/kernel/kexec.c
> > @@ -123,6 +123,11 @@ static struct page *kimage_alloc_page(struct kimage *image,
> >  				       gfp_t gfp_mask,
> >  				       unsigned long dest);
> >  
> > +void kimage_set_start_addr(struct kimage *image, unsigned long start)
> > +{
> > +	image->start = start;
> > +}
> 
> Why a separate function? It is used only once in the next patch.

Right now there is only one user. But once other image loader support
comes along or other arches support file based kexec, they can make
use of same function.

This is a pretty important modification as it decides what's the starting
point of next kernel image. I wanted to make it a function callable by
users who wanted to modify it instead of of letting them directly 
modify image->start.

[..]
> > +	/* Call arch image load handlers */
> > +	ldata = arch_kexec_kernel_image_load(image,
> > +			image->kernel_buf, image->kernel_buf_len,
> > +			image->initrd_buf, image->initrd_buf_len,
> > +			image->cmdline_buf, image->cmdline_buf_len);
> > +
> > +	if (IS_ERR(ldata)) {
> > +		ret = PTR_ERR(ldata);
> > +		goto out;
> > +	}
> > +
> > +	image->image_loader_data = ldata;
> > +out:
> > +	return ret;
> 
> You probably want to drop this "out:" label and simply return the error
> value directly in each error path above for simplicity.
> 

Ok, will do. I don't seem to be doing anything in "out" except return ret.
So will get rid of this label and return early in error path.

> > +static int kimage_file_normal_alloc(struct kimage **rimage, int kernel_fd,
> > +		int initrd_fd, const char __user *cmdline_ptr,
> > +		unsigned long cmdline_len)
> > +{
> > +	int result;
> > +	struct kimage *image;
> > +
> > +	/* Allocate and initialize a controlling structure */
> > +	image = do_kimage_alloc_init();
> > +	if (!image)
> > +		return -ENOMEM;
> > +
> > +	image->file_mode = 1;
> > +	image->file_handler_idx = -1;
> > +
> > +	result = kimage_file_prepare_segments(image, kernel_fd, initrd_fd,
> > +			cmdline_ptr, cmdline_len);
> > +	if (result)
> > +		goto out_free_image;
> > +
> > +	result = sanity_check_segment_list(image);
> > +	if (result)
> > +		goto out_free_post_load_bufs;
> 
> Dunno, it could probably be a larger restructuring effort but if you
> do load a segment and sanity-check it right after loading, instead of
> loading all of them first and then iterating over them, you could save
> yourself some work in the error case when a segment fails the check.
> 

Could be. I am trying to reuse exisitng code. In current code, user space
passes a list of segments and then kernel calls this function to make sure
all the segments passed in make sense.

Here also arch dependent part of kernel is preparing a list of segments
wanted and then generic code is reusing the existing function to make
sure segment list is sane. I like code reuse part of it.

Also, segment loading has not taken place yet. They are loaded later
in kimage_load_segment().

[..]
> > +	/* Walk the RAM ranges and allocate a suitable range for the buffer */
> > +	walk_system_ram_res(0, -1, kbuf, walk_ram_range_callback);
> > +
> > +	kbuf->image = NULL;
> > +	kfree(kbuf);
> 
> This is freed after kzalloc'ing it a bit earlier, why not make it a
> stack variable for simplicity? struct kexec_buf doesn't seem that
> large...

Ya, I was not sure whether to make it stack variable or allocate
dynamically. It seems to be roughly 60bytes in size on 64bit. I guess
I will convert it into a stack variable.

Thanks
Vivek


From hpa at zytor.com  Mon Feb 24 14:08:11 2014
From: hpa at zytor.com (H. Peter Anvin)
Date: Mon, 24 Feb 2014 11:08:11 -0800
Subject: [PATCH 07/11] kexec: Create a relocatable object called purgatory
In-Reply-To: <1390849071-21989-8-git-send-email-vgoyal@redhat.com>
References: <1390849071-21989-1-git-send-email-vgoyal@redhat.com>
 <1390849071-21989-8-git-send-email-vgoyal@redhat.com>
Message-ID: <530B989B.8010507@zytor.com>

On 01/27/2014 10:57 AM, Vivek Goyal wrote:
> +
> +/**
> + * memcpy - Copy one area of memory to another
> + * @dest: Where to copy to
> + * @src: Where to copy from
> + * @count: The size of the area.
> + */
> +static void *memcpy(void *dest, const void *src, unsigned long count)
> +{
> +	char *tmp = dest;
> +	const char *s = src;
> +
> +	while (count--)
> +		*tmp++ = *s++;
> +	return dest;
> +}
> +
> +static int memcmp(const void *cs, const void *ct, size_t count)
> +{
> +	const unsigned char *su1, *su2;
> +	int res = 0;
> +
> +	for (su1 = cs, su2 = ct; 0 < count; ++su1, ++su2, count--)
> +		if ((res = *su1 - *su2) != 0)
> +			break;
> +	return res;
> +}
> +

<bikeshed>

There multiple implementations of memcpy(), memcmp() and memset() in
this patchset, and they make my eyes want to bleed (especially
memcmp()).  Can we centralize there, and perhaps even share code with
the stuff in arch/x86/boot already?

</bikeshed>

	-hpa



From chaowang at redhat.com  Mon Feb 24 23:12:55 2014
From: chaowang at redhat.com (WANG Chao)
Date: Tue, 25 Feb 2014 12:12:55 +0800
Subject: More frequent kexec-tools releases
In-Reply-To: <20140206235851.GB19799@verge.net.au>
References: <20140131052304.GC25099@verge.net.au>
 <20140131143047.GA10594@redhat.com>
 <20140204083151.GE30621@verge.net.au>
 <20140204124148.GH17028@verge.net.au>
 <52F18FFA.5060103@cn.fujitsu.com>
 <20140205064906.GB29499@verge.net.au>
 <20140205132015.GA6042@redhat.com>
 <20140206015513.GX5125@verge.net.au>
 <20140206142332.GA3674@redhat.com>
 <20140206235851.GB19799@verge.net.au>
Message-ID: <20140225041255.GA32292@dhcp-17-89.nay.redhat.com>

On 02/07/14 at 08:58am, Simon Horman wrote:
> On Thu, Feb 06, 2014 at 09:23:32AM -0500, Vivek Goyal wrote:
> > On Thu, Feb 06, 2014 at 10:55:13AM +0900, Simon Horman wrote:
> > 
> > [..]
> > > > Thanks Simon. I did git pull but I don't see new tag in my tree. Not sure
> > > > why. 
> > > 
> > > Could you try again? I messed up the push.
> > 
> > It works now. Thanks.
> 
> It seems that a few bugs showed up in 2.0.5, fixes for which
> are now in the git repository. I am thinking it would be a good
> idea to release these as 2.0.6 unless people would rather that I held off.

As you mentioned, I found 2.0.5 doesn't build on i386. I consider these
are major bugs, which deserves a hot fix release as 2.0.6. What do you
think?

Thanks
WANG Chao


From vgoyal at redhat.com  Tue Feb 25 11:43:42 2014
From: vgoyal at redhat.com (Vivek Goyal)
Date: Tue, 25 Feb 2014 11:43:42 -0500
Subject: [PATCH 07/11] kexec: Create a relocatable object called purgatory
In-Reply-To: <530B989B.8010507@zytor.com>
References: <1390849071-21989-1-git-send-email-vgoyal@redhat.com>
 <1390849071-21989-8-git-send-email-vgoyal@redhat.com>
 <530B989B.8010507@zytor.com>
Message-ID: <20140225164342.GC2701@redhat.com>

On Mon, Feb 24, 2014 at 11:08:11AM -0800, H. Peter Anvin wrote:
> On 01/27/2014 10:57 AM, Vivek Goyal wrote:
> > +
> > +/**
> > + * memcpy - Copy one area of memory to another
> > + * @dest: Where to copy to
> > + * @src: Where to copy from
> > + * @count: The size of the area.
> > + */
> > +static void *memcpy(void *dest, const void *src, unsigned long count)
> > +{
> > +	char *tmp = dest;
> > +	const char *s = src;
> > +
> > +	while (count--)
> > +		*tmp++ = *s++;
> > +	return dest;
> > +}
> > +
> > +static int memcmp(const void *cs, const void *ct, size_t count)
> > +{
> > +	const unsigned char *su1, *su2;
> > +	int res = 0;
> > +
> > +	for (su1 = cs, su2 = ct; 0 < count; ++su1, ++su2, count--)
> > +		if ((res = *su1 - *su2) != 0)
> > +			break;
> > +	return res;
> > +}
> > +
> 
> <bikeshed>
> 
> There multiple implementations of memcpy(), memcmp() and memset() in
> this patchset, and they make my eyes want to bleed (especially
> memcmp()).  Can we centralize there, and perhaps even share code with
> the stuff in arch/x86/boot already?
> 
> </bikeshed>

Hi hpa,

There is multiple implementation of memcpy() only (sha256.c and
purgatory.c). I will merge the two and make them use single definition of
memcpy().

I can't see multiple implementation of memcpy() and memcmp() in purgatory
code.

W.r.t sharing the code with arch/x86/boot/, I am not sure how to do it.

I see two implementations of memcpy() under arch/x86/boot.

One is in copy.S. This is assembly code and looks like is supposed to
run in 16bit mode. (code16).

Other one is in compressed/misc.c and there are two definitions, one
for 32bit and one fore 64bit.

I am not sure why there is a need to write memcpy() in assembly when
C will do just fine for my case. I don't have to write two versions of
memcpy() and use it both for 32bit and 64bit.

So I can just make all the purgatory code share same version of memcpy(),
memcmp() and memset(), is that fine. I have taken implementations of
these functions from lib/string.c

Thanks
Vivek

> 
> 	-hpa


From hpa at zytor.com  Tue Feb 25 11:55:42 2014
From: hpa at zytor.com (H. Peter Anvin)
Date: Tue, 25 Feb 2014 08:55:42 -0800
Subject: [PATCH 07/11] kexec: Create a relocatable object called purgatory
In-Reply-To: <20140225164342.GC2701@redhat.com>
References: <1390849071-21989-1-git-send-email-vgoyal@redhat.com>
 <1390849071-21989-8-git-send-email-vgoyal@redhat.com>
 <530B989B.8010507@zytor.com> <20140225164342.GC2701@redhat.com>
Message-ID: <530CCB0E.3060009@zytor.com>

On 02/25/2014 08:43 AM, Vivek Goyal wrote:
> 
> W.r.t sharing the code with arch/x86/boot/, I am not sure how to do it.
> 

Pretty much we have been doing #includes (a bit sad, I know)... there
are already a lot of them between arch/x86/boot,
arch/x86/boot/compressed, and arch/x86/realmode.  In that sense
collecting these "limited environments" together and have these kinds of
stuff together in one place seems like a good idea.

Does purgatory move large amounts of data around?  If so, we probably
*do* want to use rep movsl, but otherwise you're definitely right, using
C code makes more sense.

> I see two implementations of memcpy() under arch/x86/boot.
> 
> One is in copy.S. This is assembly code and looks like is supposed to
> run in 16bit mode. (code16).
> 
> Other one is in compressed/misc.c and there are two definitions, one
> for 32bit and one fore 64bit.

They are basically the 16-, 32-, and 64-bit variants of the same code.

> I am not sure why there is a need to write memcpy() in assembly when
> C will do just fine for my case. I don't have to write two versions of
> memcpy() and use it both for 32bit and 64bit.

The point would be to use the ones we already have.

> So I can just make all the purgatory code share same version of memcpy(),
> memcmp() and memset(), is that fine. I have taken implementations of
> these functions from lib/string.c

It depends on if you care about performance.  For memcpy() and memset()
in particular, the CPU has internally optimized versions of these that
beats C at least on any newer silicon.

	-hpa



From hpa at zytor.com  Tue Feb 25 13:38:24 2014
From: hpa at zytor.com (H. Peter Anvin)
Date: Tue, 25 Feb 2014 10:38:24 -0800
Subject: [PATCH 08/11] kexec-bzImage: Support for loading bzImage using
 64bit entry
In-Reply-To: <1390849071-21989-9-git-send-email-vgoyal@redhat.com>
References: <1390849071-21989-1-git-send-email-vgoyal@redhat.com>
 <1390849071-21989-9-git-send-email-vgoyal@redhat.com>
Message-ID: <530CE320.6000808@zytor.com>

On 01/27/2014 10:57 AM, Vivek Goyal wrote:
> This is loader specific code which can load bzImage and set it up for
> 64bit entry. This does not take care of 32bit entry or real mode entry
> yet.

Is there any use in that?  Real mode entry especially is more than a bit
scary when coming from another kernel already...

	-hpa




From vgoyal at redhat.com  Tue Feb 25 13:43:42 2014
From: vgoyal at redhat.com (Vivek Goyal)
Date: Tue, 25 Feb 2014 13:43:42 -0500
Subject: [PATCH 08/11] kexec-bzImage: Support for loading bzImage using
 64bit entry
In-Reply-To: <530CE320.6000808@zytor.com>
References: <1390849071-21989-1-git-send-email-vgoyal@redhat.com>
 <1390849071-21989-9-git-send-email-vgoyal@redhat.com>
 <530CE320.6000808@zytor.com>
Message-ID: <20140225184342.GF2701@redhat.com>

On Tue, Feb 25, 2014 at 10:38:24AM -0800, H. Peter Anvin wrote:
> On 01/27/2014 10:57 AM, Vivek Goyal wrote:
> > This is loader specific code which can load bzImage and set it up for
> > 64bit entry. This does not take care of 32bit entry or real mode entry
> > yet.
> 
> Is there any use in that?  Real mode entry especially is more than a bit
> scary when coming from another kernel already...

I think 64bit entry should be good for x86_64. When we start supporting
this new system call on x86(32bit), then we can implement 32bit entry 
support (which should not be hard).

I have no plans to implement 16bit entry support. I just wanted to mention
explicitly what is currently supported.

Thanks
Vivek


From vgoyal at redhat.com  Tue Feb 25 13:20:02 2014
From: vgoyal at redhat.com (Vivek Goyal)
Date: Tue, 25 Feb 2014 13:20:02 -0500
Subject: [PATCH 07/11] kexec: Create a relocatable object called purgatory
In-Reply-To: <530CCB0E.3060009@zytor.com>
References: <1390849071-21989-1-git-send-email-vgoyal@redhat.com>
 <1390849071-21989-8-git-send-email-vgoyal@redhat.com>
 <530B989B.8010507@zytor.com> <20140225164342.GC2701@redhat.com>
 <530CCB0E.3060009@zytor.com>
Message-ID: <20140225182002.GD2701@redhat.com>

On Tue, Feb 25, 2014 at 08:55:42AM -0800, H. Peter Anvin wrote:
> On 02/25/2014 08:43 AM, Vivek Goyal wrote:
> > 
> > W.r.t sharing the code with arch/x86/boot/, I am not sure how to do it.
> > 
> 
> Pretty much we have been doing #includes (a bit sad, I know)... there
> are already a lot of them between arch/x86/boot,
> arch/x86/boot/compressed, and arch/x86/realmode.  In that sense
> collecting these "limited environments" together and have these kinds of
> stuff together in one place seems like a good idea.
> 
> Does purgatory move large amounts of data around?  If so, we probably
> *do* want to use rep movsl, but otherwise you're definitely right, using
> C code makes more sense.

No, I don't move lots of data around in purgatory. We just copy backup
region and that's 640KB of data. 

So we don't copy a lot and it is not a performance sensitive path. 

Hence I would like to keep it simple. That is have C version of memcpy()
in purgatory() which works both for 32bit and 64bit and reuse that across
purgatory code.

Please let me know if you don't like the idea and you still think there
should be a shared implementation between arch/x86/boot/ and
arch/x86/purgatory/.

Thanks
Vivek


From ptesarik at suse.cz  Tue Feb 25 14:35:19 2014
From: ptesarik at suse.cz (Petr Tesarik)
Date: Tue, 25 Feb 2014 20:35:19 +0100
Subject: [PATCH 06/11] kexec: A new system call, kexec_file_load, for in
 kernel kexec
In-Reply-To: <20140224164131.GJ4631@redhat.com>
References: <1390849071-21989-1-git-send-email-vgoyal@redhat.com>
 <1390849071-21989-7-git-send-email-vgoyal@redhat.com>
 <20140221145910.GE11531@pd.tnic> <20140224164131.GJ4631@redhat.com>
Message-ID: <20140225203519.77abfa8d@hananiah.suse.cz>

On Mon, 24 Feb 2014 11:41:31 -0500
Vivek Goyal <vgoyal at redhat.com> wrote:

> On Fri, Feb 21, 2014 at 03:59:10PM +0100, Borislav Petkov wrote:
> 
>[...]
> > 
> > ...
> > 
> > > diff --git a/include/uapi/linux/kexec.h b/include/uapi/linux/kexec.h
> > > index d6629d4..5fddb1b 100644
> > > --- a/include/uapi/linux/kexec.h
> > > +++ b/include/uapi/linux/kexec.h
> > > @@ -13,6 +13,10 @@
> > >  #define KEXEC_PRESERVE_CONTEXT	0x00000002
> > >  #define KEXEC_ARCH_MASK		0xffff0000
> > >  
> > > +/* Kexec file load interface flags */
> > > +#define KEXEC_FILE_UNLOAD	0x00000001
> > > +#define KEXEC_FILE_ON_CRASH	0x00000002
> > 
> > BIT()
> 
> What's that?

#define BIT(nr)                 (1UL << (nr))

For my part I'm not convinced it's a better way to do it, unless
Borislav also wanted to suggest adding an enum for the bit number
values...

Petr T


From hpa at zytor.com  Tue Feb 25 16:09:34 2014
From: hpa at zytor.com (H. Peter Anvin)
Date: Tue, 25 Feb 2014 13:09:34 -0800
Subject: [PATCH 07/11] kexec: Create a relocatable object called purgatory
In-Reply-To: <20140225182002.GD2701@redhat.com>
References: <1390849071-21989-1-git-send-email-vgoyal@redhat.com>
 <1390849071-21989-8-git-send-email-vgoyal@redhat.com>
 <530B989B.8010507@zytor.com> <20140225164342.GC2701@redhat.com>
 <530CCB0E.3060009@zytor.com> <20140225182002.GD2701@redhat.com>
Message-ID: <530D068E.4040700@zytor.com>

On 02/25/2014 10:20 AM, Vivek Goyal wrote:
> 
> Please let me know if you don't like the idea and you still think there
> should be a shared implementation between arch/x86/boot/ and
> arch/x86/purgatory/.
> 

That is what I would *prefer*.  There are some other string functions in
arch/x86/boot/string.c which also ought to be sharable (and are in
places already.)

	-hpa



From bp at alien8.de  Tue Feb 25 16:47:48 2014
From: bp at alien8.de (Borislav Petkov)
Date: Tue, 25 Feb 2014 22:47:48 +0100
Subject: [PATCH 06/11] kexec: A new system call, kexec_file_load, for in
 kernel kexec
In-Reply-To: <20140225203519.77abfa8d@hananiah.suse.cz>
References: <1390849071-21989-1-git-send-email-vgoyal@redhat.com>
 <1390849071-21989-7-git-send-email-vgoyal@redhat.com>
 <20140221145910.GE11531@pd.tnic> <20140224164131.GJ4631@redhat.com>
 <20140225203519.77abfa8d@hananiah.suse.cz>
Message-ID: <20140225214748.GA21559@pd.tnic>

On Tue, Feb 25, 2014 at 08:35:19PM +0100, Petr Tesarik wrote:
> #define BIT(nr)                 (1UL << (nr))
> 
> For my part I'm not convinced it's a better way to do it, unless
> Borislav also wanted to suggest adding an enum for the bit number
> values...

Well,

#define KEXEC_FILE_UNLOAD	BIT(1)

is much more readable.

The enum thing is also nice to have but it's not my personal preference.

-- 
Regards/Gruss,
    Boris.

Sent from a fat crate under my desk. Formatting is fine.
--


From vgoyal at redhat.com  Wed Feb 26 09:52:46 2014
From: vgoyal at redhat.com (Vivek Goyal)
Date: Wed, 26 Feb 2014 09:52:46 -0500
Subject: [PATCH 07/11] kexec: Create a relocatable object called purgatory
In-Reply-To: <530D068E.4040700@zytor.com>
References: <1390849071-21989-1-git-send-email-vgoyal@redhat.com>
 <1390849071-21989-8-git-send-email-vgoyal@redhat.com>
 <530B989B.8010507@zytor.com> <20140225164342.GC2701@redhat.com>
 <530CCB0E.3060009@zytor.com> <20140225182002.GD2701@redhat.com>
 <530D068E.4040700@zytor.com>
Message-ID: <20140226145246.GA23022@redhat.com>

On Tue, Feb 25, 2014 at 01:09:34PM -0800, H. Peter Anvin wrote:
> On 02/25/2014 10:20 AM, Vivek Goyal wrote:
> > 
> > Please let me know if you don't like the idea and you still think there
> > should be a shared implementation between arch/x86/boot/ and
> > arch/x86/purgatory/.
> > 
> 
> That is what I would *prefer*.  There are some other string functions in
> arch/x86/boot/string.c which also ought to be sharable (and are in
> places already.)
> 

Ok, I will look into it. Possibly move optimized 32bit and 64bit version of
memcpy in arch/x86/boot/string.c and include it in purgaotry files.

Or we could define new C version of routines in boot/string.c and leave
optimized versions where they are.

Thanks
Vivek


From bp at alien8.de  Wed Feb 26 10:37:09 2014
From: bp at alien8.de (Borislav Petkov)
Date: Wed, 26 Feb 2014 16:37:09 +0100
Subject: [PATCH 06/11] kexec: A new system call, kexec_file_load, for in
 kernel kexec
In-Reply-To: <20140224164131.GJ4631@redhat.com>
References: <1390849071-21989-1-git-send-email-vgoyal@redhat.com>
 <1390849071-21989-7-git-send-email-vgoyal@redhat.com>
 <20140221145910.GE11531@pd.tnic> <20140224164131.GJ4631@redhat.com>
Message-ID: <20140226153709.GE22639@pd.tnic>

On Mon, Feb 24, 2014 at 11:41:31AM -0500, Vivek Goyal wrote:
> Right now there is only one user. But once other image loader support
> comes along or other arches support file based kexec, they can make
> use of same function.
> 
> This is a pretty important modification as it decides what's the starting
> point of next kernel image. I wanted to make it a function callable by
> users who wanted to modify it instead of of letting them directly 
> modify image->start.

But are you expecting any other way to set image->start by the other
arches/image loaders?

> Could be. I am trying to reuse exisitng code. In current code, user space
> passes a list of segments and then kernel calls this function to make sure
> all the segments passed in make sense.
> 
> Here also arch dependent part of kernel is preparing a list of segments
> wanted and then generic code is reusing the existing function to make
> sure segment list is sane. I like code reuse part of it.

Right, ok, this was just an idea. Maybe not worth it.

Thanks.

-- 
Regards/Gruss,
    Boris.

Sent from a fat crate under my desk. Formatting is fine.
--


From bp at alien8.de  Wed Feb 26 11:00:08 2014
From: bp at alien8.de (Borislav Petkov)
Date: Wed, 26 Feb 2014 17:00:08 +0100
Subject: [PATCH 07/11] kexec: Create a relocatable object called purgatory
In-Reply-To: <1390849071-21989-8-git-send-email-vgoyal@redhat.com>
References: <1390849071-21989-1-git-send-email-vgoyal@redhat.com>
 <1390849071-21989-8-git-send-email-vgoyal@redhat.com>
Message-ID: <20140226160008.GF22639@pd.tnic>

On Mon, Jan 27, 2014 at 01:57:47PM -0500, Vivek Goyal wrote:
> Create a stand alone relocatable object purgatory which runs between two
> kernels. This name, concept and some code has been taken from kexec-tools.

... and the concept probably originates from Dante's "Divine Comedy" :-P

> Idea is that this code runs after a crash and it runs in minimal environment.
> So keep it separate from rest of the kernel and in long term we will have
> to practically do no maintenance of this code.
> 
> This code also has the logic to do verify sha256 hashes of various
> segments which have been loaded into memory. So first we verify that
> the kernel we are jumping to is fine and has not been corrupted and
> make progress only if checsums are verified.
> 
> This code also takes care of copying some memory contents to backup region.
> 
> sha256 hash related code has been taken from crypto/sha256_generic.c. I
> could not call into functions exported by sha256_generic.c directly as
> we don't link against the kernel. Purgatory is a stand alone object.
> 
> Also sha256_generic.c is supposed to work with higher level crypto
> abstrations and API and there was no point in importing all that in
> purgatory. So instead of doing #include on sha256_generic.c I just
> copied relevant portions of code into arch/x86/purgatory/sha256.c. Now
> we shouldn't have to touch this code at all. Do let me know if there are
> better ways to handle it.

Ok, but what about configurable encryption algorithms? Maybe there are
people who don't want to use sha-2 and prefer something else instead.

> Signed-off-by: Vivek Goyal <vgoyal at redhat.com>

Also checkpatch:

...
total: 429 errors, 5 warnings, 1409 lines checked

> diff --git a/arch/x86/Makefile b/arch/x86/Makefile
> index 13b22e0..fedcd16 100644
> --- a/arch/x86/Makefile
> +++ b/arch/x86/Makefile
> @@ -160,6 +160,11 @@ archscripts: scripts_basic
>  archheaders:
>  	$(Q)$(MAKE) $(build)=arch/x86/syscalls all
>  
> +archprepare:
> +ifeq ($(CONFIG_KEXEC),y)
> +	$(Q)$(MAKE) $(build)=arch/x86/purgatory arch/x86/purgatory/kexec-purgatory.c
> +endif

I wonder if this could be put into arch/x86/boot/ and built there too...
But hpa said that already.

...

> diff --git a/arch/x86/purgatory/entry64.S b/arch/x86/purgatory/entry64.S
> new file mode 100644
> index 0000000..e405c0f
> --- /dev/null
> +++ b/arch/x86/purgatory/entry64.S
> @@ -0,0 +1,111 @@
> +/*
> + * Copyright (C) 2003,2004  Eric Biederman (ebiederm at xmission.com)
> + * Copyright (C) 2014  Red Hat Inc.
> +
> + * Author(s): Vivek Goyal <vgoyal at redhat.com>
> + *
> + * This code has been taken from kexec-tools.
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License as published by
> + * the Free Software Foundation (version 2 of the License).
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + * GNU General Public License for more details.
> + *
> + * You should have received a copy of the GNU General Public License
> + * along with this program; if not, write to the Free Software
> + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.

Yeah, can we drop this boilerplate gunk and refer to COPYING instead.

> + */
> +
> +	.text
> +	.balign 16
> +	.code64
> +	.globl entry64, entry64_regs
> +
> +
> +entry64:
> +	/* Setup a gdt that should be preserved */
> +	lgdt gdt(%rip)
> +
> +	/* load the data segments */
> +	movl    $0x18, %eax     /* data segment */
> +	movl    %eax, %ds
> +	movl    %eax, %es
> +	movl    %eax, %ss
> +	movl    %eax, %fs
> +	movl    %eax, %gs
> +
> +	/* Setup new stack */
> +	leaq    stack_init(%rip), %rsp
> +	pushq   $0x10 /* CS */
> +	leaq    new_cs_exit(%rip), %rax
> +	pushq   %rax
> +	lretq
> +new_cs_exit:
> +
> +	/* Load the registers */
> +	movq	rax(%rip), %rax
> +	movq	rbx(%rip), %rbx
> +	movq	rcx(%rip), %rcx
> +	movq	rdx(%rip), %rdx
> +	movq	rsi(%rip), %rsi
> +	movq	rdi(%rip), %rdi
> +	movq    rsp(%rip), %rsp
> +	movq	rbp(%rip), %rbp
> +	movq	r8(%rip), %r8
> +	movq	r9(%rip), %r9
> +	movq	r10(%rip), %r10
> +	movq	r11(%rip), %r11
> +	movq	r12(%rip), %r12
> +	movq	r13(%rip), %r13
> +	movq	r14(%rip), %r14
> +	movq	r15(%rip), %r15

Huh, is the purpose to simply clear the arch registers here?

	xor %reg,%reg

?

If so, you don't need the entry64_regs and below definitions at all.
>From the looks of it, though, something's populating those regs before
we jump to rip below...

> +
> +	/* Jump to the new code... */
> +	jmpq	*rip(%rip)
> +
> +	.section ".rodata"
> +	.balign 4
> +entry64_regs:
> +rax:	.quad 0x00000000
> +rbx:	.quad 0x00000000
> +rcx:	.quad 0x00000000
> +rdx:	.quad 0x00000000
> +rsi:	.quad 0x00000000
> +rdi:	.quad 0x00000000
> +rsp:	.quad 0x00000000
> +rbp:	.quad 0x00000000
> +r8:	.quad 0x00000000
> +r9:	.quad 0x00000000
> +r10:	.quad 0x00000000
> +r11:	.quad 0x00000000
> +r12:	.quad 0x00000000
> +r13:	.quad 0x00000000
> +r14:	.quad 0x00000000
> +r15:	.quad 0x00000000
> +rip:	.quad 0x00000000
> +	.size entry64_regs, . - entry64_regs
> +
> +	/* GDT */
> +	.section ".rodata"
> +	.balign 16
> +gdt:
> +	/* 0x00 unusable segment
> +	 * 0x08 unused
> +	 * so use them as gdt ptr
> +	 */
> +	.word gdt_end - gdt - 1
> +	.quad gdt
> +	.word 0, 0, 0
> +
> +	/* 0x10 4GB flat code segment */
> +	.word 0xFFFF, 0x0000, 0x9A00, 0x00AF
> +
> +	/* 0x18 4GB flat data segment */
> +	.word 0xFFFF, 0x0000, 0x9200, 0x00CF
> +gdt_end:
> +stack:	.quad   0, 0
> +stack_init:
> diff --git a/arch/x86/purgatory/purgatory.c b/arch/x86/purgatory/purgatory.c
> new file mode 100644
> index 0000000..375cfb7
> --- /dev/null
> +++ b/arch/x86/purgatory/purgatory.c
> @@ -0,0 +1,103 @@
> +/*
> + * purgatory: Runs between two kernels
> + *
> + * Copyright (C) 2013 Red Hat Inc.
> + *
> + * Author:
> + *
> + * Vivek Goyal <vgoyal at redhat.com>
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License as published by
> + * the Free Software Foundation (version 2 of the License).
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + * GNU General Public License for more details.
> + *
> + * You should have received a copy of the GNU General Public License
> + * along with this program; if not, write to the Free Software
> + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.

Ditto for the boilerplate gunk.

> + */
> +
> +#include "sha256.h"
> +
> +struct sha_region {
> +	unsigned long start;
> +	unsigned long len;
> +};
> +
> +unsigned long backup_dest = 0;
> +unsigned long backup_src = 0;
> +unsigned long backup_sz = 0;
> +
> +u8 sha256_digest[SHA256_DIGEST_SIZE] = { 0 };
> +
> +struct sha_region sha_regions[16] = {};
> +
> +/**
> + * memcpy - Copy one area of memory to another
> + * @dest: Where to copy to
> + * @src: Where to copy from
> + * @count: The size of the area.
> + */
> +static void *memcpy(void *dest, const void *src, unsigned long count)
> +{
> +	char *tmp = dest;
> +	const char *s = src;
> +
> +	while (count--)
> +		*tmp++ = *s++;
> +	return dest;
> +}
> +
> +static int memcmp(const void *cs, const void *ct, size_t count)
> +{
> +	const unsigned char *su1, *su2;
> +	int res = 0;
> +
> +	for (su1 = cs, su2 = ct; 0 < count; ++su1, ++su2, count--)
> +		if ((res = *su1 - *su2) != 0)
> +			break;
> +	return res;
> +}
> +
> +static int copy_backup_region(void)
> +{
> +	if (backup_dest)
> +		memcpy((void *)backup_dest, (void *)backup_src, backup_sz);
> +
> +	return 0;
> +}
> +
> +int verify_sha256_digest(void)
> +{
> +	struct sha_region *ptr, *end;
> +	u8 digest[SHA256_DIGEST_SIZE];
> +	struct sha256_state sctx;
> +
> +	sha256_init(&sctx);
> +	end = &sha_regions[sizeof(sha_regions)/sizeof(sha_regions[0])];
> +	for (ptr = sha_regions; ptr < end; ptr++)
> +		sha256_update(&sctx, (uint8_t *)(ptr->start), ptr->len);
> +
> +	sha256_final(&sctx, digest);
> +
> +	if (memcmp(digest, sha256_digest, sizeof(digest)) != 0)
> +		return 1;
> +
> +        return 0;
> +}
> +
> +void purgatory(void)
> +{
> +	int ret;
> +
> +	ret = verify_sha256_digest();

Yeah, again, hardcoding sha256 is kinda jucky. We probably should link
the needed crypto API stuff stuff and support multiple encryption algos.

> +	if (ret) {
> +		/* loop forever */
> +		for(;;);
> +	}
> +	copy_backup_region();

What is this thing supposed to do? I see in patch 11/11
arch_update_purgatory() does some preparations for KEXEC_TYPE_CRASH.

> +}
> diff --git a/arch/x86/purgatory/setup-x86_32.S b/arch/x86/purgatory/setup-x86_32.S
> new file mode 100644
> index 0000000..a9d5aa5
> --- /dev/null
> +++ b/arch/x86/purgatory/setup-x86_32.S
> @@ -0,0 +1,29 @@
> +/*
> + * purgatory:  setup code
> + *
> + * Copyright (C) 2014 Red Hat Inc.
> + *
> + * This code has been taken from kexec-tools.
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License as published by
> + * the Free Software Foundation (version 2 of the License).
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + * GNU General Public License for more details.
> + *
> + * You should have received a copy of the GNU General Public License
> + * along with this program; if not, write to the Free Software
> + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.


Ditto on the boilerplate.

> + */
> +
> +	.text
> +	.globl purgatory_start
> +	.balign 16
> +purgatory_start:
> +	.code32
> +
> +	/* This is just a stub. Write code when 32bit support comes along */

I'm guessing we want to support 32-bit secure boot with kexec at some
point...

> +	call purgatory
> diff --git a/arch/x86/purgatory/setup-x86_64.S b/arch/x86/purgatory/setup-x86_64.S
> new file mode 100644
> index 0000000..d23bc54
> --- /dev/null
> +++ b/arch/x86/purgatory/setup-x86_64.S
> @@ -0,0 +1,68 @@
> +/*
> + * purgatory:  setup code
> + *
> + * Copyright (C) 2003,2004  Eric Biederman (ebiederm at xmission.com)
> + * Copyright (C) 2014 Red Hat Inc.
> + *
> + * This code has been taken from kexec-tools.
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License as published by
> + * the Free Software Foundation (version 2 of the License).
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + * GNU General Public License for more details.
> + *
> + * You should have received a copy of the GNU General Public License
> + * along with this program; if not, write to the Free Software
> + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.

Boilerplate gunk.

...

Bah, that's a huge patch - it could use some splitting.

-- 
Regards/Gruss,
    Boris.

Sent from a fat crate under my desk. Formatting is fine.
--


From vgoyal at redhat.com  Wed Feb 26 11:32:56 2014
From: vgoyal at redhat.com (Vivek Goyal)
Date: Wed, 26 Feb 2014 11:32:56 -0500
Subject: [PATCH 07/11] kexec: Create a relocatable object called purgatory
In-Reply-To: <20140226160008.GF22639@pd.tnic>
References: <1390849071-21989-1-git-send-email-vgoyal@redhat.com>
 <1390849071-21989-8-git-send-email-vgoyal@redhat.com>
 <20140226160008.GF22639@pd.tnic>
Message-ID: <20140226163256.GD23022@redhat.com>

On Wed, Feb 26, 2014 at 05:00:08PM +0100, Borislav Petkov wrote:

[..]
> > Also sha256_generic.c is supposed to work with higher level crypto
> > abstrations and API and there was no point in importing all that in
> > purgatory. So instead of doing #include on sha256_generic.c I just
> > copied relevant portions of code into arch/x86/purgatory/sha256.c. Now
> > we shouldn't have to touch this code at all. Do let me know if there are
> > better ways to handle it.
> 
> Ok, but what about configurable encryption algorithms? Maybe there are
> people who don't want to use sha-2 and prefer something else instead.

We have been using sha256 for last 7-8 years in kexec-tools and nobody
asked for changing hash algorithm so far.

So yes, somebody wanting to use a different algorithm is a possibility
but I don't think it is likely in near future.

This patchset is already very big. I would rather make it work with
sha256 and down the line one can make it more generic if they feel
the need. This is not a user space API/ABI and one should be able to
change it without breaking any user space applications.

So I really don't feel the need of making it more complicated, pull in
all the crypto API in purgaotry to support other kind of hash algorithms
in purgatory.

> 
> > Signed-off-by: Vivek Goyal <vgoyal at redhat.com>
> 
> Also checkpatch:
> 
> ...
> total: 429 errors, 5 warnings, 1409 lines checked

Will run checkpatch.

> 
> > diff --git a/arch/x86/Makefile b/arch/x86/Makefile
> > index 13b22e0..fedcd16 100644
> > --- a/arch/x86/Makefile
> > +++ b/arch/x86/Makefile
> > @@ -160,6 +160,11 @@ archscripts: scripts_basic
> >  archheaders:
> >  	$(Q)$(MAKE) $(build)=arch/x86/syscalls all
> >  
> > +archprepare:
> > +ifeq ($(CONFIG_KEXEC),y)
> > +	$(Q)$(MAKE) $(build)=arch/x86/purgatory arch/x86/purgatory/kexec-purgatory.c
> > +endif
> 
> I wonder if this could be put into arch/x86/boot/ and built there too...
> But hpa said that already.

I thought hpa wanted to shared memcpy(), memset() and memcmp() functions
from arch/x86/. He did nto ask to move arch/x86/purgatory/ in
arch/x86/boot.

I personally felt that arch/x86/boot/ has all the code to build kernel
and purgaotry code does not deal with it. So I felt it is better to create
arch/x86/purgatory.

hpa, what do you think. Is there any strong reason that purgatory/ dir
 should be under arch/x86/boot/ and not under arch/x86/.

[..]
> > + * You should have received a copy of the GNU General Public License
> > + * along with this program; if not, write to the Free Software
> > + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
> 
> Yeah, can we drop this boilerplate gunk and refer to COPYING instead.

Ok. Will do.

[..]
> > +	/* Load the registers */
> > +	movq	rax(%rip), %rax
> > +	movq	rbx(%rip), %rbx
> > +	movq	rcx(%rip), %rcx
> > +	movq	rdx(%rip), %rdx
> > +	movq	rsi(%rip), %rsi
> > +	movq	rdi(%rip), %rdi
> > +	movq    rsp(%rip), %rsp
> > +	movq	rbp(%rip), %rbp
> > +	movq	r8(%rip), %r8
> > +	movq	r9(%rip), %r9
> > +	movq	r10(%rip), %r10
> > +	movq	r11(%rip), %r11
> > +	movq	r12(%rip), %r12
> > +	movq	r13(%rip), %r13
> > +	movq	r14(%rip), %r14
> > +	movq	r15(%rip), %r15
> 
> Huh, is the purpose to simply clear the arch registers here?
> 
> 	xor %reg,%reg

No. One can modify purgatory object symbol entry64_regs dynamically from
outside and purpose of this code is to load values into registers. At
compile time value of entry64_regs is 0 so it kind of gives the impression
that we are just trying to zero registers.

At kernel load time, we set values of some of those registers. Stack and
kernel entry point is one of those. Look at
arch/x86/kernel/kexec-bzimage.c

        regs64.rbx = 0; /* Bootstrap Processor */
        regs64.rsi = bootparam_load_addr;
        regs64.rip = kernel_load_addr + 0x200;
	regs64.rsp = (unsigned long)stack;
	ret = kexec_purgatory_get_set_symbol(image, "entry64_regs", &regs64,
                                        sizeof(regs64), 0);

[..]
> > +int verify_sha256_digest(void)
> > +{
> > +	struct sha_region *ptr, *end;
> > +	u8 digest[SHA256_DIGEST_SIZE];
> > +	struct sha256_state sctx;
> > +
> > +	sha256_init(&sctx);
> > +	end = &sha_regions[sizeof(sha_regions)/sizeof(sha_regions[0])];
> > +	for (ptr = sha_regions; ptr < end; ptr++)
> > +		sha256_update(&sctx, (uint8_t *)(ptr->start), ptr->len);
> > +
> > +	sha256_final(&sctx, digest);
> > +
> > +	if (memcmp(digest, sha256_digest, sizeof(digest)) != 0)
> > +		return 1;
> > +
> > +        return 0;
> > +}
> > +
> > +void purgatory(void)
> > +{
> > +	int ret;
> > +
> > +	ret = verify_sha256_digest();
> 
> Yeah, again, hardcoding sha256 is kinda jucky. We probably should link
> the needed crypto API stuff stuff and support multiple encryption algos.

There is no easy way to link to kernel crypto API as purgatory object
does not link against kernel. Most likely it will have to be either a
common library against which both kernel and purgatory link or use
all the #include magic. I really don't want to make things complicated
here.

The purpose of this isolated code in a directory is that write it once
and almost never touch it again.

> 
> > +	if (ret) {
> > +		/* loop forever */
> > +		for(;;);
> > +	}
> > +	copy_backup_region();
> 
> What is this thing supposed to do? I see in patch 11/11
> arch_update_purgatory() does some preparations for KEXEC_TYPE_CRASH.

Kdump kernel runs from reserved region of memory. But we also found on
x86, that it still needed first 640KB of memory to boot. So before jumping
to second kernel, we copy first 640KB in reserved region and let second
kernel use first 640KB. We call this concept as backup region as we are
backing up an area of memory so that second kernel does not overwrite it.

For more details on backup region have a look at this paper.

http://lse.sourceforge.net/kdump/documentation/ols2oo5-kdump-paper.pdf
 
[..]
> > + */
> > +
> > +	.text
> > +	.globl purgatory_start
> > +	.balign 16
> > +purgatory_start:
> > +	.code32
> > +
> > +	/* This is just a stub. Write code when 32bit support comes along */
> 
> I'm guessing we want to support 32-bit secure boot with kexec at some
> point...

Yep. Right now these patches support 64bit kernel only and I put some
code for 32bit so that there are no compilation failures. 

Though 32bit is becoming less relevant with every passing day, still
supporting it on 32bit is a good idea. It can happen down the line tough.

[..]
> Bah, that's a huge patch - it could use some splitting.

I will see if I can find a way to split this patch. Thanks for reviewing
it.

Thanks
Vivek


From vgoyal at redhat.com  Wed Feb 26 10:46:54 2014
From: vgoyal at redhat.com (Vivek Goyal)
Date: Wed, 26 Feb 2014 10:46:54 -0500
Subject: [PATCH 06/11] kexec: A new system call, kexec_file_load, for in
 kernel kexec
In-Reply-To: <20140226153709.GE22639@pd.tnic>
References: <1390849071-21989-1-git-send-email-vgoyal@redhat.com>
 <1390849071-21989-7-git-send-email-vgoyal@redhat.com>
 <20140221145910.GE11531@pd.tnic> <20140224164131.GJ4631@redhat.com>
 <20140226153709.GE22639@pd.tnic>
Message-ID: <20140226154654.GB23022@redhat.com>

On Wed, Feb 26, 2014 at 04:37:09PM +0100, Borislav Petkov wrote:
> On Mon, Feb 24, 2014 at 11:41:31AM -0500, Vivek Goyal wrote:
> > Right now there is only one user. But once other image loader support
> > comes along or other arches support file based kexec, they can make
> > use of same function.
> > 
> > This is a pretty important modification as it decides what's the starting
> > point of next kernel image. I wanted to make it a function callable by
> > users who wanted to modify it instead of of letting them directly 
> > modify image->start.
> 
> But are you expecting any other way to set image->start by the other
> arches/image loaders?

No. I am expecting other loaders to just call this function to set the
start of kernel image.

Thanks
Vivek


From ptesarik at suse.cz  Wed Feb 26 16:05:46 2014
From: ptesarik at suse.cz (Petr Tesarik)
Date: Wed, 26 Feb 2014 22:05:46 +0100
Subject: [PATCH] makedumpfile: Fix string append in dump_log_entry()
Message-ID: <20140226220546.4030cdbf@hananiah.suse.cz>

To quote the sprintf(3) man page:

    Some programs imprudently rely on code such as the following

        sprintf(buf, "%s some further text", buf);

    to append text to buf.  However, the standards explicitly note that
    the results are undefined if source and destination buffers overlap
    when calling sprintf(), snprintf(), vsprintf(), and vsnprintf().
    Depending on the version of gcc(1) used, and the compiler options
    employed, calls such as the above will not produce the expected results.

The original code is actually miscompiled on openSUSE 13.1.

It's also overkill to call sprintf() for something that can be done
with a simple assignment.

Signed-off-by: Petr Tesarik <ptesarik at suse.cz>
---
 makedumpfile.c | 13 +++++++------
 1 file changed, 7 insertions(+), 6 deletions(-)

diff --git a/makedumpfile.c b/makedumpfile.c
index 579be61..013fce7 100644
--- a/makedumpfile.c
+++ b/makedumpfile.c
@@ -3866,7 +3866,7 @@ reset_bitmap_of_free_pages(unsigned long node_zones, struct cycle *cycle)
 static int
 dump_log_entry(char *logptr, int fp)
 {
-	char *msg, *p;
+	char *msg, *p, *bufp;
 	unsigned int i, text_len;
 	unsigned long long ts_nsec;
 	char buf[BUFSIZE];
@@ -3881,18 +3881,19 @@ dump_log_entry(char *logptr, int fp)
 
 	msg = logptr + SIZE(printk_log);
 
-	sprintf(buf, "[%5lld.%06ld] ", nanos, rem/1000);
+	bufp = buf;
+	bufp += sprintf(buf, "[%5lld.%06ld] ", nanos, rem/1000);
 
 	for (i = 0, p = msg; i < text_len; i++, p++) {
 		if (isprint(*p) || isspace(*p))
-			sprintf(buf, "%s%c", buf, *p);
+			*bufp++ = *p;
 		else
-			sprintf(buf, "%s\\x%02x", buf, *p);
+			bufp += sprintf(bufp, "\\x%02x", *p);
 	}
 
-	sprintf(buf, "%s\n", buf);
+	*bufp++ = '\n';
 
-	if (write(info->fd_dumpfile, buf, strlen(buf)) < 0)
+	if (write(info->fd_dumpfile, buf, bufp - buf) < 0)
 		return FALSE;
 	else
 		return TRUE;
-- 
1.8.4.5


From aravinda at linux.vnet.ibm.com  Thu Feb 27 01:02:20 2014
From: aravinda at linux.vnet.ibm.com (Aravinda Prasad)
Date: Thu, 27 Feb 2014 11:32:20 +0530
Subject: [PATCH] makedumpfile/eppic: Properly resolve structure members
Message-ID: <20140227060220.25635.83843.stgit@aravindap>

makedumpfile/eppic was not able to resolve member of the
structure in cases such as:

struct abc
{
	...
	...
	struct xyz
	...
}

and eppic script:

sample()
{
	struct abc *a;
	struct xyz *x;

	x->member;
}

would fail to resolve "member" of structure xyz. However
it works if "struct abc *a;" line is removed from eppic
script. This patch fixes this issue.

Signed-off-by: Aravinda Prasad <aravinda at linux.vnet.ibm.com>
---
 dwarf_info.c      |    2 +-
 extension_eppic.c |   17 +++++++++++------
 2 files changed, 12 insertions(+), 7 deletions(-)

diff --git a/dwarf_info.c b/dwarf_info.c
index c5752c9..b7012b2 100644
--- a/dwarf_info.c
+++ b/dwarf_info.c
@@ -1468,7 +1468,7 @@ get_die_attr_type(unsigned long long die_off, int *type_flag,
 {
 	Dwarf_Die result;
 
-	if (!die_attr_off)
+	if (!die_attr_off || !die_off)
 		return FALSE;
 
 	if (!get_die_from_offset((Dwarf_Off) die_off, &result)) {
diff --git a/extension_eppic.c b/extension_eppic.c
index 7e045c9..20d996d 100644
--- a/extension_eppic.c
+++ b/extension_eppic.c
@@ -24,6 +24,8 @@
 #include "makedumpfile.h"
 #include "extension_eppic.h"
 
+static int apigetctype(int, char *, type_t *);
+
 /*
  * Most of the functions included in this file performs similar
  * functionality as in the applications/crash/eppic.c file part of
@@ -183,7 +185,15 @@ drilldown(ull offset, type_t *t)
 			goto label;
 		case DW_TAG_structure_type:
 			eppic_type_mkstruct(t);
-			goto label;
+label:
+			eppic_type_setsize(t, GET_DIE_LENGTH(t_die_off, TRUE));
+			eppic_type_setidx(t, (ull)t_die_off);
+			tstr = GET_DIE_NAME(t_die_off);
+			/* Drill down further */
+			if (tstr)
+				apigetctype(V_STRUCT, tstr, t);
+			die_off = 0;
+			break;
 		/* Unknown TAG ? */
 		default:
 			die_off = t_die_off;
@@ -191,11 +201,6 @@ drilldown(ull offset, type_t *t)
 		}
 	}
 
-label:
-	eppic_type_setsize(t, GET_DIE_LENGTH(t_die_off, TRUE));
-	eppic_type_setidx(t, (ull)t_die_off);
-	tstr = GET_DIE_NAME(t_die_off);
-
 out:
 	eppic_setupidx(t, ref, nidx, idxlst);
 	if (fctflg)



From aruna at linux.vnet.ibm.com  Thu Feb 27 01:19:54 2014
From: aruna at linux.vnet.ibm.com (Aruna Balakrishnaiah)
Date: Thu, 27 Feb 2014 11:49:54 +0530
Subject: [PATCH] makedumpfile: Add support to module data structures
Message-ID: <20140227061942.2765.37183.stgit@aruna-ThinkPad-T420>

When trying to refer a module data structure GET_DIE_NFIELDS
does not set the dwarf_info to the right module.

For instance:

struct ap_device {
	...
	struct list_head list;
	...
};

struct ap_device *dev;

As a result, it was able to resolve only dev->list and it was failing to
resolve dev->list.next.
The patch takes care of handling this by introducing GET_DIE_NFIELDS_ALL
which takes care of setting the dwarf_info to the appropriate module.

Signed-off-by: Aruna Balakrishnaiah <aruna at linux.vnet.ibm.com>
---
 dwarf_info.c      |    8 -----
 erase_info.c      |   80 ++++++++++++++++++++++++++++++++++++++++++++++++++++-
 erase_info.h      |    3 +-
 extension_eppic.c |    2 +
 extension_eppic.h |    2 +
 5 files changed, 83 insertions(+), 12 deletions(-)

diff --git a/dwarf_info.c b/dwarf_info.c
index 6e21b8a..268e922 100644
--- a/dwarf_info.c
+++ b/dwarf_info.c
@@ -489,7 +489,6 @@ get_die_from_offset(Dwarf_Off offset, Dwarf_Die *die)
 		return FALSE;
 
 	if (!dwarf_offdie(dwarf_info.dwarfd, offset, die)) {
-		ERRMSG("Can't find the DIE.\n");
 		return FALSE;
 	}
 
@@ -1343,14 +1342,12 @@ get_die_nfields(unsigned long long die_off)
 	Dwarf_Die result, child, *die;
 
 	if (!get_die_from_offset((Dwarf_Off) die_off, &result)) {
-		ERRMSG("Can't find the DIE.\n");
 		return -1;
 	}
 
 	die = &result;
 	tag = dwarf_tag(die);
 	if (tag != DW_TAG_structure_type && tag != DW_TAG_union_type) {
-		ERRMSG("DIE is not of structure or union type.\n");
 		clean_dwfl_info();
 		return -1;
 	}
@@ -1388,14 +1385,12 @@ get_die_member(unsigned long long die_off, int index, long *offset,
 		return -1;
 
 	if (!get_die_from_offset((Dwarf_Off) die_off, &result)) {
-		ERRMSG("Can't find the DIE.\n");
 		return -1;
 	}
 
 	die = &result;
 	tag = dwarf_tag(die);
 	if (tag != DW_TAG_structure_type && tag != DW_TAG_union_type) {
-		ERRMSG("DIE is not of structure or union type.\n");
 		clean_dwfl_info();
 		return -1;
 	}
@@ -1471,7 +1466,6 @@ get_die_attr_type(unsigned long long die_off, int *type_flag,
 		return FALSE;
 
 	if (!get_die_from_offset((Dwarf_Off) die_off, &result)) {
-		ERRMSG("Can't find the DIE.\n");
 		return FALSE;
 	}
 
@@ -1509,7 +1503,6 @@ get_die_name(unsigned long long die_off)
 		return NULL;
 
 	if (!get_die_from_offset((Dwarf_Off) die_off, &result)) {
-		ERRMSG("Can't find the DIE.\n");
 		return NULL;
 	}
 
@@ -1554,7 +1547,6 @@ get_die_length(unsigned long long die_off, int flag)
 		return FALSE;
 
 	if (!get_die_from_offset((Dwarf_Off) die_off, &result)) {
-		ERRMSG("Can't find the DIE.\n");
 		return FALSE;
 	}
 
diff --git a/erase_info.c b/erase_info.c
index a789389..e0e0f71 100644
--- a/erase_info.c
+++ b/erase_info.c
@@ -34,7 +34,7 @@ struct call_back eppic_cb = {
 	&get_die_offset,
 	&get_die_length,
 	&get_die_member_all,
-	&get_die_nfields,
+	&get_die_nfields_all,
 	&get_symbol_addr_all,
 	&update_filter_info_raw
 };
@@ -2028,6 +2028,84 @@ get_domain_all(char *symname, int cmd, unsigned long long *die) {
 }
 
 /*
+ * Search for die in modules as well as vmlinux
+ */
+int
+get_die_nfields_all(unsigned long long die_off)
+{
+	short vmlinux_searched = 0;
+	long nfields = -1;
+	unsigned int i, current_mod;
+	struct module_info *modules;
+
+	/* Search in vmlinux if debuginfo is set to vmlinux */
+	if (!strcmp(get_dwarf_module_name(), "vmlinux")) {
+		nfields = get_die_nfields(die_off);
+		if (nfields > 0)
+			return nfields;
+
+		vmlinux_searched = 1;
+	}
+
+	/*
+	 * Proceed the search in modules. Try in the module
+	 * which resulted in a hit in the previous search
+	 */
+
+	modules = mod_st.modules;
+	current_mod = mod_st.current_mod;
+
+	if (strcmp(get_dwarf_module_name(), modules[current_mod].name)) {
+		if (!set_dwarf_debuginfo(modules[current_mod].name,
+				info->system_utsname.release, NULL, -1)) {
+			ERRMSG("Cannot set to current module %s\n",
+					modules[current_mod].name);
+			return -1;
+		}
+	}
+
+	nfields = get_die_nfields(die_off);
+	if (nfields > 0)
+		return nfields;
+
+	/* Search in all modules */
+	for (i = 0; i < mod_st.num_modules; i++) {
+
+		/* Already searched. Skip */
+		if (i == current_mod)
+			continue;
+
+		if (!set_dwarf_debuginfo(modules[i].name,
+				info->system_utsname.release, NULL, -1)) {
+			ERRMSG("Skipping Module section %s\n", modules[i].name);
+			continue;
+		}
+
+		nfields = get_die_nfields(die_off);
+
+		if (nfields < 0)
+			continue;
+
+		/*
+		 * Die found. Set the current_mod to this module index,
+		 * a minor optimization for fast lookup next time
+		 */
+		mod_st.current_mod = i;
+		return nfields;
+	}
+
+	/* Die not found in any module. Set debuginfo back to vmlinux */
+	set_dwarf_debuginfo("vmlinux", NULL, info->name_vmlinux,
+			info->fd_vmlinux);
+
+	if (!vmlinux_searched)
+		return get_die_nfields(die_off);
+	else
+		return -1;
+
+}
+
+/*
  * Search for die member in modules as well as vmlinux
  */
 int
diff --git a/erase_info.h b/erase_info.h
index a90fac0..4d4957e 100644
--- a/erase_info.h
+++ b/erase_info.h
@@ -35,6 +35,7 @@ unsigned long long get_symbol_addr_all(char *);
 long get_domain_all(char *, int, unsigned long long *);
 int get_die_member_all(unsigned long long die_off, int index, long *offset,
 		char **name, int *nbits, int *fbits, unsigned long long *m_die);
+int get_die_nfields_all(unsigned long long die_off);
 
 struct call_back {
 	long (*get_domain_all)(char *, int, unsigned long long *);
@@ -48,7 +49,7 @@ struct call_back {
 	int (*get_die_member_all)(unsigned long long die_off, int index,
 		long *offset, char **name, int *nbits, int *fbits,
 		unsigned long long *m_die);
-	int (*get_die_nfields)(unsigned long long die_off);
+	int (*get_die_nfields_all)(unsigned long long die_off);
 	unsigned long long (*get_symbol_addr_all)(char *symname);
 	int (*update_filter_info_raw)(unsigned long long, int, int);
 };
diff --git a/extension_eppic.c b/extension_eppic.c
index 7e045c9..bb36d5a 100644
--- a/extension_eppic.c
+++ b/extension_eppic.c
@@ -219,7 +219,7 @@ apimember(char *mname, ull idx, type_t *tm, member_t *m, ull *last_index)
 	ull m_die, die_off = idx;
 	char *name = NULL;
 
-	nfields = GET_DIE_NFIELDS(die_off);
+	nfields = GET_DIE_NFIELDS_ALL(die_off);
 	/*
 	 * GET_DIE_NFIELDS() returns < 0 if the die is not structure type
 	 * or union type
diff --git a/extension_eppic.h b/extension_eppic.h
index 42437f2..24189ba 100644
--- a/extension_eppic.h
+++ b/extension_eppic.h
@@ -88,7 +88,7 @@ struct call_back *cb;
 #define GET_DIE_OFFSET cb->get_die_offset
 #define GET_DIE_LENGTH cb->get_die_length
 #define GET_DIE_MEMBER_ALL cb->get_die_member_all
-#define GET_DIE_NFIELDS cb->get_die_nfields
+#define GET_DIE_NFIELDS_ALL cb->get_die_nfields_all
 #define GET_SYMBOL_ADDR_ALL cb->get_symbol_addr_all
 #define UPDATE_FILTER_INFO_RAW cb->update_filter_info_raw
 



From aruna at linux.vnet.ibm.com  Thu Feb 27 01:31:00 2014
From: aruna at linux.vnet.ibm.com (Aruna Balakrishnaiah)
Date: Thu, 27 Feb 2014 12:01:00 +0530
Subject: [PATCH 00/10] makedumpfile/eppic: Sample eppic scripts
Message-ID: <20140227063007.5924.5819.stgit@aruna-ThinkPad-T420>

The series has few sample eppic scripts to scrub the security
data.


---

Aruna Balakrishnaiah (10):
      Scrub executable name for each user process
      Scrub filenames of cached dentries
      Scrub all entries in the keyring
      Clear the message data of all ap_bus requests
      Scrub data in tcp socket buffers
      Scrub data of udp socket buffers
      Scrub data of unix socket buffers
      Scrub socket buffers of guest network I/O
      Scrub buffers involved in guest block I/O
      Install sample eppic scripts


 Makefile                           |    1 
 eppic_scripts/ap_messages.c        |   78 ++++++++++++++++++++++++++++++
 eppic_scripts/dir_names.c          |   78 ++++++++++++++++++++++++++++++
 eppic_scripts/keyring.c            |   57 ++++++++++++++++++++++
 eppic_scripts/proc_names.c         |   49 +++++++++++++++++++
 eppic_scripts/tcp_sk_buf.c         |   78 ++++++++++++++++++++++++++++++
 eppic_scripts/udp_sk_buf.c         |   79 ++++++++++++++++++++++++++++++
 eppic_scripts/unix_sk_buff.c       |   81 +++++++++++++++++++++++++++++++
 eppic_scripts/vhost_net_buffers.c  |   95 ++++++++++++++++++++++++++++++++++++
 eppic_scripts/vhost_scsi_buffers.c |   71 +++++++++++++++++++++++++++
 makedumpfile.spec                  |    3 +
 11 files changed, 670 insertions(+)
 create mode 100644 eppic_scripts/ap_messages.c
 create mode 100644 eppic_scripts/dir_names.c
 create mode 100644 eppic_scripts/keyring.c
 create mode 100644 eppic_scripts/proc_names.c
 create mode 100644 eppic_scripts/tcp_sk_buf.c
 create mode 100644 eppic_scripts/udp_sk_buf.c
 create mode 100644 eppic_scripts/unix_sk_buff.c
 create mode 100644 eppic_scripts/vhost_net_buffers.c
 create mode 100644 eppic_scripts/vhost_scsi_buffers.c

-- 



From aruna at linux.vnet.ibm.com  Thu Feb 27 01:31:05 2014
From: aruna at linux.vnet.ibm.com (Aruna Balakrishnaiah)
Date: Thu, 27 Feb 2014 12:01:05 +0530
Subject: [PATCH 01/10] Scrub executable name for each user process
In-Reply-To: <20140227063007.5924.5819.stgit@aruna-ThinkPad-T420>
References: <20140227063007.5924.5819.stgit@aruna-ThinkPad-T420>
Message-ID: <20140227063105.5924.88321.stgit@aruna-ThinkPad-T420>

Walk all processes via the tasks lists starting from init_task

   extern struct task_struct init_task;

   struct task_struct {
        ...
        struct list_head tasks;
        ...
        char comm[TASK_COMM_LEN]; /* executable name excluding path */
        ...
   };

For each user space process clear executable name

   struct task_struct *tsk;
   list_for_each_entry(tsk, &init_task, tasks) {
       if (tsk->mm)
           memset(tsk->comm, 0, TASK_COMM_LEN);
   }


Signed-off-by: Aruna Balakrishnaiah <aruna at linux.vnet.ibm.com>
---
 eppic_scripts/proc_names.c |   49 ++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 49 insertions(+)
 create mode 100644 eppic_scripts/proc_names.c

diff --git a/eppic_scripts/proc_names.c b/eppic_scripts/proc_names.c
new file mode 100644
index 0000000..12876df
--- /dev/null
+++ b/eppic_scripts/proc_names.c
@@ -0,0 +1,49 @@
+string
+proc_opt()
+{
+	    return "l";
+}
+
+string
+proc_usage()
+{
+	    return "\n";
+}
+
+static void
+proc_showusage()
+{
+	    printf("usage : proc %s", proc_usage());
+}
+
+string
+proc_help()
+{
+	    return "Help";
+}
+
+int
+proc()
+{
+	struct list_head *head, *next;
+	struct task_struct *tsk;
+
+	tsk = &init_task;
+
+	head = (struct list_head *) &(tsk->tasks);
+	next = (struct list_head *) tsk->tasks.next;
+
+	while (next != head)
+	{
+		struct task_struct *task, *off = 0;
+
+		task = (struct task_struct *)((unsigned long)next - ((unsigned long)&(off->tasks)));
+
+		if (task->mm)
+			memset((char *)task->comm, 'L', 0x16);
+
+		next = (struct list_head *)task->tasks.next;
+	}
+
+	return 1;
+}



From aruna at linux.vnet.ibm.com  Thu Feb 27 01:31:15 2014
From: aruna at linux.vnet.ibm.com (Aruna Balakrishnaiah)
Date: Thu, 27 Feb 2014 12:01:15 +0530
Subject: [PATCH 03/10] Scrub all entries in the keyring
In-Reply-To: <20140227063007.5924.5819.stgit@aruna-ThinkPad-T420>
References: <20140227063007.5924.5819.stgit@aruna-ThinkPad-T420>
Message-ID: <20140227063115.5924.24207.stgit@aruna-ThinkPad-T420>

Clear all entries in the keyring

   Scan the keyring_name_hash hash table

   static struct list_head keyring_name_hash[KEYRING_NAME_HASH_SIZE];

   for (i = 0; i < KEYRING_NAME_HASH_SIZE; i++)
       if (!list_empty(&keyring_name_hash[i])) {
           ...
       }

   For each non-empty list walk all keyring entries

   struct key {
        ...
        struct key_type         *type;          /* type of key */
        ...
        unsigned short          datalen;        /* payload data length */
        ...
        union {
                struct list_head        link;
                ...
        } type_data;
        ...
        union {
                unsigned long           value;
                void __rcu              *rcudata;
                void                    *data;
                struct keyring_list __rcu *subscriptions;
        } payload;
   };

   struct key *key;
   list_for_each_entry(key, &keyring_name_hash[i], type_data.link) {
       ...
   }

   Clear value/rcudata/data dependent on the type of the key.

Signed-off-by: Aruna Balakrishnaiah <aruna at linux.vnet.ibm.com>
---
 eppic_scripts/keyring.c |   57 +++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 57 insertions(+)
 create mode 100644 eppic_scripts/keyring.c

diff --git a/eppic_scripts/keyring.c b/eppic_scripts/keyring.c
new file mode 100644
index 0000000..22e7db8
--- /dev/null
+++ b/eppic_scripts/keyring.c
@@ -0,0 +1,57 @@
+string
+skey_opt()
+{
+	    return "l";
+}
+
+string
+skey_usage()
+{
+	    return "\n";
+}
+
+static void
+skey_showusage()
+{
+	    printf("usage : skey %s", skey_usage());
+}
+
+string
+skey_help()
+{
+	    return "Help";
+}
+
+int
+skey()
+{
+	int i;
+	struct list_head **tab;
+
+	tab = &keyring_name_hash;
+
+	for (i = 0; i < 32; i++)
+	{
+		struct list_head *next, *head;
+
+		head = (struct list_head *) (tab + i);
+		next = (struct list_head *) head->next;
+
+		if (!next)
+			continue;
+
+		while (next != head)
+		{
+			struct key *mykey, *off = 0;
+
+			mykey = (struct key *)((unsigned long)(next) - ((unsigned long)&(off->type_data)));
+
+			memset((char *)&(mykey->payload.value), 'A', 0x8);
+			memset((char *)mykey->payload.rcudata, 'A', 0x20);
+			memset((char *)mykey->payload.data, 'A', 0x20);
+
+			next = (struct list_head *) mykey->type_data.link.next;
+		}
+	}
+	return 1;
+}



From aruna at linux.vnet.ibm.com  Thu Feb 27 01:31:10 2014
From: aruna at linux.vnet.ibm.com (Aruna Balakrishnaiah)
Date: Thu, 27 Feb 2014 12:01:10 +0530
Subject: [PATCH 02/10] Scrub filenames of cached dentries
In-Reply-To: <20140227063007.5924.5819.stgit@aruna-ThinkPad-T420>
References: <20140227063007.5924.5819.stgit@aruna-ThinkPad-T420>
Message-ID: <20140227063110.5924.1298.stgit@aruna-ThinkPad-T420>

 i) iterate over all mounted filesystems

   struct vfsmount {
        struct list_head mnt_hash;
        ...
        struct dentry *mnt_root;        /* root of the mounted tree */
        ...
   };

   for (u = 0; i < HASH_SIZE; u++) {
       struct vfsmount *mnt;
       list_for_each_entry(mnt, &mount_hashtable[u], mnt_hash) {
          struct dentry *root;
          root = mnt->mnt_root;
          ...
       }
   }

   ii) recursively walk the dentries of each tree starting from root dentry
       and clear d_name and d_iname

   struct dentry {
        ...
        struct qstr d_name;
        ...
        unsigned char d_iname[DNAME_INLINE_LEN];        /* small names */
        ...
        struct list_head d_subdirs;     /* our children */
        ...
   };

   void walk_dentries(struct dentry *dentry)
   {
       struct dentry *child;
       memset(dentry->d_iname, 0, DNAME_INLINE_LEN);
       memset(dentry->d_name.name, 0, dentry->d_name.len);
       list_for_each_entry(child, &dentry->d_subdirs, d_u.d_child)
           walk_dentries(child);
   }

Signed-off-by: Aruna Balakrishnaiah <aruna at linux.vnet.ibm.com>
---
 eppic_scripts/dir_names.c |   78 +++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 78 insertions(+)
 create mode 100644 eppic_scripts/dir_names.c

diff --git a/eppic_scripts/dir_names.c b/eppic_scripts/dir_names.c
new file mode 100644
index 0000000..dbe6d00
--- /dev/null
+++ b/eppic_scripts/dir_names.c
@@ -0,0 +1,78 @@
+string
+vfs_opt()
+{
+	    return "l";
+}
+
+string
+vfs_usage()
+{
+	    return "\n";
+}
+
+static void
+vfs_showusage()
+{
+	    printf("usage : vfs %s", vfs_usage());
+}
+
+string
+vfs_help()
+{
+	    return "Help";
+}
+
+void
+rm_names(struct dentry *dir)
+{
+	struct list_head *next, *head;
+
+	memset(dir->d_iname, 0, 0x20);
+	memset(dir->d_name.name, 0, 0x20);
+
+	head = (struct list_head *)&(dir->d_subdirs);
+	next = (struct list_head *)dir->d_subdirs.next;
+
+	while (next != head)
+	{
+		struct dentry *child, *off = 0;
+
+		child = (struct dentry *)((unsigned long)next - (unsigned long)&(off->d_u));
+		rm_names(child);
+		next = child->d_u.d_child.next;
+	}
+
+	return;
+}
+
+int
+vfs()
+{
+	int i;
+	struct list_head *tab;
+
+	tab = (struct list_head *)mount_hashtable;
+
+	for (i = 0; i < 256; i++)
+	{
+		struct list_head *head, *next;
+
+		head = (struct list_head *) (tab + i);
+		next = (struct list_head *) head->next;
+
+		if (!next)
+			continue;
+
+		while (next != head)
+		{
+			struct mount *mntfs;
+			struct dentry *root;
+
+			mntfs = (struct mount *)((unsigned long)next);
+			root = (struct dentry *)mntfs->mnt.mnt_root;
+			rm_names(root);
+			next = mntfs->mnt_hash.next;
+		}
+	}
+	return 1;
+}



From aruna at linux.vnet.ibm.com  Thu Feb 27 01:31:40 2014
From: aruna at linux.vnet.ibm.com (Aruna Balakrishnaiah)
Date: Thu, 27 Feb 2014 12:01:40 +0530
Subject: [PATCH 06/10] Scrub data of udp socket buffers
In-Reply-To: <20140227063007.5924.5819.stgit@aruna-ThinkPad-T420>
References: <20140227063007.5924.5819.stgit@aruna-ThinkPad-T420>
Message-ID: <20140227063140.5924.25060.stgit@aruna-ThinkPad-T420>

Find all udp sockets (struct sock *sk)

 udp sockets:

   Iterate from 0 to udp_table->mask and get udp_hslot from hash table:
     for (i = 0; i < udp->table->mask; i++) {
         struct udp_hslot *hslot = udp_table->hash[i];
         ...
     }
   For each hslot iterate over hslot->head null list to get sockets:
     struct sock *sk;
     sk_nulls_for_each(sk, node, &hslot->head) {
         ...
     }

  For each socket iterate over the socket buffers in
  sk_receive_queue and sk_write_queue:

   struct sock {
        ...
        struct sk_buff_head     sk_receive_queue;
        ...
        struct sk_buff_head     sk_write_queue;
        ...
   };

   struct sk_buff_head {
        struct sk_buff  *next;
        struct sk_buff  *prev;
   };

   For each struct sk_buff in the two lists clear the memory referenced
   by skb->data / skb->data_len:

   struct sk_buff {
        ...
        unsigned int            data_len;
        ...
        unsigned char           *data;
        ...
   };


Signed-off-by: Aruna Balakrishnaiah <aruna at linux.vnet.ibm.com>
---
 eppic_scripts/udp_sk_buf.c |   79 ++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 79 insertions(+)
 create mode 100644 eppic_scripts/udp_sk_buf.c

diff --git a/eppic_scripts/udp_sk_buf.c b/eppic_scripts/udp_sk_buf.c
new file mode 100644
index 0000000..7e64300
--- /dev/null
+++ b/eppic_scripts/udp_sk_buf.c
@@ -0,0 +1,79 @@
+string
+udp_opt()
+{
+	    return "l";
+}
+
+string
+udp_usage()
+{
+	    return "\n";
+}
+
+static void
+udp_showusage()
+{
+	    printf("usage : udp %s", udp_usage());
+}
+
+string
+udp_help()
+{
+	    return "Help";
+}
+
+int
+udp()
+{
+	int i;
+	int size;
+	struct udp_table *table;
+	struct sock_common *off = 0;
+
+	table = &udp_table;
+
+	for (i = 0; i < table->mask; i++) {
+		struct hlist_nulls_node *pos;
+
+		pos = table->hash[i].head.first;
+
+		while (!((unsigned long)pos & 1)) {
+			struct sock *sk;
+			struct sk_buff *next;
+			struct sk_buff_head *head;
+			struct hlist_nulls_node *node;
+
+			sk  = (struct sock *)((unsigned long)pos - ((unsigned long)&(off->skc_dontcopy_begin)));
+
+			head = (struct sk_buff_head *)&(sk->sk_receive_queue);
+			next = (struct sk_buff *)sk->sk_receive_queue.next;
+
+			while (next != head)
+			{
+				struct sk_buff *buff = (struct sk_buff *)next;
+
+				memset((char *)buff->data, 'L', buff->data_len);
+				memset((char *)&(buff->data_len), 'L', 0x4);
+
+				next = buff->next;
+			}
+
+                        head = (struct sk_buff_head *)&(sk->sk_write_queue);
+			next = (struct sk_buff *)sk->sk_write_queue.next;
+
+			while (next != head)
+			{
+				struct sk_buff *buff = (struct sk_buff *)next;
+
+				memset((char *)buff->data, 'L', buff->data_len);
+				memset((char *)&(buff->data_len), 'L', 0x4);
+
+				next = buff->next;
+                        }
+
+			node = (struct hlist_nulls_node *)((unsigned long)sk + (unsigned long)&(off->skc_dontcopy_begin));
+		        pos = node->next;
+		}
+	}
+	return 1;
+}



From aruna at linux.vnet.ibm.com  Thu Feb 27 01:31:45 2014
From: aruna at linux.vnet.ibm.com (Aruna Balakrishnaiah)
Date: Thu, 27 Feb 2014 12:01:45 +0530
Subject: [PATCH 07/10] Scrub data of unix socket buffers
In-Reply-To: <20140227063007.5924.5819.stgit@aruna-ThinkPad-T420>
References: <20140227063007.5924.5819.stgit@aruna-ThinkPad-T420>
Message-ID: <20140227063145.5924.86410.stgit@aruna-ThinkPad-T420>

 Iterate from 0 to UNIX_HASH_SIZE and then walk the hlist in
     for (i = 0; i < UNIX_HASH_SIZE; i++) {
         struct list_head *list = &unix_socket_table[i];
         ...
     }
   Walk each non-empty list in unix_socket_table
     struct sock *sk;
     sk_for_each(sk, node, &unix_socket_table[i])


   For each socket iterate over the socket buffers in
   sk_receive_queue and sk_write_queue:

   struct sock {
        ...
        struct sk_buff_head     sk_receive_queue;
        ...
        struct sk_buff_head     sk_write_queue;
        ...
   };

   struct sk_buff_head {
        struct sk_buff  *next;
        struct sk_buff  *prev;
   };

   For each struct sk_buff in the two lists clear the memory referenced
   by skb->data / skb->data_len:

   struct sk_buff {
        ...
        unsigned int            data_len;
        ...
        unsigned char           *data;
        ...
   };

Signed-off-by: Aruna Balakrishnaiah <aruna at linux.vnet.ibm.com>
---
 eppic_scripts/unix_sk_buff.c |   81 ++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 81 insertions(+)
 create mode 100644 eppic_scripts/unix_sk_buff.c

diff --git a/eppic_scripts/unix_sk_buff.c b/eppic_scripts/unix_sk_buff.c
new file mode 100644
index 0000000..6ab1e6c
--- /dev/null
+++ b/eppic_scripts/unix_sk_buff.c
@@ -0,0 +1,81 @@
+string
+sunix_opt()
+{
+	    return "l";
+}
+
+string
+sunix_usage()
+{
+	    return "\n";
+}
+
+static void
+sunix_showusage()
+{
+	    printf("usage : sunix %s", sunix_usage());
+}
+
+string
+sunix_help()
+{
+	    return "Help";
+}
+
+int
+sunix()
+{
+	int i;
+	int size;
+	struct hlist_head **tab;
+	struct sock_common *off = 0;
+
+	tab = &unix_socket_table;
+
+	for (i = 0; i < 256; i++) {
+		struct hlist_node *pos;
+		struct hlist_node *node;
+		struct hlist_head *tmp;
+
+		tmp = (struct hlist_head *)(tab + i);
+		pos = tmp->first;
+
+		while (pos) {
+			struct sock *sk;
+			struct sk_buff *next;
+			struct sk_buff_head *head;
+
+			sk = (struct sock *)((unsigned long)pos - (unsigned long)&(off->skc_dontcopy_begin));
+
+			head = (struct sk_buff_head *)&(sk->sk_receive_queue);
+			next = (struct sk_buff *)sk->sk_receive_queue.next;
+
+			while (next != head)
+			{
+				struct sk_buff *buff = (struct sk_buff *)next;
+
+				memset((char *)buff->data, 'L', buff->data_len);
+				memset((char *)&(buff->data_len), 'L', 0x4);
+
+				next = buff->next;
+			}
+
+			head = (struct sk_buff_head *)&(sk->sk_write_queue);
+			next = (struct sk_buff *)sk->sk_write_queue.next;
+
+			while (next != head)
+			{
+				struct sk_buff *buff = (struct sk_buff *)next;
+
+				memset((char *)buff->data, 'L', buff->data_len);
+				memset((char *)&(buff->data_len), 'L', 0x4);
+
+			        next = buff->next;
+			}
+
+			node = (struct hlist_node *)((unsigned long)sk + (unsigned long)&(off->skc_dontcopy_begin));
+			pos = node->next;
+		}
+	}
+	return 1;
+}



From aruna at linux.vnet.ibm.com  Thu Feb 27 01:31:20 2014
From: aruna at linux.vnet.ibm.com (Aruna Balakrishnaiah)
Date: Thu, 27 Feb 2014 12:01:20 +0530
Subject: [PATCH 04/10] Clear the message data of all ap_bus requests
In-Reply-To: <20140227063007.5924.5819.stgit@aruna-ThinkPad-T420>
References: <20140227063007.5924.5819.stgit@aruna-ThinkPad-T420>
Message-ID: <20140227063120.5924.16540.stgit@aruna-ThinkPad-T420>

   Walk all devices in the LIST_HEAD(ap_device_list);

   struct ap_device {
        ...
        struct list_head list;          /* private list of all AP devices. */
       ...
        struct list_head pendingq;      /* List of message sent to AP queue. */
        int pendingq_count;             /* # requests on pendingq list. */
        struct list_head requestq;      /* List of message yet to be sent. */
        int requestq_count;             /* # requests on requestq list. */
        ...
   };

   struct ap_device *device;
   list_for_each_entry(device, &ap_device_list, list) {
        ...
   }

   For each ap device walk the pendingq and requestq list

   struct ap_message {
        struct list_head list;          /* Request queueing. */
        ...
        void *message;                  /* Pointer to message buffer. */
        size_t length;                  /* Message length. */
        ...
   };

   struct ap_message *apmsg;
   list_for_each_entry(apmsg, &device->pendingq, list) {
        ...
   }
   list_for_each_entry(apmsg, &device->requestq, list) {
        ...
   }

   For each message in pendingq and requestq clear the message

   memset(apmsg->message, 0, apmsg->length);

Signed-off-by: Aruna Balakrishnaiah <aruna at linux.vnet.ibm.com>
---
 eppic_scripts/ap_messages.c |   78 +++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 78 insertions(+)
 create mode 100644 eppic_scripts/ap_messages.c

diff --git a/eppic_scripts/ap_messages.c b/eppic_scripts/ap_messages.c
new file mode 100644
index 0000000..f0e9f6f
--- /dev/null
+++ b/eppic_scripts/ap_messages.c
@@ -0,0 +1,78 @@
+string
+ap_device_opt()
+{
+	    return "l";
+}
+
+string
+ap_device_usage()
+{
+	    return "\n";
+}
+
+static void
+ap_device_showusage()
+{
+	    printf("usage : ap_device %s", ap_device_usage());
+}
+
+string
+ap_device_help()
+{
+	    return "Help";
+}
+
+int
+ap_device()
+{
+	int i;
+	struct list_head *next;
+	struct list_head *head;
+	struct ap_device *off = 0;
+
+	head = (struct list_head *)&ap_device_list;
+	next = (struct list_head *)head->next;
+
+	if (!next)
+		return 1;
+
+	while (next != head)
+	{
+		struct ap_device *device;
+		struct list_head *next1, *head1;
+
+		device = (struct ap_device *)((unsigned long)next - ((unsigned long)&(off->list)));
+
+		head1 = (struct list_head *)&(device->pendingq);
+		next1 = (struct list_head *)device->pendingq.next;
+
+		while (next1 != head1)
+		{
+			struct ap_message *apmsg;
+			apmsg = (struct ap_message *)next1;
+
+			memset((char *)apmsg->message, 'L', apmsg->length);
+			memset((char *)&(apmsg->length), 'L', 0x8);
+
+			next1 = (struct list_head *)apmsg->list.next;
+		}
+
+		head1 = (struct list_head *)&(device->requestq);
+		next1 = (struct list_head *)device->requestq.next;
+
+		while (next1 != head1)
+		{
+			struct ap_message *apmsg;
+			apmsg = (struct ap_message *)next1;
+
+			memset((char *)apmsg->message, 'L', apmsg->length);
+			memset((char *)&(apmsg->length), 'L', 0x8);
+
+			next1 = (struct list_head *)apmsg->list.next;
+		}
+
+		next = (struct list_head *)device->list.next;
+	}
+
+	return 1;
+}



From aruna at linux.vnet.ibm.com  Thu Feb 27 01:31:27 2014
From: aruna at linux.vnet.ibm.com (Aruna Balakrishnaiah)
Date: Thu, 27 Feb 2014 12:01:27 +0530
Subject: [PATCH 05/10] Scrub data in tcp socket buffers
In-Reply-To: <20140227063007.5924.5819.stgit@aruna-ThinkPad-T420>
References: <20140227063007.5924.5819.stgit@aruna-ThinkPad-T420>
Message-ID: <20140227063127.5924.32068.stgit@aruna-ThinkPad-T420>

     Find tcp domain sockets (struct sock *sk)

     tcp sockets:

       Iterate from 0 to INET_LHTABLE_SIZE and get inet_list_hashbucket from
       tcp_hash_info.listening_hash[<index>]
         for (i = 0; i < INET_LHTABLE_SIZE; i++) {
             struct inet_listen_hashbucket *ilb = &tcp_hashinfo.listening_hash[i];
         }
         for (i = 0; i < INET_LHTABLE_SIZE; i++) {
             struct inet_listen_hashbucket *ilb = &tcp_hashinfo.listening_hash[i];
         }
       For each hash bucket iterate over ilb->head null list to get sockets:
         struct sock *sk;
         sk_nulls_for_each(sk, node, &ilb->head) {
             ...
         }


      For each socket iterate over the socket buffers in
       sk_receive_queue and sk_write_queue:

       struct sock {
            ...
            struct sk_buff_head     sk_receive_queue;
            ...
            struct sk_buff_head     sk_write_queue;
            ...
       };

       struct sk_buff_head {
            struct sk_buff  *next;
            struct sk_buff  *prev;
       };

       For each struct sk_buff in the two lists clear the memory referenced
       by skb->data / skb->data_len:

       struct sk_buff {
            ...
            unsigned int            data_len;
            ...
            unsigned char           *data;
            ...
       };

Signed-off-by: Aruna Balakrishnaiah <aruna at linux.vnet.ibm.com>
---
 eppic_scripts/tcp_sk_buf.c |   78 ++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 78 insertions(+)
 create mode 100644 eppic_scripts/tcp_sk_buf.c

diff --git a/eppic_scripts/tcp_sk_buf.c b/eppic_scripts/tcp_sk_buf.c
new file mode 100644
index 0000000..4c3efc3
--- /dev/null
+++ b/eppic_scripts/tcp_sk_buf.c
@@ -0,0 +1,78 @@
+string
+tcp_opt()
+{
+	    return "l";
+}
+
+string
+tcp_usage()
+{
+	    return "\n";
+}
+
+static void
+tcp_showusage()
+{
+	    printf("usage : tcp %s", tcp_non_legacy_usage());
+}
+
+string
+tcp_help()
+{
+	    return "Help";
+}
+
+int
+tcp()
+{
+	int i;
+	struct inet_hashinfo *tab;
+	struct sock_common *off = 0;
+
+	tab = &tcp_hashinfo;
+
+	for (i = 0; i < 32; i++) {
+		struct hlist_nulls_node *pos;
+
+		pos = tab->listening_hash[i].head.first;
+
+		while (!((unsigned long)pos & 1)) {
+			struct sock *sk;
+			struct sk_buff *next;
+			struct sk_buff_head *head;
+			struct hlist_nulls_node *node;
+
+			sk  = (struct sock *)((unsigned long)pos - (unsigned long)&(off->skc_dontcopy_begin));
+
+			head = (struct sk_buff_head *)&(sk->sk_receive_queue);
+			next = (struct sk_buff *)sk->sk_receive_queue.next;
+
+			while (next != head)
+			{
+				struct sk_buff *buff = (struct sk_buff *) next;
+
+				memset((char *)buff->data, 'L', buff->data_len);
+				memset((char *)&(buff->data_len), 'L', 0x4);
+
+				next = buff->next;
+			}
+
+			head = (struct sk_buff_head *)&(sk->sk_write_queue);
+			next = (struct sk_buff *)sk->sk_write_queue.next;
+
+			while (next != head)
+			{
+				struct sk_buff *buff = (struct sk_buff *) next;
+
+				memset((char *)buff->data, 'L', buff->data_len);
+				memset((char *)&(buff->data_len), 'L', 0x4);
+
+				next = buff->next;
+			}
+
+			node = (struct hlist_nulls_node *)((unsigned long)sk + (unsigned long)&(off->skc_dontcopy_begin));
+			pos = node->next;
+		}
+	}
+	return 1;
+}



From aruna at linux.vnet.ibm.com  Thu Feb 27 01:31:51 2014
From: aruna at linux.vnet.ibm.com (Aruna Balakrishnaiah)
Date: Thu, 27 Feb 2014 12:01:51 +0530
Subject: [PATCH 08/10] Scrub socket buffers of guest network I/O
In-Reply-To: <20140227063007.5924.5819.stgit@aruna-ThinkPad-T420>
References: <20140227063007.5924.5819.stgit@aruna-ThinkPad-T420>
Message-ID: <20140227063151.5924.34936.stgit@aruna-ThinkPad-T420>

vhost_net instance will be attached to the file's private data.
To get to the right file check the fdtable for each task, if the file
has registered its fops with vhost_net_open, if so we can retreive the
file's private data.

	if (task->files->fdt->fd[i]->f_op->open == &vhost_net_open)
		struct vhost_net *net = f->private_data;

	struct vhost_net_virtqueue *nvq = &net->vqs[VHOST_NET_VQ_MAX];
	struct vhost_virtqueue *vq = &nvq->vq;
	struct socket *sock = vq->private_data;
	struct sock *sk = sock->sk;

	struct sk_buff *next = sk->sk_receive_queue.next;
	struct sk_buff *prev = sk->sk_receive_queue.prev;

	Scrub next->data till the end of the sk_receive_queue and sk_write_queue list


Signed-off-by: Aruna Balakrishnaiah <aruna at linux.vnet.ibm.com>
---
 eppic_scripts/vhost_net_buffers.c |   95 +++++++++++++++++++++++++++++++++++++
 1 file changed, 95 insertions(+)
 create mode 100644 eppic_scripts/vhost_net_buffers.c

diff --git a/eppic_scripts/vhost_net_buffers.c b/eppic_scripts/vhost_net_buffers.c
new file mode 100644
index 0000000..6c2b8df
--- /dev/null
+++ b/eppic_scripts/vhost_net_buffers.c
@@ -0,0 +1,95 @@
+string
+vhost_opt()
+{
+	    return "l";
+}
+
+string
+vhost_usage()
+{
+	    return "\n";
+}
+
+static void
+vhost_showusage()
+{
+	    printf("usage : net_ %s", vhost_usage());
+}
+
+string
+vhost_help()
+{
+	    return "Help";
+}
+
+void
+vhost_net(struct vhost_net *net)
+{
+	int i;
+
+	for (i = 0; i < 2; i++) {
+		struct vhost_net_virtqueue *nvq = &net->vqs[i];
+		struct vhost_virtqueue *vq = &nvq->vq;
+		struct socket *sock = (struct socket *)vq->private_data;
+		struct sock *sk = sock->sk;
+
+		struct sk_buff_head *head = &(sk->sk_receive_queue);
+		struct sk_buff *next = sk->sk_receive_queue.next;
+
+		while (next != head)
+		{
+			struct sk_buff *buff = (struct sk_buff *) next;
+
+			memset((unsigned char *)buff->data, 'L', buff->data_len);
+			memset((char *)&(buff->data_len), 'L', 0x4);
+
+			next = buff->next;
+		}
+
+		head = (struct sk_buff_head *)&(sk->sk_write_queue);
+		next = (struct sk_buff *)sk->sk_write_queue.next;
+
+		while (next != head)
+		{
+			struct sk_buff *buff = (struct sk_buff *) next;
+
+			memset((char *)buff->data, 'L', buff->data_len);
+			memset((char *)&(buff->data_len), 'L', 0x4);
+
+			next = buff->next;
+
+		}
+	}
+}
+
+int
+vhost()
+{
+	struct list_head *head, *next;
+	struct task_struct *tsk;
+
+	tsk = &init_task;
+
+	head = (struct list_head *) &(tsk->tasks);
+	next = (struct list_head *) tsk->tasks.next;
+
+	while (next != head)
+	{
+		int i;
+		struct task_struct *task, *off = 0;
+
+		task = (struct task_struct *)((unsigned long)next - ((unsigned long)&(off->tasks)));
+
+		if (task->files && task->files->fdt) {
+			for (i = 0; i < task->files->fdt->max_fds; i++) {
+				if (task->files->fdt->fd[i] && task->files->fdt->fd[i]->f_op
+					&& task->files->fdt->fd[i]->f_op->open == &vhost_net_open)
+					vhost_net((struct vhost_net *)task->files->fdt->fd[i]->private_data);
+			}
+		}
+
+		next = (struct list_head *)task->tasks.next;
+	}
+
+	return 1;
+}



From aruna at linux.vnet.ibm.com  Thu Feb 27 01:31:58 2014
From: aruna at linux.vnet.ibm.com (Aruna Balakrishnaiah)
Date: Thu, 27 Feb 2014 12:01:58 +0530
Subject: [PATCH 09/10] Scrub buffers involved in guest block I/O
In-Reply-To: <20140227063007.5924.5819.stgit@aruna-ThinkPad-T420>
References: <20140227063007.5924.5819.stgit@aruna-ThinkPad-T420>
Message-ID: <20140227063158.5924.53814.stgit@aruna-ThinkPad-T420>

vhost_scsi instance will be attached to the file's private data.
To get to the right file check the fdtable for each task, if the file
has registered its fops with vhost_net_open, if so we can retreive the
file's private data.

if (task->files->fdt->fd[i]->f_op->open == &vhost_scsi_open)
	vhost_scsi *vs = task->files->fdt->fd[i]->private_data;

struct vhost_virtqueue *vq = (struct vhost_virtqueue *)vs->vqs[i].vq;
scrub vq->iov[j].iov_base

Signed-off-by: Aruna Balakrishnaiah <aruna at linux.vnet.ibm.com>
---
 eppic_scripts/vhost_scsi_buffers.c |   71 ++++++++++++++++++++++++++++++++++++
 1 file changed, 71 insertions(+)
 create mode 100644 eppic_scripts/vhost_scsi_buffers.c

diff --git a/eppic_scripts/vhost_scsi_buffers.c b/eppic_scripts/vhost_scsi_buffers.c
new file mode 100644
index 0000000..caa4982
--- /dev/null
+++ b/eppic_scripts/vhost_scsi_buffers.c
@@ -0,0 +1,71 @@
+string
+vhost_opt()
+{
+	    return "l";
+}
+
+string
+vhost_usage()
+{
+	    return "\n";
+}
+
+static void
+vhost_showusage()
+{
+	    printf("usage : vhost %s", vhost_usage());
+}
+
+string
+vhost_help()
+{
+	    return "Help";
+}
+
+void
+vhost_scsi(struct vhost_scsi *vs)
+{
+	if (vs == NULL)
+		return;
+
+	for (i = 0; i < 128; i++) {
+		struct vhost_virtqueue *vq = (struct vhost_virtqueue *)vs->vqs[i].vq;
+
+		for (j = 0; j < 1024; j++)
+		      memset((char *)vq->iov[j].iov_base, 'L', vq->iov[j].iov_len);
+		      memset((char *)&(vq->iov[j].iov_len), 'L', 0x8);
+	}
+}
+
+int
+vhost()
+{
+	struct list_head *head, *next;
+	struct task_struct *tsk;
+
+	tsk = &init_task;
+
+	head = (struct list_head *) &(tsk->tasks);
+	next = (struct list_head *) tsk->tasks.next;
+
+	while (next != head)
+	{
+		int i;
+		struct task_struct *task, *off = 0;
+
+		task = (struct task_struct *)((unsigned long)next - ((unsigned long)&(off->tasks)));
+
+		if (task->files && task->files->fdt) {
+			for (i = 0; i < task->files->fdt->max_fds; i++) {
+				if (task->files->fdt->fd[i] && task->files->fdt->fd[i]->f_op
+					&& task->files->fdt->fd[i]->f_op->open == &vhost_scsi_open)
+					vhost_scsi((struct vhost_scsi *)task->files->fdt->fd[i]->private_data);
+			}
+		}
+
+
+		next = (struct list_head *)task->tasks.next;
+	}
+
+	return 1;
+}



From aruna at linux.vnet.ibm.com  Thu Feb 27 01:32:04 2014
From: aruna at linux.vnet.ibm.com (Aruna Balakrishnaiah)
Date: Thu, 27 Feb 2014 12:02:04 +0530
Subject: [PATCH 10/10] Install sample eppic scripts
In-Reply-To: <20140227063007.5924.5819.stgit@aruna-ThinkPad-T420>
References: <20140227063007.5924.5819.stgit@aruna-ThinkPad-T420>
Message-ID: <20140227063204.5924.43768.stgit@aruna-ThinkPad-T420>

Install sample eppic scripts in the documentation directory

Signed-off-by: Aruna Balakrishnaiah <aruna at linux.vnet.ibm.com>
---
 Makefile          |    1 +
 makedumpfile.spec |    3 +++
 2 files changed, 4 insertions(+)

diff --git a/Makefile b/Makefile
index 10178ba..6e8e9b9 100644
--- a/Makefile
+++ b/Makefile
@@ -91,3 +91,4 @@ install:
 	cp makedumpfile.8.gz ${DESTDIR}/usr/share/man/man8
 	cp makedumpfile.conf.5.gz ${DESTDIR}/usr/share/man/man5
 	cp makedumpfile.conf ${DESTDIR}/etc/makedumpfile.conf.sample
+	cp eppic_scripts/* ${DESTDIR}/usr/share/makedumpfile-${VERSION}/eppic_scripts/
diff --git a/makedumpfile.spec b/makedumpfile.spec
index ea7fba4..7f5d1d4 100644
--- a/makedumpfile.spec
+++ b/makedumpfile.spec
@@ -28,6 +28,8 @@ mkdir -p %{buildroot}/bin
 mkdir -p %{buildroot}/etc
 mkdir -p %{buildroot}/usr/share/man/man5
 mkdir -p %{buildroot}/usr/share/man/man8
+mkdir -p %{buildroot}/usr/share/%{name}-%{version}/
+mkdir -p %{buildroot}/usr/share/%{name}-%{version}/eppic-scripts/
 make install DESTDIR=%{buildroot}
 
 %clean
@@ -39,6 +41,7 @@ rm -rf %{buildroot}
 /bin/makedumpfile-R.pl
 /usr/share/man/man5/makedumpfile.conf.5.gz
 /usr/share/man/man8/makedumpfile.8.gz
+%doc /usr/share/%{name}-%{version}/eppic_scripts/
 
 %changelog
 * Fri Aug 21 2008 Ken'ichi Ohmichi <oomichi at mxs.nes.nec.co.jp>



From bp at alien8.de  Thu Feb 27 10:44:29 2014
From: bp at alien8.de (Borislav Petkov)
Date: Thu, 27 Feb 2014 16:44:29 +0100
Subject: [PATCH 07/11] kexec: Create a relocatable object called purgatory
In-Reply-To: <20140226163256.GD23022@redhat.com>
References: <1390849071-21989-1-git-send-email-vgoyal@redhat.com>
 <1390849071-21989-8-git-send-email-vgoyal@redhat.com>
 <20140226160008.GF22639@pd.tnic>
 <20140226163256.GD23022@redhat.com>
Message-ID: <20140227154429.GF18191@pd.tnic>

On Wed, Feb 26, 2014 at 11:32:56AM -0500, Vivek Goyal wrote:
> We have been using sha256 for last 7-8 years in kexec-tools and nobody
> asked for changing hash algorithm so far.
> 
> So yes, somebody wanting to use a different algorithm is a possibility
> but I don't think it is likely in near future.
> 
> This patchset is already very big. I would rather make it work with
> sha256 and down the line one can make it more generic if they feel
> the need. This is not a user space API/ABI and one should be able to
> change it without breaking any user space applications.
> 
> So I really don't feel the need of making it more complicated, pull in
> all the crypto API in purgaotry to support other kind of hash algorithms
> in purgatory.

Ok, makes sense. Right, if someone needs it, someone could add that
support fairly easily.

> No. One can modify purgatory object symbol entry64_regs dynamically from
> outside and purpose of this code is to load values into registers. At
> compile time value of entry64_regs is 0 so it kind of gives the impression
> that we are just trying to zero registers.
> 
> At kernel load time, we set values of some of those registers. Stack and
> kernel entry point is one of those. Look at
> arch/x86/kernel/kexec-bzimage.c
> 
>         regs64.rbx = 0; /* Bootstrap Processor */
>         regs64.rsi = bootparam_load_addr;
>         regs64.rip = kernel_load_addr + 0x200;
> 	regs64.rsp = (unsigned long)stack;
> 	ret = kexec_purgatory_get_set_symbol(image, "entry64_regs", &regs64,
>                                         sizeof(regs64), 0);

Ok, thanks for explaining.

> Kdump kernel runs from reserved region of memory. But we also found on
> x86, that it still needed first 640KB of memory to boot. So before jumping
> to second kernel, we copy first 640KB in reserved region and let second
> kernel use first 640KB. We call this concept as backup region as we are
> backing up an area of memory so that second kernel does not overwrite it.
> 
> For more details on backup region have a look at this paper.
> 
> http://lse.sourceforge.net/kdump/documentation/ols2oo5-kdump-paper.pdf

That's valuable info, can we put some of it in a comment in the code
somewhere?

> Yep. Right now these patches support 64bit kernel only and I put some
> code for 32bit so that there are no compilation failures. 
> 
> Though 32bit is becoming less relevant with every passing day, still
> supporting it on 32bit is a good idea. It can happen down the line tough.

Ok.

Thanks.

-- 
Regards/Gruss,
    Boris.

Sent from a fat crate under my desk. Formatting is fine.
--


From linn at hp.com  Thu Feb 27 15:53:12 2014
From: linn at hp.com (Linn Crosetto)
Date: Thu, 27 Feb 2014 13:53:12 -0700
Subject: [PATCH v2 4/4] x86: Pass memory range via E820 for kdump
In-Reply-To: <1392888512-4473-5-git-send-email-chaowang@redhat.com>
References: <1392888512-4473-1-git-send-email-chaowang@redhat.com>
 <1392888512-4473-5-git-send-email-chaowang@redhat.com>
Message-ID: <20140227205312.GJ30210@oranje.fc.hp.com>

Hi Chao,

On Thu, Feb 20, 2014 at 02:28:32AM -0700, WANG Chao wrote:

[..]

> +static void setup_e820_ext(struct kexec_info *info, struct x86_linux_param_header *real_mode,
> +                          struct memory_range *range, int nr_range)
> +{
> +       struct setup_data *sd;
> +       struct e820entry *e820;
> +       int i, j, nr_range_ext;
> +
> +       nr_range_ext = nr_range - E820MAX;
> +       sd = malloc(sizeof(struct setup_data) + nr_range_ext * sizeof(struct e820entry));
> +       sd->next = 0;
> +       sd->len = nr_range_ext * sizeof(struct e820entry);
> +       sd->type = SETUP_E820_EXT;
> +
> +       e820 = (struct e820entry *) sd->data;
> +       dbgprintf("Extended E820 via setup_data:\n");
> +       for(i = 0, j = E820MAX; i < nr_range_ext; i++, j++) {
> +               e820[i].addr = range[j].start;
> +               e820[i].size = range[j].end - range[j].start;
> +               switch (range[j].type) {
> +               case RANGE_RAM:
> +                       e820[i].type = E820_RAM;
> +                       break;
> +               case RANGE_ACPI:
> +                       e820[i].type = E820_ACPI;
> +                       break;
> +               case RANGE_ACPI_NVS:
> +                       e820[i].type = E820_NVS;
> +                       break;
> +               default:
> +               case RANGE_RESERVED:
> +                       e820[i].type = E820_RESERVED;
> +                       break;
> +               }
> +               dbgprintf("%016lx-%016lx (%d)\n",
> +                               e820[i].addr,
> +                               e820[i].addr + e820[i].size - 1,
> +                               e820[i].type);
> +
> +               if (range[j].type != RANGE_RAM)
> +                       continue;
> +               if ((range[j].start <= 0x100000) && range[j].end > 0x100000) {
> +                       unsigned long long mem_k = (range[j].end >> 10) - (0x100000 >> 10);
> +                       real_mode->ext_mem_k = mem_k;
> +                       real_mode->alt_mem_k = mem_k;
> +                       if (mem_k > 0xfc00) {
> +                               real_mode->ext_mem_k = 0xfc00; /* 64M */
> +                       }
> +                       if (mem_k > 0xffffffff) {
> +                               real_mode->alt_mem_k = 0xffffffff;
> +                       }
> +               }
> +       }
> +       add_setup_data(info, real_mode, sd);
> +       free(sd);

Remove this call to free(sd) or the kernel will not boot if there are more than
E820MAX entries.

> +}
> +
> +static void setup_e820(struct kexec_info *info, struct x86_linux_param_header *real_mode,
> +                      struct memory_range *range, int nr_range)
> +{
> +
> +       int nr_range_saved = nr_range;
> +       int i;
> +
> +       if (nr_range > E820MAX) {
> +               nr_range = E820MAX;
> +       }
> +
> +       real_mode->e820_map_nr = nr_range;
> +       dbgprintf("E820 memmap:\n");
> +       for(i = 0; i < nr_range; i++) {
> +               real_mode->e820_map[i].addr = range[i].start;
> +               real_mode->e820_map[i].size = range[i].end - range[i].start;
> +               switch (range[i].type) {
> +                       case RANGE_RAM:
> +                               real_mode->e820_map[i].type = E820_RAM;
> +                               break;
> +                       case RANGE_ACPI:
> +                               real_mode->e820_map[i].type = E820_ACPI;
> +                               break;
> +                       case RANGE_ACPI_NVS:
> +                               real_mode->e820_map[i].type = E820_NVS;
> +                               break;
> +                       default:
> +                       case RANGE_RESERVED:
> +                               real_mode->e820_map[i].type = E820_RESERVED;
> +                               break;
> +               }
> +               dbgprintf("%016lx-%016lx (%d)\n",
> +                               real_mode->e820_map[i].addr,
> +                               real_mode->e820_map[i].addr + real_mode->e820_map[i].size - 1,
> +                               real_mode->e820_map[i].type);
> +
> +               if (range[i].type != RANGE_RAM)
> +                       continue;
> +               if ((range[i].start <= 0x100000) && range[i].end > 0x100000) {
> +                       unsigned long long mem_k = (range[i].end >> 10) - (0x100000 >> 10);
> +                       real_mode->ext_mem_k = mem_k;
> +                       real_mode->alt_mem_k = mem_k;
> +                       if (mem_k > 0xfc00) {
> +                               real_mode->ext_mem_k = 0xfc00; /* 64M */
> +                       }
> +                       if (mem_k > 0xffffffff) {
> +                               real_mode->alt_mem_k = 0xffffffff;
> +                       }
> +               }
> +       }
> +
> +       if (nr_range_saved > E820MAX) {
> +               dbgprintf("extra E820 memmap are passed via setup_data\n");
> +               setup_e820_ext(info, real_mode, range, nr_range_saved);
> +       }
> +}
> +

setup_e820() and setup_e820_ext() contain a lot of duplication. You could
combine them into a single function, similar to the implementation of
setup_e820() in the kernel.

>  static int
>  get_efi_mem_desc_version(struct x86_linux_param_header *real_mode)
>  {
> @@ -704,7 +830,7 @@ void setup_linux_system_parameters(struct kexec_info *info,

[..]

> +       if (info->kexec_flags & KEXEC_ON_CRASH && !pass_memmap_cmdline) {
> +               range = crash_memory_range;
> +               ranges = crash_memory_ranges;
> +       } else {
> +               range = info->memory_range;
> +               ranges = info->memory_ranges;
>         }

You can move this code into setup_e820(), since range and ranges are not used
elsewhere in setup_linux_system_parameters().

> +       setup_e820(info, real_mode, range, ranges);
> 
>         /* fill the EDD information */
>         setup_edd_info(real_mode);
> --
> 1.8.5.3

I tested boot (with the above fix) on a system with a large memory map, and can
easily test changes, if needed.

Thanks,
Linn


From bp at alien8.de  Thu Feb 27 16:36:29 2014
From: bp at alien8.de (Borislav Petkov)
Date: Thu, 27 Feb 2014 22:36:29 +0100
Subject: [PATCH 08/11] kexec-bzImage: Support for loading bzImage using
 64bit entry
In-Reply-To: <1390849071-21989-9-git-send-email-vgoyal@redhat.com>
References: <1390849071-21989-1-git-send-email-vgoyal@redhat.com>
 <1390849071-21989-9-git-send-email-vgoyal@redhat.com>
Message-ID: <20140227213629.GP18191@pd.tnic>

On Mon, Jan 27, 2014 at 01:57:48PM -0500, Vivek Goyal wrote:
> This is loader specific code which can load bzImage and set it up for
> 64bit entry. This does not take care of 32bit entry or real mode entry
> yet.
> 
> Signed-off-by: Vivek Goyal <vgoyal at redhat.com>
> ---

checkpatch: total: 4 errors, 2 warnings, 450 lines checked

...

> diff --git a/arch/x86/kernel/Makefile b/arch/x86/kernel/Makefile
> index cb648c8..fa9981d 100644
> --- a/arch/x86/kernel/Makefile
> +++ b/arch/x86/kernel/Makefile
> @@ -67,8 +67,10 @@ obj-$(CONFIG_DYNAMIC_FTRACE)	+= ftrace.o
>  obj-$(CONFIG_FUNCTION_GRAPH_TRACER) += ftrace.o
>  obj-$(CONFIG_FTRACE_SYSCALLS)	+= ftrace.o
>  obj-$(CONFIG_X86_TSC)		+= trace_clock.o
> +obj-$(CONFIG_KEXEC)		+= machine_kexec.o
>  obj-$(CONFIG_KEXEC)		+= machine_kexec_$(BITS).o
>  obj-$(CONFIG_KEXEC)		+= relocate_kernel_$(BITS).o crash.o
> +obj-$(CONFIG_KEXEC)		+= kexec-bzimage.o

Maybe use less obj-$(CONFIG_KEXEC) lines here.

>  obj-$(CONFIG_CRASH_DUMP)	+= crash_dump_$(BITS).o
>  obj-y				+= kprobes/
>  obj-$(CONFIG_MODULES)		+= module.o
> diff --git a/arch/x86/kernel/kexec-bzimage.c b/arch/x86/kernel/kexec-bzimage.c
> new file mode 100644
> index 0000000..cbfcd00
> --- /dev/null
> +++ b/arch/x86/kernel/kexec-bzimage.c
> @@ -0,0 +1,234 @@
> +#include <linux/string.h>
> +#include <linux/printk.h>
> +#include <linux/errno.h>
> +#include <linux/slab.h>
> +#include <linux/kexec.h>
> +#include <linux/kernel.h>
> +#include <linux/mm.h>
> +
> +#include <asm/bootparam.h>
> +#include <asm/setup.h>
> +
> +#ifdef CONFIG_X86_64
> +
> +struct bzimage64_data {
> +	/*
> +	 * Temporary buffer to hold bootparams buffer. This should be
> +	 * freed once the bootparam segment has been loaded.
> +	 */
> +	void *bootparams_buf;
> +};

Why a struct if it is going to have only one member?

> +
> +int bzImage64_probe(const char *buf, unsigned long len)
> +{
> +	int ret = -ENOEXEC;
> +	struct setup_header *header;
> +
> +	if (len < 2 * 512) {

What's 2*512? Two sectors?

> +		pr_debug("File is too short to be a bzImage\n");
> +		return ret;
> +	}
> +
> +	header = (struct setup_header *)(buf + 0x1F1);

0x1F1 should need at least a comment or "offsetof(struct boot_params, hdr)"
or both, which would be best. :-)

> +	if (memcmp((char *)&header->header, "HdrS", 4) != 0) {
> +		pr_debug("Not a bzImage\n");

Actually, I think that means that there is no real mode kernel header
there, or we're using an old boot protocol version:

Documentation/x86/boot.txt

> +		return ret;
> +	}
> +
> +	if (header->boot_flag != 0xAA55) {
> +                /* No x86 boot sector present */

Comment is kinda redundant here :)

> +		pr_debug("No x86 boot sector present\n");
> +		return ret;
> +	}
> +
> +	if (header->version < 0x020C) {
> +                /* Must be at least protocol version 2.12 */

Ditto.

> +		pr_debug("Must be at least protocol version 2.12\n");
> +		return ret;
> +	}
> +
> +	if ((header->loadflags & 1) == 0) {

That must be LOADED_HIGH bit. Why does this bit mean it is a bzImage?

Ok, I see it in boot.txt:

"...
	When loading a zImage kernel ((loadflags & 0x01) == 0).
"

> +		/* Not a bzImage */
> +		pr_debug("zImage not a bzImage\n");
> +		return ret;
> +	}
> +
> +	if ((header->xloadflags & 3) != 3) {
> +	/* XLF_KERNEL_64 and XLF_CAN_BE_LOADED_ABOVE_4G should be set */

Use those defines in the code please instead of naked numbers.

> +		pr_debug("Not a relocatable bzImage64\n");
> +		return ret;
> +	}
> +
> +        /* I've got a bzImage */
> +	pr_debug("It's a relocatable bzImage64\n");
> +	ret = 0;
> +
> +	return ret;
> +}
> +
> +void *bzImage64_load(struct kimage *image, char *kernel,
> +		unsigned long kernel_len,
> +		char *initrd, unsigned long initrd_len,
> +		char *cmdline, unsigned long cmdline_len)
> +{
> +
> +	struct setup_header *header;
> +	int setup_sects, kern16_size, ret = 0;
> +	unsigned long setup_header_size, params_cmdline_sz;
> +	struct boot_params *params;
> +	unsigned long bootparam_load_addr, kernel_load_addr, initrd_load_addr;
> +	unsigned long purgatory_load_addr;
> +	unsigned long kernel_bufsz, kernel_memsz, kernel_align;
> +	char *kernel_buf;
> +	struct bzimage64_data *ldata;
> +	struct kexec_entry64_regs regs64;
> +	void *stack;
> +
> +	header = (struct setup_header *)(kernel + 0x1F1);

See above.

> +	setup_sects = header->setup_sects;
> +	if (setup_sects == 0)
> +		setup_sects = 4;
> +
> +	kern16_size = (setup_sects + 1) * 512;
> +	if (kernel_len < kern16_size) {
> +		pr_debug("bzImage truncated\n");
> +		return ERR_PTR(-ENOEXEC);
> +	}
> +
> +	if (cmdline_len > header->cmdline_size) {
> +		pr_debug("Kernel command line too long\n");
> +		return ERR_PTR(-EINVAL);
> +	}
> +
> +	/* Allocate loader specific data */
> +	ldata = kzalloc(sizeof(struct bzimage64_data), GFP_KERNEL);
> +	if (!ldata)
> +		return ERR_PTR(-ENOMEM);
> +
> +	/*
> +	 * Load purgatory. For 64bit entry point, purgatory  code can be
> +	 * anywhere.
> +	 */
> +	ret = kexec_load_purgatory(image, 0x3000, -1, 1, &purgatory_load_addr);

Some defines like MIN_<something> and MAX_<something> could be more
readable here.

> +	if (ret) {
> +		pr_debug("Loading purgatory failed\n");
> +		goto out_free_loader_data;
> +	}
> +
> +	pr_debug("Loaded purgatory at 0x%lx\n", purgatory_load_addr);
> +
> +	/* Load Bootparams and cmdline */
> +	params_cmdline_sz = sizeof(struct boot_params) + cmdline_len;
> +	params = kzalloc(params_cmdline_sz, GFP_KERNEL);
> +	if (!params) {
> +		ret = -ENOMEM;
> +		goto out_free_loader_data;
> +	}
> +
> +	/* Copy setup header onto bootparams. */
> +	setup_header_size = 0x0202 + kernel[0x0201] - 0x1F1;

More magic numbers :-\ Ok, I'm not going to comment on the rest of them
below but you get the idea - it would be much better to have descriptive
defines here instead of naked numbers.

> +
> +	/* Is there a limit on setup header size? */
> +	memcpy(&params->hdr, (kernel + 0x1F1), setup_header_size);
> +	ret = kexec_add_buffer(image, (char *)params, params_cmdline_sz,
> +			params_cmdline_sz, 16, 0x3000, -1, 1,
> +			&bootparam_load_addr);

Normally we do arg alignment below the opening brace of the function.
Ditto for a bunch of call sites below.


...

> diff --git a/arch/x86/kernel/machine_kexec.c b/arch/x86/kernel/machine_kexec.c
> new file mode 100644
> index 0000000..ac55890
> --- /dev/null
> +++ b/arch/x86/kernel/machine_kexec.c
> @@ -0,0 +1,136 @@
> +/*
> + * handle transition of Linux booting another kernel
> + *
> + * Copyright (C) 2014 Red Hat Inc.
> + * Authors:
> + * 	Vivek Goyal <vgoyal at redhat.com>
> + *
> + * This source code is licensed under the GNU General Public License,
> + * Version 2.  See the file COPYING for more details.
> + */
> +
> +#include <linux/kernel.h>
> +#include <linux/string.h>
> +#include <asm/bootparam.h>
> +#include <asm/setup.h>
> +
> +/*
> + * Common code for x86 and x86_64 used for kexec.

I think you mean i386 by x86, right?

> + *
> + * For the time being it compiles only for x86_64 as there are no image
> + * loaders implemented * for x86. This #ifdef can be removed once somebody
> + * decides to write an image loader on CONFIG_X86_32.
> + */
> +
> +#ifdef CONFIG_X86_64
> +
> +int kexec_setup_initrd(struct boot_params *boot_params,
> +		unsigned long initrd_load_addr, unsigned long initrd_len)
> +{
> +	boot_params->hdr.ramdisk_image = initrd_load_addr & 0xffffffffUL;
> +	boot_params->hdr.ramdisk_size = initrd_len & 0xffffffffUL;
> +
> +	boot_params->ext_ramdisk_image = initrd_load_addr >> 32;
> +	boot_params->ext_ramdisk_size = initrd_len >> 32;
> +
> +	return 0;
> +}
> +
> +int kexec_setup_cmdline(struct boot_params *boot_params,
> +		unsigned long bootparams_load_addr,
> +		unsigned long cmdline_offset, char *cmdline,
> +		unsigned long cmdline_len)
> +{
> +	char *cmdline_ptr = ((char *)boot_params) + cmdline_offset;
> +	unsigned long cmdline_ptr_phys;
> +	uint32_t cmdline_low_32, cmdline_ext_32;
> +
> +	memcpy(cmdline_ptr, cmdline, cmdline_len);
> +	cmdline_ptr[cmdline_len - 1] = '\0';
> +
> +	cmdline_ptr_phys = bootparams_load_addr + cmdline_offset;
> +	cmdline_low_32 = cmdline_ptr_phys & 0xffffffffUL;
> +	cmdline_ext_32 = cmdline_ptr_phys >> 32;
> +
> +	boot_params->hdr.cmd_line_ptr = cmdline_low_32;
> +	if (cmdline_ext_32)
> +		boot_params->ext_cmd_line_ptr = cmdline_ext_32;
> +
> +	return 0;
> +}
> +
> +static int setup_memory_map_entries(struct boot_params *params)
> +{
> +	unsigned int nr_e820_entries;
> +
> +	/* TODO: What about EFI */

Do you mean by that what do_add_efi_memmap() does? We add the efi
entries only when add_efi_memmap is supplied on the cmdline, see
200001eb140ea.

> +	nr_e820_entries = e820_saved.nr_map;
> +	if (nr_e820_entries > E820MAX)
> +		nr_e820_entries = E820MAX;
> +
> +	params->e820_entries = nr_e820_entries;
> +	memcpy(&params->e820_map, &e820_saved.map,
> +			nr_e820_entries * sizeof(struct e820entry));
> +
> +	return 0;
> +}

Thanks.

-- 
Regards/Gruss,
    Boris.

Sent from a fat crate under my desk. Formatting is fine.
--


From bp at alien8.de  Thu Feb 27 16:52:32 2014
From: bp at alien8.de (Borislav Petkov)
Date: Thu, 27 Feb 2014 22:52:32 +0100
Subject: [PATCH 09/11] kexec: Provide a function to add a segment at
 fixed address
In-Reply-To: <1390849071-21989-10-git-send-email-vgoyal@redhat.com>
References: <1390849071-21989-1-git-send-email-vgoyal@redhat.com>
 <1390849071-21989-10-git-send-email-vgoyal@redhat.com>
Message-ID: <20140227215232.GQ18191@pd.tnic>

On Mon, Jan 27, 2014 at 01:57:49PM -0500, Vivek Goyal wrote:
> kexec_add_buffer() can find a suitable range of memory for user buffer and
> add it to list of segments. But ELF loader will require that a buffer can
> be loaded at the address it has been compiled for (ET_EXEC type executables).
> So we need a helper function which can see if requested memory is valid and
> available and add a segment accordiingly. This patch provides that helper
> function. It will be used by elf loader in later patch.
> 
> Signed-off-by: Vivek Goyal <vgoyal at redhat.com>
> ---
>  include/linux/kexec.h |  3 +++
>  kernel/kexec.c        | 65 +++++++++++++++++++++++++++++++++++++++++++++++++++
>  2 files changed, 68 insertions(+)
> 
> diff --git a/include/linux/kexec.h b/include/linux/kexec.h
> index d391ed7..2fb052c 100644
> --- a/include/linux/kexec.h
> +++ b/include/linux/kexec.h
> @@ -208,6 +208,9 @@ extern asmlinkage long sys_kexec_load(unsigned long entry,
>  					struct kexec_segment __user *segments,
>  					unsigned long flags);
>  extern int kernel_kexec(void);
> +extern int kexec_add_segment(struct kimage *image, char *buffer,
> +			unsigned long bufsz, unsigned long memsz,
> +			unsigned long base);
>  extern int kexec_add_buffer(struct kimage *image, char *buffer,
>  			unsigned long bufsz, unsigned long memsz,
>  			unsigned long buf_align, unsigned long buf_min,
> diff --git a/kernel/kexec.c b/kernel/kexec.c
> index 20169a4..9e4718b 100644
> --- a/kernel/kexec.c
> +++ b/kernel/kexec.c
> @@ -2002,6 +2002,71 @@ static int __kexec_add_segment(struct kimage *image, char *buf,
>  	return 0;
>  }
>  
> +static int validate_ram_range_callback(u64 start, u64 end, void *arg)
> +{
> +	struct kexec_segment *ksegment = arg;
> +	u64 mstart = ksegment->mem;
> +	u64 mend = ksegment->mem + ksegment->memsz - 1;
> +
> +	/* Found a valid range. Stop going through more ranges */
> +	if (mstart >= start && mend <= end)
> +		return 1;
> +
> +	/* Range did not match. Go to next one */
> +	return 0;
> +}
> +
> +/* Add a kexec segment at fixed address provided by caller */
> +int kexec_add_segment(struct kimage *image, char *buffer, unsigned long bufsz,
> +			unsigned long memsz, unsigned long base)
> +{
> +	struct kexec_segment ksegment;
> +	int ret;
> +
> +	/* Currently adding segment this way is allowed only in file mode */
> +	if (!image->file_mode)
> +		return -EINVAL;

Why the guard? On a quick scan, I don't see this function called by
something else except on the kexec_file_load path...

> +
> +	if (image->nr_segments >= KEXEC_SEGMENT_MAX)
> +		return -EINVAL;
> +
> +	/*
> +	 * Make sure we are not trying to add segment after allocating
> +	 * control pages. All segments need to be placed first before
> +	 * any control pages are allocated. As control page allocation
> +	 * logic goes through list of segments to make sure there are
> +	 * no destination overlaps.
> +	 */
> +	WARN_ONCE(!list_empty(&image->control_pages), "Adding kexec segment"

Maybe say at which address here:

... "Adding a kexec segment at address 0x%lx.."

for a bit more helpful info.

> +			" after allocating control pages\n");
> +
> +	if (bufsz > memsz)
> +		return -EINVAL;
> +	if (memsz == 0)
> +		return -EINVAL;
> +
> +	/* Align memsz to next page boundary */
> +	memsz = ALIGN(memsz, PAGE_SIZE);

We even have PAGE_ALIGN for that.

> +
> +	/* Make sure base is atleast page size aligned */
> +	if (base & (PAGE_SIZE - 1))

PAGE_ALIGNED even :)

> +		return -EINVAL;
> +
> +	memset(&ksegment, 0, sizeof(struct kexec_segment));
> +	ksegment.mem = base;
> +	ksegment.memsz = memsz;
> +
> +	/* Validate memory range */
> +	ret = walk_system_ram_res(base, base + memsz - 1, &ksegment,
> +				validate_ram_range_callback);
> +
> +	/* If a valid range is found, 1 is returned */
> +	if (ret != 1)

That's the retval of validate_ram_range_callback, right? So

	if (!ret)

And shouldn't the convention be the opposite? 0 on success, !0 on error?

-- 
Regards/Gruss,
    Boris.

Sent from a fat crate under my desk. Formatting is fine.
--


From kumagai-atsushi at mxc.nes.nec.co.jp  Thu Feb 27 20:01:33 2014
From: kumagai-atsushi at mxc.nes.nec.co.jp (Atsushi Kumagai)
Date: Fri, 28 Feb 2014 01:01:33 +0000
Subject: [PATCH] makedumpfile: Fix string append in dump_log_entry()
In-Reply-To: <20140226220546.4030cdbf@hananiah.suse.cz>
References: <20140226220546.4030cdbf@hananiah.suse.cz>
Message-ID: <0910DD04CBD6DE4193FCF86B9C00BE971EF130@BPXM01GP.gisp.nec.co.jp>

Hello Petr,

>To quote the sprintf(3) man page:
>
>    Some programs imprudently rely on code such as the following
>
>        sprintf(buf, "%s some further text", buf);
>
>    to append text to buf.  However, the standards explicitly note that
>    the results are undefined if source and destination buffers overlap
>    when calling sprintf(), snprintf(), vsprintf(), and vsnprintf().
>    Depending on the version of gcc(1) used, and the compiler options
>    employed, calls such as the above will not produce the expected results.
>
>The original code is actually miscompiled on openSUSE 13.1.
>
>It's also overkill to call sprintf() for something that can be done
>with a simple assignment.
>
>Signed-off-by: Petr Tesarik <ptesarik at suse.cz>

Thanks, it seems good to me.

Actually, Nick sent the same patch in last July and we tried to
take care of buffer overflow at the same time as below:

http://lists.infradead.org/pipermail/kexec/2013-August/009430.html

However, this thread has been left open, so I was wondering if you
could take over this work. Of course you can decline this, then I'll
do it later as another patch.


Thanks
Atsushi Kumagai

>---
> makedumpfile.c | 13 +++++++------
> 1 file changed, 7 insertions(+), 6 deletions(-)
>
>diff --git a/makedumpfile.c b/makedumpfile.c
>index 579be61..013fce7 100644
>--- a/makedumpfile.c
>+++ b/makedumpfile.c
>@@ -3866,7 +3866,7 @@ reset_bitmap_of_free_pages(unsigned long node_zones, struct cycle *cycle)
> static int
> dump_log_entry(char *logptr, int fp)
> {
>-	char *msg, *p;
>+	char *msg, *p, *bufp;
> 	unsigned int i, text_len;
> 	unsigned long long ts_nsec;
> 	char buf[BUFSIZE];
>@@ -3881,18 +3881,19 @@ dump_log_entry(char *logptr, int fp)
>
> 	msg = logptr + SIZE(printk_log);
>
>-	sprintf(buf, "[%5lld.%06ld] ", nanos, rem/1000);
>+	bufp = buf;
>+	bufp += sprintf(buf, "[%5lld.%06ld] ", nanos, rem/1000);
>
> 	for (i = 0, p = msg; i < text_len; i++, p++) {
> 		if (isprint(*p) || isspace(*p))
>-			sprintf(buf, "%s%c", buf, *p);
>+			*bufp++ = *p;
> 		else
>-			sprintf(buf, "%s\\x%02x", buf, *p);
>+			bufp += sprintf(bufp, "\\x%02x", *p);
> 	}
>
>-	sprintf(buf, "%s\n", buf);
>+	*bufp++ = '\n';
>
>-	if (write(info->fd_dumpfile, buf, strlen(buf)) < 0)
>+	if (write(info->fd_dumpfile, buf, bufp - buf) < 0)
> 		return FALSE;
> 	else
> 		return TRUE;
>--
>1.8.4.5


From kumagai-atsushi at mxc.nes.nec.co.jp  Fri Feb 28 01:51:07 2014
From: kumagai-atsushi at mxc.nes.nec.co.jp (Atsushi Kumagai)
Date: Fri, 28 Feb 2014 06:51:07 +0000
Subject: [PATCH] makedumpfile: Add support to module data structures
In-Reply-To: <20140227061942.2765.37183.stgit@aruna-ThinkPad-T420>
References: <20140227061942.2765.37183.stgit@aruna-ThinkPad-T420>
Message-ID: <0910DD04CBD6DE4193FCF86B9C00BE971EF46E@BPXM01GP.gisp.nec.co.jp>

>diff --git a/dwarf_info.c b/dwarf_info.c
>index 6e21b8a..268e922 100644
>--- a/dwarf_info.c
>+++ b/dwarf_info.c
>@@ -489,7 +489,6 @@ get_die_from_offset(Dwarf_Off offset, Dwarf_Die *die)
> 		return FALSE;
>
> 	if (!dwarf_offdie(dwarf_info.dwarfd, offset, die)) {
>-		ERRMSG("Can't find the DIE.\n");
> 		return FALSE;
> 	}
>
>@@ -1343,14 +1342,12 @@ get_die_nfields(unsigned long long die_off)
> 	Dwarf_Die result, child, *die;
>
> 	if (!get_die_from_offset((Dwarf_Off) die_off, &result)) {
>-		ERRMSG("Can't find the DIE.\n");
> 		return -1;
> 	}
>
> 	die = &result;
> 	tag = dwarf_tag(die);
> 	if (tag != DW_TAG_structure_type && tag != DW_TAG_union_type) {
>-		ERRMSG("DIE is not of structure or union type.\n");
> 		clean_dwfl_info();
> 		return -1;
> 	}
>@@ -1388,14 +1385,12 @@ get_die_member(unsigned long long die_off, int index, long *offset,
> 		return -1;
>
> 	if (!get_die_from_offset((Dwarf_Off) die_off, &result)) {
>-		ERRMSG("Can't find the DIE.\n");
> 		return -1;
> 	}
>
> 	die = &result;
> 	tag = dwarf_tag(die);
> 	if (tag != DW_TAG_structure_type && tag != DW_TAG_union_type) {
>-		ERRMSG("DIE is not of structure or union type.\n");
> 		clean_dwfl_info();
> 		return -1;
> 	}
>@@ -1471,7 +1466,6 @@ get_die_attr_type(unsigned long long die_off, int *type_flag,
> 		return FALSE;
>
> 	if (!get_die_from_offset((Dwarf_Off) die_off, &result)) {
>-		ERRMSG("Can't find the DIE.\n");
> 		return FALSE;
> 	}
>
>@@ -1509,7 +1503,6 @@ get_die_name(unsigned long long die_off)
> 		return NULL;
>
> 	if (!get_die_from_offset((Dwarf_Off) die_off, &result)) {
>-		ERRMSG("Can't find the DIE.\n");
> 		return NULL;
> 	}
>
>@@ -1554,7 +1547,6 @@ get_die_length(unsigned long long die_off, int flag)
> 		return FALSE;
>
> 	if (!get_die_from_offset((Dwarf_Off) die_off, &result)) {
>-		ERRMSG("Can't find the DIE.\n");
> 		return FALSE;
> 	}

Why did you remove these error messages ?
This change looks unrelated to the subject, you should at least
do it separately.


Thanks
Atsushi Kumagai

>diff --git a/erase_info.c b/erase_info.c
>index a789389..e0e0f71 100644
>--- a/erase_info.c
>+++ b/erase_info.c
>@@ -34,7 +34,7 @@ struct call_back eppic_cb = {
> 	&get_die_offset,
> 	&get_die_length,
> 	&get_die_member_all,
>-	&get_die_nfields,
>+	&get_die_nfields_all,
> 	&get_symbol_addr_all,
> 	&update_filter_info_raw
> };
>@@ -2028,6 +2028,84 @@ get_domain_all(char *symname, int cmd, unsigned long long *die) {
> }
>
> /*
>+ * Search for die in modules as well as vmlinux
>+ */
>+int
>+get_die_nfields_all(unsigned long long die_off)
>+{
>+	short vmlinux_searched = 0;
>+	long nfields = -1;
>+	unsigned int i, current_mod;
>+	struct module_info *modules;
>+
>+	/* Search in vmlinux if debuginfo is set to vmlinux */
>+	if (!strcmp(get_dwarf_module_name(), "vmlinux")) {
>+		nfields = get_die_nfields(die_off);
>+		if (nfields > 0)
>+			return nfields;
>+
>+		vmlinux_searched = 1;
>+	}
>+
>+	/*
>+	 * Proceed the search in modules. Try in the module
>+	 * which resulted in a hit in the previous search
>+	 */
>+
>+	modules = mod_st.modules;
>+	current_mod = mod_st.current_mod;
>+
>+	if (strcmp(get_dwarf_module_name(), modules[current_mod].name)) {
>+		if (!set_dwarf_debuginfo(modules[current_mod].name,
>+				info->system_utsname.release, NULL, -1)) {
>+			ERRMSG("Cannot set to current module %s\n",
>+					modules[current_mod].name);
>+			return -1;
>+		}
>+	}
>+
>+	nfields = get_die_nfields(die_off);
>+	if (nfields > 0)
>+		return nfields;
>+
>+	/* Search in all modules */
>+	for (i = 0; i < mod_st.num_modules; i++) {
>+
>+		/* Already searched. Skip */
>+		if (i == current_mod)
>+			continue;
>+
>+		if (!set_dwarf_debuginfo(modules[i].name,
>+				info->system_utsname.release, NULL, -1)) {
>+			ERRMSG("Skipping Module section %s\n", modules[i].name);
>+			continue;
>+		}
>+
>+		nfields = get_die_nfields(die_off);
>+
>+		if (nfields < 0)
>+			continue;
>+
>+		/*
>+		 * Die found. Set the current_mod to this module index,
>+		 * a minor optimization for fast lookup next time
>+		 */
>+		mod_st.current_mod = i;
>+		return nfields;
>+	}
>+
>+	/* Die not found in any module. Set debuginfo back to vmlinux */
>+	set_dwarf_debuginfo("vmlinux", NULL, info->name_vmlinux,
>+			info->fd_vmlinux);
>+
>+	if (!vmlinux_searched)
>+		return get_die_nfields(die_off);
>+	else
>+		return -1;
>+
>+}
>+
>+/*
>  * Search for die member in modules as well as vmlinux
>  */
> int
>diff --git a/erase_info.h b/erase_info.h
>index a90fac0..4d4957e 100644
>--- a/erase_info.h
>+++ b/erase_info.h
>@@ -35,6 +35,7 @@ unsigned long long get_symbol_addr_all(char *);
> long get_domain_all(char *, int, unsigned long long *);
> int get_die_member_all(unsigned long long die_off, int index, long *offset,
> 		char **name, int *nbits, int *fbits, unsigned long long *m_die);
>+int get_die_nfields_all(unsigned long long die_off);
>
> struct call_back {
> 	long (*get_domain_all)(char *, int, unsigned long long *);
>@@ -48,7 +49,7 @@ struct call_back {
> 	int (*get_die_member_all)(unsigned long long die_off, int index,
> 		long *offset, char **name, int *nbits, int *fbits,
> 		unsigned long long *m_die);
>-	int (*get_die_nfields)(unsigned long long die_off);
>+	int (*get_die_nfields_all)(unsigned long long die_off);
> 	unsigned long long (*get_symbol_addr_all)(char *symname);
> 	int (*update_filter_info_raw)(unsigned long long, int, int);
> };
>diff --git a/extension_eppic.c b/extension_eppic.c
>index 7e045c9..bb36d5a 100644
>--- a/extension_eppic.c
>+++ b/extension_eppic.c
>@@ -219,7 +219,7 @@ apimember(char *mname, ull idx, type_t *tm, member_t *m, ull *last_index)
> 	ull m_die, die_off = idx;
> 	char *name = NULL;
>
>-	nfields = GET_DIE_NFIELDS(die_off);
>+	nfields = GET_DIE_NFIELDS_ALL(die_off);
> 	/*
> 	 * GET_DIE_NFIELDS() returns < 0 if the die is not structure type
> 	 * or union type
>diff --git a/extension_eppic.h b/extension_eppic.h
>index 42437f2..24189ba 100644
>--- a/extension_eppic.h
>+++ b/extension_eppic.h
>@@ -88,7 +88,7 @@ struct call_back *cb;
> #define GET_DIE_OFFSET cb->get_die_offset
> #define GET_DIE_LENGTH cb->get_die_length
> #define GET_DIE_MEMBER_ALL cb->get_die_member_all
>-#define GET_DIE_NFIELDS cb->get_die_nfields
>+#define GET_DIE_NFIELDS_ALL cb->get_die_nfields_all
> #define GET_SYMBOL_ADDR_ALL cb->get_symbol_addr_all
> #define UPDATE_FILTER_INFO_RAW cb->update_filter_info_raw
>
>
>
>_______________________________________________
>kexec mailing list
>kexec at lists.infradead.org
>http://lists.infradead.org/mailman/listinfo/kexec


From aruna at linux.vnet.ibm.com  Fri Feb 28 02:08:33 2014
From: aruna at linux.vnet.ibm.com (Aruna Balakrishnaiah)
Date: Fri, 28 Feb 2014 12:38:33 +0530
Subject: [PATCH] makedumpfile: Add support to module data structures
In-Reply-To: <0910DD04CBD6DE4193FCF86B9C00BE971EF46E@BPXM01GP.gisp.nec.co.jp>
References: <20140227061942.2765.37183.stgit@aruna-ThinkPad-T420>
 <0910DD04CBD6DE4193FCF86B9C00BE971EF46E@BPXM01GP.gisp.nec.co.jp>
Message-ID: <531035F1.9080400@linux.vnet.ibm.com>

On Friday 28 February 2014 12:21 PM, Atsushi Kumagai wrote:
>> diff --git a/dwarf_info.c b/dwarf_info.c
>> index 6e21b8a..268e922 100644
>> --- a/dwarf_info.c
>> +++ b/dwarf_info.c
>> @@ -489,7 +489,6 @@ get_die_from_offset(Dwarf_Off offset, Dwarf_Die *die)
>> 		return FALSE;
>>
>> 	if (!dwarf_offdie(dwarf_info.dwarfd, offset, die)) {
>> -		ERRMSG("Can't find the DIE.\n");
>> 		return FALSE;
>> 	}
>>
>> @@ -1343,14 +1342,12 @@ get_die_nfields(unsigned long long die_off)
>> 	Dwarf_Die result, child, *die;
>>
>> 	if (!get_die_from_offset((Dwarf_Off) die_off, &result)) {
>> -		ERRMSG("Can't find the DIE.\n");
>> 		return -1;
>> 	}
>>
>> 	die = &result;
>> 	tag = dwarf_tag(die);
>> 	if (tag != DW_TAG_structure_type && tag != DW_TAG_union_type) {
>> -		ERRMSG("DIE is not of structure or union type.\n");
>> 		clean_dwfl_info();
>> 		return -1;
>> 	}
>> @@ -1388,14 +1385,12 @@ get_die_member(unsigned long long die_off, int index, long *offset,
>> 		return -1;
>>
>> 	if (!get_die_from_offset((Dwarf_Off) die_off, &result)) {
>> -		ERRMSG("Can't find the DIE.\n");
>> 		return -1;
>> 	}
>>
>> 	die = &result;
>> 	tag = dwarf_tag(die);
>> 	if (tag != DW_TAG_structure_type && tag != DW_TAG_union_type) {
>> -		ERRMSG("DIE is not of structure or union type.\n");
>> 		clean_dwfl_info();
>> 		return -1;
>> 	}
>> @@ -1471,7 +1466,6 @@ get_die_attr_type(unsigned long long die_off, int *type_flag,
>> 		return FALSE;
>>
>> 	if (!get_die_from_offset((Dwarf_Off) die_off, &result)) {
>> -		ERRMSG("Can't find the DIE.\n");
>> 		return FALSE;
>> 	}
>>
>> @@ -1509,7 +1503,6 @@ get_die_name(unsigned long long die_off)
>> 		return NULL;
>>
>> 	if (!get_die_from_offset((Dwarf_Off) die_off, &result)) {
>> -		ERRMSG("Can't find the DIE.\n");
>> 		return NULL;
>> 	}
>>
>> @@ -1554,7 +1547,6 @@ get_die_length(unsigned long long die_off, int flag)
>> 		return FALSE;
>>
>> 	if (!get_die_from_offset((Dwarf_Off) die_off, &result)) {
>> -		ERRMSG("Can't find the DIE.\n");
>> 		return FALSE;
>> 	}
> Why did you remove these error messages ?
> This change looks unrelated to the subject, you should at least
> do it separately.

It was throwing unnecessary messages when a particular die
is not found in a module.

Since this patch takes care of setting the debug info to the right
module , removed the error messages here.

Regards,
Aruna

>
> Thanks
> Atsushi Kumagai
>
>> diff --git a/erase_info.c b/erase_info.c
>> index a789389..e0e0f71 100644
>> --- a/erase_info.c
>> +++ b/erase_info.c
>> @@ -34,7 +34,7 @@ struct call_back eppic_cb = {
>> 	&get_die_offset,
>> 	&get_die_length,
>> 	&get_die_member_all,
>> -	&get_die_nfields,
>> +	&get_die_nfields_all,
>> 	&get_symbol_addr_all,
>> 	&update_filter_info_raw
>> };
>> @@ -2028,6 +2028,84 @@ get_domain_all(char *symname, int cmd, unsigned long long *die) {
>> }
>>
>> /*
>> + * Search for die in modules as well as vmlinux
>> + */
>> +int
>> +get_die_nfields_all(unsigned long long die_off)
>> +{
>> +	short vmlinux_searched = 0;
>> +	long nfields = -1;
>> +	unsigned int i, current_mod;
>> +	struct module_info *modules;
>> +
>> +	/* Search in vmlinux if debuginfo is set to vmlinux */
>> +	if (!strcmp(get_dwarf_module_name(), "vmlinux")) {
>> +		nfields = get_die_nfields(die_off);
>> +		if (nfields > 0)
>> +			return nfields;
>> +
>> +		vmlinux_searched = 1;
>> +	}
>> +
>> +	/*
>> +	 * Proceed the search in modules. Try in the module
>> +	 * which resulted in a hit in the previous search
>> +	 */
>> +
>> +	modules = mod_st.modules;
>> +	current_mod = mod_st.current_mod;
>> +
>> +	if (strcmp(get_dwarf_module_name(), modules[current_mod].name)) {
>> +		if (!set_dwarf_debuginfo(modules[current_mod].name,
>> +				info->system_utsname.release, NULL, -1)) {
>> +			ERRMSG("Cannot set to current module %s\n",
>> +					modules[current_mod].name);
>> +			return -1;
>> +		}
>> +	}
>> +
>> +	nfields = get_die_nfields(die_off);
>> +	if (nfields > 0)
>> +		return nfields;
>> +
>> +	/* Search in all modules */
>> +	for (i = 0; i < mod_st.num_modules; i++) {
>> +
>> +		/* Already searched. Skip */
>> +		if (i == current_mod)
>> +			continue;
>> +
>> +		if (!set_dwarf_debuginfo(modules[i].name,
>> +				info->system_utsname.release, NULL, -1)) {
>> +			ERRMSG("Skipping Module section %s\n", modules[i].name);
>> +			continue;
>> +		}
>> +
>> +		nfields = get_die_nfields(die_off);
>> +
>> +		if (nfields < 0)
>> +			continue;
>> +
>> +		/*
>> +		 * Die found. Set the current_mod to this module index,
>> +		 * a minor optimization for fast lookup next time
>> +		 */
>> +		mod_st.current_mod = i;
>> +		return nfields;
>> +	}
>> +
>> +	/* Die not found in any module. Set debuginfo back to vmlinux */
>> +	set_dwarf_debuginfo("vmlinux", NULL, info->name_vmlinux,
>> +			info->fd_vmlinux);
>> +
>> +	if (!vmlinux_searched)
>> +		return get_die_nfields(die_off);
>> +	else
>> +		return -1;
>> +
>> +}
>> +
>> +/*
>>  * Search for die member in modules as well as vmlinux
>>  */
>> int
>> diff --git a/erase_info.h b/erase_info.h
>> index a90fac0..4d4957e 100644
>> --- a/erase_info.h
>> +++ b/erase_info.h
>> @@ -35,6 +35,7 @@ unsigned long long get_symbol_addr_all(char *);
>> long get_domain_all(char *, int, unsigned long long *);
>> int get_die_member_all(unsigned long long die_off, int index, long *offset,
>> 		char **name, int *nbits, int *fbits, unsigned long long *m_die);
>> +int get_die_nfields_all(unsigned long long die_off);
>>
>> struct call_back {
>> 	long (*get_domain_all)(char *, int, unsigned long long *);
>> @@ -48,7 +49,7 @@ struct call_back {
>> 	int (*get_die_member_all)(unsigned long long die_off, int index,
>> 		long *offset, char **name, int *nbits, int *fbits,
>> 		unsigned long long *m_die);
>> -	int (*get_die_nfields)(unsigned long long die_off);
>> +	int (*get_die_nfields_all)(unsigned long long die_off);
>> 	unsigned long long (*get_symbol_addr_all)(char *symname);
>> 	int (*update_filter_info_raw)(unsigned long long, int, int);
>> };
>> diff --git a/extension_eppic.c b/extension_eppic.c
>> index 7e045c9..bb36d5a 100644
>> --- a/extension_eppic.c
>> +++ b/extension_eppic.c
>> @@ -219,7 +219,7 @@ apimember(char *mname, ull idx, type_t *tm, member_t *m, ull *last_index)
>> 	ull m_die, die_off = idx;
>> 	char *name = NULL;
>>
>> -	nfields = GET_DIE_NFIELDS(die_off);
>> +	nfields = GET_DIE_NFIELDS_ALL(die_off);
>> 	/*
>> 	 * GET_DIE_NFIELDS() returns < 0 if the die is not structure type
>> 	 * or union type
>> diff --git a/extension_eppic.h b/extension_eppic.h
>> index 42437f2..24189ba 100644
>> --- a/extension_eppic.h
>> +++ b/extension_eppic.h
>> @@ -88,7 +88,7 @@ struct call_back *cb;
>> #define GET_DIE_OFFSET cb->get_die_offset
>> #define GET_DIE_LENGTH cb->get_die_length
>> #define GET_DIE_MEMBER_ALL cb->get_die_member_all
>> -#define GET_DIE_NFIELDS cb->get_die_nfields
>> +#define GET_DIE_NFIELDS_ALL cb->get_die_nfields_all
>> #define GET_SYMBOL_ADDR_ALL cb->get_symbol_addr_all
>> #define UPDATE_FILTER_INFO_RAW cb->update_filter_info_raw
>>
>>
>>
>> _______________________________________________
>> kexec mailing list
>> kexec at lists.infradead.org
>> http://lists.infradead.org/mailman/listinfo/kexec



From kumagai-atsushi at mxc.nes.nec.co.jp  Fri Feb 28 02:30:50 2014
From: kumagai-atsushi at mxc.nes.nec.co.jp (Atsushi Kumagai)
Date: Fri, 28 Feb 2014 07:30:50 +0000
Subject: [PATCH] makedumpfile: Add support to module data structures
In-Reply-To: <531035F1.9080400@linux.vnet.ibm.com>
References: <20140227061942.2765.37183.stgit@aruna-ThinkPad-T420>
 <0910DD04CBD6DE4193FCF86B9C00BE971EF46E@BPXM01GP.gisp.nec.co.jp>
 <531035F1.9080400@linux.vnet.ibm.com>
Message-ID: <0910DD04CBD6DE4193FCF86B9C00BE971EF4F0@BPXM01GP.gisp.nec.co.jp>

>On Friday 28 February 2014 12:21 PM, Atsushi Kumagai wrote:
>>> diff --git a/dwarf_info.c b/dwarf_info.c
>>> index 6e21b8a..268e922 100644
>>> --- a/dwarf_info.c
>>> +++ b/dwarf_info.c
>>> @@ -489,7 +489,6 @@ get_die_from_offset(Dwarf_Off offset, Dwarf_Die *die)
>>> 		return FALSE;
>>>
>>> 	if (!dwarf_offdie(dwarf_info.dwarfd, offset, die)) {
>>> -		ERRMSG("Can't find the DIE.\n");
>>> 		return FALSE;
>>> 	}
>>>
>>> @@ -1343,14 +1342,12 @@ get_die_nfields(unsigned long long die_off)
>>> 	Dwarf_Die result, child, *die;
>>>
>>> 	if (!get_die_from_offset((Dwarf_Off) die_off, &result)) {
>>> -		ERRMSG("Can't find the DIE.\n");
>>> 		return -1;
>>> 	}
>>>
>>> 	die = &result;
>>> 	tag = dwarf_tag(die);
>>> 	if (tag != DW_TAG_structure_type && tag != DW_TAG_union_type) {
>>> -		ERRMSG("DIE is not of structure or union type.\n");
>>> 		clean_dwfl_info();
>>> 		return -1;
>>> 	}
>>> @@ -1388,14 +1385,12 @@ get_die_member(unsigned long long die_off, int index, long *offset,
>>> 		return -1;
>>>
>>> 	if (!get_die_from_offset((Dwarf_Off) die_off, &result)) {
>>> -		ERRMSG("Can't find the DIE.\n");
>>> 		return -1;
>>> 	}
>>>
>>> 	die = &result;
>>> 	tag = dwarf_tag(die);
>>> 	if (tag != DW_TAG_structure_type && tag != DW_TAG_union_type) {
>>> -		ERRMSG("DIE is not of structure or union type.\n");
>>> 		clean_dwfl_info();
>>> 		return -1;
>>> 	}
>>> @@ -1471,7 +1466,6 @@ get_die_attr_type(unsigned long long die_off, int *type_flag,
>>> 		return FALSE;
>>>
>>> 	if (!get_die_from_offset((Dwarf_Off) die_off, &result)) {
>>> -		ERRMSG("Can't find the DIE.\n");
>>> 		return FALSE;
>>> 	}
>>>
>>> @@ -1509,7 +1503,6 @@ get_die_name(unsigned long long die_off)
>>> 		return NULL;
>>>
>>> 	if (!get_die_from_offset((Dwarf_Off) die_off, &result)) {
>>> -		ERRMSG("Can't find the DIE.\n");
>>> 		return NULL;
>>> 	}
>>>
>>> @@ -1554,7 +1547,6 @@ get_die_length(unsigned long long die_off, int flag)
>>> 		return FALSE;
>>>
>>> 	if (!get_die_from_offset((Dwarf_Off) die_off, &result)) {
>>> -		ERRMSG("Can't find the DIE.\n");
>>> 		return FALSE;
>>> 	}
>> Why did you remove these error messages ?
>> This change looks unrelated to the subject, you should at least
>> do it separately.
>
>It was throwing unnecessary messages when a particular die
>is not found in a module.
>
>Since this patch takes care of setting the debug info to the right
>module , removed the error messages here.
>
>Regards,
>Aruna

Thanks, I understand. I misunderstood that these changed functions are
old common utility, but in fact they are introduced for eppic.
So there is no problem.

Acked-by: Atsushi Kumagai <kumagai-atsushi at mxc.nes.nec.co.jp>

>
>>
>> Thanks
>> Atsushi Kumagai
>>
>>> diff --git a/erase_info.c b/erase_info.c
>>> index a789389..e0e0f71 100644
>>> --- a/erase_info.c
>>> +++ b/erase_info.c
>>> @@ -34,7 +34,7 @@ struct call_back eppic_cb = {
>>> 	&get_die_offset,
>>> 	&get_die_length,
>>> 	&get_die_member_all,
>>> -	&get_die_nfields,
>>> +	&get_die_nfields_all,
>>> 	&get_symbol_addr_all,
>>> 	&update_filter_info_raw
>>> };
>>> @@ -2028,6 +2028,84 @@ get_domain_all(char *symname, int cmd, unsigned long long *die) {
>>> }
>>>
>>> /*
>>> + * Search for die in modules as well as vmlinux
>>> + */
>>> +int
>>> +get_die_nfields_all(unsigned long long die_off)
>>> +{
>>> +	short vmlinux_searched = 0;
>>> +	long nfields = -1;
>>> +	unsigned int i, current_mod;
>>> +	struct module_info *modules;
>>> +
>>> +	/* Search in vmlinux if debuginfo is set to vmlinux */
>>> +	if (!strcmp(get_dwarf_module_name(), "vmlinux")) {
>>> +		nfields = get_die_nfields(die_off);
>>> +		if (nfields > 0)
>>> +			return nfields;
>>> +
>>> +		vmlinux_searched = 1;
>>> +	}
>>> +
>>> +	/*
>>> +	 * Proceed the search in modules. Try in the module
>>> +	 * which resulted in a hit in the previous search
>>> +	 */
>>> +
>>> +	modules = mod_st.modules;
>>> +	current_mod = mod_st.current_mod;
>>> +
>>> +	if (strcmp(get_dwarf_module_name(), modules[current_mod].name)) {
>>> +		if (!set_dwarf_debuginfo(modules[current_mod].name,
>>> +				info->system_utsname.release, NULL, -1)) {
>>> +			ERRMSG("Cannot set to current module %s\n",
>>> +					modules[current_mod].name);
>>> +			return -1;
>>> +		}
>>> +	}
>>> +
>>> +	nfields = get_die_nfields(die_off);
>>> +	if (nfields > 0)
>>> +		return nfields;
>>> +
>>> +	/* Search in all modules */
>>> +	for (i = 0; i < mod_st.num_modules; i++) {
>>> +
>>> +		/* Already searched. Skip */
>>> +		if (i == current_mod)
>>> +			continue;
>>> +
>>> +		if (!set_dwarf_debuginfo(modules[i].name,
>>> +				info->system_utsname.release, NULL, -1)) {
>>> +			ERRMSG("Skipping Module section %s\n", modules[i].name);
>>> +			continue;
>>> +		}
>>> +
>>> +		nfields = get_die_nfields(die_off);
>>> +
>>> +		if (nfields < 0)
>>> +			continue;
>>> +
>>> +		/*
>>> +		 * Die found. Set the current_mod to this module index,
>>> +		 * a minor optimization for fast lookup next time
>>> +		 */
>>> +		mod_st.current_mod = i;
>>> +		return nfields;
>>> +	}
>>> +
>>> +	/* Die not found in any module. Set debuginfo back to vmlinux */
>>> +	set_dwarf_debuginfo("vmlinux", NULL, info->name_vmlinux,
>>> +			info->fd_vmlinux);
>>> +
>>> +	if (!vmlinux_searched)
>>> +		return get_die_nfields(die_off);
>>> +	else
>>> +		return -1;
>>> +
>>> +}
>>> +
>>> +/*
>>>  * Search for die member in modules as well as vmlinux
>>>  */
>>> int
>>> diff --git a/erase_info.h b/erase_info.h
>>> index a90fac0..4d4957e 100644
>>> --- a/erase_info.h
>>> +++ b/erase_info.h
>>> @@ -35,6 +35,7 @@ unsigned long long get_symbol_addr_all(char *);
>>> long get_domain_all(char *, int, unsigned long long *);
>>> int get_die_member_all(unsigned long long die_off, int index, long *offset,
>>> 		char **name, int *nbits, int *fbits, unsigned long long *m_die);
>>> +int get_die_nfields_all(unsigned long long die_off);
>>>
>>> struct call_back {
>>> 	long (*get_domain_all)(char *, int, unsigned long long *);
>>> @@ -48,7 +49,7 @@ struct call_back {
>>> 	int (*get_die_member_all)(unsigned long long die_off, int index,
>>> 		long *offset, char **name, int *nbits, int *fbits,
>>> 		unsigned long long *m_die);
>>> -	int (*get_die_nfields)(unsigned long long die_off);
>>> +	int (*get_die_nfields_all)(unsigned long long die_off);
>>> 	unsigned long long (*get_symbol_addr_all)(char *symname);
>>> 	int (*update_filter_info_raw)(unsigned long long, int, int);
>>> };
>>> diff --git a/extension_eppic.c b/extension_eppic.c
>>> index 7e045c9..bb36d5a 100644
>>> --- a/extension_eppic.c
>>> +++ b/extension_eppic.c
>>> @@ -219,7 +219,7 @@ apimember(char *mname, ull idx, type_t *tm, member_t *m, ull *last_index)
>>> 	ull m_die, die_off = idx;
>>> 	char *name = NULL;
>>>
>>> -	nfields = GET_DIE_NFIELDS(die_off);
>>> +	nfields = GET_DIE_NFIELDS_ALL(die_off);
>>> 	/*
>>> 	 * GET_DIE_NFIELDS() returns < 0 if the die is not structure type
>>> 	 * or union type
>>> diff --git a/extension_eppic.h b/extension_eppic.h
>>> index 42437f2..24189ba 100644
>>> --- a/extension_eppic.h
>>> +++ b/extension_eppic.h
>>> @@ -88,7 +88,7 @@ struct call_back *cb;
>>> #define GET_DIE_OFFSET cb->get_die_offset
>>> #define GET_DIE_LENGTH cb->get_die_length
>>> #define GET_DIE_MEMBER_ALL cb->get_die_member_all
>>> -#define GET_DIE_NFIELDS cb->get_die_nfields
>>> +#define GET_DIE_NFIELDS_ALL cb->get_die_nfields_all
>>> #define GET_SYMBOL_ADDR_ALL cb->get_symbol_addr_all
>>> #define UPDATE_FILTER_INFO_RAW cb->update_filter_info_raw
>>>
>>>
>>>
>>> _______________________________________________
>>> kexec mailing list
>>> kexec at lists.infradead.org
>>> http://lists.infradead.org/mailman/listinfo/kexec
>
>
>_______________________________________________
>kexec mailing list
>kexec at lists.infradead.org
>http://lists.infradead.org/mailman/listinfo/kexec


From chaowang at redhat.com  Fri Feb 28 03:32:24 2014
From: chaowang at redhat.com (WANG Chao)
Date: Fri, 28 Feb 2014 16:32:24 +0800
Subject: [PATCH v2 4/4] x86: Pass memory range via E820 for kdump
In-Reply-To: <20140227205312.GJ30210@oranje.fc.hp.com>
References: <1392888512-4473-1-git-send-email-chaowang@redhat.com>
 <1392888512-4473-5-git-send-email-chaowang@redhat.com>
 <20140227205312.GJ30210@oranje.fc.hp.com>
Message-ID: <20140228083224.GC13117@dhcp-17-89.nay.redhat.com>

On 02/27/14 at 01:53pm, Linn Crosetto wrote:
> Hi Chao,
> 
> On Thu, Feb 20, 2014 at 02:28:32AM -0700, WANG Chao wrote:
> 
> [..]
> 
> > +static void setup_e820_ext(struct kexec_info *info, struct x86_linux_param_header *real_mode,
> > +                          struct memory_range *range, int nr_range)
> > +{
> > +       struct setup_data *sd;
> > +       struct e820entry *e820;
> > +       int i, j, nr_range_ext;
> > +
> > +       nr_range_ext = nr_range - E820MAX;
> > +       sd = malloc(sizeof(struct setup_data) + nr_range_ext * sizeof(struct e820entry));
> > +       sd->next = 0;
> > +       sd->len = nr_range_ext * sizeof(struct e820entry);
> > +       sd->type = SETUP_E820_EXT;
> > +
> > +       e820 = (struct e820entry *) sd->data;
> > +       dbgprintf("Extended E820 via setup_data:\n");
> > +       for(i = 0, j = E820MAX; i < nr_range_ext; i++, j++) {
> > +               e820[i].addr = range[j].start;
> > +               e820[i].size = range[j].end - range[j].start;
> > +               switch (range[j].type) {
> > +               case RANGE_RAM:
> > +                       e820[i].type = E820_RAM;
> > +                       break;
> > +               case RANGE_ACPI:
> > +                       e820[i].type = E820_ACPI;
> > +                       break;
> > +               case RANGE_ACPI_NVS:
> > +                       e820[i].type = E820_NVS;
> > +                       break;
> > +               default:
> > +               case RANGE_RESERVED:
> > +                       e820[i].type = E820_RESERVED;
> > +                       break;
> > +               }
> > +               dbgprintf("%016lx-%016lx (%d)\n",
> > +                               e820[i].addr,
> > +                               e820[i].addr + e820[i].size - 1,
> > +                               e820[i].type);
> > +
> > +               if (range[j].type != RANGE_RAM)
> > +                       continue;
> > +               if ((range[j].start <= 0x100000) && range[j].end > 0x100000) {
> > +                       unsigned long long mem_k = (range[j].end >> 10) - (0x100000 >> 10);
> > +                       real_mode->ext_mem_k = mem_k;
> > +                       real_mode->alt_mem_k = mem_k;
> > +                       if (mem_k > 0xfc00) {
> > +                               real_mode->ext_mem_k = 0xfc00; /* 64M */
> > +                       }
> > +                       if (mem_k > 0xffffffff) {
> > +                               real_mode->alt_mem_k = 0xffffffff;
> > +                       }
> > +               }
> > +       }
> > +       add_setup_data(info, real_mode, sd);
> > +       free(sd);
> 
> Remove this call to free(sd) or the kernel will not boot if there are more than
> E820MAX entries.

You're right.

> 
> > +}
> > +
> > +static void setup_e820(struct kexec_info *info, struct x86_linux_param_header *real_mode,
> > +                      struct memory_range *range, int nr_range)
> > +{
> > +
> > +       int nr_range_saved = nr_range;
> > +       int i;
> > +
> > +       if (nr_range > E820MAX) {
> > +               nr_range = E820MAX;
> > +       }
> > +
> > +       real_mode->e820_map_nr = nr_range;
> > +       dbgprintf("E820 memmap:\n");
> > +       for(i = 0; i < nr_range; i++) {
> > +               real_mode->e820_map[i].addr = range[i].start;
> > +               real_mode->e820_map[i].size = range[i].end - range[i].start;
> > +               switch (range[i].type) {
> > +                       case RANGE_RAM:
> > +                               real_mode->e820_map[i].type = E820_RAM;
> > +                               break;
> > +                       case RANGE_ACPI:
> > +                               real_mode->e820_map[i].type = E820_ACPI;
> > +                               break;
> > +                       case RANGE_ACPI_NVS:
> > +                               real_mode->e820_map[i].type = E820_NVS;
> > +                               break;
> > +                       default:
> > +                       case RANGE_RESERVED:
> > +                               real_mode->e820_map[i].type = E820_RESERVED;
> > +                               break;
> > +               }
> > +               dbgprintf("%016lx-%016lx (%d)\n",
> > +                               real_mode->e820_map[i].addr,
> > +                               real_mode->e820_map[i].addr + real_mode->e820_map[i].size - 1,
> > +                               real_mode->e820_map[i].type);
> > +
> > +               if (range[i].type != RANGE_RAM)
> > +                       continue;
> > +               if ((range[i].start <= 0x100000) && range[i].end > 0x100000) {
> > +                       unsigned long long mem_k = (range[i].end >> 10) - (0x100000 >> 10);
> > +                       real_mode->ext_mem_k = mem_k;
> > +                       real_mode->alt_mem_k = mem_k;
> > +                       if (mem_k > 0xfc00) {
> > +                               real_mode->ext_mem_k = 0xfc00; /* 64M */
> > +                       }
> > +                       if (mem_k > 0xffffffff) {
> > +                               real_mode->alt_mem_k = 0xffffffff;
> > +                       }
> > +               }
> > +       }
> > +
> > +       if (nr_range_saved > E820MAX) {
> > +               dbgprintf("extra E820 memmap are passed via setup_data\n");
> > +               setup_e820_ext(info, real_mode, range, nr_range_saved);
> > +       }
> > +}
> > +
> 
> setup_e820() and setup_e820_ext() contain a lot of duplication. You could
> combine them into a single function, similar to the implementation of
> setup_e820() in the kernel.

OK. That makes sense to me.

> 
> >  static int
> >  get_efi_mem_desc_version(struct x86_linux_param_header *real_mode)
> >  {
> > @@ -704,7 +830,7 @@ void setup_linux_system_parameters(struct kexec_info *info,
> 
> [..]
> 
> > +       if (info->kexec_flags & KEXEC_ON_CRASH && !pass_memmap_cmdline) {
> > +               range = crash_memory_range;
> > +               ranges = crash_memory_ranges;
> > +       } else {
> > +               range = info->memory_range;
> > +               ranges = info->memory_ranges;
> >         }
> 
> You can move this code into setup_e820(), since range and ranges are not used
> elsewhere in setup_linux_system_parameters().

Will do.

> 
> > +       setup_e820(info, real_mode, range, ranges);
> > 
> >         /* fill the EDD information */
> >         setup_edd_info(real_mode);
> > --
> > 1.8.5.3
> 
> I tested boot (with the above fix) on a system with a large memory map, and can
> easily test changes, if needed.

Thanks for testing. The result on that real system is helpful and convincing.

I'm holding off v3 for serveral days in case someone would have a
comment.

Thanks
WANG Chao


From holzheu at linux.vnet.ibm.com  Fri Feb 28 07:41:48 2014
From: holzheu at linux.vnet.ibm.com (Michael Holzheu)
Date: Fri, 28 Feb 2014 13:41:48 +0100
Subject: makedumpfile: get_max_mapnr() from ELF header problem
Message-ID: <20140228134148.15b60ceb@holzheu>

Hello Atsushi,

On s390 we have the following little problem:

We use hypervisor or stand-alone dump tools to create Linux system
dumps. These tools do not know the kernel parameter line and dump the
full physical memory.

We use makedumpfile to filter those dumps.

If a Linux system has specified the "mem=" parameter, the dump tools
still dump the whole phypsical memory.

Unfortunately in "get_max_mapnr()" makedumpfile uses the ELF header to
get the maxmimum page frame number. Since this is not the correct value
in our case makedumpfile fails to filter the dump.

We get the following error on s390 with makedumpfile version 1.5.3:

makedumpfile -c -d 31 vmcore dump.kdump
cyclic buffer size has been changed: 22156083 => 22156032
Excluding unnecessary pages        : [ 21 %] vtop_s390x: Address too big for the number of page table levels.
readmem: Can't convert a virtual address(8000180104670) to physical address.
readmem: type_addr: 0, addr:8000180104670, size:32768
__exclude_unnecessary_pages: Can't read the buffer of struct page.
Excluding unnecessary pages        : [ 23 %] vtop_s390x: Address too big for the number of page table levels. readmem: Can't convert a
virtual address(8000180104670) to physical address. readmem: type_addr:
0, addr:8000180104670, size:327681.5.5 __exclude_unnecessary_pages: 
Can't read the buffer of struct page.

Since version 1.5.4 makedumpfile seems to loop in __exclude_unnecessary_pages().

We thought about several ways to fix this problem but have not found a
good solution up to now.

Do you have an idea how we could fix that?

Best Regards,
Michael



From bp at alien8.de  Fri Feb 28 09:58:32 2014
From: bp at alien8.de (Borislav Petkov)
Date: Fri, 28 Feb 2014 15:58:32 +0100
Subject: [PATCH 10/11] kexec: Support for loading ELF x86_64 images
In-Reply-To: <1390849071-21989-11-git-send-email-vgoyal@redhat.com>
References: <1390849071-21989-1-git-send-email-vgoyal@redhat.com>
 <1390849071-21989-11-git-send-email-vgoyal@redhat.com>
Message-ID: <20140228145832.GF4326@pd.tnic>

On Mon, Jan 27, 2014 at 01:57:50PM -0500, Vivek Goyal wrote:
> This patch provides support for kexec for loading ELF x86_64 images. I have
> tested it with loading vmlinux and it worked.

Can you please enlighten me what the use case for ELF kernel images is? bzImage
I understand but what produces ELF images?

I see that kexec_file_load() can receive ELF segments too but why are we
doing that?

> Signed-off-by: Vivek Goyal <vgoyal at redhat.com>
> ---
>  arch/x86/include/asm/kexec-elf.h   |  11 ++
>  arch/x86/kernel/Makefile           |   1 +
>  arch/x86/kernel/kexec-elf.c        | 231 +++++++++++++++++++++++++++++++++++++
>  arch/x86/kernel/machine_kexec_64.c |   2 +
>  4 files changed, 245 insertions(+)
>  create mode 100644 arch/x86/include/asm/kexec-elf.h
>  create mode 100644 arch/x86/kernel/kexec-elf.c
> 
> diff --git a/arch/x86/include/asm/kexec-elf.h b/arch/x86/include/asm/kexec-elf.h
> new file mode 100644
> index 0000000..afef382
> --- /dev/null
> +++ b/arch/x86/include/asm/kexec-elf.h
> @@ -0,0 +1,11 @@
> +#ifndef _ASM_KEXEC_ELF_H
> +#define _ASM_KEXEC_ELF_H
> +
> +extern int elf_x86_64_probe(const char *buf, unsigned long len);
> +extern void *elf_x86_64_load(struct kimage *image, char *kernel,
> +		unsigned long kernel_len, char *initrd,
> +		unsigned long initrd_len, char *cmdline,
> +		unsigned long cmdline_len);
> +extern int elf_x86_64_cleanup(struct kimage *image);
> +
> +#endif  /* _ASM_KEXEC_ELF_H */
> diff --git a/arch/x86/kernel/Makefile b/arch/x86/kernel/Makefile
> index fa9981d..2d77de7 100644
> --- a/arch/x86/kernel/Makefile
> +++ b/arch/x86/kernel/Makefile
> @@ -71,6 +71,7 @@ obj-$(CONFIG_KEXEC)		+= machine_kexec.o
>  obj-$(CONFIG_KEXEC)		+= machine_kexec_$(BITS).o
>  obj-$(CONFIG_KEXEC)		+= relocate_kernel_$(BITS).o crash.o
>  obj-$(CONFIG_KEXEC)		+= kexec-bzimage.o
> +obj-$(CONFIG_KEXEC)		+= kexec-elf.o

It looks like kexec could slowly grow its own dir now:

arch/x86/kexec/

or so.

>  obj-$(CONFIG_CRASH_DUMP)	+= crash_dump_$(BITS).o
>  obj-y				+= kprobes/
>  obj-$(CONFIG_MODULES)		+= module.o
> diff --git a/arch/x86/kernel/kexec-elf.c b/arch/x86/kernel/kexec-elf.c
> new file mode 100644
> index 0000000..ff1017c
> --- /dev/null
> +++ b/arch/x86/kernel/kexec-elf.c
> @@ -0,0 +1,231 @@
> +#include <linux/string.h>
> +#include <linux/printk.h>
> +#include <linux/errno.h>
> +#include <linux/slab.h>
> +#include <linux/kexec.h>
> +#include <linux/kernel.h>
> +#include <linux/mm.h>
> +
> +#include <asm/bootparam.h>
> +#include <asm/setup.h>
> +
> +#ifdef CONFIG_X86_64
> +
> +struct elf_x86_64_data {
> +	/*
> +	 * Temporary buffer to hold bootparams buffer. This should be
> +	 * freed once the bootparam segment has been loaded.
> +	 */
> +	void *bootparams_buf;
> +};
> +
> +int elf_x86_64_probe(const char *buf, unsigned long len)
> +{
> +	int ret = -ENOEXEC;
> +	Elf_Ehdr *ehdr;
> +
> +	if (len < sizeof(Elf_Ehdr)) {
> +		pr_debug("File is too short to be an ELF executable.\n");
> +		return ret;
> +	}
> +
> +	ehdr = (Elf_Ehdr *)buf;
> +
> +	if (memcmp(ehdr->e_ident, ELFMAG, SELFMAG) != 0
> +	    || ehdr->e_type != ET_EXEC || !elf_check_arch(ehdr)
> +	    || ehdr->e_phentsize != sizeof(Elf_Phdr))
> +		return -ENOEXEC;
> +
> +	if (ehdr->e_phoff >= len
> +	    || (ehdr->e_phnum * sizeof(Elf_Phdr) > len - ehdr->e_phoff))
> +		return -ENOEXEC;
> +
> +        /* I've got a bzImage */
> +	pr_debug("It's an elf_x86_64 image.\n");
> +	ret = 0;
> +
> +	return ret;

I think you can drop 'ret' here and return the error vals directly.

> +}
> +
> +static int elf_exec_load(struct kimage *image, char *kernel)
> +{
> +	Elf_Ehdr *ehdr;
> +	Elf_Phdr *phdrs;
> +	int i, ret;
> +	size_t filesz;
> +	char *buffer;
> +
> +	ehdr = (Elf_Ehdr *)kernel;
> +	phdrs = (void *)ehdr + ehdr->e_phoff;
> +
> +	for (i = 0; i < ehdr->e_phnum; i++) {
> +		if (phdrs[i].p_type != PT_LOAD)
> +			continue;

newline

> +		filesz = phdrs[i].p_filesz;
> +		if (filesz > phdrs[i].p_memsz)
> +			filesz = phdrs[i].p_memsz;
> +
> +		buffer = (char *)ehdr + phdrs[i].p_offset;
> +		ret = kexec_add_segment(image, buffer, filesz, phdrs[i].p_memsz,
> +						phdrs[i].p_paddr);
> +		if (ret)
> +			break;
> +	}
> +
> +	return ret;
> +}
> +
> +/* Fill in fields which are usually present in bzImage */
> +static int init_linux_parameters(struct boot_params *params)
> +{
> +	/*
> +	 * FIXME: It is odd that the information which comes from kernel
> +	 * has to be faked by loading kernel. I guess it is limitation of
> +	 * ELF format. Right now keeping it same as kexec-tools
> +	 * implementation. But this most likely needs fixing.
> +	 */
> +	memcpy(&params->hdr.header, "HdrS", 4);
> +	params->hdr.version = 0x0206;
> +	params->hdr.initrd_addr_max = 0x37FFFFFF;
> +	params->hdr.cmdline_size = 2048;
> +	return 0;
> +}

Why a separate function? Its body is small enough to be merged into
elf_x86_64_load.

> +
> +void *elf_x86_64_load(struct kimage *image, char *kernel,
> +		unsigned long kernel_len,
> +		char *initrd, unsigned long initrd_len,
> +		char *cmdline, unsigned long cmdline_len)
> +{

Btw, this functionality below looks very similar to the one in
bzImage64_load(). Can we share some of it?

-- 
Regards/Gruss,
    Boris.

Sent from a fat crate under my desk. Formatting is fine.
--


From vgoyal at redhat.com  Fri Feb 28 11:31:35 2014
From: vgoyal at redhat.com (Vivek Goyal)
Date: Fri, 28 Feb 2014 11:31:35 -0500
Subject: [PATCH 08/11] kexec-bzImage: Support for loading bzImage using
 64bit entry
In-Reply-To: <20140227213629.GP18191@pd.tnic>
References: <1390849071-21989-1-git-send-email-vgoyal@redhat.com>
 <1390849071-21989-9-git-send-email-vgoyal@redhat.com>
 <20140227213629.GP18191@pd.tnic>
Message-ID: <20140228163134.GG28744@redhat.com>

On Thu, Feb 27, 2014 at 10:36:29PM +0100, Borislav Petkov wrote:

Hi Boris,

Thanks for taking time to review this large patchset. Please find
my comments inline.

[..]
> > diff --git a/arch/x86/kernel/Makefile b/arch/x86/kernel/Makefile
> > index cb648c8..fa9981d 100644
> > --- a/arch/x86/kernel/Makefile
> > +++ b/arch/x86/kernel/Makefile
> > @@ -67,8 +67,10 @@ obj-$(CONFIG_DYNAMIC_FTRACE)	+= ftrace.o
> >  obj-$(CONFIG_FUNCTION_GRAPH_TRACER) += ftrace.o
> >  obj-$(CONFIG_FTRACE_SYSCALLS)	+= ftrace.o
> >  obj-$(CONFIG_X86_TSC)		+= trace_clock.o
> > +obj-$(CONFIG_KEXEC)		+= machine_kexec.o
> >  obj-$(CONFIG_KEXEC)		+= machine_kexec_$(BITS).o
> >  obj-$(CONFIG_KEXEC)		+= relocate_kernel_$(BITS).o crash.o
> > +obj-$(CONFIG_KEXEC)		+= kexec-bzimage.o
> 
> Maybe use less obj-$(CONFIG_KEXEC) lines here.

Ok, Will put some of them in single line.

[..]
> > +struct bzimage64_data {
> > +	/*
> > +	 * Temporary buffer to hold bootparams buffer. This should be
> > +	 * freed once the bootparam segment has been loaded.
> > +	 */
> > +	void *bootparams_buf;
> > +};
> 
> Why a struct if it is going to have only one member?

Well, I had started with a generic idea of bootloader being able to store
some data in image and retrieve it later. Finally it turned out to be only
one field in current implementation.

But I still like it as it allows storing more data down the line. There
is no other place where we can store bootloader specific data. So this
is the mechanism I created.

> 
> > +
> > +int bzImage64_probe(const char *buf, unsigned long len)
> > +{
> > +	int ret = -ENOEXEC;
> > +	struct setup_header *header;
> > +
> > +	if (len < 2 * 512) {
> 
> What's 2*512? Two sectors?

Yep, two sectors.

> 
> > +		pr_debug("File is too short to be a bzImage\n");
> > +		return ret;
> > +	}
> > +
> > +	header = (struct setup_header *)(buf + 0x1F1);
> 
> 0x1F1 should need at least a comment or "offsetof(struct boot_params, hdr)"
> or both, which would be best. :-)

Ok, I will put a comment.

> 
> > +	if (memcmp((char *)&header->header, "HdrS", 4) != 0) {
> > +		pr_debug("Not a bzImage\n");
> 
> Actually, I think that means that there is no real mode kernel header
> there, or we're using an old boot protocol version:

So Documentation/x86/boot.txt says following.


If the "HdrS" (0x53726448) magic number is not found at offset 0x202,
the boot protocol version is "old".  Loading an old kernel, the
following parameters should be assumed:

        Image type = zImage
        initrd not supported
        Real-mode kernel must be located at 0x90000.

So if it is old version then it is zImage (and not bzImage). So pr_debug()
message seems to be correct that image one is trying to load is not
bzImage and this loader will not handle this image.

> 
> Documentation/x86/boot.txt
> 
> > +		return ret;
> > +	}
> > +
> > +	if (header->boot_flag != 0xAA55) {
> > +                /* No x86 boot sector present */
> 
> Comment is kinda redundant here :)

Ok, will get rid of it.

> 
> > +		pr_debug("No x86 boot sector present\n");
> > +		return ret;
> > +	}
> > +
> > +	if (header->version < 0x020C) {
> > +                /* Must be at least protocol version 2.12 */
> 
> Ditto.

Will get rid of it.

> 
> > +		pr_debug("Must be at least protocol version 2.12\n");
> > +		return ret;
> > +	}
> > +
> > +	if ((header->loadflags & 1) == 0) {
> 
> That must be LOADED_HIGH bit. Why does this bit mean it is a bzImage?

Yep, that's LOADED_HIGH check. I think if LOADED_HIGH is not set, then
that means protected mode code needs to be loaded at 0x10000 and I think
that also means that it is zImage and not bzImage.

Atleast this loader does not handle anything which is that old where
protected mode code needs to be loaded at 0x10000.

> 
> Ok, I see it in boot.txt:
> 
> "...
> 	When loading a zImage kernel ((loadflags & 0x01) == 0).
> "
> 
> > +		/* Not a bzImage */
> > +		pr_debug("zImage not a bzImage\n");
> > +		return ret;
> > +	}
> > +
> > +	if ((header->xloadflags & 3) != 3) {
> > +	/* XLF_KERNEL_64 and XLF_CAN_BE_LOADED_ABOVE_4G should be set */
> 
> Use those defines in the code please instead of naked numbers.

Agreed. Using these defines is more readable. Will change it.


[..]
> > +void *bzImage64_load(struct kimage *image, char *kernel,
> > +		unsigned long kernel_len,
> > +		char *initrd, unsigned long initrd_len,
> > +		char *cmdline, unsigned long cmdline_len)
> > +{
> > +
> > +	struct setup_header *header;
> > +	int setup_sects, kern16_size, ret = 0;
> > +	unsigned long setup_header_size, params_cmdline_sz;
> > +	struct boot_params *params;
> > +	unsigned long bootparam_load_addr, kernel_load_addr, initrd_load_addr;
> > +	unsigned long purgatory_load_addr;
> > +	unsigned long kernel_bufsz, kernel_memsz, kernel_align;
> > +	char *kernel_buf;
> > +	struct bzimage64_data *ldata;
> > +	struct kexec_entry64_regs regs64;
> > +	void *stack;
> > +
> > +	header = (struct setup_header *)(kernel + 0x1F1);
> 
> See above.

Will comment or use offsetof().

[..]
> > +	/* Allocate loader specific data */
> > +	ldata = kzalloc(sizeof(struct bzimage64_data), GFP_KERNEL);
> > +	if (!ldata)
> > +		return ERR_PTR(-ENOMEM);
> > +
> > +	/*
> > +	 * Load purgatory. For 64bit entry point, purgatory  code can be
> > +	 * anywhere.
> > +	 */
> > +	ret = kexec_load_purgatory(image, 0x3000, -1, 1, &purgatory_load_addr);
> 
> Some defines like MIN_<something> and MAX_<something> could be more
> readable here.

Ok, atleast will use MAX_<something> for "-1". I might define one
internally to this file for representing minimum address of 0x3000.

> 
> > +	if (ret) {
> > +		pr_debug("Loading purgatory failed\n");
> > +		goto out_free_loader_data;
> > +	}
> > +
> > +	pr_debug("Loaded purgatory at 0x%lx\n", purgatory_load_addr);
> > +
> > +	/* Load Bootparams and cmdline */
> > +	params_cmdline_sz = sizeof(struct boot_params) + cmdline_len;
> > +	params = kzalloc(params_cmdline_sz, GFP_KERNEL);
> > +	if (!params) {
> > +		ret = -ENOMEM;
> > +		goto out_free_loader_data;
> > +	}
> > +
> > +	/* Copy setup header onto bootparams. */
> > +	setup_header_size = 0x0202 + kernel[0x0201] - 0x1F1;
> 
> More magic numbers :-\ Ok, I'm not going to comment on the rest of them
> below but you get the idea - it would be much better to have descriptive
> defines here instead of naked numbers.

That's how boot.txt defines it. Look at 64-bit BOOT PROTOCOL.

0x0202 + byte value at offset 0x0201

Now one can argue that create some new defines to represent those magic
numbers and include that file in kexec-bzimage loader. I will see what
can I do.

> 
> > +
> > +	/* Is there a limit on setup header size? */
> > +	memcpy(&params->hdr, (kernel + 0x1F1), setup_header_size);
> > +	ret = kexec_add_buffer(image, (char *)params, params_cmdline_sz,
> > +			params_cmdline_sz, 16, 0x3000, -1, 1,
> > +			&bootparam_load_addr);
> 
> Normally we do arg alignment below the opening brace of the function.
> Ditto for a bunch of call sites below.

Hmm.., I have seen all kinds of alignments. But anyway, if you prefer
that, I will change atleast some of them.

[..]
> > +#include <linux/kernel.h>
> > +#include <linux/string.h>
> > +#include <asm/bootparam.h>
> > +#include <asm/setup.h>
> > +
> > +/*
> > + * Common code for x86 and x86_64 used for kexec.
> 
> I think you mean i386 by x86, right?

Yes.

[..]
> > +static int setup_memory_map_entries(struct boot_params *params)
> > +{
> > +	unsigned int nr_e820_entries;
> > +
> > +	/* TODO: What about EFI */
> 
> Do you mean by that what do_add_efi_memmap() does? We add the efi
> entries only when add_efi_memmap is supplied on the cmdline, see
> 200001eb140ea.

I meant in general I have not done any EFI handling. I am not even
sure what needs to be done for EFI. I am just going through memory
map and filling up E820 map in bootparams so that second kernel knows
what are the memory areas available.

At some point of time we need to start passing EFI memory map to
second kernel. (All the new code you and dave young have added to
make kexec work on EFI systems).

I wanted to that in a separate patch. This patch series is alredy very
big. bzImage signing and verification also I am planning to post in a
separate series.

Thanks
Vivek


From vgoyal at redhat.com  Fri Feb 28 11:56:28 2014
From: vgoyal at redhat.com (Vivek Goyal)
Date: Fri, 28 Feb 2014 11:56:28 -0500
Subject: [PATCH 09/11] kexec: Provide a function to add a segment at
 fixed address
In-Reply-To: <20140227215232.GQ18191@pd.tnic>
References: <1390849071-21989-1-git-send-email-vgoyal@redhat.com>
 <1390849071-21989-10-git-send-email-vgoyal@redhat.com>
 <20140227215232.GQ18191@pd.tnic>
Message-ID: <20140228165628.GH28744@redhat.com>

On Thu, Feb 27, 2014 at 10:52:32PM +0100, Borislav Petkov wrote:

[..]
> > +/* Add a kexec segment at fixed address provided by caller */
> > +int kexec_add_segment(struct kimage *image, char *buffer, unsigned long bufsz,
> > +			unsigned long memsz, unsigned long base)
> > +{
> > +	struct kexec_segment ksegment;
> > +	int ret;
> > +
> > +	/* Currently adding segment this way is allowed only in file mode */
> > +	if (!image->file_mode)
> > +		return -EINVAL;
> 
> Why the guard? On a quick scan, I don't see this function called by
> something else except on the kexec_file_load path...

This is more of future proofing it. I have been putting this check to
catch any accidental errors if somebody ends up calling this function
from old mode.

But I am not very particular about it. If you don't like it, I can get
rid of it.
 
> 
> > +
> > +	if (image->nr_segments >= KEXEC_SEGMENT_MAX)
> > +		return -EINVAL;
> > +
> > +	/*
> > +	 * Make sure we are not trying to add segment after allocating
> > +	 * control pages. All segments need to be placed first before
> > +	 * any control pages are allocated. As control page allocation
> > +	 * logic goes through list of segments to make sure there are
> > +	 * no destination overlaps.
> > +	 */
> > +	WARN_ONCE(!list_empty(&image->control_pages), "Adding kexec segment"
> 
> Maybe say at which address here:
> 
> ... "Adding a kexec segment at address 0x%lx.."
> 
> for a bit more helpful info.

I think address does not matter here. You can't add a segemnt after you
have allocated a control page. So I am not sure how printing address will
help.

> 
> > +			" after allocating control pages\n");
> > +
> > +	if (bufsz > memsz)
> > +		return -EINVAL;
> > +	if (memsz == 0)
> > +		return -EINVAL;
> > +
> > +	/* Align memsz to next page boundary */
> > +	memsz = ALIGN(memsz, PAGE_SIZE);
> 
> We even have PAGE_ALIGN for that.

Ok, there is not much difference between two, but I can use PAGE_ALIGN().

> 
> > +
> > +	/* Make sure base is atleast page size aligned */
> > +	if (base & (PAGE_SIZE - 1))
> 
> PAGE_ALIGNED even :)

Will use it. :-)

> 
> > +		return -EINVAL;
> > +
> > +	memset(&ksegment, 0, sizeof(struct kexec_segment));
> > +	ksegment.mem = base;
> > +	ksegment.memsz = memsz;
> > +
> > +	/* Validate memory range */
> > +	ret = walk_system_ram_res(base, base + memsz - 1, &ksegment,
> > +				validate_ram_range_callback);
> > +
> > +	/* If a valid range is found, 1 is returned */
> > +	if (ret != 1)
> 
> That's the retval of validate_ram_range_callback, right? So
> 
> 	if (!ret)
> 
> And shouldn't the convention be the opposite? 0 on success, !0 on error?

Ok, this one is little twisted.

walk_system_ram_res() stops calling callback function if callback
function returned non zero code.

So in this case, once we have found the range to be valid, we don't want
to continue to loop and look at any more ranges. So we return "1". If
we return "0" for success, outer loop of walk_system_ram_res() will
continue with next ranges.

Given the fact that "0" is interpreted as success by walk_system_ram_res()
and it continues with next set of ranges, I could not use 0 as final
measure of success. Negative returns are errors. So I thought of using
postive values of ret to indicate whether range was found or not.

If there are better ways to handle it, I am all for it.

Thanks
Vivek


From vgoyal at redhat.com  Fri Feb 28 12:11:43 2014
From: vgoyal at redhat.com (Vivek Goyal)
Date: Fri, 28 Feb 2014 12:11:43 -0500
Subject: [PATCH 10/11] kexec: Support for loading ELF x86_64 images
In-Reply-To: <20140228145832.GF4326@pd.tnic>
References: <1390849071-21989-1-git-send-email-vgoyal@redhat.com>
 <1390849071-21989-11-git-send-email-vgoyal@redhat.com>
 <20140228145832.GF4326@pd.tnic>
Message-ID: <20140228171142.GI28744@redhat.com>

On Fri, Feb 28, 2014 at 03:58:32PM +0100, Borislav Petkov wrote:
> On Mon, Jan 27, 2014 at 01:57:50PM -0500, Vivek Goyal wrote:
> > This patch provides support for kexec for loading ELF x86_64 images. I have
> > tested it with loading vmlinux and it worked.
> 
> Can you please enlighten me what the use case for ELF kernel images is? bzImage
> I understand but what produces ELF images?

Before bzImage is generated, we produce an ELF vmlinux (linux-2.6/vmlinux).
And then this vmlinux is processed further to produce bzImage.

In theory you can load this vmlinux and boot into it using kexec system
call.

In general, Eric wanted to support ELF images hence I put in this patch.

> 
> I see that kexec_file_load() can receive ELF segments too but why are we
> doing that?

So kexec_file_load() does not know what kind of file it is. Whether an
ELF file or an bzImage file. It will just call all the image loaders and
see if some loader recognizes the file and claims it.

So idea is what kind of image one should be able to load using this
new system call and kexec into. 

My primary use case is bzImage. Others think that it should be generic
enough to be able to handle ELF too.

> 
> > Signed-off-by: Vivek Goyal <vgoyal at redhat.com>
> > ---
> >  arch/x86/include/asm/kexec-elf.h   |  11 ++
> >  arch/x86/kernel/Makefile           |   1 +
> >  arch/x86/kernel/kexec-elf.c        | 231 +++++++++++++++++++++++++++++++++++++
> >  arch/x86/kernel/machine_kexec_64.c |   2 +
> >  4 files changed, 245 insertions(+)
> >  create mode 100644 arch/x86/include/asm/kexec-elf.h
> >  create mode 100644 arch/x86/kernel/kexec-elf.c
> > 
> > diff --git a/arch/x86/include/asm/kexec-elf.h b/arch/x86/include/asm/kexec-elf.h
> > new file mode 100644
> > index 0000000..afef382
> > --- /dev/null
> > +++ b/arch/x86/include/asm/kexec-elf.h
> > @@ -0,0 +1,11 @@
> > +#ifndef _ASM_KEXEC_ELF_H
> > +#define _ASM_KEXEC_ELF_H
> > +
> > +extern int elf_x86_64_probe(const char *buf, unsigned long len);
> > +extern void *elf_x86_64_load(struct kimage *image, char *kernel,
> > +		unsigned long kernel_len, char *initrd,
> > +		unsigned long initrd_len, char *cmdline,
> > +		unsigned long cmdline_len);
> > +extern int elf_x86_64_cleanup(struct kimage *image);
> > +
> > +#endif  /* _ASM_KEXEC_ELF_H */
> > diff --git a/arch/x86/kernel/Makefile b/arch/x86/kernel/Makefile
> > index fa9981d..2d77de7 100644
> > --- a/arch/x86/kernel/Makefile
> > +++ b/arch/x86/kernel/Makefile
> > @@ -71,6 +71,7 @@ obj-$(CONFIG_KEXEC)		+= machine_kexec.o
> >  obj-$(CONFIG_KEXEC)		+= machine_kexec_$(BITS).o
> >  obj-$(CONFIG_KEXEC)		+= relocate_kernel_$(BITS).o crash.o
> >  obj-$(CONFIG_KEXEC)		+= kexec-bzimage.o
> > +obj-$(CONFIG_KEXEC)		+= kexec-elf.o
> 
> It looks like kexec could slowly grow its own dir now:
> 
> arch/x86/kexec/

I was rather thinking of arch/x86/kernel/kexec. But that's for some other
day. Not part of this patchset. This is alredy too big and I don't want
to make any changes which are nice to have and bloat the patch size.

> 
> or so.
> 
> >  obj-$(CONFIG_CRASH_DUMP)	+= crash_dump_$(BITS).o
> >  obj-y				+= kprobes/
> >  obj-$(CONFIG_MODULES)		+= module.o
> > diff --git a/arch/x86/kernel/kexec-elf.c b/arch/x86/kernel/kexec-elf.c
> > new file mode 100644
> > index 0000000..ff1017c
> > --- /dev/null
> > +++ b/arch/x86/kernel/kexec-elf.c
> > @@ -0,0 +1,231 @@
> > +#include <linux/string.h>
> > +#include <linux/printk.h>
> > +#include <linux/errno.h>
> > +#include <linux/slab.h>
> > +#include <linux/kexec.h>
> > +#include <linux/kernel.h>
> > +#include <linux/mm.h>
> > +
> > +#include <asm/bootparam.h>
> > +#include <asm/setup.h>
> > +
> > +#ifdef CONFIG_X86_64
> > +
> > +struct elf_x86_64_data {
> > +	/*
> > +	 * Temporary buffer to hold bootparams buffer. This should be
> > +	 * freed once the bootparam segment has been loaded.
> > +	 */
> > +	void *bootparams_buf;
> > +};
> > +
> > +int elf_x86_64_probe(const char *buf, unsigned long len)
> > +{
> > +	int ret = -ENOEXEC;
> > +	Elf_Ehdr *ehdr;
> > +
> > +	if (len < sizeof(Elf_Ehdr)) {
> > +		pr_debug("File is too short to be an ELF executable.\n");
> > +		return ret;
> > +	}
> > +
> > +	ehdr = (Elf_Ehdr *)buf;
> > +
> > +	if (memcmp(ehdr->e_ident, ELFMAG, SELFMAG) != 0
> > +	    || ehdr->e_type != ET_EXEC || !elf_check_arch(ehdr)
> > +	    || ehdr->e_phentsize != sizeof(Elf_Phdr))
> > +		return -ENOEXEC;
> > +
> > +	if (ehdr->e_phoff >= len
> > +	    || (ehdr->e_phnum * sizeof(Elf_Phdr) > len - ehdr->e_phoff))
> > +		return -ENOEXEC;
> > +
> > +        /* I've got a bzImage */
> > +	pr_debug("It's an elf_x86_64 image.\n");
> > +	ret = 0;
> > +
> > +	return ret;
> 
> I think you can drop 'ret' here and return the error vals directly.

Yep, will simplify this one.

> 
> > +}
> > +
> > +static int elf_exec_load(struct kimage *image, char *kernel)
> > +{
> > +	Elf_Ehdr *ehdr;
> > +	Elf_Phdr *phdrs;
> > +	int i, ret;
> > +	size_t filesz;
> > +	char *buffer;
> > +
> > +	ehdr = (Elf_Ehdr *)kernel;
> > +	phdrs = (void *)ehdr + ehdr->e_phoff;
> > +
> > +	for (i = 0; i < ehdr->e_phnum; i++) {
> > +		if (phdrs[i].p_type != PT_LOAD)
> > +			continue;
> 
> newline

What's that?

> 
> > +		filesz = phdrs[i].p_filesz;
> > +		if (filesz > phdrs[i].p_memsz)
> > +			filesz = phdrs[i].p_memsz;
> > +
> > +		buffer = (char *)ehdr + phdrs[i].p_offset;
> > +		ret = kexec_add_segment(image, buffer, filesz, phdrs[i].p_memsz,
> > +						phdrs[i].p_paddr);
> > +		if (ret)
> > +			break;
> > +	}
> > +
> > +	return ret;
> > +}
> > +
> > +/* Fill in fields which are usually present in bzImage */
> > +static int init_linux_parameters(struct boot_params *params)
> > +{
> > +	/*
> > +	 * FIXME: It is odd that the information which comes from kernel
> > +	 * has to be faked by loading kernel. I guess it is limitation of
> > +	 * ELF format. Right now keeping it same as kexec-tools
> > +	 * implementation. But this most likely needs fixing.
> > +	 */
> > +	memcpy(&params->hdr.header, "HdrS", 4);
> > +	params->hdr.version = 0x0206;
> > +	params->hdr.initrd_addr_max = 0x37FFFFFF;
> > +	params->hdr.cmdline_size = 2048;
> > +	return 0;
> > +}
> 
> Why a separate function? Its body is small enough to be merged into
> elf_x86_64_load.

Actually this logic shows the limitation of ELF format kernel image.
This information should be exported by the image so that loader can
do some verifications. But instead loader is hardcoding this info and
faking things.

For example, it should be kernel which tells what's the maximum command
line size it can handle and then loader can return error if user specified
command line size is greater than what new kernel can handle.

Similarly, what's the max address initrd can be loaded at.

Actually I have copied this code from kexec-tools. And I am wondering
if some of this is 

I am not sure why we set hdr.version and hdr.header. Are there any
assumptions in booth path kernel is making. May be some other code
down the line is parsing it or it is completely redundant. I think
I will play with removing setting of hdr.version and hdr.header and
see how does it go.

so I put it in a separate function because user space code had it
that way. Also because I did not like this part of the code and this
looks like a limitation of ELF format, I wanted to isolate it in
a separate function so that it is easy to spot it.

> 
> > +
> > +void *elf_x86_64_load(struct kimage *image, char *kernel,
> > +		unsigned long kernel_len,
> > +		char *initrd, unsigned long initrd_len,
> > +		char *cmdline, unsigned long cmdline_len)
> > +{
> 
> Btw, this functionality below looks very similar to the one in
> bzImage64_load(). Can we share some of it?

It looks similar but values with which some of the functions are called
are different. I will see if there are some obivious candidate to share
the code. It is not a lot of code to begin with.

Thanks
Vivek


From bp at alien8.de  Fri Feb 28 12:28:57 2014
From: bp at alien8.de (Borislav Petkov)
Date: Fri, 28 Feb 2014 18:28:57 +0100
Subject: [PATCH 11/11] kexec: Support for Kexec on panic using new system
 call
In-Reply-To: <1390849071-21989-12-git-send-email-vgoyal@redhat.com>
References: <1390849071-21989-1-git-send-email-vgoyal@redhat.com>
 <1390849071-21989-12-git-send-email-vgoyal@redhat.com>
Message-ID: <20140228172857.GG4326@pd.tnic>

On Mon, Jan 27, 2014 at 01:57:51PM -0500, Vivek Goyal wrote:
> This patch adds support for loading a kexec on panic (kdump) kernel usning
> new system call. Right now this primarily works with bzImage loader only.
> But changes to ELF loader should be minimal as all the core infrastrcture
> is there.
> 
> Only thing preventing making ELF load in crash reseved memory is
> that kernel vmlinux is of type ET_EXEC and it expects to be loaded at
> address it has been compiled for. At that location current kernel is
> already running. One first needs to make vmlinux fully relocatable
> and export it is type ET_DYN and then modify this ELF loader to support
> images of type ET_DYN.
> 
> I am leaving it as a future TODO item.
> 
> Signed-off-by: Vivek Goyal <vgoyal at redhat.com>

checkpatch: total: 2 errors, 10 warnings, 977 lines checked

> diff --git a/arch/x86/include/asm/kexec.h b/arch/x86/include/asm/kexec.h
> index 9bd6fec..a330d85 100644
> --- a/arch/x86/include/asm/kexec.h
> +++ b/arch/x86/include/asm/kexec.h
> @@ -25,6 +25,8 @@
>  #include <asm/ptrace.h>
>  #include <asm/bootparam.h>
>  
> +struct kimage;
> +
>  /*
>   * KEXEC_SOURCE_MEMORY_LIMIT maximum page get_free_page can return.
>   * I.e. Maximum page that is mapped directly into kernel memory,
> @@ -62,6 +64,10 @@
>  # define KEXEC_ARCH KEXEC_ARCH_X86_64
>  #endif
>  
> +/* Memory to backup during crash kdump */
> +#define KEXEC_BACKUP_SRC_START	(0UL)
> +#define KEXEC_BACKUP_SRC_END	(655360UL)	/* 640K */

I guess

#define KEXEC_BACKUP_SRC_END	(640 * 1024UL)

should be more clear.

>  /*
>   * CPU does not save ss and sp on stack if execution is already
>   * running in kernel mode at the time of NMI occurrence. This code
> @@ -161,8 +167,21 @@ struct kimage_arch {
>  	pud_t *pud;
>  	pmd_t *pmd;
>  	pte_t *pte;
> +	/* Details of backup region */
> +	unsigned long backup_src_start;
> +	unsigned long backup_src_sz;
> +
> +	/* Physical address of backup segment */
> +	unsigned long backup_load_addr;
> +
> +	/* Core ELF header buffer */
> +	unsigned long elf_headers;
> +	unsigned long elf_headers_sz;
> +	unsigned long elf_load_addr;
>  };
> +#endif /* CONFIG_X86_32 */
>  
> +#ifdef CONFIG_X86_64
>  struct kexec_entry64_regs {
>  	uint64_t rax;
>  	uint64_t rbx;
> @@ -189,11 +208,13 @@ extern crash_vmclear_fn __rcu *crash_vmclear_loaded_vmcss;
>  
>  extern int kexec_setup_initrd(struct boot_params *boot_params,
>  		unsigned long initrd_load_addr, unsigned long initrd_len);
> -extern int kexec_setup_cmdline(struct boot_params *boot_params,
> +extern int kexec_setup_cmdline(struct kimage *image,
> +		struct boot_params *boot_params,
>  		unsigned long bootparams_load_addr,
>  		unsigned long cmdline_offset, char *cmdline,
>  		unsigned long cmdline_len);
> -extern int kexec_setup_boot_parameters(struct boot_params *params);
> +extern int kexec_setup_boot_parameters(struct kimage *image,
> +					struct boot_params *params);
>  
>  
>  #endif /* __ASSEMBLY__ */
> diff --git a/arch/x86/kernel/crash.c b/arch/x86/kernel/crash.c
> index a57902e..8eabde4 100644
> --- a/arch/x86/kernel/crash.c
> +++ b/arch/x86/kernel/crash.c
> @@ -4,6 +4,9 @@
>   * Created by: Hariprasad Nellitheertha (hari at in.ibm.com)
>   *
>   * Copyright (C) IBM Corporation, 2004. All rights reserved.
> + * Copyright (C) Red Hat Inc., 2014. All rights reserved.
> + * Authors:
> + * 	Vivek Goyal <vgoyal at redhat.com>
>   *
>   */
>  
> @@ -16,6 +19,7 @@
>  #include <linux/elf.h>
>  #include <linux/elfcore.h>
>  #include <linux/module.h>
> +#include <linux/slab.h>
>  
>  #include <asm/processor.h>
>  #include <asm/hardirq.h>
> @@ -28,6 +32,45 @@
>  #include <asm/reboot.h>
>  #include <asm/virtext.h>
>  
> +/* Alignment required for elf header segment */
> +#define ELF_CORE_HEADER_ALIGN   4096
> +
> +/* This primarily reprsents number of split ranges due to exclusion */
> +#define CRASH_MAX_RANGES	16
> +
> +struct crash_mem_range {
> +	unsigned long long start, end;

u64?

> +};
> +
> +struct crash_mem {
> +	unsigned int nr_ranges;
> +	struct crash_mem_range ranges[CRASH_MAX_RANGES];
> +};
> +
> +/* Misc data about ram ranges needed to prepare elf headers */
> +struct crash_elf_data {
> +	struct kimage *image;
> +	/*
> +	 * Total number of ram ranges we have after various ajustments for
> +	 * GART, crash reserved region etc.
> +	 */
> +	unsigned int max_nr_ranges;
> +	unsigned long gart_start, gart_end;
> +
> +	/* Pointer to elf header */
> +	void *ehdr;
> +	/* Pointer to next phdr */
> +	void *bufp;
> +	struct crash_mem mem;
> +};
> +
> +/* Used while prepareing memory map entries for second kernel */

s/prepareing/preparing/

> +struct crash_memmap_data {
> +	struct boot_params *params;
> +	/* Type of memory */
> +	unsigned int type;
> +};
> +
>  int in_crash_kexec;
>  
>  /*
> @@ -137,3 +180,534 @@ void native_machine_crash_shutdown(struct pt_regs *regs)
>  #endif
>  	crash_save_cpu(regs, safe_smp_processor_id());
>  }
> +
> +#ifdef CONFIG_X86_64
> +
> +static int get_nr_ram_ranges_callback(unsigned long start_pfn,
> +				unsigned long nr_pfn, void *arg)
> +{
> +	int *nr_ranges = arg;
> +
> +	(*nr_ranges)++;
> +	return 0;
> +}
> +
> +static int get_gart_ranges_callback(u64 start, u64 end, void *arg)
> +{
> +	struct crash_elf_data *ced = arg;
> +
> +	ced->gart_start = start;
> +	ced->gart_end = end;
> +
> +	/* Not expecting more than 1 gart aperture */
> +	return 1;
> +}
> +
> +
> +/* Gather all the required information to prepare elf headers for ram regions */
> +static int fill_up_ced(struct crash_elf_data *ced, struct kimage *image)

All other functions have nice, spelled out names but not this one :)

Why not fill_up_crash_elf_data()?

> +{
> +	unsigned int nr_ranges = 0;
> +
> +	ced->image = image;
> +
> +	walk_system_ram_range(0, -1, &nr_ranges,
> +				get_nr_ram_ranges_callback);
> +
> +	ced->max_nr_ranges = nr_ranges;
> +
> +	/*
> +	 * We don't create ELF headers for GART aperture as an attempt
> +	 * to dump this memory in second kernel leads to hang/crash.
> +	 * If gart aperture is present, one needs to exclude that region
> +	 * and that could lead to need of extra phdr.
> +	 */
> +

superfluous newline.

> +	walk_ram_res("GART", IORESOURCE_MEM, 0, -1,
> +				ced, get_gart_ranges_callback);
> +
> +	/*
> +	 * If we have gart region, excluding that could potentially split
> +	 * a memory range, resulting in extra header. Account for  that.
> +	 */
> +	if (ced->gart_end)
> +		ced->max_nr_ranges++;
> +
> +	/* Exclusion of crash region could split memory ranges */
> +	ced->max_nr_ranges++;
> +
> +	/* If crashk_low_res is there, another range split possible */
> +	if (crashk_low_res.end != 0)
> +		ced->max_nr_ranges++;
> +
> +	return 0;
> +}

...

> +int load_crashdump_segments(struct kimage *image)
> +{
> +	unsigned long src_start, src_sz;
> +	unsigned long elf_addr, elf_sz;
> +	int ret;
> +
> +	/*
> +	 * Determine and load a segment for backup area. First 640K RAM
> +	 * region is backup source
> +	 */
> +
> +	ret = walk_system_ram_res(KEXEC_BACKUP_SRC_START, KEXEC_BACKUP_SRC_END,
> +				image, determine_backup_region);
> +
> +	/* Zero or postive return values are ok */
> +	if (ret < 0)
> +		return ret;
> +
> +	src_start = image->arch.backup_src_start;
> +	src_sz = image->arch.backup_src_sz;
> +
> +	/* Add backup segment. */
> +	if (src_sz) {
> +		ret = kexec_add_buffer(image, __va(src_start), src_sz, src_sz,
> +					PAGE_SIZE, 0, -1, 0,
> +					&image->arch.backup_load_addr);
> +		if (ret)
> +			return ret;
> +	}
> +
> +	/* Prepare elf headers and add a segment */
> +	ret = prepare_elf_headers(image, &elf_addr, &elf_sz);
> +	if (ret)
> +		return ret;
> +
> +	image->arch.elf_headers = elf_addr;
> +	image->arch.elf_headers_sz = elf_sz;
> +
> +	ret = kexec_add_buffer(image, (char *)elf_addr, elf_sz, elf_sz,

For some reason, my compiler complains here:

arch/x86/kernel/crash.c: In function ?load_crashdump_segments?:
arch/x86/kernel/crash.c:704:6: warning: ?elf_sz? may be used uninitialized in this function [-Wuninitialized]
arch/x86/kernel/crash.c:704:24: warning: ?elf_addr? may be used uninitialized in this function [-Wuninitialized]

It is likely bogus, though.

...

> -int kexec_setup_cmdline(struct boot_params *boot_params,
> +int kexec_setup_cmdline(struct kimage *image, struct boot_params *boot_params,
>  		unsigned long bootparams_load_addr,
>  		unsigned long cmdline_offset, char *cmdline,
>  		unsigned long cmdline_len)
>  {
>  	char *cmdline_ptr = ((char *)boot_params) + cmdline_offset;
> -	unsigned long cmdline_ptr_phys;
> +	unsigned long cmdline_ptr_phys, len;
>  	uint32_t cmdline_low_32, cmdline_ext_32;
>  
>  	memcpy(cmdline_ptr, cmdline, cmdline_len);
> +	if (image->type == KEXEC_TYPE_CRASH) {
> +		len = sprintf(cmdline_ptr + cmdline_len - 1,
> +			" elfcorehdr=0x%lx", image->arch.elf_load_addr);
> +		cmdline_len += len;
> +	}
>  	cmdline_ptr[cmdline_len - 1] = '\0';
>  
> +	pr_debug("Final command line is:%s\n", cmdline_ptr);

one space after ":"

The rest looks ok to me, but that doesn't mean a whole lot considering
my very limited kexec knowledge.

Thanks.

-- 
Regards/Gruss,
    Boris.

Sent from a fat crate under my desk. Formatting is fine.
--


From vgoyal at redhat.com  Fri Feb 28 16:06:11 2014
From: vgoyal at redhat.com (Vivek Goyal)
Date: Fri, 28 Feb 2014 16:06:11 -0500
Subject: [PATCH 11/11] kexec: Support for Kexec on panic using new system
 call
In-Reply-To: <20140228172857.GG4326@pd.tnic>
References: <1390849071-21989-1-git-send-email-vgoyal@redhat.com>
 <1390849071-21989-12-git-send-email-vgoyal@redhat.com>
 <20140228172857.GG4326@pd.tnic>
Message-ID: <20140228210611.GB17195@redhat.com>

On Fri, Feb 28, 2014 at 06:28:57PM +0100, Borislav Petkov wrote:

[..]
> > +/* Memory to backup during crash kdump */
> > +#define KEXEC_BACKUP_SRC_START	(0UL)
> > +#define KEXEC_BACKUP_SRC_END	(655360UL)	/* 640K */
> 
> I guess
> 
> #define KEXEC_BACKUP_SRC_END	(640 * 1024UL)
> 
> should be more clear.

Will Change.

[..]
> > +/* Alignment required for elf header segment */
> > +#define ELF_CORE_HEADER_ALIGN   4096
> > +
> > +/* This primarily reprsents number of split ranges due to exclusion */
> > +#define CRASH_MAX_RANGES	16
> > +
> > +struct crash_mem_range {
> > +	unsigned long long start, end;
> 
> u64?

Ok, that's shorter. Can use that.

[..]
> > +
> > +/* Used while prepareing memory map entries for second kernel */
> 
> s/prepareing/preparing/

Yep typo. Will fix.

[..]
> > +static int get_gart_ranges_callback(u64 start, u64 end, void *arg)
> > +{
> > +	struct crash_elf_data *ced = arg;
> > +
> > +	ced->gart_start = start;
> > +	ced->gart_end = end;
> > +
> > +	/* Not expecting more than 1 gart aperture */
> > +	return 1;
> > +}
> > +
> > +
> > +/* Gather all the required information to prepare elf headers for ram regions */
> > +static int fill_up_ced(struct crash_elf_data *ced, struct kimage *image)
> 
> All other functions have nice, spelled out names but not this one :)
> 
> Why not fill_up_crash_elf_data()?

Will change it.

> 
> > +{
> > +	unsigned int nr_ranges = 0;
> > +
> > +	ced->image = image;
> > +
> > +	walk_system_ram_range(0, -1, &nr_ranges,
> > +				get_nr_ram_ranges_callback);
> > +
> > +	ced->max_nr_ranges = nr_ranges;
> > +
> > +	/*
> > +	 * We don't create ELF headers for GART aperture as an attempt
> > +	 * to dump this memory in second kernel leads to hang/crash.
> > +	 * If gart aperture is present, one needs to exclude that region
> > +	 * and that could lead to need of extra phdr.
> > +	 */
> > +
> 
> superfluous newline.

Will remove.

[..]
> > +int load_crashdump_segments(struct kimage *image)
> > +{
> > +	unsigned long src_start, src_sz;
> > +	unsigned long elf_addr, elf_sz;
> > +	int ret;
> > +
> > +	/*
> > +	 * Determine and load a segment for backup area. First 640K RAM
> > +	 * region is backup source
> > +	 */
> > +
> > +	ret = walk_system_ram_res(KEXEC_BACKUP_SRC_START, KEXEC_BACKUP_SRC_END,
> > +				image, determine_backup_region);
> > +
> > +	/* Zero or postive return values are ok */
> > +	if (ret < 0)
> > +		return ret;
> > +
> > +	src_start = image->arch.backup_src_start;
> > +	src_sz = image->arch.backup_src_sz;
> > +
> > +	/* Add backup segment. */
> > +	if (src_sz) {
> > +		ret = kexec_add_buffer(image, __va(src_start), src_sz, src_sz,
> > +					PAGE_SIZE, 0, -1, 0,
> > +					&image->arch.backup_load_addr);
> > +		if (ret)
> > +			return ret;
> > +	}
> > +
> > +	/* Prepare elf headers and add a segment */
> > +	ret = prepare_elf_headers(image, &elf_addr, &elf_sz);
> > +	if (ret)
> > +		return ret;
> > +
> > +	image->arch.elf_headers = elf_addr;
> > +	image->arch.elf_headers_sz = elf_sz;
> > +
> > +	ret = kexec_add_buffer(image, (char *)elf_addr, elf_sz, elf_sz,
> 
> For some reason, my compiler complains here:
> 
> arch/x86/kernel/crash.c: In function ?load_crashdump_segments?:
> arch/x86/kernel/crash.c:704:6: warning: ?elf_sz? may be used uninitialized in this function [-Wuninitialized]
> arch/x86/kernel/crash.c:704:24: warning: ?elf_addr? may be used uninitialized in this function [-Wuninitialized]
> 
> It is likely bogus, though.

Hmm..., I did not see these warnings with my setup. elf_addr and elf_sz
will be initialized by prepare_elf_headers(). Not sure why compiler is
complaining.

[..]
> > +	pr_debug("Final command line is:%s\n", cmdline_ptr);
> 
> one space after ":"

Ok. will do.

> 
> The rest looks ok to me, but that doesn't mean a whole lot considering
> my very limited kexec knowledge.

Thanks for review. We need many eyes on this patch set. I will make
changes and post another version for review.

Thanks
Vivek


From yadviga at mvista.com  Fri Feb 28 06:48:43 2014
From: yadviga at mvista.com (Yadviga)
Date: Fri, 28 Feb 2014 15:48:43 +0400
Subject: separate lowmem and highmem in crashdump segments for ppc32
In-Reply-To: <530FA89D.2010105@mvista.com>
References: <530FA89D.2010105@mvista.com>
Message-ID: <5310779B.8050400@mvista.com>


Hello all
I would like to suggest the patch for ppc32 arch against kexec-2.0.5.
Could you please include it into kexec tools.

The patch separates highmem and lowmem.
Usually highmem and lowmem merges in common segment.
Virtual  addresses for this segment are invalid because code from
crashdump-elf.c set virtual address -1 for lowmem
addresses if they share segment with highmem addresses.

                 /* HIGMEM has a virtual address of -1 */

                  if (elf_info->lowmem_limit
&& (mend > (elf_info->lowmem_limit - 1)))
                          phdr->p_vaddr = -1;

The patch locates them in different segments.
So lowmem will have the valid  virtual address

This is result of gdb backtrace before applying the patch.

powerpc-montavista-linux-gnuspe-gdb vmlinux /opt/tmp/vmcore_kexec2.0.5
GNU gdb (MontaVista Linux G++ 4.7-140117041417) 7.6
Copyright (C) 2013 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later
<http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.  Type "show copying"
and "show warranty" for details.
This GDB was configured as "--host=i686-pc-linux-gnu
--target=powerpc-montavista-linux-gnuspe".
For bug reporting instructions, please see:
<http://support.mvista.com/>...
Reading symbols from /home/yadviga/MVL7/mvl7kernel_jan/vmlinux...done.
[New LWP 1993]
#0  0xc033c1e0 in sysrq_handle_crash (key=99) at drivers/tty/sysrq.c:138
138             *killer = 1;
(gdb) bt
#0  0xc033c1e0 in sysrq_handle_crash (key=99) at drivers/tty/sysrq.c:138
#1  0xc033ca68 in __handle_sysrq (key=99,
      key at entry=<error reading variable: Cannot access memory at address
0xcf6a5ed4>,
      check_mask=<optimized out>) at drivers/tty/sysrq.c:533
(gdb)

Here is backtrace after aapying the patch. Backtrace looks better.

powerpc-montavista-linux-gnuspe-gdb vmlinux /opt/tmp/vmcore
GNU gdb (MontaVista Linux G++ 4.7-140117041417) 7.6
...
Reading symbols from /home/yadviga/MVL7/mvl7kernel_jan/vmlinux...done.
[New LWP 1969]
#0  0xc033c1e0 in sysrq_handle_crash (key=99) at drivers/tty/sysrq.c:138
138             *killer = 1;
(gdb) bt
#0  0xc033c1e0 in sysrq_handle_crash (key=99) at drivers/tty/sysrq.c:138
#1  0xc033ca68 in __handle_sysrq (key=99,
check_mask=check_mask at entry=false) at drivers/tty/sysrq.c:533
#2  0xc033cb24 in write_sysrq_trigger (file=<optimized out>,
buf=<optimized out>, count=2,
      ppos=<optimized out>) at drivers/tty/sysrq.c:1030
#3  0xc0192654 in proc_reg_write (file=<optimized out>, buf=<optimized
out>, count=<optimized out>,
      ppos=<optimized out>) at fs/proc/inode.c:224
#4  0xc0135dd4 in vfs_write (file=file at entry=0xcfb2e480,
      buf=buf at entry=0x1011b408 <Address 0x1011b408 out of bounds>,
count=count at entry=2,
      pos=pos at entry=0xcf063f18) at fs/read_write.c:446
#5  0xc0136258 in SYSC_write (count=2, buf=0x1011b408 <Address
0x1011b408 out of bounds>, fd=<optimized out>)
      at fs/read_write.c:494
#6  SyS_write (fd=<optimized out>, buf=269595656, count=2) at
fs/read_write.c:487
#7  0xc000ed08 in syscall_dotrace_cont () at
arch/powerpc/kernel/entry_32.S:385
Backtrace stopped: frame did not save the PC
(gdb)

Best regards
Yadviga




-------------- next part --------------
>From f8454324a060b997b652362fdaa2f01a7c548cc0 Mon Sep 17 00:00:00 2001
From: Yadviga Grigoryeva <yadviga at mvista.com>
Date: Fri, 28 Feb 2014 00:49:59 +0400
Subject: [PATCH] separate highmem and lowmem for ppc32

The patch separates highmem and lowmem.
Usually highmem and lowmem merges in common segment.
Virtual  addresses for this segment are invalid because
 code from crashdump-elf.c set virtual address -1 for lowmem 
addresses if they share segment with highmem addresses

               /* HIGMEM has a virtual address of -1 */

                if (elf_info->lowmem_limit
                   && (mend > (elf_info->lowmem_limit - 1)))
                        phdr->p_vaddr = -1;

The patch locates them in different segments.
So lowmem will have the valid  virtual address

Signed-off-by: Yadviga Grigoryeva <yadviga at mvista.com>
---
 kexec/arch/ppc/crashdump-powerpc.c |   28 ++++++++++++++++++++++++++++
 1 files changed, 28 insertions(+), 0 deletions(-)

diff --git a/kexec/arch/ppc/crashdump-powerpc.c b/kexec/arch/ppc/crashdump-powerpc.c
index c06d310..39a12ca 100644
--- a/kexec/arch/ppc/crashdump-powerpc.c
+++ b/kexec/arch/ppc/crashdump-powerpc.c
@@ -214,6 +214,34 @@ static int get_crash_memory_ranges(struct memory_range **range, int *ranges)
 		crash_memory_range[memory_ranges++].end = cend;
 	}
 
+#ifndef CONFIG_PPC64
+	/* separate lowmem and highmem in segment */
+	if (memory_ranges < crash_max_memory_ranges ) {
+		int k,l;
+		for (l=0; l<memory_ranges; l++) {
+			if (crash_memory_range[l].start <
+			    elf_info32.lowmem_limit &&
+			    crash_memory_range[l].end >
+			    elf_info32.lowmem_limit) {
+				/* shift crash_memory_range */
+				for (k=memory_ranges; k>l; k--) {
+					crash_memory_range[k].start
+						= crash_memory_range[k-1].start;
+					crash_memory_range[k].end
+						= crash_memory_range[k-1].end;
+					crash_memory_range[k].type
+						= crash_memory_range[k-1].type;
+				}
+				memory_ranges++;
+				crash_memory_range[l].end
+					= elf_info32.lowmem_limit;
+				crash_memory_range[l+1].start
+					= elf_info32.lowmem_limit;
+			break;
+			}
+		}
+	}
+#endif
 	*range = crash_memory_range;
 	*ranges = memory_ranges;
 
-- 
1.6.3.3.334.gb7e98.dirty



