aboutsummaryrefslogtreecommitdiffstats
path: root/arch/powerpc/boot
diff options
context:
space:
mode:
authorOliver O'Halloran <oohall@gmail.com>2016-11-22 21:55:13 -0500
committerMichael Ellerman <mpe@ellerman.id.au>2016-11-24 01:34:01 -0500
commita1ff57416af9a7971a801d553cd53edd8afb28d6 (patch)
tree531cebbcf7a6788ca1e140a93e5923ec117ffd5c /arch/powerpc/boot
parent9e5f68842276672a05737c23e407250f776cbf35 (diff)
powerpc/boot: Fix the early OPAL console wrappers
When configured with CONFIG_PPC_EARLY_DEBUG_OPAL=y the kernel expects the OPAL entry and base addresses to be passed in r8 and r9 respectively. Currently the wrapper does not attempt to restore these values before entering the decompressed kernel which causes the kernel to branch into whatever happens to be in r9 when doing a write to the OPAL console in early boot. This patch adds a platform_ops hook that can be used to branch into the new kernel. The OPAL console driver patches this at runtime so that if the console is used it will be restored just prior to entering the kernel. Fixes: 656ad58ef19e ("powerpc/boot: Add OPAL console to epapr wrappers") Cc: stable@vger.kernel.org # v4.8+ Signed-off-by: Oliver O'Halloran <oohall@gmail.com> Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>
Diffstat (limited to 'arch/powerpc/boot')
-rw-r--r--arch/powerpc/boot/main.c8
-rw-r--r--arch/powerpc/boot/opal-calls.S13
-rw-r--r--arch/powerpc/boot/opal.c11
-rw-r--r--arch/powerpc/boot/ops.h1
4 files changed, 31 insertions, 2 deletions
diff --git a/arch/powerpc/boot/main.c b/arch/powerpc/boot/main.c
index 57d42d129033..78aaf4ffd7ab 100644
--- a/arch/powerpc/boot/main.c
+++ b/arch/powerpc/boot/main.c
@@ -232,8 +232,12 @@ void start(void)
232 console_ops.close(); 232 console_ops.close();
233 233
234 kentry = (kernel_entry_t) vmlinux.addr; 234 kentry = (kernel_entry_t) vmlinux.addr;
235 if (ft_addr) 235 if (ft_addr) {
236 kentry(ft_addr, 0, NULL); 236 if(platform_ops.kentry)
237 platform_ops.kentry(ft_addr, vmlinux.addr);
238 else
239 kentry(ft_addr, 0, NULL);
240 }
237 else 241 else
238 kentry((unsigned long)initrd.addr, initrd.size, 242 kentry((unsigned long)initrd.addr, initrd.size,
239 loader_info.promptr); 243 loader_info.promptr);
diff --git a/arch/powerpc/boot/opal-calls.S b/arch/powerpc/boot/opal-calls.S
index ff2f1b97bc53..2a99fc9a3ccf 100644
--- a/arch/powerpc/boot/opal-calls.S
+++ b/arch/powerpc/boot/opal-calls.S
@@ -12,6 +12,19 @@
12 12
13 .text 13 .text
14 14
15 .globl opal_kentry
16opal_kentry:
17 /* r3 is the fdt ptr */
18 mtctr r4
19 li r4, 0
20 li r5, 0
21 li r6, 0
22 li r7, 0
23 ld r11,opal@got(r2)
24 ld r8,0(r11)
25 ld r9,8(r11)
26 bctr
27
15#define OPAL_CALL(name, token) \ 28#define OPAL_CALL(name, token) \
16 .globl name; \ 29 .globl name; \
17name: \ 30name: \
diff --git a/arch/powerpc/boot/opal.c b/arch/powerpc/boot/opal.c
index 1f37e1c1d6d8..d7b4fd47eb44 100644
--- a/arch/powerpc/boot/opal.c
+++ b/arch/powerpc/boot/opal.c
@@ -23,14 +23,25 @@ struct opal {
23 23
24static u32 opal_con_id; 24static u32 opal_con_id;
25 25
26/* see opal-wrappers.S */
26int64_t opal_console_write(int64_t term_number, u64 *length, const u8 *buffer); 27int64_t opal_console_write(int64_t term_number, u64 *length, const u8 *buffer);
27int64_t opal_console_read(int64_t term_number, uint64_t *length, u8 *buffer); 28int64_t opal_console_read(int64_t term_number, uint64_t *length, u8 *buffer);
28int64_t opal_console_write_buffer_space(uint64_t term_number, uint64_t *length); 29int64_t opal_console_write_buffer_space(uint64_t term_number, uint64_t *length);
29int64_t opal_console_flush(uint64_t term_number); 30int64_t opal_console_flush(uint64_t term_number);
30int64_t opal_poll_events(uint64_t *outstanding_event_mask); 31int64_t opal_poll_events(uint64_t *outstanding_event_mask);
31 32
33void opal_kentry(unsigned long fdt_addr, void *vmlinux_addr);
34
32static int opal_con_open(void) 35static int opal_con_open(void)
33{ 36{
37 /*
38 * When OPAL loads the boot kernel it stashes the OPAL base and entry
39 * address in r8 and r9 so the kernel can use the OPAL console
40 * before unflattening the devicetree. While executing the wrapper will
41 * probably trash r8 and r9 so this kentry hook restores them before
42 * entering the decompressed kernel.
43 */
44 platform_ops.kentry = opal_kentry;
34 return 0; 45 return 0;
35} 46}
36 47
diff --git a/arch/powerpc/boot/ops.h b/arch/powerpc/boot/ops.h
index 309d1b127e96..fad1862f4b2d 100644
--- a/arch/powerpc/boot/ops.h
+++ b/arch/powerpc/boot/ops.h
@@ -30,6 +30,7 @@ struct platform_ops {
30 void * (*realloc)(void *ptr, unsigned long size); 30 void * (*realloc)(void *ptr, unsigned long size);
31 void (*exit)(void); 31 void (*exit)(void);
32 void * (*vmlinux_alloc)(unsigned long size); 32 void * (*vmlinux_alloc)(unsigned long size);
33 void (*kentry)(unsigned long fdt_addr, void *vmlinux_addr);
33}; 34};
34extern struct platform_ops platform_ops; 35extern struct platform_ops platform_ops;
35 36