diff mbox series

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

Message ID 20190920135823.471-2-grimm@linux.ibm.com
State RFC
Headers show
Series PEF support in skiboot | expand

Checks

Context Check Description
snowpatch_ozlabs/apply_patch success Successfully applied on branch master (470ffb5f29d741c3bed600f7bb7bf0cbb270e05a)
snowpatch_ozlabs/snowpatch_job_snowpatch-skiboot success Test snowpatch/job/snowpatch-skiboot on branch master
snowpatch_ozlabs/snowpatch_job_snowpatch-skiboot-dco success Signed-off-by present

Commit Message

Ryan Grimm Sept. 20, 2019, 1:58 p.m. UTC
Signed-off-by: Ryan Grimm <grimm@linux.ibm.com>
---
 doc/opal-uv-api.rst | 372 ++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 372 insertions(+)
 create mode 100644 doc/opal-uv-api.rst

Comments

Ryan Grimm Oct. 16, 2019, 2:31 p.m. UTC | #1
Oliver,

Can you check out this documententation about the interface between
OPAL and UV and let us know if it makes sense or if there are any
glaring technical problems?

http link: 
https://lists.ozlabs.org/pipermail/skiboot/2019-September/015320.html

Thanks,
Ryan
Oliver O'Halloran Nov. 17, 2019, 10:40 p.m. UTC | #2
On Fri, Sep 20, 2019 at 11:59 PM Ryan Grimm <grimm@linux.ibm.com> wrote:
>
> Signed-off-by: Ryan Grimm <grimm@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?).
diff mbox series

Patch

diff --git a/doc/opal-uv-api.rst b/doc/opal-uv-api.rst
new file mode 100644
index 00000000..d7151ca6
--- /dev/null
+++ b/doc/opal-uv-api.rst
@@ -0,0 +1,372 @@ 
+.. SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
+
+=================
+OPAL UV API (RFC)
+=================
+
+.. contents::
+    :depth: 3
+
+.. sectnum::
+    :depth: 3
+
+This document describes the function calling interface between OPAL
+and the Ultravisor.
+
+Protected Execution Facility
+############################
+
+Protected Execution Facility (PEF) is an architectural change for
+POWER 9 that enables Secure Virtual Machines (SVMs). When enabled,
+PEF adds a new higher privileged mode, called Ultravisor mode, to
+POWER architecture. Along with the new mode there is new firmware
+called the Protected Execution Ultravisor (or Ultravisor for short).
+Ultravisor mode is the highest privileged mode in POWER architecture.
+
++------------------+
+| Privilege States |
++==================+
+|  Problem         |
++------------------+
+|  Supervisor      |
++------------------+
+|  Hypervisor      |
++------------------+
+|  Ultravisor      |
++------------------+
+
+PEF protects SVMs from the hypervisor, privileged users, and other
+VMs in the system. SVMs are protected while at rest and can only be
+executed by an authorized machine. All virtual machines utilize
+hypervisor services. The Ultravisor filters calls between the SVMs
+and the hypervisor to assure that information does not accidentally
+leak. All hypercalls except H_RANDOM are reflected to the hypervisor.
+H_RANDOM is not reflected to prevent the hypervisor from influencing
+random values in the SVM.
+
+To support this there is a refactoring of the ownership of resources
+in the CPU. Some of the resources which were previously hypervisor
+privileged are now ultravisor privileged.
+
+Hardware
+========
+
+The hardware changes include the following:
+
+* There is a new bit in the MSR that determines whether the current
+  process is running in secure mode, MSR(S) bit 41. MSR(S)=1, process
+  is in secure mode, MSR(s)=0 process is in normal mode.
+
+* The MSR(S) bit can only be set by the Ultravisor.
+
+* HRFID cannot be used to set the MSR(S) bit. If the hypervisor needs
+  to return to a SVM it must use an ultracall. It can determine if
+  the VM it is returning to is secure.
+
+* There is a new Ultravisor privileged register, SMFCTRL, which has an
+  enable/disable bit SMFCTRL(E).
+
+* The privilege of a process is now determined by three MSR bits,
+  MSR(S, HV, PR). In each of the tables below the modes are listed
+  from least privilege to highest privilege. The higher privilege
+  modes can access all the resources of the lower privilege modes.
+
+**Secure Mode MSR Settings**
+
++---+---+---+---------------+
+| S | HV| PR|Privilege      |
++===+===+===+===============+
+| 1 | 0 | 1 | Problem       |
++---+---+---+---------------+
+| 1 | 0 | 0 | Privileged(OS)|
++---+---+---+---------------+
+| 1 | 1 | 0 | Ultravisor    |
++---+---+---+---------------+
+| 1 | 1 | 1 | Reserved      |
++---+---+---+---------------+
+
+**Normal Mode MSR Settings**
+
++---+---+---+---------------+
+| S | HV| PR|Privilege      |
++===+===+===+===============+
+| 0 | 0 | 1 | Problem       |
++---+---+---+---------------+
+| 0 | 0 | 0 | Privileged(OS)|
++---+---+---+---------------+
+| 0 | 1 | 0 | Hypervisor    |
++---+---+---+---------------+
+| 0 | 1 | 1 | Problem (HV)  |
++---+---+---+---------------+
+
+* Memory is partitioned into secure and normal memory. Only processes
+  that are running in secure mode can access secure memory.
+
+* The hardware does not allow anything that is not running secure to
+  access secure memory. This means that the Hypervisor cannot access
+  the memory of the SVM without using an ultracall (asking the
+  Ultravisor). The Ultravisor will only allow the hypervisor to see
+  the SVM memory encrypted.
+
+* I/O systems are not allowed to directly address secure memory. This
+  limits the SVMs to virtual I/O only.
+
+* The architecture allows the SVM to share pages of memory with the
+  hypervisor that are not protected with encryption. However, this
+  sharing must be initiated by the SVM.
+
+* When a process is running in secure mode all hypercalls
+  (syscall lev=1) are reflected to the Ultravisor.
+
+* When a process is in secure mode all interrupts go to the
+  Ultravisor.
+
+* The following resources have become Ultravisor privileged and
+  require an Ultravisor interface to manipulate:
+
+        * Processor configurations registers (SCOMs).
+
+        * Stop state information.
+
+        * The debug registers CIABR, DAWR, and DAWRX become Ultravisor
+          resources when SMFCTRL(D) is set. If SMFCTRL(D) is not set they do
+          not work in secure mode. When set, reading and writing requires
+          an Ultravisor call, otherwise that will cause a Hypervisor Emulation
+          Assistance interrupt.
+
+        * PTCR and partition table entries (partition table is in secure
+          memory). An attempt to write to PTCR will cause a Hypervisor
+          Emulation Assitance interrupt.
+
+        * LDBAR (LD Base Address Register) and IMC (In-Memory Collection)
+          non-architected registers. An attempt to write to them will cause a
+          Hypervisor Emulation Assistance interrupt.
+
+        * Paging for an SVM, sharing of memory with Hypervisor for an SVM.
+          (Including Virtual Processor Area (VPA) and virtual I/O).
+
+Software/Microcode
+==================
+
+The software changes include:
+
+* When the UV_ESM ultracall is made the Ultravisor copies the VM into
+  secure memory, decrypts the verification information, and checks the
+  integrity of the SVM. If the integrity check passes the Ultravisor
+  passes control in secure mode.
+
+The Ultravisor offers new services to the hypervisor and SVMs. These
+are accessed through ultracalls.
+
+Terminology
+===========
+
+* Hypercalls: special system calls used to request services from
+  Hypervisor.
+
+* Normal memory: Memory that is accessible to Hypervisor.
+
+* Normal page: Page backed by normal memory and available to
+  Hypervisor.
+
+* Secure memory: Memory that is accessible only to Ultravisor and
+  SVMs.
+
+* Secure page: Page backed by secure memory and only available to
+  Ultravisor and SVM.
+
+* SVM: Secure Virtual Machine.
+
+* Ultracalls: special system calls used to request services from
+  Ultravisor.
+
+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 {
+                        compatible = "ibm,uv-firmware";
+                        #address-cells = <0x2>;
+                        #size-cells = <0x2>;
+                        secure-memory-ranges = < 0x1003c 0x00000000 0x4 0x00000000
+                                                 0x1203c 0x00000000 0x4 0x00000000  >;
+                        reg = < 0x0 0xc0000000 >;
+                };
+        };
+
+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.
+
+``init_uv`` parses secure memory ranges and copies the UV into the start of the
+first available secure range.
+
+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, 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 */
+        };
+
+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``.
+
+.. code-block:: dts
+
+        ibm,uv-fdt {
+                 compatible = "ibm,uv-fdt";
+                 wrapping-key-password = "gUMShz6l2x4O9IeHrvBSuBR0FYANZTYK";
+        };
+
+The UV parses ``sys_fdt``, creates internal structures, and threads return in
+hypervisor privilege mode and 0 in ``uv_ret_code``.
+
+If successful, skiboot sets a variable named ``uv_present`` to true.  Skiboot uses
+the macro ``is_uv_present`` to dermine if the UV is initialized and ready to
+perform ucalls.
+
+uv_base_addr is not needed by the UV but is used by ``cpu_start_ultravisor``.  This
+member could be moved into a separate structure for ``cpu_start_ultravisor``.
+
+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.]
+
+Ultracalls
+##########
+
+Ultravisor calls API
+====================
+
+This section describes Ultravisor calls (ultracalls) needed by skiboot.
+The ultracalls allow the skiboot to request services from the
+Ultravisor such as initializing a chip unit via XSCOM.
+
+The specific service needed from an ultracall is specified in register
+R3 (the first parameter to the ultracall). Other parameters to the
+ultracall, if any, are specified in registers R4 through R12.
+
+Return value of all ultracalls is in register R3. Other output values
+from the ultracall, if any, are returned in registers R4 through R12.
+
+Each ultracall returns specific error codes, applicable in the context
+of the ultracall. However, like with the PowerPC Architecture Platform
+Reference (PAPR), if no specific error code is defined for a
+particular situation, then the ultracall will fallback to an erroneous
+parameter-position based code. i.e U_PARAMETER, U_P2, U_P3 etc
+depending on the ultracall parameter that may have caused the error.
+
+For now this only covers ultracalls currently implemented and being used by
+skiboot but others can be added here when it makes sense.
+
+The full specification for all ultracalls will eventually be made available in
+the public/OpenPower version of the PAPR specification.
+
+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,
+                u64 pcb_addr)
+
+Return values
+~~~~~~~~~~~~~
+
+* U_SUCCESS     on success.
+* U_PERMISSION  if called from VM context.
+* U_PARAMETER   if invalid partiton or address.
+* 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,
+                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
+* U_BUSY        if unit is busy
+
+References
+##########
+
+.. [1] `Supporting Protected Computing on IBM Power Architecture <https://developer.ibm.com/articles/l-support-protected-computing/>`_