[Skiboot] [RFC PATCH v2 1/8] doc/opal-uv-api.rst

Oliver O'Halloran oohall at gmail.com
Mon Nov 18 09:40:21 AEDT 2019


On Fri, Sep 20, 2019 at 11:59 PM Ryan Grimm <grimm at linux.ibm.com> wrote:
>
> Signed-off-by: Ryan Grimm <grimm at linux.ibm.com>

*snip*

> +Ultravisor Initialization
> +#########################
> +
> +Loading The Ultravisor
> +======================
> +
> +Skiboot uses secure and trusted boot to load and verify the compressed UV image
> +from the PNOR into regular memory.  It unpacks the UV into regular memory in
> +the function ``init_uv``.
> +
> +``init_uv`` finds the UV node in the device tree via the "ibm,ultravisor"
> +compatible property.  For example:
> +
> +.. code-block:: dts
> +
> +        ibm,ultravisor {
> +                compatible = "ibm,ultravisor";
> +                ibm,uv-firmware {
Nodes with a reg should have a unit address.

> +                        compatible = "ibm,uv-firmware";

> +                        #address-cells = <0x2>;
> +                        #size-cells = <0x2>;
What's the address space below this node?

> +                        reg = < 0x0 0xc0000000 >;
This should be four cells (2 address, 2 size).

> +                        secure-memory-ranges = < 0x1003c 0x00000000 0x4 0x00000000
> +                                                 0x1203c 0x00000000 0x4 0x00000000  >;
> +                };
> +        };
> +
> +In the case of Mambo or BML, skiboot does not load the UV from the PNOR, so the
> +proprety reg must be provided so skiboot knows where to copy the UV image from,
> +like the example above.
>
> +Otherwise, on Hostboot, skiboot creates the reg property which it uses to start
> +the UV.

ibm,uv-firmware should be a reserved-memory node. Skiboot's memory
allocator checks for reservations and ensures that local_alloc()
doesn't allocate over them and this appears to bypass that checking
entirely. I realise this is similar to what we do for the kernel and
initramfs, but those are loaded in low memory (below 0x3000...0000)
which is always marked as reserved.

> +``init_uv`` parses secure memory ranges and copies the UV into the start of the
> +first available secure range.

Can you elaborate on what secure-memory-ranges actually means?

>
> +Starting The Ultravisor
> +=======================
> +
> +Skiboot starts the UV in ``main_cpu_entry`` before the kernel is loaded and booted.
> +Skiboot creates a job on all threads and sends them to ``start_uv`` in asm/head.S.
> +This function's prototype is:

> +.. code-block:: c
> +
> +        /**
> +        * @brief Start UV.
> +        *
> +        * @param uv_load_addr Load address of ultravisor.
> +        * @param uv_opal Pointer to uv_opal strucutre.
> +        *
> +        * @return 0 on success, else a negative error code on failure.
> +        */
> +        u64 start_uv(u64 uv_load_addr, struct uv_opal *uv_opal);
> +
> +The opal ultravisor api

ABI

> defined in ``struct uv_opal``, allows passing configuration
> +information to the UV and obtaining a return code from the ultravisor post
> +initialization.  It is defined as:
> +
> +.. code-block:: c
> +
> +        struct uv_opal {
> +                __be32 magic;           /**< 'OPUV' 0x4F505556 OPUV_MAGIC */
> +                __be32 version;         /**< uv_opal struct version */
> +                __be32 uv_ret_code;     /**< 0 - Success, <0> : error. */
> +                __be32 uv_api_ver;      /**< Current uv api version. */
> +                __be64 uv_base_addr;    /**< Base address of UV in secure memory. */
> +                __be64 sys_fdt;         /**< System FDT. */
> +                __be64 uv_fdt;          /**< UV FDT in secure memory. */
> +                __be64 uv_mem;          /**< struct memcons */
> +        };

 It looks like everything here except the return code is static data
provided by OPAL so why isn't this all in the DT? I don't see the
point of having a return code in here either since that can be
returned via r3, as it is for a normal function call.

> +The ``uv_fdt`` is constructed in secure memory. It is allocated after the
> +ultravisor image at ``uv_base_addr + UV_LOAD_MAX_SIZE``.  This allows the
> +ultravisor to load at start of the first secure memory range and recover the
> +memory allocated to ``uv_fdt``.

...so why not just build it in HV memory? The UV is going to unflatten
the FDT anyway so where does the location of the FDT matter?

> +Ultravisor Failed Start Recovery
> +================================
> +
> +If the Ultravisor fails to start it will return a error code in ``uv_ret_code``.
> +skiboot will continue to be in ultravisor privilege mode, and will need to
> +perform a recovery action.
> +
> +[**TODO**: Need to describe the steps for Ultravisor load failure recovery action.]

What can we actually do here? If we can switch the XSCOM range, etc
back to be accessible with HV=1,UV=0 we can probably still come up
normally, but I'm not sure about the mechanics of that.

> +Ultracalls used by Skiboot
> +==========================
> +
> +UV_READ_SCOM
> +------------
> +
> +Perform an XSCOM read and put the value in a buffer.
> +
> +Syntax
> +~~~~~~
> +
> +.. code-block:: c
> +
> +        long ucall(unsigned long UV_READ_SCOM,
> +                unsigned long *retbuf,
> +                u64 partid,

I guess you mean chip id?

> +                u64 pcb_addr)
> +
> +Return values
> +~~~~~~~~~~~~~
> +
> +* U_SUCCESS     on success.
> +* U_PERMISSION  if called from VM context.
> +* U_PARAMETER   if invalid partiton or address.
partition?
> +* U_BUSY        if unit is busy.
> +
> +UV_WRITE_SCOM
> +-------------
> +
> +Perform an XSCOM write.
> +
> +Syntax
> +~~~~~~
> +
> +.. code-block:: c
> +
> +        long ucall(unsigned long UV_WRITE_SCOM,
> +                unsigned long *retbuf,

What's retbuf used for when doing a xscom write?

> +                u64 partid,
> +                u64 pcb_addr,
> +                u64 val)
> +
> +Return values
> +~~~~~~~~~~~~~
> +
> +One of the following values:
> +
> +* U_SUCCESS     on success.
> +* U_PERMISSION  if called from VM context
> +* U_PARAMETER   if invalid partiton
chip
> +* U_BUSY        if unit is busy

As a general comment we have these finer grained return codes from xscoms:

#define OPAL_XSCOM_BUSY         OPAL_BUSY
#define OPAL_XSCOM_CHIPLET_OFF  OPAL_WRONG_STATE
#define OPAL_XSCOM_PARTIAL_GOOD -25
#define OPAL_XSCOM_ADDR_ERROR   -26
#define OPAL_XSCOM_CLOCK_ERROR  -27
#define OPAL_XSCOM_PARITY_ERROR -28
#define OPAL_XSCOM_TIMEOUT      -29
#define OPAL_XSCOM_CTR_OFFLINED -30

Internally OPAL is going to bounce any XSCOMs from PRD or whatever to
the UV, so are we going to need those finer grained return codes? Is
that information accessible some other way? (HMER?).


More information about the Skiboot mailing list