[PATCH] powerpc/powernv: Map OPAL msglog in IOREMAP area

Christophe Leroy christophe.leroy at csgroup.eu
Thu Jul 7 19:27:47 AEST 2022


Hi

Le 16/03/2017 à 07:17, Gavin Shan a écrit :
> With OPAL msglog driver, there are two interfaces to retrieve the
> firmware (skiboot) logs: /sys/firmware/opal/msglog and xmon "do"
> command. The memory console header (descritpor) and output buffer
> are resident in memory blocks whose addresses are greater than
> 0x30000000. The memory blocks needn't be necessarily visible to
> kernel. For example when the memory visible to kernel is limited
> by "mem=768M" in bootargs. In this case, reading the memory console
> header (descriptor) and its output buffer directly causes kernel
> crash as the memory blocks aren't mapped in the linear area as the
> driver assumed.
> 
> This reworks the driver to map the memory console header (descitpor)
> and its output buffer as readonly in IOREMAP area as Michael Ellerman
> suggested before. Also, the memory console descriptor are readed into
> local descriptor so that we needn't care about its endian (big or little)
> afterwards, until we need update the output position when dumping the
> messages in the output buffer.
> 
> Signed-off-by: Gavin Shan <gwshan at linux.vnet.ibm.com>

This patch badly conflits when applying.

If it's still applicable, could you rebase and resubmit ?

Thanks
Christophe

> ---
>   arch/powerpc/platforms/powernv/opal-msglog.c | 81 ++++++++++++++++++----------
>   1 file changed, 54 insertions(+), 27 deletions(-)
> 
> diff --git a/arch/powerpc/platforms/powernv/opal-msglog.c b/arch/powerpc/platforms/powernv/opal-msglog.c
> index 7a9cde0..0f2167f 100644
> --- a/arch/powerpc/platforms/powernv/opal-msglog.c
> +++ b/arch/powerpc/platforms/powernv/opal-msglog.c
> @@ -18,38 +18,46 @@
>   
>   /* OPAL in-memory console. Defined in OPAL source at core/console.c */
>   struct memcons {
> -	__be64 magic;
> +	unsigned long	magic;
>   #define MEMCONS_MAGIC	0x6630696567726173L
> -	__be64 obuf_phys;
> -	__be64 ibuf_phys;
> -	__be32 obuf_size;
> -	__be32 ibuf_size;
> -	__be32 out_pos;
> +	unsigned long	obuf_phys;
> +	unsigned long	ibuf_phys;
> +	unsigned int	obuf_size;
> +	unsigned int	ibuf_size;
> +	unsigned int	out_pos;
>   #define MEMCONS_OUT_POS_WRAP	0x80000000u
>   #define MEMCONS_OUT_POS_MASK	0x00ffffffu
> -	__be32 in_prod;
> -	__be32 in_cons;
> +	unsigned int	in_prod;
> +	unsigned int	in_cons;
>   };
>   
> -static struct memcons *opal_memcons = NULL;
> +static struct memcons opal_memcons;
> +static void __iomem *opal_memcons_virt;
> +static void __iomem *opal_memcons_obuf;
> +
> +#define OPAL_MEMCONS_GET_FIELD(field, accessor, converter, tmp)	\
> +	tmp = accessor(opal_memcons_virt +			\
> +		       offsetof(struct memcons, field));	\
> +	opal_memcons.field = converter(tmp)
>   
>   ssize_t opal_msglog_copy(char *to, loff_t pos, size_t count)
>   {
> -	const char *conbuf;
> +	char *conbuf;
>   	ssize_t ret;
>   	size_t first_read = 0;
> -	uint32_t out_pos, avail;
> +	uint32_t out_pos, avail, val32;
>   
> -	if (!opal_memcons)
> +	if (!opal_memcons_obuf)
>   		return -ENODEV;
>   
> -	out_pos = be32_to_cpu(ACCESS_ONCE(opal_memcons->out_pos));
> +	OPAL_MEMCONS_GET_FIELD(out_pos, __raw_readl, be32_to_cpu, val32);
> +	out_pos = opal_memcons.out_pos;
>   
>   	/* Now we've read out_pos, put a barrier in before reading the new
>   	 * data it points to in conbuf. */
>   	smp_rmb();
>   
> -	conbuf = phys_to_virt(be64_to_cpu(opal_memcons->obuf_phys));
> +	conbuf = opal_memcons_obuf;
>   
>   	/* When the buffer has wrapped, read from the out_pos marker to the end
>   	 * of the buffer, and then read the remaining data as in the un-wrapped
> @@ -57,7 +65,7 @@ ssize_t opal_msglog_copy(char *to, loff_t pos, size_t count)
>   	if (out_pos & MEMCONS_OUT_POS_WRAP) {
>   
>   		out_pos &= MEMCONS_OUT_POS_MASK;
> -		avail = be32_to_cpu(opal_memcons->obuf_size) - out_pos;
> +		avail = opal_memcons.obuf_size - out_pos;
>   
>   		ret = memory_read_from_buffer(to, count, &pos,
>   				conbuf + out_pos, avail);
> @@ -75,7 +83,7 @@ ssize_t opal_msglog_copy(char *to, loff_t pos, size_t count)
>   	}
>   
>   	/* Sanity check. The firmware should not do this to us. */
> -	if (out_pos > be32_to_cpu(opal_memcons->obuf_size)) {
> +	if (out_pos > opal_memcons.obuf_size) {
>   		pr_err("OPAL: memory console corruption. Aborting read.\n");
>   		return -EINVAL;
>   	}
> @@ -104,35 +112,54 @@ static struct bin_attribute opal_msglog_attr = {
>   
>   void __init opal_msglog_init(void)
>   {
> -	u64 mcaddr;
> -	struct memcons *mc;
> +	u64 val64;
> +	u32 val32;
>   
> -	if (of_property_read_u64(opal_node, "ibm,opal-memcons", &mcaddr)) {
> +	if (of_property_read_u64(opal_node, "ibm,opal-memcons", &val64)) {
>   		pr_warn("OPAL: Property ibm,opal-memcons not found, no message log\n");
>   		return;
>   	}
>   
> -	mc = phys_to_virt(mcaddr);
> -	if (!mc) {
> +	opal_memcons_virt = ioremap_prot(val64, sizeof(opal_memcons),
> +					 (_PAGE_BASE | _PAGE_KERNEL_RO));
> +	if (!opal_memcons_virt) {
>   		pr_warn("OPAL: memory console address is invalid\n");
>   		return;
>   	}
>   
> -	if (be64_to_cpu(mc->magic) != MEMCONS_MAGIC) {
> +	OPAL_MEMCONS_GET_FIELD(magic,     __raw_readq, be64_to_cpu, val64);
> +	OPAL_MEMCONS_GET_FIELD(obuf_phys, __raw_readq, be64_to_cpu, val64);
> +	OPAL_MEMCONS_GET_FIELD(ibuf_phys, __raw_readq, be64_to_cpu, val64);
> +	OPAL_MEMCONS_GET_FIELD(obuf_size, __raw_readl, be32_to_cpu, val64);
> +	OPAL_MEMCONS_GET_FIELD(ibuf_size, __raw_readl, be32_to_cpu, val32);
> +	OPAL_MEMCONS_GET_FIELD(out_pos,   __raw_readl, be32_to_cpu, val32);
> +	OPAL_MEMCONS_GET_FIELD(in_prod,   __raw_readl, be32_to_cpu, val32);
> +	OPAL_MEMCONS_GET_FIELD(in_cons,   __raw_readl, be32_to_cpu, val32);
> +
> +	if (opal_memcons.magic != MEMCONS_MAGIC) {
>   		pr_warn("OPAL: memory console version is invalid\n");
> +		iounmap(opal_memcons_virt);
>   		return;
>   	}
>   
> -	/* Report maximum size */
> -	opal_msglog_attr.size =  be32_to_cpu(mc->ibuf_size) +
> -		be32_to_cpu(mc->obuf_size);
> +	opal_memcons_obuf = ioremap_prot(opal_memcons.obuf_phys,
> +					 opal_memcons.obuf_size,
> +					 (_PAGE_BASE | _PAGE_KERNEL_RO));
> +	if (!opal_memcons_obuf) {
> +		pr_warn("OPAL: Fail mapping output buffer (0x%lx, 0x%x)\n",
> +			opal_memcons.obuf_phys, opal_memcons.obuf_size);
> +		iounmap(opal_memcons_virt);
> +		return;
> +	}
>   
> -	opal_memcons = mc;
> +	/* Report maximum size */
> +	opal_msglog_attr.size =  opal_memcons.ibuf_size +
> +				 opal_memcons.obuf_size;
>   }
>   
>   void __init opal_msglog_sysfs_init(void)
>   {
> -	if (!opal_memcons) {
> +	if (!opal_memcons_obuf) {
>   		pr_warn("OPAL: message log initialisation failed, not creating sysfs entry\n");
>   		return;
>   	}


More information about the Linuxppc-dev mailing list