All of lore.kernel.org
 help / color / mirror / Atom feed
From: BALATON Zoltan <balaton@eik.bme.hu>
To: David Gibson <david@gibson.dropbear.id.au>
Cc: Alexey Kardashevskiy <aik@ozlabs.ru>,
	qemu-ppc@nongnu.org, qemu-devel@nongnu.org
Subject: Re: [PATCH qemu v20] spapr: Implement Open Firmware client interface
Date: Fri, 4 Jun 2021 15:50:28 +0200 (CEST)	[thread overview]
Message-ID: <537a6990-4f18-746e-a1da-5dfa51f23dbd@eik.bme.hu> (raw)
In-Reply-To: <YLnF/9H6aFzNhu5+@yekko>

On Fri, 4 Jun 2021, David Gibson wrote:
> 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.

OK, thanks for the clarification, as said in previous message I think 
doing case insesitive comparison just in the address part should work then 
we don't have to implement reg parsing in VOF.

>>> +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.

This is easy to fix, this seems to allow setting a name property or return 
a default:

>diff --git a/hw/ppc/vof.c b/hw/ppc/vof.c
index b47bbd509d..746842593e 100644
--- a/hw/ppc/vof.c
+++ b/hw/ppc/vof.c
@@ -163,14 +163,14 @@ static uint32_t vof_finddevice(const void *fdt, 
uint32_t nodeaddr)
  static const void *getprop(const void *fdt, int nodeoff, const char *propname,
                             int *proplen, bool *write0)
  {
-    const char *unit, *prop;
+    const char *unit, *prop = fdt_getprop(fdt, nodeoff, propname, proplen);

      /*
       * 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) {
+    if (!prop && strcmp(propname, "name") == 0) {
          prop = fdt_get_name(fdt, nodeoff, proplen);
          if (!prop) {
              *proplen = 0;
@@ -196,7 +196,7 @@ static const void *getprop(const void *fdt, int nodeoff, const char *propname,
      if (write0) {
          *write0 = false;
      }
-    return fdt_getprop(fdt, nodeoff, propname, proplen);
+    return prop;
  }

This allows adding a name property to "/" different from the default but 
this does not yet fix MorphOS booting with VOF on pegasos2. I think it 
tries to query name on / and check if it's called "device-tree" in which 
case it assumes Mac hardware otherwise it goes with pegasos2 so even if we 
return nothing for name it would not matter in this case as we don't use 
VOF on Mac. If we wanted that then this would become a problem so it could 
be fixed now in advance just in case other guests may need it.

>> 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.

I don't know if it matters or not but having the device tree in the same 
order as the firmware ROM helps with comparing it for debugging but I've 
found I can solve this by building the tree in reverse order so no changes 
to VOF is needed for this, just thought adding a comment somewhere may 
clarify it but it's not really a problem.

I still don't know what's MorphOS is missing, I've tried adding almost all 
misssing properties, checked what hardware is init by the firmware and 
tried to do the same in board reset code and even after that MorphOS still 
takes a different route with VOF and crashes but boots with the board 
firmware. I'm now thinking it may be either different memory organisation 
or the missing name properties that are not returned by nextprop in VOF so 
they are only appearing when explicitely queried whereas with the board 
firmware they are present as properties. With the above patch I could 
explicitely set it on nodes and test if that makes a difference.

I got to this because adding more missing props or init more devices did 
not make a difference so I'm guessing it may be something else then and 
the only difference I can see compared to board firmware are the different 
memory ranges in claimed (VOF puts itself to 0 for example); and the 
missing name and additional phandle props in the device tree. MorphOS 
copies the whole device tree on startup then later it uses this copy of 
the device tree after shutting down OF with quiesce. I can imagine it may 
use some name props like that on the cpu node without checking assuming 
it's always there and if we're missing that it may cause a NULL 
dereference. I have no better idea what else could be missing so I'll test 
this next. If it helps I can try to come up with a patch to VOF to return 
these name props or allow setting them as above.

Regards,
BALATON Zoltan


  reply	other threads:[~2021-06-04 13:51 UTC|newest]

Thread overview: 63+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2021-05-20  9:05 [PATCH qemu v20] spapr: Implement Open Firmware client interface Alexey Kardashevskiy
2021-05-20 21:59 ` BALATON Zoltan
2021-05-21  0:25   ` Alexey Kardashevskiy
2021-05-21  9:05     ` BALATON Zoltan
2021-05-21 19:57       ` BALATON Zoltan
2021-05-22  6:39         ` Alexey Kardashevskiy
2021-05-22 13:08           ` BALATON Zoltan
2021-05-23  3:47             ` Alexey Kardashevskiy
2021-05-23 12:12               ` BALATON Zoltan
2021-05-22  6:22       ` Alexey Kardashevskiy
2021-05-22 13:01         ` BALATON Zoltan
2021-05-22 15:02           ` BALATON Zoltan
2021-05-22 16:46             ` BALATON Zoltan
2021-05-23  3:41               ` Alexey Kardashevskiy
2021-05-23 12:02                 ` BALATON Zoltan
2021-05-23  3:31             ` Alexey Kardashevskiy
2021-05-23 11:24               ` BALATON Zoltan
2021-05-24  4:26                 ` Alexey Kardashevskiy
2021-05-24  5:40                   ` David Gibson
2021-05-24 11:56                     ` BALATON Zoltan
2021-05-23  3:20           ` Alexey Kardashevskiy
2021-05-23 11:19             ` BALATON Zoltan
2021-05-23 17:09               ` BALATON Zoltan
2021-05-24  6:01                 ` David Gibson
2021-05-24 10:55                   ` BALATON Zoltan
2021-05-24 12:46                     ` Alexey Kardashevskiy
2021-05-24 22:34                       ` BALATON Zoltan
2021-05-25  5:24                       ` David Gibson
2021-05-25  5:23                     ` David Gibson
2021-05-25 10:08                       ` BALATON Zoltan
2021-05-27  5:34                         ` David Gibson
2021-05-27 12:42                           ` BALATON Zoltan
2021-06-02  7:57                             ` David Gibson
2021-06-02 12:29                               ` BALATON Zoltan
2021-06-04  6:29                                 ` David Gibson
2021-06-04 13:59                                   ` BALATON Zoltan
2021-06-07  3:30                                     ` David Gibson
2021-06-07 22:54                                       ` BALATON Zoltan
2021-06-09  5:51                                         ` Alexey Kardashevskiy
2021-06-09 10:19                                           ` BALATON Zoltan
2021-06-06 22:21                                   ` BALATON Zoltan
2021-06-07  3:37                                     ` David Gibson
2021-06-07 22:20                                       ` BALATON Zoltan
2021-05-24 12:42                   ` BALATON Zoltan
2021-05-25  5:29                     ` David Gibson
2021-05-25  9:55                       ` BALATON Zoltan
2021-05-27  5:31                         ` David Gibson
2021-05-24  5:23   ` David Gibson
2021-05-24  9:57     ` BALATON Zoltan
2021-05-24 10:50       ` David Gibson
2021-05-29 18:10 ` BALATON Zoltan
2021-05-30 17:33 ` BALATON Zoltan
2021-05-31 13:07   ` BALATON Zoltan
2021-06-01 12:02     ` Alexey Kardashevskiy
2021-06-01 14:12       ` BALATON Zoltan
2021-06-04  6:21         ` David Gibson
2021-06-04 13:27           ` BALATON Zoltan
2021-06-07  3:02             ` David Gibson
2021-06-04  6:19   ` David Gibson
2021-06-04 13:50     ` BALATON Zoltan [this message]
2021-06-04 14:34       ` BALATON Zoltan
2021-06-07  3:05       ` David Gibson
2021-06-09  6:13         ` Alexey Kardashevskiy

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=537a6990-4f18-746e-a1da-5dfa51f23dbd@eik.bme.hu \
    --to=balaton@eik.bme.hu \
    --cc=aik@ozlabs.ru \
    --cc=david@gibson.dropbear.id.au \
    --cc=qemu-devel@nongnu.org \
    --cc=qemu-ppc@nongnu.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.