[PATCH 6/6] ppc64-kdump-purgatory-backup-support.patch
R Sharada
sharada at in.ibm.com
Tue Jan 17 02:17:56 EST 2006
This patch implements the purgatory support to take backup
of the first 32KB of the first kernel
- Modified the v2wrap code to make the secondary cpus spin
directly in the v2wrap after pulling them out of kexec_wait
- Use the elf_rel function support to set the various
symbols used in purgatory
- load device-tree as a separate segment
- other miscellaneous compiler warnings cleanup
- add purgatory code support for backup
- build purgatory as relocatable for ppc64
Signed-off-by: R Sharada <sharada at in.ibm.com>
Signed-off-by: Mohan Kumar M <mohan at in.ibm.com>
---
diff -puN kexec/arch/ppc64/fs2dt.c~ppc64-kdump-purgatory-backup-support kexec/arch/ppc64/fs2dt.c
--- kexec-tools-1.101/kexec/arch/ppc64/fs2dt.c~ppc64-kdump-purgatory-backup-support 2006-01-17 07:23:35.000000000 +0530
+++ kexec-tools-1.101-sharada/kexec/arch/ppc64/fs2dt.c 2006-01-17 07:23:35.000000000 +0530
@@ -374,7 +374,7 @@ void putnode(void)
}
int create_flatten_tree(struct kexec_info *info, unsigned char **bufp,
- unsigned long *sizep, char *cmdline)
+ unsigned long *sizep, char *cmdline)
{
unsigned long len;
unsigned long tlen;
@@ -420,10 +420,10 @@ int create_flatten_tree(struct kexec_inf
reserve(me, bb->totalsize); /* patched later in kexec_load */
- buf = (unsigned char *) realloc(*bufp, *sizep + bb->totalsize);
+ buf = (unsigned char *) malloc(bb->totalsize);
*bufp = buf;
- memcpy(buf+(*sizep), bb, bb->off_mem_rsvmap);
- tlen = *sizep + bb->off_mem_rsvmap;
+ memcpy(buf, bb, bb->off_mem_rsvmap);
+ tlen = bb->off_mem_rsvmap;
memcpy(buf+tlen, mem_rsrv, bb->off_dt_struct - bb->off_mem_rsvmap);
tlen = tlen + (bb->off_dt_struct - bb->off_mem_rsvmap);
memcpy(buf+tlen, dtstruct, bb->off_dt_strings - bb->off_dt_struct);
diff -puN kexec/arch/ppc64/kexec-elf-ppc64.c~ppc64-kdump-purgatory-backup-support kexec/arch/ppc64/kexec-elf-ppc64.c
--- kexec-tools-1.101/kexec/arch/ppc64/kexec-elf-ppc64.c~ppc64-kdump-purgatory-backup-support 2006-01-17 07:23:35.000000000 +0530
+++ kexec-tools-1.101-sharada/kexec/arch/ppc64/kexec-elf-ppc64.c 2006-01-17 07:23:35.000000000 +0530
@@ -4,6 +4,7 @@
* Copyright (C) 2004 Adam Litke (agl at us.ibm.com)
* Copyright (C) 2004 IBM Corp.
* Copyright (C) 2005 R Sharada (sharada at in.ibm.com)
+ * Copyright (C) 2006 Mohan Kumar M (mohan at in.ibm.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
@@ -45,6 +46,7 @@ unsigned long initrd_base, initrd_size;
int create_flatten_tree(struct kexec_info *, unsigned char **, unsigned long *,
char *);
+int my_r2(struct mem_ehdr *ehdr);
int elf_ppc64_probe(const char *buf, off_t len)
{
@@ -83,6 +85,10 @@ int elf_ppc64_load(int argc, char **argv
struct bootblock *bb_ptr;
unsigned int nr_segments, i;
int result, opt;
+ unsigned long my_kernel, my_dt_offset;
+ unsigned int my_panic_kernel;
+ unsigned long my_stack, my_backup_start;
+ unsigned long toc_addr;
#define OPT_APPEND (OPT_ARCH_MAX+0)
#define OPT_RAMDISK (OPT_ARCH_MAX+1)
@@ -167,7 +173,7 @@ int elf_ppc64_load(int argc, char **argv
size = phdr->p_memsz;
hole_addr = (unsigned long)locate_hole(info, size, 0, 0,
- 0xFFFFFFFFFFFFFFFFUL, 1);
+ max_addr, 1);
ehdr.e_phdr[0].p_paddr = hole_addr;
result = elf_exec_load(&ehdr, info);
if (result < 0) {
@@ -175,24 +181,6 @@ int elf_ppc64_load(int argc, char **argv
return result;
}
- /* Add a ram-disk to the current image */
- if (ramdisk) {
- if (devicetreeblob) {
- fprintf(stderr, "Can't use ramdisk with device tree blob input\n");
- return -1;
- }
- unsigned char *ramdisk_buf = NULL;
- off_t ramdisk_size = 0;
- unsigned long long ramdisk_addr;
-
- ramdisk_buf = slurp_file(ramdisk, &ramdisk_size);
- add_buffer(info, ramdisk_buf, ramdisk_size, ramdisk_size, 0, 0,
- 0xFFFFFFFFFFFFFFFFUL, 1);
- ramdisk_addr = (unsigned long long)info->segment[info->nr_segments-1].mem;
- initrd_base = ramdisk_addr;
- initrd_size = ramdisk_size;
- }
-
/* If panic kernel is being loaded, additional segments need
* to be created.
*/
@@ -207,68 +195,136 @@ int elf_ppc64_load(int argc, char **argv
}
/* Add v2wrap to the current image */
- unsigned char *v2wrap_buf = NULL;
- off_t v2wrap_size = 0;
- unsigned long long *rsvmap_ptr;
- struct bootblock *bb_ptr;
- unsigned int devtree_size;
+ seg_buf = NULL;
+ seg_size = 0;
- v2wrap_buf = (char *) malloc(purgatory_size);
- if (v2wrap_buf == NULL) {
+ seg_buf = (char *) malloc(purgatory_size);
+ if (seg_buf == NULL) {
free_elf_info(&ehdr);
return -1;
}
- memcpy(v2wrap_buf, purgatory, purgatory_size);
- v2wrap_size = purgatory_size;
+ memcpy(seg_buf, purgatory, purgatory_size);
+ seg_size = purgatory_size;
+ elf_rel_build_load(info, &info->rhdr, purgatory, purgatory_size,
+ 0, max_addr, 1);
+
+ /* Add a ram-disk to the current image
+ * Note: Add the ramdisk after elf_rel_build_load
+ */
+ if (ramdisk) {
+ if (devicetreeblob) {
+ fprintf(stderr,
+ "Can't use ramdisk with device tree blob input\n");
+ return -1;
+ }
+ seg_buf = slurp_file(ramdisk, &seg_size);
+ add_buffer(info, seg_buf, seg_size, seg_size, 0, 0, max_addr, 1);
+ hole_addr = (unsigned long long)
+ info->segment[info->nr_segments-1].mem;
+ initrd_base = hole_addr;
+ initrd_size = (unsigned long long)
+ info->segment[info->nr_segments-1].memsz;
+ } /* ramdisk */
+
if (devicetreeblob) {
- unsigned char *blob_buf = NULL;
- off_t blob_size = 0;
- unsigned char *tmp_buf = NULL;
-
- /* Grab device tree from buffer */
- blob_buf = slurp_file(devicetreeblob, &blob_size);
-
- /* Append to purgatory */
- tmp_buf = (unsigned char *) realloc(v2wrap_buf, v2wrap_size + blob_size);
- v2wrap_buf = tmp_buf;
- memcpy(v2wrap_buf+v2wrap_size, blob_buf, blob_size);
- v2wrap_size += blob_size;
+ unsigned char *blob_buf = NULL;
+ off_t blob_size = 0;
+
+ /* Grab device tree from buffer */
+ blob_buf = slurp_file(devicetreeblob, &blob_size);
+ add_buffer(info, blob_buf, blob_size, blob_size, 0, 0,
+ max_addr, -1);
} else {
- /* create from fs2dt */
- create_flatten_tree(info, &v2wrap_buf, &v2wrap_size);
+ /* create from fs2dt */
+ seg_buf = NULL;
+ seg_size = 0;
+ create_flatten_tree(info, &seg_buf, &seg_size, cmdline);
+ add_buffer(info, seg_buf, seg_size, seg_size,
+ 0, 0, max_addr, -1);
}
- add_buffer(info, v2wrap_buf, v2wrap_size, v2wrap_size, 0, 0,
- 0xFFFFFFFFFFFFFFFFUL, -1);
/* patch reserve map address for flattened device-tree
- find last entry (both 0) in the reserve mem list. Assume DT
- entry is before this one */
+ * find last entry (both 0) in the reserve mem list. Assume DT
+ * entry is before this one
+ */
bb_ptr = (struct bootblock *)(
- (unsigned char *)info->segment[(info->nr_segments)-1].buf +
- 0x100);
+ (unsigned char *)info->segment[(info->nr_segments)-1].buf);
rsvmap_ptr = (long long *)(
(unsigned char *)info->segment[(info->nr_segments)-1].buf +
- bb_ptr->off_mem_rsvmap + 0x100);
- while (*rsvmap_ptr || *(rsvmap_ptr+1)){
+ bb_ptr->off_mem_rsvmap);
+ while (*rsvmap_ptr || *(rsvmap_ptr+1))
rsvmap_ptr += 2;
- }
rsvmap_ptr -= 2;
*rsvmap_ptr = (unsigned long long)(
- info->segment[(info->nr_segments)-1].mem + 0x100);
- rsvmap_ptr++;
- *rsvmap_ptr = (unsigned long long)bb_ptr->totalsize;
+ info->segment[(info->nr_segments)-1].mem);
+ rsvmap_ptr++;
+ *rsvmap_ptr = (unsigned long long)bb_ptr->totalsize;
- unsigned int nr_segments;
nr_segments = info->nr_segments;
- lp = info->segment[nr_segments-1].buf + 0x100;
- lp--;
- *lp = info->segment[0].mem;
- info->entry = info->segment[nr_segments-1].mem;
- unsigned int i;
+ /* Set kernel */
+ my_kernel = (unsigned long )info->segment[0].mem;
+ elf_rel_set_symbol(&info->rhdr, "kernel", &my_kernel, sizeof(my_kernel));
+
+ /* Set dt_offset */
+ my_dt_offset = (unsigned long )info->segment[nr_segments-1].mem;
+ elf_rel_set_symbol(&info->rhdr, "dt_offset", &my_dt_offset,
+ sizeof(my_dt_offset));
+
+ if (info->kexec_flags & KEXEC_ON_CRASH) {
+ my_panic_kernel = 1;
+ /* Set panic flag */
+ elf_rel_set_symbol(&info->rhdr, "panic_kernel",
+ &my_panic_kernel, sizeof(my_panic_kernel));
+
+ /* Set backup address */
+ my_backup_start = info->backup_start;
+ elf_rel_set_symbol(&info->rhdr, "backup_start",
+ &my_backup_start, sizeof(my_backup_start));
+ }
+
+ /* Set stack address */
+ my_stack = locate_hole(info, 16*1024, 0, 0, max_addr, 1);
+ my_stack += 16*1024;
+ elf_rel_set_symbol(&info->rhdr, "stack", &my_stack, sizeof(my_stack));
+
+ /* Set toc */
+ toc_addr = (unsigned long) my_r2(&info->rhdr);
+ elf_rel_set_symbol(&info->rhdr, "my_toc", &toc_addr, sizeof(toc_addr));
+
+#ifdef DEBUG
+ my_kernel = 0;
+ my_dt_offset = 0;
+ my_panic_kernel = 0;
+ my_backup_start = 0;
+ my_stack = 0;
+ toc_addr = 0;
+
+ elf_rel_get_symbol(&info->rhdr, "kernel", &my_kernel, sizeof(my_kernel));
+ elf_rel_get_symbol(&info->rhdr, "dt_offset", &my_dt_offset,
+ sizeof(my_dt_offset));
+ elf_rel_get_symbol(&info->rhdr, "panic_kernel", &my_panic_kernel,
+ sizeof(my_panic_kernel));
+ elf_rel_get_symbol(&info->rhdr, "backup_start", &my_backup_start,
+ sizeof(my_backup_start));
+ elf_rel_get_symbol(&info->rhdr, "stack", &my_stack, sizeof(my_stack));
+ elf_rel_get_symbol(&info->rhdr, "my_toc", &toc_addr,
+ sizeof(toc_addr));
+
+ fprintf(stderr, "info->entry is %p\n", info->entry);
+ fprintf(stderr, "kernel is %Lx\n", my_kernel);
+ fprintf(stderr, "dt_offset is %Lx\n", my_dt_offset);
+ fprintf(stderr, "panic_kernel is %x\n", my_panic_kernel);
+ fprintf(stderr, "backup_start is %Lx\n", my_backup_start);
+ fprintf(stderr, "stack is %Lx\n", my_stack);
+ fprintf(stderr, "toc_addr is %Lx\n", toc_addr);
+ fprintf(stderr, "purgatory size is %d\n", purgatory_size);
+#endif
+
for (i = 0; i < nr_segments; i++)
- printf("segment[i].mem:%lx\n", info->segment[i].mem);
+ fprintf(stderr, "segment[%d].mem:%p memsz:%ld\n", i,
+ info->segment[i].mem, info->segment[i].memsz);
return 0;
}
diff -puN kexec/arch/ppc64/kexec-elf-rel-ppc64.c~ppc64-kdump-purgatory-backup-support kexec/arch/ppc64/kexec-elf-rel-ppc64.c
--- kexec-tools-1.101/kexec/arch/ppc64/kexec-elf-rel-ppc64.c~ppc64-kdump-purgatory-backup-support 2006-01-17 07:23:35.000000000 +0530
+++ kexec-tools-1.101-sharada/kexec/arch/ppc64/kexec-elf-rel-ppc64.c 2006-01-17 07:35:50.000000000 +0530
@@ -1,5 +1,6 @@
#include <stdio.h>
#include <elf.h>
+#include <string.h>
#include "../../kexec.h"
#include "../../kexec-elf.h"
@@ -21,20 +22,19 @@ static struct mem_shdr *toc_section(cons
{
struct mem_shdr *shdr, *shdr_end;
unsigned char *strtab;
- strtab = ehdr->e_shdr[ehdr->e_shstrndx].sh_data;
+ strtab = (unsigned char *)ehdr->e_shdr[ehdr->e_shstrndx].sh_data;
shdr_end = &ehdr->e_shdr[ehdr->e_shnum];
- for(shdr = ehdr->e_shdr; shdr != shdr_end; shdr++) {
- if (strcmp(shdr->sh_name, ".toc") == 0) {
+ for(shdr = ehdr->e_shdr; shdr != shdr_end; shdr++)
+ if ( shdr->sh_size &&
+ strcmp(&strtab[shdr->sh_name], ".toc") == 0)
return shdr;
- }
- }
return NULL;
}
/* r2 is the TOC pointer: it actually points 0x8000 into the TOC (this
gives the value maximum span in an instruction which uses a signed
offset) */
-static unsigned long my_r2(const struct mem_ehdr *ehdr)
+unsigned long my_r2(const struct mem_ehdr *ehdr)
{
struct mem_shdr *shdr;
shdr = toc_section(ehdr);
@@ -53,7 +53,7 @@ void machine_apply_elf_rel(struct mem_eh
/* Simply set it */
*(uint32_t *)location = value;
break;
-
+
case R_PPC64_ADDR64:
/* Simply set it */
*(uint64_t *)location = value;
@@ -78,15 +78,34 @@ void machine_apply_elf_rel(struct mem_eh
/* Convert value to relative */
value -= address;
if (value + 0x2000000 > 0x3ffffff || (value & 3) != 0){
- die("REL24 %li out of range!\n",
+ die("REL24 %li out of range!\n",
(long int)value);
}
/* Only replace bits 2 through 26 */
- *(uint32_t *)location
- = (*(uint32_t *)location & ~0x03fffffc)
- | (value & 0x03fffffc);
+ *(uint32_t *)location = (*(uint32_t *)location & ~0x03fffffc)
+ | (value & 0x03fffffc);
+ break;
+
+ case R_PPC64_ADDR16_LO:
+ *(uint16_t *)location = value & 0xffff;
+ break;
+
+ case R_PPC64_ADDR16_HI:
+ *(uint16_t *)location = (value>>16) & 0xffff;
break;
+
+ case R_PPC64_ADDR16_HA:
+ *(uint16_t *)location = ((value>>16) & 0xffff);
+ break;
+
+ case R_PPC64_ADDR16_HIGHEST:
+ *(uint16_t *)location = ((value>>48) & 0xffff);
+ break;
+ case R_PPC64_ADDR16_HIGHER:
+ *(uint16_t *)location = ((value>>32) & 0xffff);
+ break;
+
default:
die("Unknown rela relocation: %lu\n", r_type);
break;
diff -puN kexec/arch/ppc64/kexec-zImage-ppc64.c~ppc64-kdump-purgatory-backup-support kexec/arch/ppc64/kexec-zImage-ppc64.c
--- kexec-tools-1.101/kexec/arch/ppc64/kexec-zImage-ppc64.c~ppc64-kdump-purgatory-backup-support 2006-01-17 07:23:35.000000000 +0530
+++ kexec-tools-1.101-sharada/kexec/arch/ppc64/kexec-zImage-ppc64.c 2006-01-17 07:23:35.000000000 +0530
@@ -153,7 +153,8 @@ int zImage_ppc64_load(FILE *file, int ar
return -1;
}
mem_offset = p->p_vaddr - load_loc;
- if (fread(segment->buf+mem_offset, p->p_filesz, 1, file) != 1) {
+ if (fread((void *)segment->buf+mem_offset, p->p_filesz, 1,
+ file) != 1) {
perror("read error: ");
return -1;
}
diff -puN purgatory/Makefile~ppc64-kdump-purgatory-backup-support purgatory/Makefile
--- kexec-tools-1.101/purgatory/Makefile~ppc64-kdump-purgatory-backup-support 2006-01-17 07:23:35.000000000 +0530
+++ kexec-tools-1.101-sharada/purgatory/Makefile 2006-01-17 07:23:35.000000000 +0530
@@ -21,13 +21,11 @@ PCFLAGS += $(call cc-option, -fnobuiltin
PCFLAGS += $(call cc-option, -fnostdinc)
PCFLAGS += $(call cc-option, -fno-zero-initialized-in-bss)
-PURGATORY_C_SRCS:=
-ifneq ($(ARCH),ppc64)
+PURGATORY_C_SRCS:=
PURGATORY_C_SRCS += purgatory/purgatory.c
PURGATORY_C_SRCS += purgatory/printf.c
PURGATORY_C_SRCS += purgatory/string.c
-endif
-PURGATORY_S_OBJS:=
+PURGATORY_S_OBJS:=
include purgatory/arch/$(ARCH)/Makefile
@@ -61,12 +59,7 @@ $(PURGATORY_S_OBJS): $(OBJDIR)/%.o: %.S
$(PURGATORY): $(PURGATORY_OBJS) $(UTIL_LIB)
$(MKDIR) -p $(@D)
-ifneq ($(ARCH),ppc64)
$(LD) $(LDFLAGS) --no-undefined -e purgatory_start -r -o $@ $(PURGATORY_OBJS) $(UTIL_LIB)
-else
- $(LD) -Ttext=0 -e 0 -o $(OBJDIR)/purgatory/v2wrap.elf $(PURGATORY_OBJS)
- objcopy -O binary $(OBJDIR)/purgatory/v2wrap.elf $@
-endif
echo::
@echo "PURGATORY_C_SRCS $(PURGATORY_C_SRCS)"
diff -puN purgatory/arch/ppc64/Makefile~ppc64-kdump-purgatory-backup-support purgatory/arch/ppc64/Makefile
--- kexec-tools-1.101/purgatory/arch/ppc64/Makefile~ppc64-kdump-purgatory-backup-support 2006-01-17 07:23:35.000000000 +0530
+++ kexec-tools-1.101-sharada/purgatory/arch/ppc64/Makefile 2006-01-17 07:23:35.000000000 +0530
@@ -2,6 +2,7 @@
# Purgatory ppc
#
-PURGATORY_C_SRCS+=
PURGATORY_S_SRCS+= purgatory/arch/ppc64/v2wrap.S
-
+PURGATORY_C_SRCS += purgatory/arch/ppc64/purgatory-ppc64.c
+PURGATORY_C_SRCS += purgatory/arch/ppc64/console-ppc64.c
+PURGATORY_C_SRCS += purgatory/arch/ppc64/crashdump_backup.c
diff -puN /dev/null purgatory/arch/ppc64/console-ppc64.c
--- /dev/null 2004-07-01 07:56:11.000000000 +0530
+++ kexec-tools-1.101-sharada/purgatory/arch/ppc64/console-ppc64.c 2006-01-17 07:23:35.000000000 +0530
@@ -0,0 +1,27 @@
+/*
+ * kexec: Linux boots Linux
+ *
+ * Created by: Mohan Kumar M (mohan at in.ibm.com)
+ *
+ * Copyright (C) IBM Corporation, 2005. All rights reserved
+ *
+ * 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.
+ */
+
+#include <purgatory.h>
+
+void putchar(int c)
+{
+ return;
+}
diff -puN /dev/null purgatory/arch/ppc64/purgatory-ppc64.c
--- /dev/null 2004-07-01 07:56:11.000000000 +0530
+++ kexec-tools-1.101-sharada/purgatory/arch/ppc64/purgatory-ppc64.c 2006-01-17 07:23:35.000000000 +0530
@@ -0,0 +1,41 @@
+/*
+ * kexec: Linux boots Linux
+ *
+ * Created by: Mohan Kumar M (mohan at in.ibm.com)
+ *
+ * Copyright (C) IBM Corporation, 2005. All rights reserved
+ *
+ * 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.
+ */
+
+#include <purgatory.h>
+#include "purgatory-ppc64.h"
+
+unsigned int panic_kernel = 0;
+unsigned long backup_start = 0;
+unsigned long stack = 0;
+unsigned long dt_offset = 0;
+unsigned long my_toc = 0;
+unsigned long kernel = 0;
+
+void setup_arch(void)
+{
+ return;
+}
+
+void post_verification_setup_arch(void)
+{
+ if (panic_kernel)
+ crashdump_backup_memory();
+}
diff -puN /dev/null purgatory/arch/ppc64/purgatory-ppc64.h
--- /dev/null 2004-07-01 07:56:11.000000000 +0530
+++ kexec-tools-1.101-sharada/purgatory/arch/ppc64/purgatory-ppc64.h 2006-01-17 07:23:35.000000000 +0530
@@ -0,0 +1,6 @@
+#ifndef PURGATORY_PPC64_H
+#define PURGATORY_PPC64_H
+
+void crashdump_backup_memory(void);
+
+#endif /* PURGATORY_PPC64_H */
diff -puN purgatory/arch/ppc64/v2wrap.S~ppc64-kdump-purgatory-backup-support purgatory/arch/ppc64/v2wrap.S
--- kexec-tools-1.101/purgatory/arch/ppc64/v2wrap.S~ppc64-kdump-purgatory-backup-support 2006-01-17 07:23:35.000000000 +0530
+++ kexec-tools-1.101-sharada/purgatory/arch/ppc64/v2wrap.S 2006-01-17 07:23:35.000000000 +0530
@@ -2,6 +2,7 @@
# kexec: Linux boots Linux
#
# Copyright (C) 2004 - 2005, Milton D Miller II, IBM Corporation
+# Copyright (C) 2006, Mohan Kumar M (mohan at in.ibm.com), IBM Corporation
#
# 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
@@ -18,14 +19,17 @@
#
# v2wrap.S
-# a wrapper to place in front of a v2 device tree
-# to call a ppc64 kernel with the expected arguments
+# a wrapper to call purgatory code to backup first
+# 32kB of first kernel into the backup region
+# reserved by kexec-tools.
+# Invokes ppc64 kernel with the expected arguments
# of kernel(device-tree, phys-offset, 0)
+
#
# calling convention:
# r3 = physical number of this cpu (all cpus)
# r4 = address of this chunk (master only)
-# master enters at start (aka first byte of this chunk)
+# master enters at purgatory_start (aka first byte of this chunk)
# slaves (additional cpus), if any, enter a copy of the
# first 0x100 bytes of this code relocated to 0x0
#
@@ -34,50 +38,50 @@
# and the slaves are sent to address 0x60
# with r3 = their physical cpu number.
+#define LOADADDR(rn,name) \
+ lis rn,name##@highest; \
+ ori rn,rn,name##@higher; \
+ rldicr rn,rn,32,31; \
+ oris rn,rn,name##@h; \
+ ori rn,rn,name##@l
# look a bit like a Linux kernel here ...
.machine ppc64
- .org 0
-start: b master
+ .globl purgatory_start
+purgatory_start: b master
tweq 0,0
-secondary_hold:
- .llong 0
-
- .org 0x20 # need a bit more space than after slave,
master:
- std 4,secondary_hold at l(0) # bring slaves up here to this copy
- sync # try to get the slaves to see this
or 1,1,1 # low priority to let other thread catchup
isync
- mr 5,3 # save cpu id to r5
- addi 3,4,0x100 # r3 = boot param block
- lwz 6,20(3) # fetch version number
- cmpwi 0,6,2 # v2 ?
- blt 80f
- stw 5,28(3) # save my cpu number as boot_cpu_phys
-80: b 81f
-
- .org 0x60 # ABI: slaves start at 60 with r3=phys
-slave: ld 4,secondary_hold at l(0);
- cmpdi 0,4,0
- beq slave
-
- # ahh, master told us where he is running from
- # jump into our copy of the code up there so this code can change
- addi 5,4,1f-start
- mtctr 5
- bctr
+ mr 17,3 # save cpu id to r17
+ mr 15,4 # save physical address in reg15
- # ok, now wait for the master to tell is to go back to the new block
-1: ld 5,copied at l(4)
- cmpdi 0,5,0
- beq 1b
- ba 0x60
+ LOADADDR(6,my_toc)
+ ld 2,0(6) #setup toc
+ LOADADDR(6,stack)
+ ld 1,0(6) #setup stack
+ subi 1,1,112
+ bl .purgatory
+ nop
+
+ b 81f
+ .org purgatory_start + 0x60 # ABI: slaves start at 60 with r3=phys
+slave:
+ # load slave spin code address and branch into that
+ LOADADDR(6,slave_spin)
+ ld 4,0(6)
+ mtctr 4
+ bctr
- .long 0 # just an eye-catcher, delete if space needed
- .long 0 # just an eye-catcher, delete if space needed
+spin: .long 1
+slave_spin_code:
+ lis 5,spin at ha
+ lwz 5,spin at l(5)
+ cmpwi 0,5,0
+ bne slave_spin_code
+ ba 0x60
81: # master continues here
or 3,3,3 # ok back to high, lets boot
@@ -85,7 +89,17 @@ slave: ld 4,secondary_hold at l(0);
mtctr 6 # delay a bit for slaves to catch up
83: bdnz 83b # before we overwrite 0-100 again
- ld 4,-8(3) # kernel pointer is at -8(bb) by loader
+ LOADADDR(16, dt_offset)
+ ld 3,0(16) # load device-tree address
+ mr 16,3 # save dt address in reg16
+ lwz 6,20(3) # fetch version number
+ cmpwi 0,6,2 # v2 ?
+ blt 80f
+ stw 17,28(3) # save my cpu number as boot_cpu_phys
+80:
+ LOADADDR(6,kernel)
+ ld 4,0(6) # load the kernel address
+
addi 5,4,-8 # prepare copy with update form instructions
li 6,0x100/8
mtctr 6
@@ -103,12 +117,12 @@ slave: ld 4,secondary_hold at l(0);
icbi 0,6
sync
isync
- std 6,-16(3) # send slaves back down
+ lis 6,spin at ha
+ li 0,0
+ stw 0,spin at l(6)
+ mr 3,16 # restore dt address
+
bctr # start kernel
- .org 0xf0
-copied: .llong 0
-kernel: .llong 0
- .org 0x100
-__end_stub:
- .equ boot_block, . - start
+slave_spin: .llong slave_spin_code
+
diff -puN kexec/kexec-elf.c~ppc64-kdump-purgatory-backup-support kexec/kexec-elf.c
--- kexec-tools-1.101/kexec/kexec-elf.c~ppc64-kdump-purgatory-backup-support 2006-01-17 07:23:35.000000000 +0530
+++ kexec-tools-1.101-sharada/kexec/kexec-elf.c 2006-01-17 07:29:17.000000000 +0530
@@ -113,21 +113,21 @@ static int build_mem_elf32_ehdr(const ch
}
return -1;
}
- if (elf32_to_cpu(ehdr, lehdr.e_entry) > ULONG_MAX) {
+ if (elf32_to_cpu(ehdr, lehdr.e_entry) > UINT32_MAX) {
/* entry is to large */
if (probe_debug) {
fprintf(stderr, "ELF e_entry to large\n");
}
return -1;
}
- if (elf32_to_cpu(ehdr, lehdr.e_phoff) > ULONG_MAX) {
+ if (elf32_to_cpu(ehdr, lehdr.e_phoff) > UINT32_MAX) {
/* phoff is to large */
if (probe_debug) {
fprintf(stderr, "ELF e_phoff to large\n");
}
return -1;
}
- if (elf32_to_cpu(ehdr, lehdr.e_shoff) > ULONG_MAX) {
+ if (elf32_to_cpu(ehdr, lehdr.e_shoff) > UINT32_MAX) {
/* shoff is to large */
if (probe_debug) {
fprintf(stderr, "ELF e_shoff to large\n");
@@ -146,7 +146,7 @@ static int build_mem_elf32_ehdr(const ch
ehdr->e_shstrndx = elf16_to_cpu(ehdr, lehdr.e_shstrndx);
if ((ehdr->e_phnum > 0) &&
- (elf16_to_cpu(ehdr, lehdr.e_phentsize) != sizeof(Elf32_Phdr)))
+ (elf16_to_cpu(ehdr, lehdr.e_phentsize) != sizeof(Elf32_Phdr)))
{
/* Invalid program header size */
if (probe_debug) {
@@ -185,21 +185,21 @@ static int build_mem_elf64_ehdr(const ch
}
return -1;
}
- if (elf32_to_cpu(ehdr, lehdr.e_entry) > ULONG_MAX) {
+ if (elf32_to_cpu(ehdr, lehdr.e_entry) > UINT32_MAX) {
/* entry is to large */
if (probe_debug) {
fprintf(stderr, "ELF e_entry to large\n");
}
return -1;
}
- if (elf32_to_cpu(ehdr, lehdr.e_phoff) > ULONG_MAX) {
+ if (elf32_to_cpu(ehdr, lehdr.e_phoff) > UINT32_MAX) {
/* phoff is to large */
if (probe_debug) {
fprintf(stderr, "ELF e_phoff to large\n");
}
return -1;
}
- if (elf32_to_cpu(ehdr, lehdr.e_shoff) > ULONG_MAX) {
+ if (elf32_to_cpu(ehdr, lehdr.e_shoff) > UINT32_MAX) {
/* shoff is to large */
if (probe_debug) {
fprintf(stderr, "ELF e_shoff to large\n");
@@ -218,7 +218,7 @@ static int build_mem_elf64_ehdr(const ch
ehdr->e_shstrndx = elf16_to_cpu(ehdr, lehdr.e_shstrndx);
if ((ehdr->e_phnum > 0) &&
- (elf16_to_cpu(ehdr, lehdr.e_phentsize) != sizeof(Elf64_Phdr)))
+ (elf16_to_cpu(ehdr, lehdr.e_phentsize) != sizeof(Elf64_Phdr)))
{
/* Invalid program header size */
if (probe_debug) {
@@ -302,7 +302,7 @@ static int build_mem_ehdr(const char *bu
return 0;
}
-static int build_mem_elf32_phdr(const char *buf, off_t len,
+static int build_mem_elf32_phdr(const char *buf, off_t len,
struct mem_ehdr *ehdr, int idx)
{
struct mem_phdr *phdr;
@@ -312,12 +312,12 @@ static int build_mem_elf32_phdr(const ch
phdr = &ehdr->e_phdr[idx];
memcpy(&lphdr, pbuf, sizeof(lphdr));
- if ( (elf32_to_cpu(ehdr, lphdr.p_filesz) > ULONG_MAX) ||
- (elf32_to_cpu(ehdr, lphdr.p_memsz) > ULONG_MAX) ||
- (elf32_to_cpu(ehdr, lphdr.p_offset) > ULONG_MAX) ||
- (elf32_to_cpu(ehdr, lphdr.p_paddr) > ULONG_MAX) ||
- (elf32_to_cpu(ehdr, lphdr.p_vaddr) > ULONG_MAX) ||
- (elf32_to_cpu(ehdr, lphdr.p_align) > ULONG_MAX))
+ if ( (elf32_to_cpu(ehdr, lphdr.p_filesz) > UINT32_MAX) ||
+ (elf32_to_cpu(ehdr, lphdr.p_memsz) > UINT32_MAX) ||
+ (elf32_to_cpu(ehdr, lphdr.p_offset) > UINT32_MAX) ||
+ (elf32_to_cpu(ehdr, lphdr.p_paddr) > UINT32_MAX) ||
+ (elf32_to_cpu(ehdr, lphdr.p_vaddr) > UINT32_MAX) ||
+ (elf32_to_cpu(ehdr, lphdr.p_align) > UINT32_MAX))
{
fprintf(stderr, "Program segment size out of range\n");
return -1;
@@ -345,12 +345,12 @@ static int build_mem_elf64_phdr(const ch
phdr = &ehdr->e_phdr[idx];
memcpy(&lphdr, pbuf, sizeof(lphdr));
- if ( (elf64_to_cpu(ehdr, lphdr.p_filesz) > ULONG_MAX) ||
- (elf64_to_cpu(ehdr, lphdr.p_memsz) > ULONG_MAX) ||
- (elf64_to_cpu(ehdr, lphdr.p_offset) > ULONG_MAX) ||
- (elf64_to_cpu(ehdr, lphdr.p_paddr) > ULONG_MAX) ||
- (elf64_to_cpu(ehdr, lphdr.p_vaddr) > ULONG_MAX) ||
- (elf64_to_cpu(ehdr, lphdr.p_align) > ULONG_MAX))
+ if ( (elf64_to_cpu(ehdr, lphdr.p_filesz) > UINT64_MAX) ||
+ (elf64_to_cpu(ehdr, lphdr.p_memsz) > UINT64_MAX) ||
+ (elf64_to_cpu(ehdr, lphdr.p_offset) > UINT64_MAX) ||
+ (elf64_to_cpu(ehdr, lphdr.p_paddr) > UINT64_MAX) ||
+ (elf64_to_cpu(ehdr, lphdr.p_vaddr) > UINT64_MAX) ||
+ (elf64_to_cpu(ehdr, lphdr.p_align) > UINT64_MAX))
{
fprintf(stderr, "Program segment size out of range\n");
return -1;
@@ -388,7 +388,7 @@ static int build_mem_phdrs(const char *b
fprintf(stderr, "Invalid ei_class?\n");
return -1;
}
- phdr_size *= ehdr->e_phnum;
+ phdr_size *= ehdr->e_phnum;
if (ehdr->e_phoff + phdr_size > len) {
/* The program header did not fit in the file buffer */
if (probe_debug) {
@@ -396,7 +396,7 @@ static int build_mem_phdrs(const char *b
}
return -1;
}
-
+
/* Allocate the e_phdr array */
mem_phdr_size = sizeof(ehdr->e_phdr[0]) * ehdr->e_phnum;
ehdr->e_phdr = xmalloc(mem_phdr_size);
@@ -440,7 +440,7 @@ static int build_mem_phdrs(const char *b
return 0;
}
-static int build_mem_elf32_shdr(const char *buf, off_t len,
+static int build_mem_elf32_shdr(const char *buf, off_t len,
struct mem_ehdr *ehdr, int idx)
{
struct mem_shdr *shdr;
@@ -451,12 +451,12 @@ static int build_mem_elf32_shdr(const ch
shdr = &ehdr->e_shdr[idx];
memcpy(&lshdr, sbuf, sizeof(lshdr));
- if ( (elf32_to_cpu(ehdr, lshdr.sh_flags) > ULONG_MAX) ||
- (elf32_to_cpu(ehdr, lshdr.sh_addr) > ULONG_MAX) ||
- (elf32_to_cpu(ehdr, lshdr.sh_offset) > ULONG_MAX) ||
- (elf32_to_cpu(ehdr, lshdr.sh_size) > ULONG_MAX) ||
- (elf32_to_cpu(ehdr, lshdr.sh_addralign) > ULONG_MAX) ||
- (elf32_to_cpu(ehdr, lshdr.sh_entsize) > ULONG_MAX))
+ if ( (elf32_to_cpu(ehdr, lshdr.sh_flags) > UINT32_MAX) ||
+ (elf32_to_cpu(ehdr, lshdr.sh_addr) > UINT32_MAX) ||
+ (elf32_to_cpu(ehdr, lshdr.sh_offset) > UINT32_MAX) ||
+ (elf32_to_cpu(ehdr, lshdr.sh_size) > UINT32_MAX) ||
+ (elf32_to_cpu(ehdr, lshdr.sh_addralign) > UINT32_MAX) ||
+ (elf32_to_cpu(ehdr, lshdr.sh_entsize) > UINT32_MAX))
{
fprintf(stderr, "Program section size out of range\n");
return -1;
@@ -510,7 +510,7 @@ static int build_mem_elf32_shdr(const ch
return 0;
}
-static int build_mem_elf64_shdr(const char *buf, off_t len,
+static int build_mem_elf64_shdr(const char *buf, off_t len,
struct mem_ehdr *ehdr, int idx)
{
struct mem_shdr *shdr;
@@ -521,12 +521,12 @@ static int build_mem_elf64_shdr(const ch
shdr = &ehdr->e_shdr[idx];
memcpy(&lshdr, sbuf, sizeof(lshdr));
- if ( (elf64_to_cpu(ehdr, lshdr.sh_flags) > ULONG_MAX) ||
- (elf64_to_cpu(ehdr, lshdr.sh_addr) > ULONG_MAX) ||
- (elf64_to_cpu(ehdr, lshdr.sh_offset) > ULONG_MAX) ||
- (elf64_to_cpu(ehdr, lshdr.sh_size) > ULONG_MAX) ||
- (elf64_to_cpu(ehdr, lshdr.sh_addralign) > ULONG_MAX) ||
- (elf64_to_cpu(ehdr, lshdr.sh_entsize) > ULONG_MAX))
+ if ( (elf64_to_cpu(ehdr, lshdr.sh_flags) > UINT64_MAX) ||
+ (elf64_to_cpu(ehdr, lshdr.sh_addr) > UINT64_MAX) ||
+ (elf64_to_cpu(ehdr, lshdr.sh_offset) > UINT64_MAX) ||
+ (elf64_to_cpu(ehdr, lshdr.sh_size) > UINT64_MAX) ||
+ (elf64_to_cpu(ehdr, lshdr.sh_addralign) > UINT64_MAX) ||
+ (elf64_to_cpu(ehdr, lshdr.sh_entsize) > UINT64_MAX))
{
fprintf(stderr, "Program section size out of range\n");
return -1;
@@ -608,7 +608,7 @@ static int build_mem_shdrs(const char *b
}
return -1;
}
-
+
/* Allocate the e_shdr array */
mem_shdr_size = sizeof(ehdr->e_shdr[0]) * ehdr->e_shnum;
ehdr->e_shdr = xmalloc(mem_shdr_size);
@@ -635,7 +635,7 @@ static int build_mem_shdrs(const char *b
{
/* The section does not fit in the buffer */
if (probe_debug) {
- fprintf(stderr, "ELF section %d not in file\n",
+ fprintf(stderr, "ELF section %d not in file\n",
i);
}
return -1;
@@ -653,14 +653,14 @@ static int build_mem_shdrs(const char *b
return 0;
}
-static void read_nhdr(const struct mem_ehdr *ehdr,
+static void read_nhdr(const struct mem_ehdr *ehdr,
ElfNN_Nhdr *hdr, const unsigned char *note)
{
memcpy(hdr, note, sizeof(*hdr));
hdr->n_namesz = elf32_to_cpu(ehdr, hdr->n_namesz);
hdr->n_descsz = elf32_to_cpu(ehdr, hdr->n_descsz);
hdr->n_type = elf32_to_cpu(ehdr, hdr->n_type);
-
+
}
static int build_mem_notes(const char *buf, off_t len, struct mem_ehdr *ehdr)
{
@@ -686,7 +686,7 @@ static int build_mem_notes(const char *b
if (!note_start) {
return 0;
}
-
+
/* Walk through and count the notes */
ehdr->e_notenum = 0;
for(note = note_start; note < note_end; note+= note_size) {
@@ -708,7 +708,7 @@ static int build_mem_notes(const char *b
note_size += (hdr.n_namesz + 3) & ~3;
desc = note + note_size;
note_size += (hdr.n_descsz + 3) & ~3;
-
+
if ((hdr.n_namesz != 0) && (name[hdr.n_namesz -1] != '\0')) {
die("Note name is not null termiated");
}
@@ -716,7 +716,7 @@ static int build_mem_notes(const char *b
ehdr->e_note[i].n_name = name;
ehdr->e_note[i].n_desc = desc;
ehdr->e_note[i].n_descsz = hdr.n_descsz;
-
+
}
return 0;
}
diff -puN kexec/kexec-elf-rel.c~ppc64-kdump-purgatory-backup-support kexec/kexec-elf-rel.c
--- kexec-tools-1.101/kexec/kexec-elf-rel.c~ppc64-kdump-purgatory-backup-support 2006-01-17 07:23:35.000000000 +0530
+++ kexec-tools-1.101-sharada/kexec/kexec-elf-rel.c 2006-01-17 07:23:35.000000000 +0530
@@ -155,7 +155,7 @@ int build_elf_rel_info(const char *buf,
if (probe_debug) {
fprintf(stderr, "No ELF section headers\n");
}
- return -1;
+ return -1;
}
if (!machine_verify_elf_rel(ehdr)) {
/* It does not meant the native architecture constraints */
@@ -251,7 +251,7 @@ int elf_rel_load(struct mem_ehdr *ehdr,
/* Allocate where we will put the relocated object */
buf = xmalloc(bufsz);
- buf_addr = add_buffer(info, buf, bufsz, bufsz + bss_pad + bsssz,
+ buf_addr = add_buffer(info, buf, bufsz, bufsz + bss_pad + bsssz,
buf_align, min, max, end);
ehdr->rel_addr = buf_addr;
ehdr->rel_size = bufsz + bss_pad + bsssz;
@@ -269,7 +269,7 @@ int elf_rel_load(struct mem_ehdr *ehdr,
unsigned long off;
/* Adjust the address */
data_addr = (data_addr + (align - 1)) & ~(align -1);
-
+
/* Update the section */
off = data_addr - buf_addr;
memcpy(buf + off, shdr->sh_data, shdr->sh_size);
@@ -306,7 +306,7 @@ int elf_rel_load(struct mem_ehdr *ehdr,
continue;
}
if ((shdr->sh_info > ehdr->e_shnum) ||
- (shdr->sh_link > ehdr->e_shnum))
+ (shdr->sh_link > ehdr->e_shnum))
{
die("Invalid section number\n");
}
@@ -350,12 +350,12 @@ int elf_rel_load(struct mem_ehdr *ehdr,
/* The final address of that location */
address = section->sh_addr + rel.r_offset;
-
+
/* The relevant symbol */
sym = elf_sym(ehdr, symtab->sh_data + (rel.r_sym * elf_sym_size(ehdr)));
-#if 0
+#ifdef DEBUG
fprintf(stderr, "sym: %10s info: %02x other: %02x shndx: %lx value: %lx size: %lx\n",
- strtab + sym.st_name,
+ strtab + sym.st_name,
sym.st_info,
sym.st_other,
sym.st_shndx,
@@ -364,8 +364,18 @@ int elf_rel_load(struct mem_ehdr *ehdr,
#endif
if (sym.st_shndx == STN_UNDEF) {
- die("Undefined symbol: %s\n",
+ /*
+ * NOTE: ppc64 elf .ro shows up a UNDEF section.
+ * From Elf 1.2 Spec:
+ * 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?
+ */
+ /*
+ die("Undefined symbol: %s\n",
strtab + sym.st_name);
+ */
}
sec_base = 0;
if (sym.st_shndx == SHN_COMMON) {
@@ -383,14 +393,14 @@ int elf_rel_load(struct mem_ehdr *ehdr,
else {
sec_base = ehdr->e_shdr[sym.st_shndx].sh_addr;
}
-#if 0
+#ifdef DEBUG
fprintf(stderr, "sym: %s value: %lx addr: %lx\n",
strtab + sym.st_name, value, address);
#endif
value = sym.st_value;
value += sec_base;
value += rel.r_addend;
- machine_apply_elf_rel(ehdr, rel.r_type,
+ machine_apply_elf_rel(ehdr, rel.r_type,
(void *)location, address, value);
}
}
@@ -399,7 +409,7 @@ int elf_rel_load(struct mem_ehdr *ehdr,
return result;
}
-void elf_rel_build_load(struct kexec_info *info, struct mem_ehdr *ehdr,
+void elf_rel_build_load(struct kexec_info *info, struct mem_ehdr *ehdr,
const char *buf, off_t len, unsigned long min, unsigned long max,
int end)
{
@@ -452,8 +462,8 @@ int elf_rel_find_symbol(struct mem_ehdr
if (strcmp(strtab + sym.st_name, name) != 0) {
continue;
}
- if ((sym.st_shndx == STN_UNDEF) ||
- (sym.st_shndx > ehdr->e_shnum))
+ if ((sym.st_shndx == STN_UNDEF) ||
+ (sym.st_shndx > ehdr->e_shnum))
{
die("Symbol: %s has Bad section index %d\n",
name, sym.st_shndx);
@@ -491,7 +501,7 @@ void elf_rel_set_symbol(struct mem_ehdr
result = elf_rel_find_symbol(ehdr, name, &sym);
if (result < 0) {
- die("Symbol: %s not found cannot set\n",
+ die("Symbol: %s not found cannot set\n",
name);
}
if (sym.st_size != size) {
diff -puN /dev/null purgatory/arch/ppc64/crashdump_backup.c
--- /dev/null 2004-07-01 07:56:11.000000000 +0530
+++ kexec-tools-1.101-sharada/purgatory/arch/ppc64/crashdump_backup.c 2006-01-17 07:23:35.000000000 +0530
@@ -0,0 +1,41 @@
+/*
+ * kexec: Linux boots Linux
+ *
+ * Created by: Mohan Kumar M (mohan at in.ibm.com)
+ *
+ * Copyright (C) IBM Corporation, 2005. All rights reserved
+ *
+ * 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.
+ */
+
+#include <stdint.h>
+#include <string.h>
+
+#define BACKUP_REGION_SOURCE 0x0
+#define BACKUP_REGION_SIZE 32*1024
+
+extern unsigned long backup_start;
+
+/* Backup first 32KB of memory to backup region reserved by kexec */
+void crashdump_backup_memory(void)
+{
+ void *dest, *src;
+
+ src = (void *)BACKUP_REGION_SOURCE;
+
+ if (backup_start) {
+ dest = (void *)(backup_start);
+ memcpy(dest, src, BACKUP_REGION_SIZE);
+ }
+}
_
More information about the Linuxppc64-dev
mailing list