diff options
author | Zou Nan hai <nanhai.zou@intel.com> | 2006-11-21 07:13:56 +0800 |
---|---|---|
committer | Simon Horman <horms@verge.net.au> | 2006-12-12 18:30:49 +0900 |
commit | 7f093bceb950d24d91359965d135c835c584c953 (patch) | |
tree | 01803b2674bbe2b80f94f7599afa538fc1e4b0a8 | |
parent | 6675c146d462deccaaa1c7541aaebd58ce08295c (diff) |
send slave cpus to SAL slave loop on crash (IA64)
On Tue, 2006-11-21 at 07:33, Jay Lan wrote:
> Zou, Nanhai wrote:
> >> We do not rely on machine crash on CPU 0 any more. If the
> >> crashing CPU is not cpu 0 and the cpu 0 not being returned to
> >> the slave loop, this case is handled by our PROM now.
> >>
> >> However, if somebody tries to boot up a production kernel using
> '-le'
> >> option _after_ the kexec'ed kernel is up running, the third kernel
> >> would not boot unless we boot up the second kernel with cpu 0. I
> >> posted a question on "if running 'kexec -le' on a kexec'ed kdump
> >> kernel is legal" earlier and Vivek responded saying the scenario
> >> is not guranteed to work. So, i think we are fine here.
> >>
> >
> > Ok, so with this patch and the PROM fix, on a SN system,
> > 1. Kdump -> 2nd kernel works.
> > 2. Kdump -> 2nd kernel -> Kexec to third kernel will not work.
> > 3. Kexec -> 2nd Kernel -> Kexec -> 3rd kernel works?
> > 4. Kexec -> 2nd Kernel -> Kdump -> 3rd kernel works?
> >
> > I think if scenario 1, 3 and 4 works it will be ok. Scenario 2 is
> not so useful I guess.
> >
>
> With the patch Nanhai sent to me to fix '-l' option on SN system,
> now scenario 1, 3 and 4 all works. Of course, you need to include
> 'crashkernel' parameter in "append" option when you do 'kexec -l'
> in order for scenario #4 to work. You do not need crashkernel
> parameter for #3 though.
>
> Thanks,
> - jay
>
>
This is the patch,
This patch make normal "kexec -l" first try physical address suggested
by vmlinux.
If there is no enough memory, kexec tools will search /proc/iomem and
find a place to put the new kernel.
This is necessary for "kexec -l" to work on SN platform.
Signed-off-by: Zou Nan hai <nanhai.zou@intel.com>
-rw-r--r-- | kexec/arch/ia64/kexec-elf-ia64.c | 12 | ||||
-rw-r--r-- | kexec/arch/ia64/kexec-ia64.c | 44 | ||||
-rw-r--r-- | kexec/arch/ia64/kexec-ia64.h | 4 |
3 files changed, 55 insertions, 5 deletions
diff --git a/kexec/arch/ia64/kexec-elf-ia64.c b/kexec/arch/ia64/kexec-elf-ia64.c index bd2350c..2dd0bc8 100644 --- a/kexec/arch/ia64/kexec-elf-ia64.c +++ b/kexec/arch/ia64/kexec-elf-ia64.c @@ -86,7 +86,8 @@ void elf_ia64_usage(void) /* Move the crash kerenl physical offset to reserved region */ -static void move_loaded_segments(struct kexec_info *info, struct mem_ehdr *ehdr) +void move_loaded_segments(struct kexec_info *info, struct mem_ehdr *ehdr, + unsigned long addr) { int i; long offset; @@ -94,7 +95,7 @@ static void move_loaded_segments(struct kexec_info *info, struct mem_ehdr *ehdr) for(i = 0; i < ehdr->e_phnum; i++) { phdr = &ehdr->e_phdr[i]; if (phdr->p_type == PT_LOAD) { - offset = mem_min - phdr->p_paddr; + offset = addr - phdr->p_paddr; break; } } @@ -189,7 +190,12 @@ int elf_ia64_load(int argc, char **argv, const char *buf, off_t len, free_elf_info(&ehdr); return -1; } - move_loaded_segments(info, &ehdr); + move_loaded_segments(info, &ehdr, mem_min); + } else { + if (update_loaded_segments(info, &ehdr)) { + fprintf(stderr, "Failed to place kernel\n"); + return -1; + } } entry = ehdr.e_entry; diff --git a/kexec/arch/ia64/kexec-ia64.c b/kexec/arch/ia64/kexec-ia64.c index 48fad60..f71236d 100644 --- a/kexec/arch/ia64/kexec-ia64.c +++ b/kexec/arch/ia64/kexec-ia64.c @@ -29,13 +29,15 @@ #include <getopt.h> #include <sched.h> #include <sys/utsname.h> +#include <limits.h> #include "../../kexec.h" #include "../../kexec-syscall.h" +#include "elf.h" #include "kexec-ia64.h" #include <arch/options.h> static struct memory_range memory_range[MAX_MEMORY_RANGES]; - +static int memory_ranges; /* Reserve range for EFI memmap and Boot parameter */ static int split_range(int range, unsigned long start, unsigned long end) { @@ -73,7 +75,6 @@ int get_memory_ranges(struct memory_range **range, int *ranges, unsigned long kexec_flags) { const char iomem[]= "/proc/iomem"; - int memory_ranges = 0; char line[MAX_LINE]; FILE *fp; fp = fopen(iomem, "r"); @@ -209,6 +210,45 @@ int arch_compat_trampoline(struct kexec_info *info) return 0; } +int update_loaded_segments(struct kexec_info *info, struct mem_ehdr *ehdr) +{ + int i; + struct mem_phdr *phdr; + unsigned long start_addr = ULONG_MAX, end_addr = 0; + unsigned long align = 1UL<<26; // 64M + for(i = 0; i < ehdr->e_phnum; i++) { + phdr = &ehdr->e_phdr[i]; + if (phdr->p_type == PT_LOAD) { + if (phdr->p_paddr < start_addr) + start_addr = phdr->p_paddr; + if ((phdr->p_paddr + phdr->p_memsz) > end_addr) + end_addr = phdr->p_paddr + phdr->p_memsz; + } + + } + + for (i = 0; i < memory_ranges + && memory_range[i].start <= start_addr; i++) { + if (memory_range[i].type == RANGE_RAM && + memory_range[i].end > end_addr) + return; + } + + for (i = 0; i < memory_ranges; i++) { + if (memory_range[i].type == RANGE_RAM) { + unsigned long start = + (memory_range[i].start + align - 1)&~(align - 1); + unsigned long end = memory_range[i].end; + if (end > start && + (end - start) > (end_addr - start_addr)) { + move_loaded_segments(info, ehdr, start); + return 0; + } + } + } + return 1; +} + void arch_update_purgatory(struct kexec_info *info) { } diff --git a/kexec/arch/ia64/kexec-ia64.h b/kexec/arch/ia64/kexec-ia64.h index 62d05c1..138bf40 100644 --- a/kexec/arch/ia64/kexec-ia64.h +++ b/kexec/arch/ia64/kexec-ia64.h @@ -7,6 +7,10 @@ int elf_ia64_probe(const char *buf, off_t len); int elf_ia64_load(int argc, char **argv, const char *buf, off_t len, struct kexec_info *info); void elf_ia64_usage(void); +int update_loaded_segments(struct kexec_info *info, struct mem_ehdr *ehdr); +void move_loaded_segments(struct kexec_info *info, struct mem_ehdr *ehdr, + unsigned long addr); + #define MAX_MEMORY_RANGES 1024 #define EFI_PAGE_SIZE (1UL<<12) #define ELF_PAGE_SIZE (1UL<<16) |