blob: b34e43aa8dae35b59c405fa22de4b86658436066 [file] [log] [blame] [view]
OpenSBI Domain Support
======================
An OpenSBI domain is a system-level partition (subset) of underlying hardware
having its own memory regions (RAM and MMIO devices) and HARTs. The OpenSBI
will try to achieve secure isolation between domains using RISC-V platform
features such as PMP, ePMP, IOPMP, SiFive Shield, etc.
Important entities which help implement OpenSBI domain support are:
* **struct sbi_domain_memregion** - Representation of a domain memory region
* **struct sbi_hartmask** - Representation of domain HART set
* **struct sbi_domain** - Representation of a domain instance
Each HART of a RISC-V platform must have an OpenSBI domain assigned to it.
The OpenSBI platform support is responsible for populating domains and
providing HART id to domain mapping. The OpenSBI domain support will by
default assign **the ROOT domain** to all HARTs of a RISC-V platform, so
it is not mandatory for the OpenSBI platform support to populate domains.
Domain Memory Region
--------------------
A domain memory region is represented by **struct sbi_domain_memregion** in
OpenSBI and has following details:
* **order** - The size of a memory region is **2 ^ order** where **order**
must be **3 <= order <= __riscv_xlen**
* **base** - The base address of a memory region is **2 ^ order**
aligned start address
* **flags** - The flags of a memory region represent memory type (i.e.
RAM or MMIO) and allowed accesses (i.e. READ, WRITE, EXECUTE, etc.)
Domain Instance
---------------
A domain instance is represented by **struct sbi_domain** in OpenSBI and
has following details:
* **index** - Logical index of this domain
* **name** - Name of this domain
* **assigned_harts** - HARTs assigned to this domain
* **possible_harts** - HARTs possible in this domain
* **hartindex_to_context_table** - Contexts corresponding to possible HARTs
* **regions** - Array of memory regions terminated by a memory region
with order zero
* **boot_hartid** - HART id of the HART booting this domain. The domain
boot HART will be started at boot-time if boot HART is possible and
assigned for this domain.
* **next_addr** - Address of the next booting stage for this domain
* **next_arg1** - Arg1 (or 'a1' register) of the next booting stage for
this domain
* **next_mode** - Privilege mode of the next booting stage for this
domain. This can be either S-mode or U-mode.
* **system_reset_allowed** - Is domain allowed to reset the system?
* **system_suspend_allowed** - Is domain allowed to suspend the system?
The memory regions represented by **regions** in **struct sbi_domain** have
following additional constraints to align with RISC-V PMP requirements:
* A memory region to protect OpenSBI firmware from S-mode and U-mode
should always be present
* For two overlapping memory regions, one should be sub-region of another
* Two overlapping memory regions should not be of same size
* Two overlapping memory regions cannot have same flags
* Memory access checks on overlapping address should prefer smallest
overlapping memory region flags.
ROOT Domain
-----------
**The ROOT domain** is the default OpenSBI domain which is assigned by
default to all HARTs of a RISC-V platform. The OpenSBI domain support
will hand-craft **the ROOT domain** very early at boot-time in the
following manner:
* **index** - Logical index of the ROOT domain is always zero
* **name** - Name of the ROOT domain is "root"
* **assigned_harts** - At boot-time all valid HARTs of a RISC-V platform
are assigned the ROOT domain which changes later based on OpenSBI
platform support
* **possible_harts** - All valid HARTs of a RISC-V platform are possible
HARTs of the ROOT domain
* **hartindex_to_context_table** - Contexts corresponding to ROOT domain's possible HARTs
* **regions** - Two memory regions available to the ROOT domain:
**A)** A memory region to protect OpenSBI firmware from S-mode and U-mode
**B)** A memory region of **order=__riscv_xlen** allowing S-mode and
U-mode access to full memory address space
* **boot_hartid** - Coldboot HART is the HART booting the ROOT domain
* **next_addr** - Next booting stage address in coldboot HART scratch
space is the next address for the ROOT domain
* **next_arg1** - Next booting stage arg1 in coldboot HART scratch space
is the next arg1 for the ROOT domain
* **next_mode** - Next booting stage mode in coldboot HART scratch space
is the next mode for the ROOT domain
* **system_reset_allowed** - The ROOT domain is allowed to reset the system
* **system_suspend_allowed** - The ROOT domain is allowed to suspend the system
Domain Effects
--------------
Few noteworthy effects of a system partitioned into domains are as follows:
* At any point in time, a HART is running in exactly one OpenSBI domain context
* The SBI IPI and RFENCE calls from HART A are restricted to the HARTs in
domain assigned to HART A
* The SBI HSM calls which try to change/read state of HART B from HART A will
only work if both HART A and HART B are assigned same domain
* A HART running in S-mode or U-mode can only access memory based on the
memory regions of the domain assigned to the HART
Domain Device Tree Bindings
---------------------------
The OpenSBI domains can be described in the **device tree (DT) blob** (or
flattened device tree) passed to the OpenSBI firmwares by the previous
booting stage. This allows OpenSBI platform support to parse and populate
OpenSBI domains from the device tree blob (or flattened device tree).
### Domain Configuration Node
All OpenSBI domain description related DT nodes should be under the domain
configuration DT node. The **/chosen** DT node is the preferred parent of
the domain configuration DT node.
The DT properties of a domain configuration DT node are as follows:
* **compatible** (Mandatory) - The compatible string of the domain
configuration. This DT property should have value *"opensbi,domain,config"*
### Domain Memory Region Node
The domain memory region DT node describes details of a memory region and
can be pointed by multiple domain instance DT nodes. The access permissions
of the memory region are specified separately in domain instance node.
The DT properties of a domain memory region DT node are as follows:
* **compatible** (Mandatory) - The compatible string of the domain memory
region. This DT property should have value *"opensbi,domain,memregion"*
* **base** (Mandatory) - The base address of the domain memory region. This
DT property should have a **2 ^ order** aligned 64 bit address (i.e. two
DT cells).
* **order** (Mandatory) - The order of the domain memory region. This DT
property should have a 32 bit value (i.e. one DT cell) in the range
**3 <= order <= __riscv_xlen**.
* **mmio** (Optional) - A boolean flag representing whether the domain
memory region is a memory-mapped I/O (MMIO) region.
* **devices** (Optional) - The list of device DT node phandles for devices
which fall under this domain memory region.
### Domain Instance Node
The domain instance DT node describes set of possible HARTs, set of memory
regions, and other details of a domain instance.
The DT properties of a domain instance DT node are as follows:
* **compatible** (Mandatory) - The compatible string of the domain instance.
This DT property should have value *"opensbi,domain,instance"*
* **possible-harts** (Optional) - The list of CPU DT node phandles for the
the domain instance. This list represents the possible HARTs of the
domain instance.
* **regions** (Optional) - The list of domain memory region DT node phandle
and access permissions for the domain instance. Each list entry is a pair
of DT node phandle and access permissions. The access permissions are
represented as a 32bit bitmask having bits: **M readable** (BIT[0]),
**M writeable** (BIT[1]), **M executable** (BIT[2]), **SU readable**
(BIT[3]), **SU writable** (BIT[4]), and **SU executable** (BIT[5]).
The enforce permission bit (BIT[6]), if set, will lock the permissions
in the PMP. This will enforce the permissions on M-mode as well which
otherwise will have unrestricted access. This bit must be used with
caution because no changes can be made to a PMP entry once its locked
until the hart is reset.
Any region of a domain defined in DT node cannot have only M-bits set
in access permissions i.e. it cannot be an m-mode only accessible region.
* **boot-hart** (Optional) - The DT node phandle of the HART booting the
domain instance. If coldboot HART is assigned to the domain instance then
this DT property is ignored and the coldboot HART is assumed to be the
boot HART of the domain instance.
* **next-arg1** (Optional) - The 64 bit next booting stage arg1 for the
domain instance. If this DT property is not available and coldboot HART
is not assigned to the domain instance then **0x0** is used as default
value. If this DT property is not available and coldboot HART is assigned
to the domain instance then **next booting stage arg1 of coldboot HART**
is used as default value.
* **next-addr** (Optional) - The 64 bit next booting stage address for the
domain instance. If this DT property is not available and coldboot HART
is not assigned to the domain instance then **0x0** is used as default
value. If this DT property is not available and coldboot HART is assigned
to the domain instance then **next booting stage address of coldboot HART**
is used as default value.
* **next-mode** (Optional) - The 32 bit next booting stage mode for the
domain instance. The possible values of this DT property are: **0x1**
(S-mode), and **0x0** (U-mode). If this DT property is not available
and coldboot HART is not assigned to the domain instance then **0x1**
is used as default value. If this DT property is not available and
coldboot HART is assigned to the domain instance then **next booting
stage mode of coldboot HART** is used as default value.
* **system-reset-allowed** (Optional) - A boolean flag representing
whether the domain instance is allowed to do system reset.
* **system-suspend-allowed** (Optional) - A boolean flag representing
whether the domain instance is allowed to do system suspend.
### Assigning HART To Domain Instance
By default, all HARTs are assigned to **the ROOT domain**. The OpenSBI
platform support can provide the HART to domain instance assignment using
platform specific callback.
The HART to domain instance assignment can be parsed from the device tree
using optional DT property **opensbi-domain** in each CPU DT node. The
value of DT property **opensbi-domain** is the DT phandle of the domain
instance DT node. If **opensbi-domain** DT property is not specified then
corresponding HART is assigned to **the ROOT domain**.
### Domain Configuration Only Accessible to OpenSBI
The software running inside a domain instance should only be aware of
devices and hardware resources accessible to itself.
To hide domain configuration from domain instances, the following should
be done:
* The previous booting stage should preferably provide a separate device
tree for each domain instance and mention location of device tree in
respective domain instance DT nodes using **next-arg1** DT property.
* If domain assigned to a HART does not have separate device tree then
OpenSBI platform support should remove all domain configuration details
from the device tree passed by previous booting stage before passing it
to the next booting stage.
### Example
```
chosen {
opensbi-domains {
compatible = "opensbi,domain,config";
tmem: tmem {
compatible = "opensbi,domain,memregion";
base = <0x0 0x80100000>;
order = <20>;
};
tuart: tuart {
compatible = "opensbi,domain,memregion";
base = <0x0 0x10011000>;
order = <12>;
mmio;
devices = <&uart1>;
};
allmem: allmem {
compatible = "opensbi,domain,memregion";
base = <0x0 0x0>;
order = <64>;
};
tdomain: trusted-domain {
compatible = "opensbi,domain,instance";
possible-harts = <&cpu0>;
regions = <&tmem 0x3f>, <&tuart 0x3f>;
boot-hart = <&cpu0>;
next-arg1 = <0x0 0x0>;
next-addr = <0x0 0x80100000>;
next-mode = <0x0>;
system-reset-allowed;
system-suspend-allowed;
};
udomain: untrusted-domain {
compatible = "opensbi,domain,instance";
possible-harts = <&cpu1 &cpu2 &cpu3 &cpu4>;
regions = <&tmem 0x0>, <&tuart 0x0>, <&allmem 0x3f>;
};
};
};
cpus {
#address-cells = <1>;
#size-cells = <0>;
timebase-frequency = <10000000>;
cpu0: cpu@0 {
device_type = "cpu";
reg = <0x00>;
compatible = "riscv";
opensbi-domain = <&tdomain>;
...
};
cpu1: cpu@1 {
device_type = "cpu";
reg = <0x01>;
compatible = "riscv";
opensbi-domain = <&udomain>;
...
};
cpu2: cpu@2 {
device_type = "cpu";
reg = <0x02>;
compatible = "riscv";
opensbi-domain = <&udomain>;
...
};
cpu3: cpu@3 {
device_type = "cpu";
reg = <0x03>;
compatible = "riscv";
opensbi-domain = <&udomain>;
...
};
cpu4: cpu@4 {
device_type = "cpu";
reg = <0x04>;
compatible = "riscv";
opensbi-domain = <&udomain>;
...
};
};
uart1: serial@10011000 {
...
};
```