mirror of
https://github.com/xen-project/xen.git
synced 2026-10-28 02:01:24 +01:00
xen/ppc: Implement early serial console on PowerNV
Implement the OPAL firmware calls required to write to the serial console on PowerNV systems. Unlike pseries/Open Firmware, the OPAL firmware interface can be used past early boot and as such the relevant functions are not marked as __init. Signed-off-by: Shawn Anastasio <sanastasio@raptorengineering.com> Acked-by: Jan Beulich <jbeulich@suse.com>
This commit is contained in:
1 parent
6fc15ec32b
commit
83ea97ecc0
5 files changed
+127
-1
No files matched your search
@@ -2,6 +2,8 @@
|
||||
#ifndef _ASM_PPC_ASM_DEFNS_H
|
||||
#define _ASM_PPC_ASM_DEFNS_H
|
||||
|
||||
#include <asm/asm-offsets.h>
|
||||
|
||||
/*
|
||||
* Load a 64-bit immediate value into the specified GPR.
|
||||
*/
|
||||
@@ -23,6 +25,18 @@
|
||||
addis reg, %r2, name@toc@ha; \
|
||||
addi reg, reg, name@toc@l
|
||||
|
||||
/*
|
||||
* Declare a global assembly function with a proper TOC setup prologue
|
||||
*/
|
||||
#define _GLOBAL_TOC(name) \
|
||||
.balign 4; \
|
||||
.type name, @function; \
|
||||
.globl name; \
|
||||
name: \
|
||||
0: addis %r2, %r12, (.TOC.-0b)@ha; \
|
||||
addi %r2, %r2, (.TOC.-0b)@l; \
|
||||
.localentry name, .-name
|
||||
|
||||
/*
|
||||
* Depending on how we were booted, the CPU could be running in either
|
||||
* Little Endian or Big Endian mode. The following trampoline from Linux
|
||||
|
||||
+27
-1
@@ -8,9 +8,29 @@
|
||||
#include <xen/init.h>
|
||||
#include <xen/lib.h>
|
||||
|
||||
/* Global OPAL struct containing entrypoint and base */
|
||||
/* Global OPAL struct containing entrypoint and base used by opal-calls.S */
|
||||
struct opal opal;
|
||||
|
||||
int64_t opal_console_write(int64_t term_number, uint64_t *length,
|
||||
const void *buffer);
|
||||
int64_t opal_console_flush(int64_t term_number);
|
||||
int64_t opal_reinit_cpus(uint64_t flags);
|
||||
|
||||
static void opal_putchar(char c)
|
||||
{
|
||||
uint64_t len;
|
||||
|
||||
if ( c == '\n' )
|
||||
{
|
||||
char buf = '\r';
|
||||
len = cpu_to_be64(1);
|
||||
opal_console_write(0, &len, &buf);
|
||||
}
|
||||
len = cpu_to_be64(1);
|
||||
opal_console_write(0, &len, &c);
|
||||
opal_console_flush(0);
|
||||
}
|
||||
|
||||
void __init boot_opal_init(const void *fdt)
|
||||
{
|
||||
int opal_node;
|
||||
@@ -45,4 +65,10 @@ void __init boot_opal_init(const void *fdt)
|
||||
|
||||
opal.base = be64_to_cpu(*opal_base);
|
||||
opal.entry = be64_to_cpu(*opal_entry);
|
||||
|
||||
early_printk_init(opal_putchar);
|
||||
|
||||
/* Ask OPAL to set HID0 for Little Endian interrupts + Radix TLB support */
|
||||
opal_reinit_cpus(OPAL_REINIT_CPUS_HILE_LE | OPAL_REINIT_CPUS_MMU_RADIX |
|
||||
OPAL_REINIT_CPUS_MMU_HASH);
|
||||
}
|
||||
@@ -1,2 +1,3 @@
|
||||
obj-y += head.o
|
||||
obj-y += of-call.o
|
||||
obj-y += opal-calls.o
|
||||
@@ -6,6 +6,7 @@
|
||||
|
||||
#include <xen/macros.h>
|
||||
#include <asm/processor.h>
|
||||
#include <asm/boot.h>
|
||||
|
||||
#define DEFINE(_sym, _val) \
|
||||
asm volatile ( "\n.ascii\"==>#define " #_sym " %0 /* " #_val " */<==\"" \
|
||||
@@ -46,6 +47,9 @@ void __dummy__(void)
|
||||
OFFSET(UREGS_cr, struct cpu_user_regs, cr);
|
||||
OFFSET(UREGS_fpscr, struct cpu_user_regs, fpscr);
|
||||
DEFINE(UREGS_sizeof, sizeof(struct cpu_user_regs));
|
||||
|
||||
OFFSET(OPAL_base, struct opal, base);
|
||||
OFFSET(OPAL_entry, struct opal, entry);
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
@@ -0,0 +1,81 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
/*
|
||||
* Adapted from Linux's arch/powerpc/boot/opal-calls.S
|
||||
*
|
||||
* Copyright (c) 2016 IBM Corporation.
|
||||
* Copyright Raptor Engineering, LLC
|
||||
*/
|
||||
|
||||
#include <asm/asm-defns.h>
|
||||
#include <asm/opal-api.h>
|
||||
#include <asm/msr.h>
|
||||
|
||||
.text
|
||||
|
||||
#define OPAL_CALL(name, token) \
|
||||
.globl name; \
|
||||
name: \
|
||||
li %r0, token; \
|
||||
b opal_call
|
||||
|
||||
_GLOBAL_TOC(opal_call)
|
||||
/* Back up LR, CR, r2 in caller's stack frame */
|
||||
mflr %r11
|
||||
mfcr %r12
|
||||
std %r2, 24(%r1)
|
||||
std %r11, 16(%r1)
|
||||
stw %r12, 8(%r1)
|
||||
|
||||
/* Use r14 (non-volatile) to store the virtual address of opal_return_mmu */
|
||||
std %r14, -8(%r1)
|
||||
stdu %r1, -48(%r1)
|
||||
LOAD_REG_ADDR(%r14, opal_return_mmu)
|
||||
|
||||
/*
|
||||
* Setup new MSR without LE or MMU. Original MSR will be preserved across
|
||||
* opal call in r13
|
||||
*/
|
||||
mfmsr %r13
|
||||
li %r11, MSR_LE | MSR_IR | MSR_DR
|
||||
andc %r12, %r13, %r11
|
||||
mthsrr1 %r12
|
||||
|
||||
LOAD_REG_ADDR(%r11, opal_return_real)
|
||||
mtlr %r11
|
||||
|
||||
/* Load the opal call entry point and base */
|
||||
LOAD_REG_ADDR(%r11, opal)
|
||||
ld %r12, OPAL_entry(%r11)
|
||||
ld %r2, OPAL_base(%r11)
|
||||
mthsrr0 %r12
|
||||
hrfid
|
||||
|
||||
opal_return_real:
|
||||
/*
|
||||
* OPAL will always return to us in Big Endian mode. Since we are going
|
||||
* to restore the old MSR with the correct endianness and MMU status set, we
|
||||
* can avoid an unnecessary FIXUP_ENDIAN trampoline by just encoding the
|
||||
* required Big Endian instructions to restore the old MSR direclty.
|
||||
*/
|
||||
.long 0xa64bbb7d /* mthsrr1 %r13 (Old MSR) */
|
||||
.long 0xa64bda7d /* mthsrr0 %r14 (Virtual address of opal_return_mmu) */
|
||||
.long 0x2402004c /* hrfid */
|
||||
|
||||
opal_return_mmu:
|
||||
/*
|
||||
* We're back in the correct endianness and MMU mode, restore registers
|
||||
* and return
|
||||
*/
|
||||
addi %r1, %r1, 48
|
||||
ld %r14, -8(%r1)
|
||||
lwz %r11, 8(%r1)
|
||||
ld %r12, 16(%r1)
|
||||
ld %r2, 24(%r1)
|
||||
mtcr %r11
|
||||
mtlr %r12
|
||||
|
||||
blr
|
||||
|
||||
OPAL_CALL(opal_console_write, OPAL_CONSOLE_WRITE)
|
||||
OPAL_CALL(opal_console_flush, OPAL_CONSOLE_FLUSH)
|
||||
OPAL_CALL(opal_reinit_cpus, OPAL_REINIT_CPUS)
|
||||