diff options
author | Maxim Uvarov <muvarov@gmail.com> | 2010-03-03 14:05:53 +0300 |
---|---|---|
committer | Simon Horman <horms@verge.net.au> | 2010-03-08 11:47:40 +1100 |
commit | 6adc05c6e3fdbc8b9f5d915af78ca05d0a09cb17 (patch) | |
tree | e7f77201ba84a243898a5984f9426626912b8eca /kexec/arch/mips/kexec-elf-mips.c | |
parent | 5996651eccbffb7c195c2911f37fda2f2258e48d (diff) |
some kexec MIPS improvements
- using simple mips* ) in configure.ac to make it compilable on mips2
and mips64
- remove kexec/arch/mips/mips-setup-simple.S which prepares cmdline for
new kernel, it is better to move this work to kernel code. BTW this code was
compilable only on o32 because of t4 is not defined on 64-64 or n32 MIPS ABIs.
- simple put cmdline as string, kernel code should catch cmdline like this
int board_kexec_prepare(struct kimage *image)
{
int i;
char *bootloader = "kexec";
board_boot_desc_ptr->argc = 0;
for(i=0;i<image->nr_segments;i++)
{
printk("segment %d
if (!strncmp(bootloader, (char*)image->segment[i].buf,
strlen(bootloader)))
{
/*
* convert command line string to array
* of parameters (as bootloader does).
*/
int argc = 0, offt;
char *str = (char *)image->segment[i].buf;
char *ptr = strchr(str, ' ');
while (ptr && (ARGV_MAX_ARGS > argc)) {
*ptr = '\0';
if (ptr[1] != ' ') {
offt = (int)(ptr - str + 1);
boot_desc_ptr->argv[argc] =
image->segment[i].mem + offt;
argc++;
}
ptr = strchr(ptr + 1, ' ');
}
boot_desc_ptr->argc = argc;
break;
}
}
Keep it as string make code simple and more readable.
- add crashdump support
- do not redefine syscalls numbers if they defined in system
remove fixups for /proc/iomem. If your board provides wrong /proc/iomem please
fix kernel, or at least you local version of kexec. No need to support it in
main line. At least add option --fake-iomem
- some minor fixes
Signed-off-by: Maxim Uvarov <muvarov@gmail.com>
Signed-off-by: Simon Horman <horms@verge.net.au>
Diffstat (limited to 'kexec/arch/mips/kexec-elf-mips.c')
-rw-r--r-- | kexec/arch/mips/kexec-elf-mips.c | 141 |
1 files changed, 75 insertions, 66 deletions
diff --git a/kexec/arch/mips/kexec-elf-mips.c b/kexec/arch/mips/kexec-elf-mips.c index 95695b6..ce6bf0c 100644 --- a/kexec/arch/mips/kexec-elf-mips.c +++ b/kexec/arch/mips/kexec-elf-mips.c @@ -25,55 +25,21 @@ #include <ip_checksum.h> #include "../../kexec.h" #include "../../kexec-elf.h" +#include "../../kexec-syscall.h" #include "kexec-mips.h" +#include "crashdump-mips.h" #include <arch/options.h> static const int probe_debug = 0; #define BOOTLOADER "kexec" #define MAX_COMMAND_LINE 256 - #define UPSZ(X) ((sizeof(X) + 3) & ~3) -static struct boot_notes { - Elf_Bhdr hdr; - Elf_Nhdr bl_hdr; - unsigned char bl_desc[UPSZ(BOOTLOADER)]; - Elf_Nhdr blv_hdr; - unsigned char blv_desc[UPSZ(BOOTLOADER_VERSION)]; - Elf_Nhdr cmd_hdr; - unsigned char command_line[0]; -} elf_boot_notes = { - .hdr = { - .b_signature = 0x0E1FB007, - .b_size = sizeof(elf_boot_notes), - .b_checksum = 0, - .b_records = 3, - }, - .bl_hdr = { - .n_namesz = 0, - .n_descsz = sizeof(BOOTLOADER), - .n_type = EBN_BOOTLOADER_NAME, - }, - .bl_desc = BOOTLOADER, - .blv_hdr = { - .n_namesz = 0, - .n_descsz = sizeof(BOOTLOADER_VERSION), - .n_type = EBN_BOOTLOADER_VERSION, - }, - .blv_desc = BOOTLOADER_VERSION, - .cmd_hdr = { - .n_namesz = 0, - .n_descsz = 0, - .n_type = EBN_COMMAND_LINE, - }, -}; - - #define OPT_APPEND (OPT_ARCH_MAX+0) +static char cmdline_buf[256] = "kexec "; int elf_mips_probe(const char *buf, off_t len) { - struct mem_ehdr ehdr; int result; result = build_elf_exec_info(buf, len, &ehdr, 0); @@ -108,16 +74,14 @@ int elf_mips_load(int argc, char **argv, const char *buf, off_t len, struct kexec_info *info) { struct mem_ehdr ehdr; - char *arg_buf; - size_t arg_bytes; - unsigned long arg_base; - struct boot_notes *notes; - size_t note_bytes; const char *command_line; int command_line_len; - unsigned char *setup_start; - uint32_t setup_size; + char *crash_cmdline; int opt; + int result; + unsigned long cmdline_addr; + size_t i; + unsigned long bss_start = 0, bss_size = 0; static const struct option options[] = { KEXEC_ARCH_OPTIONS {"command-line", 1, 0, OPT_APPEND}, @@ -144,38 +108,83 @@ int elf_mips_load(int argc, char **argv, const char *buf, off_t len, break; } } + command_line_len = 0; - setup_simple_regs.spr9 = 0; - if (command_line) { - command_line_len = strlen(command_line) + 1; - setup_simple_regs.spr9 = 2; + + /* Need to append some command line parameters internally in case of + * taking crash dumps. + */ + if (info->kexec_flags & KEXEC_ON_CRASH) { + crash_cmdline = xmalloc(COMMAND_LINE_SIZE); + memset((void *)crash_cmdline, 0, COMMAND_LINE_SIZE); + } else + crash_cmdline = NULL; + + result = build_elf_exec_info(buf, len, &ehdr, 0); + if (result < 0) + die("ELF exec parse failed\n"); + + /* Read in the PT_LOAD segments and remove CKSEG0 mask from address*/ + for (i = 0; i < ehdr.e_phnum; i++) { + struct mem_phdr *phdr; + phdr = &ehdr.e_phdr[i]; + if (phdr->p_type == PT_LOAD) + phdr->p_paddr = virt_to_phys(phdr->p_paddr); } - /* Load the ELF executable */ - elf_exec_build_load(info, &ehdr, buf, len, 0); + for (i = 0; i < ehdr.e_shnum; i++) { + struct mem_shdr *shdr; + unsigned char *strtab; + strtab = (unsigned char *)ehdr.e_shdr[ehdr.e_shstrndx].sh_data; + + shdr = &ehdr.e_shdr[i]; + if (shdr->sh_size && + strcmp((char *)&strtab[shdr->sh_name], + ".bss") == 0) { + bss_start = virt_to_phys(shdr->sh_addr); + bss_size = shdr->sh_size; + break; + } - setup_start = setup_simple_start; - setup_size = setup_simple_size; - setup_simple_regs.spr8 = ehdr.e_entry; + } - note_bytes = sizeof(elf_boot_notes) + ((command_line_len + 3) & ~3); - arg_bytes = note_bytes + ((setup_size + 3) & ~3); + /* Load the Elf data */ + result = elf_exec_load(&ehdr, info); + if (result < 0) + die("ELF exec load failed\n"); - arg_buf = xmalloc(arg_bytes); - arg_base = add_buffer_virt(info, - arg_buf, arg_bytes, arg_bytes, 4, 0, elf_max_addr(&ehdr), 1); + info->entry = (void *)virt_to_phys(ehdr.e_entry); - notes = (struct boot_notes *)(arg_buf + ((setup_size + 3) & ~3)); + /* Put cmdline right after bss for crash*/ + if (info->kexec_flags & KEXEC_ON_CRASH) + cmdline_addr = bss_start + bss_size; + else + cmdline_addr = 0; - memcpy(arg_buf, setup_start, setup_size); - memcpy(notes, &elf_boot_notes, sizeof(elf_boot_notes)); - memcpy(notes->command_line, command_line, command_line_len); + if (!bss_size) + die("No .bss segment present\n"); - notes->hdr.b_size = note_bytes; - notes->cmd_hdr.n_descsz = command_line_len; - notes->hdr.b_checksum = compute_ip_checksum(notes, note_bytes); + if (command_line) + command_line_len = strlen(command_line) + 1; + + if (info->kexec_flags & KEXEC_ON_CRASH) { + result = load_crashdump_segments(info, crash_cmdline, + 0, 0); + if (result < 0) { + free(crash_cmdline); + return -1; + } + } - info->entry = (void *)arg_base; + if (command_line) + strncat(cmdline_buf, command_line, command_line_len); + if (crash_cmdline) + strncat(cmdline_buf, crash_cmdline, + sizeof(crash_cmdline) - + strlen(crash_cmdline) - 1); + add_buffer(info, cmdline_buf, sizeof(cmdline_buf), + sizeof(cmdline_buf), sizeof(void *), + cmdline_addr, 0x0fffffff, 1); return 0; } |