qemu-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [PATCH qemu v20] spapr: Implement Open Firmware client interface


From: David Gibson
Subject: Re: [PATCH qemu v20] spapr: Implement Open Firmware client interface
Date: Fri, 4 Jun 2021 16:19:43 +1000

On Sun, May 30, 2021 at 07:33:01PM +0200, BALATON Zoltan wrote:
> Hello,
> 
> Two more problems I've found while testing with pegasos2 but I'm not sure
> how to fix them:
> 
> On Thu, 20 May 2021, Alexey Kardashevskiy wrote:
> > diff --git a/hw/ppc/vof.c b/hw/ppc/vof.c
> > new file mode 100644
> > index 000000000000..a283b7d251a7
> > --- /dev/null
> > +++ b/hw/ppc/vof.c
> > @@ -0,0 +1,1021 @@
> > +/*
> > + * QEMU PowerPC Virtual Open Firmware.
> > + *
> > + * This implements client interface from OpenFirmware IEEE1275 on the QEMU
> > + * side to leave only a very basic firmware in the VM.
> > + *
> > + * Copyright (c) 2021 IBM Corporation.
> > + *
> > + * SPDX-License-Identifier: GPL-2.0-or-later
> > + */
> > +
> > +#include "qemu/osdep.h"
> > +#include "qemu-common.h"
> > +#include "qemu/timer.h"
> > +#include "qemu/range.h"
> > +#include "qemu/units.h"
> > +#include "qapi/error.h"
> > +#include <sys/ioctl.h>
> > +#include "exec/ram_addr.h"
> > +#include "exec/address-spaces.h"
> > +#include "hw/ppc/vof.h"
> > +#include "hw/ppc/fdt.h"
> > +#include "sysemu/runstate.h"
> > +#include "qom/qom-qobject.h"
> > +#include "trace.h"
> > +
> > +#include <libfdt.h>
> > +
> > +/*
> > + * OF 1275 "nextprop" description suggests is it 32 bytes max but
> > + * LoPAPR defines "ibm,query-interrupt-source-number" which is 33 chars 
> > long.
> > + */
> > +#define OF_PROPNAME_LEN_MAX 64
> > +
> > +#define VOF_MAX_PATH        256
> > +#define VOF_MAX_SETPROPLEN  2048
> > +#define VOF_MAX_METHODLEN   256
> > +#define VOF_MAX_FORTHCODE   256
> > +#define VOF_VTY_BUF_SIZE    256
> > +
> > +typedef struct {
> > +    uint64_t start;
> > +    uint64_t size;
> > +} OfClaimed;
> > +
> > +typedef struct {
> > +    char *path; /* the path used to open the instance */
> > +    uint32_t phandle;
> > +} OfInstance;
> > +
> > +#define VOF_MEM_READ(pa, buf, size) \
> > +    address_space_read_full(&address_space_memory, \
> > +    (pa), MEMTXATTRS_UNSPECIFIED, (buf), (size))
> > +#define VOF_MEM_WRITE(pa, buf, size) \
> > +    address_space_write(&address_space_memory, \
> > +    (pa), MEMTXATTRS_UNSPECIFIED, (buf), (size))
> > +
> > +static int readstr(hwaddr pa, char *buf, int size)
> > +{
> > +    if (VOF_MEM_READ(pa, buf, size) != MEMTX_OK) {
> > +        return -1;
> > +    }
> > +    if (strnlen(buf, size) == size) {
> > +        buf[size - 1] = '\0';
> > +        trace_vof_error_str_truncated(buf, size);
> > +        return -1;
> > +    }
> > +    return 0;
> > +}
> > +
> > +static bool cmpservice(const char *s, unsigned nargs, unsigned nret,
> > +                       const char *s1, unsigned nargscheck, unsigned 
> > nretcheck)
> > +{
> > +    if (strcmp(s, s1)) {
> > +        return false;
> > +    }
> > +    if ((nargscheck && (nargs != nargscheck)) ||
> > +        (nretcheck && (nret != nretcheck))) {
> > +        trace_vof_error_param(s, nargscheck, nretcheck, nargs, nret);
> > +        return false;
> > +    }
> > +
> > +    return true;
> > +}
> > +
> > +static void prop_format(char *tval, int tlen, const void *prop, int len)
> > +{
> > +    int i;
> > +    const unsigned char *c;
> > +    char *t;
> > +    const char bin[] = "...";
> > +
> > +    for (i = 0, c = prop; i < len; ++i, ++c) {
> > +        if (*c == '\0' && i == len - 1) {
> > +            strncpy(tval, prop, tlen - 1);
> > +            return;
> > +        }
> > +        if (*c < 0x20 || *c >= 0x80) {
> > +            break;
> > +        }
> > +    }
> > +
> > +    for (i = 0, c = prop, t = tval; i < len; ++i, ++c) {
> > +        if (t >= tval + tlen - sizeof(bin) - 1 - 2 - 1) {
> > +            strcpy(t, bin);
> > +            return;
> > +        }
> > +        if (i && i % 4 == 0 && i != len - 1) {
> > +            strcat(t, " ");
> > +            ++t;
> > +        }
> > +        t += sprintf(t, "%02X", *c & 0xFF);
> > +    }
> > +}
> > +
> > +static int get_path(const void *fdt, int offset, char *buf, int len)
> > +{
> > +    int ret;
> > +
> > +    ret = fdt_get_path(fdt, offset, buf, len - 1);
> > +    if (ret < 0) {
> > +        return ret;
> > +    }
> > +
> > +    buf[len - 1] = '\0';
> > +
> > +    return strlen(buf) + 1;
> > +}
> > +
> > +static int phandle_to_path(const void *fdt, uint32_t ph, char *buf, int 
> > len)
> > +{
> > +    int ret;
> > +
> > +    ret = fdt_node_offset_by_phandle(fdt, ph);
> > +    if (ret < 0) {
> > +        return ret;
> > +    }
> > +
> > +    return get_path(fdt, ret, buf, len);
> > +}
> > +
> > +static uint32_t vof_finddevice(const void *fdt, uint32_t nodeaddr)
> > +{
> > +    char fullnode[VOF_MAX_PATH];
> > +    uint32_t ret = -1;
> > +    int offset;
> > +
> > +    if (readstr(nodeaddr, fullnode, sizeof(fullnode))) {
> > +        return (uint32_t) ret;
> > +    }
> > +
> > +    offset = fdt_path_offset(fdt, fullnode);
> > +    if (offset >= 0) {
> > +        ret = fdt_get_phandle(fdt, offset);
> > +    }
> > +    trace_vof_finddevice(fullnode, ret);
> > +    return (uint32_t) ret;
> > +}
> 
> The Linux init function that runs on pegasos2 here:
> 
> https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/tree/arch/powerpc/kernel/prom_init.c?h=v4.14.234#n2658
> 
> calls finddevice once with isa@c and next with isa@C (small and capital C)
> both of which works with the board firmware but with vof the comparison is
> case sensitive and one of these fails so I can't make it work. I don't know
> if this is a problem in libfdt or the vof_finddevice above should do
> something else to get case insensitive comparison.

This is kind of a subtle incompatibility between the traditional OF
world and the flat tree world.  In traditional OF, the unit address
(bit after the @) doesn't exist as a string.  Instead when you do the
finddevice it will parse that address and compare it against the 'reg'
properties for each of the relevant nodes.  Since that's an integer
comparison, case doesn't enter into it.

But, how to parse (and write) addresses depends on the bus, so the
firmware has to understand each bus type and act accordingly.  That
doesn't really work in the world of minimal firmwares dor the flat
tree.  So instead, we just incorporate a pre-formatted unit address in
the flat tree directly.  Most of the time that works fine, but there
are some edge cases like the one you've hit.

> > +static const void *getprop(const void *fdt, int nodeoff, const char 
> > *propname,
> > +                           int *proplen, bool *write0)
> > +{
> > +    const char *unit, *prop;
> > +
> > +    /*
> > +     * The "name" property is not actually stored as a property in the FDT,
> > +     * we emulate it by returning a pointer to the node's name and adjust
> > +     * proplen to include only the name but not the unit.
> > +     */
> > +    if (strcmp(propname, "name") == 0) {
> > +        prop = fdt_get_name(fdt, nodeoff, proplen);
> > +        if (!prop) {
> > +            *proplen = 0;
> > +            return NULL;
> > +        }
> > +
> > +        unit = memchr(prop, '@', *proplen);
> > +        if (unit) {
> > +            *proplen = unit - prop;
> > +        }
> > +        *proplen += 1;
> > +
> > +        /*
> > +         * Since it might be cut at "@" and there will be no trailing zero
> > +         * in the prop buffer, tell the caller to write zero at the end.
> > +         */
> > +        if (write0) {
> > +            *write0 = true;
> > +        }
> > +        return prop;
> > +    }
> > +
> > +    if (write0) {
> > +        *write0 = false;
> > +    }
> > +    return fdt_getprop(fdt, nodeoff, propname, proplen);
> > +}
> 
> MorphOS checks the name property of the root node ("/") to decide what
> platform it runs on so we may need to be able to set this property on /
> where it should return "bplan,Pegasos2", therefore the above maybe should do
> getprop first and only generate name property if it's not set (or at least
> check if we're on the root node and allow setting name property there). (On
> Macs the root node is named "device-tree" and this was before found to be
> needed for MorphOS.)

Ah.  Hrm.  Have to think about what to do about that.

> Other than the above two problems, I've found that getting the device tree
> from vof returns it in reverse order compared to the board firmware if I add
> it the expected order. This may or may not be a problem but to avoid it I
> can build the tree in reverse order then it comes out right so unless
> there's an easy fix this should not cause a problem but may worth a comment
> somewhere.

The order of things in the device tree *should* never matter.  If it
does, that's definitely a client bug... but of course that doesn't
necessarily mean we won't have to work around it in practice.

-- 
David Gibson                    | I'll have my music baroque, and my code
david AT gibson.dropbear.id.au  | minimalist, thank you.  NOT _the_ _other_
                                | _way_ _around_!
http://www.ozlabs.org/~dgibson

Attachment: signature.asc
Description: PGP signature


reply via email to

[Prev in Thread] Current Thread [Next in Thread]