summaryrefslogtreecommitdiff
path: root/kexec/arch/ppc64/kexec-elf-ppc64.c
diff options
context:
space:
mode:
Diffstat (limited to 'kexec/arch/ppc64/kexec-elf-ppc64.c')
-rw-r--r--kexec/arch/ppc64/kexec-elf-ppc64.c54
1 files changed, 51 insertions, 3 deletions
diff --git a/kexec/arch/ppc64/kexec-elf-ppc64.c b/kexec/arch/ppc64/kexec-elf-ppc64.c
index cc0531d..ce10367 100644
--- a/kexec/arch/ppc64/kexec-elf-ppc64.c
+++ b/kexec/arch/ppc64/kexec-elf-ppc64.c
@@ -35,6 +35,7 @@
#include "../../kexec-elf.h"
#include "../../kexec-syscall.h"
#include "kexec-ppc64.h"
+#include "../../fs2dt.h"
#include "crashdump-ppc64.h"
#include <arch/options.h>
@@ -70,6 +71,26 @@ void arch_reuse_initrd(void)
reuse_initrd = 1;
}
+static int read_prop(char *name, void *value, size_t len)
+{
+ int fd;
+ size_t rlen;
+
+ fd = open(name, O_RDONLY);
+ if (fd == -1)
+ return -1;
+
+ rlen = read(fd, value, len);
+ if (rlen < 0)
+ fprintf(stderr, "Warning : Can't read %s : %s",
+ name, strerror(errno));
+ else if (rlen != len)
+ fprintf(stderr, "Warning : short read from %s", name);
+
+ close(fd);
+ return 0;
+}
+
int elf_ppc64_load(int argc, char **argv, const char *buf, off_t len,
struct kexec_info *info)
{
@@ -82,11 +103,14 @@ int elf_ppc64_load(int argc, char **argv, const char *buf, off_t len,
off_t seg_size = 0;
struct mem_phdr *phdr;
size_t size;
+#ifdef NEED_RESERVE_DTB
uint64_t *rsvmap_ptr;
struct bootblock *bb_ptr;
+#endif
int i;
int result, opt;
uint64_t my_kernel, my_dt_offset;
+ uint64_t my_opal_base = 0, my_opal_entry = 0;
unsigned int my_panic_kernel;
uint64_t my_stack, my_backup_start;
uint64_t toc_addr;
@@ -228,18 +252,34 @@ int elf_ppc64_load(int argc, char **argv, const char *buf, off_t len,
my_dt_offset = add_buffer(info, seg_buf, seg_size, seg_size,
0, 0, max_addr, -1);
+#ifdef NEED_RESERVE_DTB
/* 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
*/
bb_ptr = (struct bootblock *)(seg_buf);
- rsvmap_ptr = (uint64_t *)(seg_buf + bb_ptr->off_mem_rsvmap);
+ rsvmap_ptr = (uint64_t *)(seg_buf + be32_to_cpu(bb_ptr->off_mem_rsvmap));
while (*rsvmap_ptr || *(rsvmap_ptr+1))
rsvmap_ptr += 2;
rsvmap_ptr -= 2;
- *rsvmap_ptr = my_dt_offset;
+ *rsvmap_ptr = cpu_to_be64(my_dt_offset);
rsvmap_ptr++;
- *rsvmap_ptr = bb_ptr->totalsize;
+ *rsvmap_ptr = cpu_to_be64((uint64_t)be32_to_cpu(bb_ptr->totalsize));
+#endif
+
+ if (read_prop("/proc/device-tree/ibm,opal/opal-base-address",
+ &my_opal_base, sizeof(my_opal_base)) == 0) {
+ my_opal_base = be64_to_cpu(my_opal_base);
+ elf_rel_set_symbol(&info->rhdr, "opal_base",
+ &my_opal_base, sizeof(my_opal_base));
+ }
+
+ if (read_prop("/proc/device-tree/ibm,opal/opal-entry-address",
+ &my_opal_entry, sizeof(my_opal_entry)) == 0) {
+ my_opal_entry = be64_to_cpu(my_opal_entry);
+ elf_rel_set_symbol(&info->rhdr, "opal_entry",
+ &my_opal_entry, sizeof(my_opal_entry));
+ }
/* Set kernel */
elf_rel_set_symbol(&info->rhdr, "kernel", &my_kernel, sizeof(my_kernel));
@@ -301,7 +341,13 @@ int elf_ppc64_load(int argc, char **argv, const char *buf, off_t len,
toc_addr = 0;
my_run_at_load = 0;
my_debug = 0;
+ my_opal_base = 0;
+ my_opal_entry = 0;
+ elf_rel_get_symbol(&info->rhdr, "opal_base", &my_opal_base,
+ sizeof(my_opal_base));
+ elf_rel_get_symbol(&info->rhdr, "opal_entry", &my_opal_entry,
+ sizeof(my_opal_entry));
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));
@@ -328,6 +374,8 @@ int elf_ppc64_load(int argc, char **argv, const char *buf, off_t len,
dbgprintf("toc_addr is %llx\n", (unsigned long long)toc_addr);
dbgprintf("purgatory size is %zu\n", purgatory_size);
dbgprintf("debug is %d\n", my_debug);
+ dbgprintf("opal_base is %llx\n", (unsigned long long) my_opal_base);
+ dbgprintf("opal_entry is %llx\n", (unsigned long long) my_opal_entry);
for (i = 0; i < info->nr_segments; i++)
fprintf(stderr, "segment[%d].mem:%p memsz:%zu\n", i,