Contributors to this document include (in alphabetical order): Jason Zhijingcheng Yu
Version Information: Draft version. Refer to the commit hash.
1. Introduction
The Capstone project is an effort to explore the design of a new CPU instruction set architecture that achieves multiple security goals including memory safety and isolation with one unified hardware abstraction.
Other formats: This document is also available in the following formats:
1.1. Goals
The ultimate goal of Capstone is to unify the numerous hardware abstracts that have been added as extensions to existing architectures as afterthought mitigations to security vulnerabilities. This goal requires a high level of flexibility and extensibility of the Capstone architecture. More specifically, we aim to support the following in a unified manner.
- Exclusive access
-
Software should be guaranteed exclusive access to certain memory regions if needed. This is in spite of the existence of software traditionally entitled to higher privileges such as the OS kernel and the hypervisor.
- Revocable delegation
-
Software components should be able to delegate authority to other components in a revocable manner. For example, after an untrusted library function has been granted access to a memory region, the caller should be able to revoke this access.
- Dynamically extensible hierarchy
-
The hierarchy of authority should be dynamically extensible, unlike traditional platforms which follow a static hierarchy of hypervisor-kernel-user. This makes it possible to use the same set of abstractions for memory isolation and memory sharing regardless of where a software component lies in the hierarchy.
- Safe context switching
-
A mechanism of context switching without trusting any other software component should be provided. This allows for a minimal TCB if necessary in case of a highly security-critical application.
1.2. Major Design Elements
The Capstone architecture design is based on the idea of capabilities, which are unforgeable tokens that represent authority to perform memory accesses and control flow transfers. Capstone extends the traditional capability model with new capability types including the following.
- Linear capabilities
-
Linear capabilities are guaranteed not to alias with other capabilities. Operations on linear capabilities maintain this property. For example, linear capabilities cannot be duplicated. Instead, they can only be moved around across different registers or between registers and memory. They can hence enable safe exclusive access to memory regions. Capabilities that do not have this property are called non-linear capabilities.
- Revocation capabilities
-
Revocation capabilities cannot be used to perform memory accesses or control flow transfers. Instead, they convey the authority to revoke other capabilities. Each revocation capability is derived from a linear capability and can later be used to revoke (i.e., invalidate) capability derived from the same linear capability. This mechanism enables revocable and arbitrarily extensible chains of delegation of authority.
- Uninitialised capabilities
-
Uninitialised capabilities convey write-only authority to memory. They can be turned into linear capabilities after the memory region has been "initialised", that is, when the whole memory region has been overwritten with fresh data. Uninitialised capabilities enable safe initialisation of memory regions and prevent secret leakage without incurring extra performance overhead.
1.3. Capstone-RISC-V ISA Overview
While Capstone does not assume any specific modern ISA, we choose to propose a Capstone extension to RISC-V due to its open nature and the availability of toolchains and simulators.
The Capstone-RISC-V ISA is a 64-bit RISC-V extension that makes the following types of changes to the base architecture:
-
Each general-purpose register is extended to 129 bits to accommodate 128-bit capabilities.
-
New instructions for manipulating capabilities are added.
-
New instructions for memory accesses using capabilities are added.
-
New instructions for control flow transfers using capabilities are added.
-
Semantics of a small number of existing instructions are changed to support capabilities.
-
Semantics of interrupts and exceptions are changed to support capabilities.
1.4. Assembly Mnemonics
Each Capstone-RISC-V instruction is given a mnemonic prefixed with CS..
In contexts where it is clear we are discussing Capstone-RISC-V instructions,
we will omit the CS. prefix for brevity.
In assembly code, the list of operands to an instruction is supplied following the
instruction mnemonic, with the operands separated by commas, in the order of
rd, rs1, rs2, imm for any operand the instruction expects.
1.5. Notations
When specifying the semantics of instructions, we use the following notations to represent the type of each operand:
- I
-
Integer register.
- C
-
Capability register.
- S
-
Sign-extended immediate.
- Z
-
Zero-extended immediate.
1.6. Bibliography
The initial design of Capstone has been discussed in the following paper:
-
Capstone: A Capability-based Foundation for Trustless Secure Memory Access by Jason Zhijingcheng Yu, Conrad Watt, Aditya Badole, Trevor E. Carlson, Prateek Saxena. In Proceedings of the 32nd USENIX Security Symposium. Anaheim, CA, USA. August 2023.
2. Programming Model
The Capstone-RISC-V ISA has extended the part of the machine state, including both some registers and the memory, to enable the storage and handling of capabilities.
2.1. Capabilities
2.1.1. Width
The width of a capability is 128 bits. We represent this as
CLEN = 128 and CLENBYTES = 16. Note that this does not
affect the width of a raw address, which is XLEN = 64 bits
(i.e., XLENBYTES = 8 bytes).
2.1.2. Fields
Each capability has the following architecturally-visible fields:
| Name | Range | Description |
|---|---|---|
|
|
Whether the capability is valid: |
|
|
The type of the capability:
|
|
|
Not applicable when |
|
|
Not applicable when |
|
|
Not applicable when |
|
|
Not applicable when |
|
|
Only applicable when |
|
|
Only applicable when |
The range of the perms field has a partial order ⇐ defined as follows:
<= = { (0, 0), (1, 1), (2, 2), (3, 3), (4, 4), (0, 1), (0, 2), (0, 3), (0, 4),
(1, 2), (1, 3), (1, 4), (2, 4), (3, 4) }
We say a capability c aliases with a capability d if and only if the intersection
between [c.base, c.end) and [d.base, d.end) is non-empty.
For two revocation capabilities c and d (i.e., c.type = d.type = 2),
we say c <t d if and only if
-
caliases withd -
The creation of
cwas earlier than the creation ofd
In addition to the above fields, an implementation also needs to maintain
sufficient metadata to test the <t relation.
It will be clear that for any pair of revocation capabilities that alias,
the order of their creations is well-defined.
2.2. Variants
Capstone currently supports two variants of the ISA, i.e. Pure Capstone and TransCapstone.
While Pure Capstone is a pure capability-based ISA, TransCapstone is a hybrid ISA that
supports both capabilities and traditional virtual memory. In TransCapstone, the memory
is divided into two parts, i.e., the secure memory and the untrusted memory. The range of
the secure memory is defined as [SBASE, SEND), where SBASE and SEND are required to
be aligned to CLEN bits. These two variants share most of the parts of the ISA, and separate
descriptions are provided for the parts that are different.
2.3. Extension to General-Purpose Registers
The Capstone-RISC-V ISA extends each of the 32 general-purpose
registers, so it contains either a capability or a raw XLEN-bit
integer.
The type of data contained in a register is maintained and confusion
of the type is not allowed, except for x0/c0 as discussed below.
In assembly code, the type of data expected in a register operand
is indicated by the alias used for the register, as summarised
in the following table.
XLEN-bit integer |
Capability |
|---|---|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
x0/c0 is a read-only register that can be used both as an
integer and as a capability, depending on the context. When used
as an integer, it has the value 0.
When used as a capability, it has the value
{ valid = 0, type = 0, cursor = 0, base = 0, end = 0, perms = 0 }.
Any attempt to write to x0/c0 will be silently ignored (no
exceptions are raised).
2.4. Extension to Other Registers
2.4.1. Program Counter
-
Pure Capstone: The program counter (
pc) is extended to contain a capability. -
TransCapstone: Similar to the general-purpose registers, the program counter (
pc) is also extended to contain a capability or an integer.
When pc contains a capability, some of the fields of the capability
are checked before each instruction fetch.
An exception is raised when any of the following conditions are met:
-
The
validfield of the capability inpcis0(invalid). -
The
cursorfield of the capability inpcis not aligned to4. -
The bound of the capability in
pcis[base, end), wherebaseandendare thebaseandendfields of the capability inpc, and thecursorfield of the capability inpcis not in the range[base, end-4](i.e.,cursor < baseorcursor > end-4).
If no exception is raised, the instruction pointed to by the cursor
field of the capability in pc is fetched and executed. The cursor
field of the capability in pc is then incremented by 4 (i.e.,
cursor += 4).
2.5. Added Registers
The Capstone-RISC-V ISA adds the following registers:
Capstone Variant |
Additional Registers |
||||||||||||||
Pure Capstone |
|
||||||||||||||
TransCapstone |
|
TODO: talk about how to read/write those registers, especially ceh, which is crucial
to the liveness of the system.
2.6. Extension to Memory
The memory is addressed using an XLEN-bit integer at byte-level
granularity.
In addition to raw integers, each CLEN-bit aligned address can
also store a capability.
The type of data contained in a memory location is maintained and
confusion of the type is not allowed.
2.7. Instruction Set
The Capstone-RISC-V instruction set is based on the RV64G instruction set.
The (uncompressed) instructions are fixed 32-bit wide, and laid out in memory
in little-endian order. In the encoding space of the RV64G instruction set,
Capstone-RISC-V instructions occupies the "custom-2" subset, i.e., the opcode
of all Capstone-RISC-V instructions is 0b1011011.
Capstone-RISC-V instruction encodings follow two basic formats: R-type and I-type, as described below (more details are also provided in the RISC-V ISA Manual).
R-type instructions receive up to three register operands, and I-type instructions receive up to two register operands and a 12-bit-wide immediate operand.
3. Capability Manipulation Instructions
Capstone provides instructions for creating, modifying, and destroying capabilities. Note that due to the guarantee of provenance of capabilities, those instructions are the only way to manipulate capabilities. In particular, it is not possible to manipulate capabilities by manipulating the content of a memory location or register using other instructions.
3.1. Cursor, Bounds, and Permissions Manipulation
3.1.1. Capability Movement
Capabilities can be moved between registers with the MOVC instruction.
An exception is raised when any of the following conditions are met:
-
rs1does not contain a capability
If no exception is raised:
If rs1 is the same register as rd, the instruction is a no-op.
If rs1 is not the same register as rd, rd will contain the original content of
rs1, and if the content is not a non-linear capability (i.e., type != 1) or
an exit capability (i.e., type != 6),
rs1 will be set to the content of cnull.
3.1.2. Cursor Increment
The CINCOFFSET and CINCOFFSETIMM instructions increment the cursor of a
capability by a give amount (offset).
An exception is raised when any of the following conditions are met:
-
rs1does not contain a capability. -
rs2does not contain an integer (for CINCOFFSET). -
The capability in
rs1does not havetype = 0(linear) ortype = 1(non-linear).
If no exception is raised:
For CINCOFFSET, the offset is read from rs2.
For CINCOFFSETIMM, the offset is the 12-bit sign-extended immediate field
imm. If the offset is 0, the instructions are semantically equivalent to
MOVC rd, rs1. Otherwise, the instructions are equal to an atomic execution
of MOVC rd, rs1 followed by an increment of the cursor field of rd by
the offset.
3.1.3. Cursor Setter and Getter
The cursor field of a capability can also be directly set and read with
the SCC and LCC instructions respectively.
For SCC, an exception is raised if any of the following conditions are met:
-
rddoes not contain a capability. -
rs1does not contain an integer. -
The capability in
rddoes not havetype = 0(linear) ortype = 1(non-linear).
For LCC, an exception is raised if any of the following conditions are met:
-
rs1does not contain a capability. -
The capability in
rs1does not havetype = 0(linear),type = 1(non-linear), ortype = 3(uninitialised).
3.1.4. Bounds Shrinking
The bounds (base and end fields) of a capability can be shrunk with the SHRINK instruction.
The instruction reads rs1 and rs2 and attempts to set the bounds of the capability in
rd to [rs1, rs2).
An exception is raised when any of the following conditions are met:
-
rddoes not contain a capability. -
The
validfield of the capability inrdis0(invalid). -
The
typefield of the capability inrdis not0,1, or3(linear, non-linear, or uninitialised). -
rs1does not contain an integer. -
rs2does not contain an integer. -
rs1 >= rs2. -
The original bounds of the capability in
rdare[base, end)andrs1 < baseorrs2 > end.
3.1.5. Bounds Splitting
The SPLIT instruction can split a capability into two by splitting the bounds.
The instruction reads a capability from rs1 and an integer from rs2 and attempts to split
the capability into two capabilities, one with bounds [base, rs2) and the other with bounds
[rs2, end), assuming the original bounds were [base, end).
An exception is raised when any of the following conditions are met:
-
rs1does not contain a capability. -
The
validfield of the capability inrs1is0(invalid). -
rs2does not contain an integer. -
The
typefield of the capability inrs1is neither0nor1(neither linear nor non-linear). -
The original bounds of the capability in
rs1are[base, end)andrs2 <= baseorrs2 >= end.
If no exception is raised: The capability in rs1 has its end field set to rs2. A new
capability is created with base = rs2 and the other fields equal to those of the original
capability in rs1. The new capability is written to rd.
3.1.6. Permission Tightening
The TIGHTEN instruction tightens the permissions (perms field) of a capability.
The instruction reads the new permissions from rs1 and attempts to set the perms field
of the capability in rd to rs1.
An exception is raised when any of the following conditions are met:
-
rddoes not contain a capability. -
The
validfield of the capability inrdis0(invalid). -
The
typefield of the capability inrdis not0,1, or3(linear, non-linear, or uninitialised). -
rs1does not contain an integer. -
The content of
rs1is outside the range ofperms. -
The
permsfield of the capability inrdispandrs1 ⇐ pdoes not hold.
3.2. Type Manipulation
Some instructions affect the type field of a capability.
3.2.1. Delinearisation
The DELIN instruction delinearises a linear capability.
An exception is raised when any of the following conditions are met:
-
rddoes not contain a capability. -
The
validfield of the capability inrdis0(invalid). -
The
typefield of the capability inrdis not0(linear).
If no exception is raised: The type field of the capability in rd
is set to 1 (non-linear).
3.2.2. Initialisation
The INIT instruction transforms an uninitialised capability into a linear capability after its associated memory region has been fully initialised (written with new data).
An exception is raised when any of the following conditions are met:
-
rddoes not contain a capability. -
The
validfield of the capability inrdis0(invalid). -
The
typefield of the capability inrdis not3(uninitialised). -
The
endfield and thecursorfield of the capability inrdare not equal.
If no exception is raised: The type field of the capability in rd
is set to 0 (linear).
3.2.3. Sealing
The SEAL instruction seals a linear capability.
An exception is raised when any of the following conditions are met:
-
rddoes not contain a capability. -
The
validfield of the capability inrdis0(invalid). -
The
typefield of the capability inrdis not0(linear). -
The
permsfield of the capability inrdis not3(read-write) or4(read-write-execute). -
The size of the memory region associated with the capability in
rdis smaller thanCLENBYTES * 32bytes. That is,end - base < CLENBYTES * 32.
If no exception is raised: The type field of the capability in rd
is set to 2 (sealed).
3.3. Dropping
TODO: check whether dropping is actually necessary.
The DROP instruction invalidates a capability.
An exception is raised when any of the following conditions are met:
-
rs1does not contain a capability. -
The
validfield of the capability inrs1is0(invalid).
If no exception is raised: The valid field of the capability in rs1
is set to 0 (invalid).
3.4. Revocation
3.4.1. Revocation Capability Creation
The MREV instruction creates a revocation capability.
An exception is raised when any of the following conditions are met:
-
rs1does not contain a capability. -
The
typefield of the capability inrs1is not0(linear). -
The
validfield of the capability inrs1is0(invalid).
If no exception is raised: A new capability is created in rd with the same
base, end, perms and cursor fields as the capability in rs1.
The type field of the new capability is set to 2 (revocation).
3.4.2. Revocation Operation
The REVOKE instruction revokes a capability.
An exception is raised when any of the following conditions are met:
-
rs1does not contain a capability. -
The
typefield of the capability inrs1is not2(revocation). -
The
validfield of the capability inrs1is0(invalid).
If no exception is raised:
For all capabilities c in the system (in either a register or
memory location), its valid field is set to 0 (invalid)
if any of the following conditions are met:
-
The type field of
cis not2(revocation), thevalidfield ofcis1(valid), andcaliases withrs1 -
The type field of
cis2(revocation), thevalidfield ofcis1(valid), andrs1 <t c
The type field of the capability in rs1 is set to 0 (linear)
if any of the following conditions are met for each invalidated c:
-
The type of
cis non-linear (i.e.,c.type != 1) -
The
permsfield ofcis not3(read-write) or4(read-write-execute)
Otherwise, the type field of the capability in rs1 is set to 3 (uninitialised),
and its cursor field is set to base.
4. Memory Access Instructions
Capstone provides instructions to load from and store to memory regions using capabilities.
4.1. Load/Store with Capabilities
Capstone offers a set of instructions for loading and storing integers of various sizes using capabilities.
4.1.1. Load
The LDD, LDW, LDH, LDB instructions load an integer in the size of doubleword, word,
halfword, and byte respectively.
In Capstone, a doubleword is defined as XLENBYTES bytes, a word, halfword, and byte
are defined as XLENBYTES/2, XLENBYTES/4, and XLENBYTES/8 bytes respectively.
An exception is raised when any of the following conditions are met:
-
rs1does not contain a capability. -
The
typefield of the capability inrs1is neither0(linear) nor1(non-linear). -
The
validfield of the capability inrs1is0(invalid). -
The
permsfield of the capability inrs1is0(no access). -
The bound of the capability in
rs1is[base, end), wherebaseandendare thebaseandendfields of the capability inrs1, and thecursorfield of the capability inrs1is not in the range[base, end-size](i.e.,cursor < baseorcursor > end-size), wheresizeis the size (in bytes) of the integer being loaded. -
The
cursorfield of the capability inrs1is not aligned to the size of the integer being loaded.
If no exception is raised: Load the content at the memory location [cursor, cursor + size) as an integer,
where cursor is the cursor field of the capability in rs1 and size is the size of the integer
(i.e., XLENBYTES, XLENBYTES/2, XLENBYTES/4, or XLENBYTES/8 bytes for LDD, LDW, LDH, and LDB respectively), to rd.
4.1.2. Store
The STD, STW, STH, STB instructions store an integer in the size of doubleword, word, halfword, and byte respectively.
An exception is raised when any of the following conditions are met:
-
rs1does not contain a capability. -
The
typefield of the capability inrs1is not0,1, or3(linear, non-linear, or uninitialized). -
The
validfield of the capability inrs1is0(invalid). -
The
permsfield of the capability inrs1is not3or4(read-write or read-write-execute). -
The bound of the capability in
rs1is[base, end), wherebaseandendare thebaseandendfields of the capability inrs1, and thecursorfield of the capability inrs1is not in the range[base, end-size](i.e.,cursor < baseorcursor > end-size), wheresizeis the size (in bytes) of the integer being loaded. -
The
cursorfield of the capability inrs1is not aligned to the size of the scalar value being loaded. -
rs2does not contain an integer.
If no exception is raised: Store the integer in rs2 to the memory location [cursor, cursor + size),
where cursor is the cursor field of the capability in rs1 and size is the size of the integer
(i.e., XLENBYTES, XLENBYTES/2, XLENBYTES/4, or XLENBYTES/8 bytes for STD, STW, STH, and STB respectively).
The cursor field of the capability in rs1 is set to cursor + size. The data contained in the CLEN-bit aligned
memory location [cbase, cend), which alias with memory location [cursor, cursor + size)
(i.e., cbase = cursor & ~(CLENBYTES - 1) and cend = cbase + CLENBYTES), will be interpreted as an integer type.
4.2. Load/Store Capabilities
In Capstone, two specific instructions (i.e., LDC and LTC) are used to load and store capabilities.
4.2.1. Load Capabilities
The LDC instruction loads a capability from memory.
An exception is raised when any of the following conditions are met:
-
rs1does not contain a capability. -
The
typefield of the capability inrs1is neither0(linear) nor1(non-linear). -
The
validfield of the capability inrs1is0(invalid). -
The
permsfield of the capability inrs1is0(no access). -
The bound of the capability in
rs1is[base, end), wherebaseandendare thebaseandendfields of the capability inrs1, and thecursorfield of the capability inrs1is not in the range[base, end-CLENBYTES](i.e.,cursor < baseorcursor > end-CLENBYTES). -
The
cursorfield of the capability inrs1is not aligned toCLENbits. -
The data contained in the memory location
[cursor, cursor + CLENBYTES), wherecursoris thecursorfield of the capability inrs1, is not a capability. -
The capability being loaded is not a non-linear capability (i.e.,
type != 1), and thepermsfield of the capability inrs1is not3or4(read-write or read-write-execute).
If no exception is raised: Load the capability at the memory location [cursor, cursor + CLENBYTES), where cursor
is the cursor field of the capability in rs1, into rd. If the capability being loaded is not a non-linear
capability (i.e., type != 1), the data contained in the memory location [cursor, cursor + CLENBYTES) will be
set to the content of cnull.
4.2.2. Store Capabilities
The STC instruction stores a capability to memory.
An exception is raised when any of the following conditions are met:
-
rs1does not contain a capability. -
The
typefield of the capability inrs1is not0,1, or3(linear, non-linear, or uninitialized). -
The
validfield of the capability inrs1is0(invalid). -
The
permsfield of the capability inrs1is not3or4(read-write or read-write-execute). -
The bound of the capability in
rs1is[base, end), wherebaseandendare thebaseandendfields of the capability inrs1, and thecursorfield of the capability inrs1is not in the range[base, end-CLENBYTES](i.e.,cursor < baseorcursor > end-CLENBYTES). -
The
cursorfield of the capability inrs1is not aligned toCLENbits. -
rs2does not contain a capability.
If no exception is raised: Store the capability in rs2 to the memory location [cursor, cursor + CLENBYTES),
where cursor is the cursor field of the capability in rs1. The cursor field of the capability in rs1
is set to cursor + CLENBYTES. If the capability in rs2 is not a non-linear capability (i.e., type != 1),
rs2 will be set to the content of cnull.
4.3. TransCapstone Added Instructions
In TransCapstone, besides the LDC and STC instructions, two additional instructions (i.e., LDCR and STCR) are added to load and store capabilities from/to the normal memory using raw addresses. These 2 instructions are only available in TransCapstone and an exception will be raised if they are executed in Pure Capstone.
4.3.1. Load with Raw Addresses
The LDCR instruction loads a capability from the normal memory using raw addresses.
An exception is raised when any of the following conditions are met:
-
rs1does not contain an integer. -
The integer in
rs1is not aligned toCLENbits. -
The integer in
rs1is in the range[SBASE, SEND)(i.e.,SBASE <= rs1 < SEND). -
The data contained in the memory location
[rs1, rs1 + CLENBYTES)is not a capability.
If no exception is raised: Load the capability at the memory location [rs1, rs1 + CLENBYTES) into rd.
If the capability being loaded is a non-linear capability (i.e. type != 1), the data contained in the
memory location [rs1, rs1 + CLENBYTES) will be set to the content of cnull.
4.3.2. Store with Raw Addresses
The STCR instruction stores a capability to the normal memory using raw addresses.
An exception is raised when any of the following conditions are met:
-
rs1does not contain an integer. -
The integer in
rs1is not aligned toCLENbits. -
The integer in
rs1is in the range[SBASE, SEND)(i.e.,SBASE <= rs1 < SEND). -
rs2does not contain a capability.
If no exception is raised: Store the capability in rs2 to the memory location [rs1, rs1 + CLENBYTES).
If the capability in rs2 is not a non-linear capability (i.e., type != 1), rs2 will be set to the
content of cnull.
5. Control Flow Instructions
5.1. Jump to Capabilities
The CJALR and CBNZ instructions allow jumping to a capability, i.e., setting the program counter to a given capability, in a unconditional or conditional manner.
An exception is raised when any of the following conditions are met:
-
Pure Capstone
-
rs1does not contain a capability. -
The
typefield of the capability inrs1is neither0(linear) nor1(non-linear). -
The
permsfield of the capability inrs1is neither2(read-execute) nor4(read-write-execute).
-
-
TransCapstone
-
cwrldis0(normal world). -
Any of the conditions for Pure Capstone are met.
-
If no exception is raised:
-
CJAL: Set the program counter (
pc) to the capability inrs1. Meanwhile, the existing capability inpc, with itscursorfield replaced by the address of the next instruction, is written to the registerrd. -
CBNZ: If the content of
rs2is zero (0), the behaviour is the same as for NOP. Otherwise, set the program counter (pc) to the capability inrs1.
5.2. Domain Crossing
Domains in Capstone-RISC-V are individual software compartments that are protected by a safe context switching mechanism, i.e., domain crossing. The mechanism is provided by the CALL and RETURN instructions.
5.2.1. CALL
The CALL instruction is used to call a sealed capability, i.e., to switch to another domain.
An exception is raised when any of the following conditions are met:
-
Pure Capstone
-
rs1does not contain a capability. -
The
validfield of the capability inrs1is0(invalid). -
The
typefield of the capability inrs1is not4(sealed). -
The
asyncfield of the capability inrs1is1(asynchronous). -
The memory location
[rs1.base, rs1.base + CLENBYTES)does not contain a capability. -
The
typefield of the capability at the memory location[rs1.base, rs1.base + CLENBYTES)is neither0(linear) nor1(non-linear). -
The
permsfield of the capability at the memory location[rs1.base, rs1.base + CLENBYTES)is neither2(read-execute) nor4(read-write-execute). -
The memory location
[rs1.base + CLENBYTES, rs1.base + 2 * CLENBYTES)does not contain a capability. -
The capability at the memory location
[rs1.base + CLENBYTES, rs1.base + 2 * CLENBYTES)is notcnulland itstypefield is not4(sealed). -
The memory location
[rs1.base + 2 * CLENBYTES, rs1.base + 3 * CLENBYTES)does not contain a capability.
-
-
TransCapstone
-
cwrldis0(normal world). -
Any of the conditions for Pure Capstone are met.
-
If no exception is raised:
-
Load the content at the memory location
[rs1.base, rs1.base + CLENBYTES)to the program counter (pc). -
Load the content at the memory location
[rs1.base + CLENBYTES, rs1.base + 2 * CLENBYTES)to theceh. -
Load the content at the memory location
[rs1.base + 2 * CLENBYTES, rs1.base + 3 * CLENBYTES)to thecsp. -
Store the former
pc,cehandcspvalues to the memory location[rs1.base, rs1.base + CLENBYTES),[rs1.base + CLENBYTES, rs1.base + 2 * CLENBYTES)and[rs1.base + 2 * CLENBYTES, rs1.base + 3 * CLENBYTES)respectively. -
Set the
typefield of the capability inrs1to5(sealed-return), set theregfield of the capability inrs1tord, and write the capability to the registercra.
5.2.2. RETURN
An exception is raised when any of the following conditions are met:
-
Pure Capstone
-
rs1does not contain a capability. -
The
validfield of the capability inrs1is0(invalid). -
The
typefield of the capability inrs1is not5(sealed-return). -
The
asyncfield of the capability inrs1is1(asynchronous). -
rs2does not contain an integer.
-
-
TransCapstone
-
cwrldis0(normal world). -
Any of the conditions for Pure Capstone are met.
-
If no exception is raised:
When rs1.asyc = 0 (synchronous):
-
Load the content at the memory location
[base, base + CLENBYTES), wherebaseis thebasefield of the capability inrs1, to the program counter (pc). -
Load the content at the memory location
[base + CLENBYTES, base + 2 * CLENBYTES), wherebaseis thebasefield of the capability inrs1, to the stack pointer (sp). -
Write the old
pcvalue with thecursorfield replaced with the content ofrs2to the memory location[base, base + CLENBYTES). -
Set the
typefield of the capability inrs1to4(sealed), and write the capability to the registerx[reg]whereregis theregfield of the capability inrs1.
When rs1.async = 1 (asynchronous):
-
Load the content at the memory location
[base, base + CLENBYTES), wherebaseis thebasefield of the capability inrs1, to the program counter (pc). -
For
i = 1, 2, …, 31, load the content at the memory location[base + i * CLENBYTES, base + (i + 1) * CLENBYTES), tox[i](thei-th general-purpose register). -
Write the old
pcvalue with thecursorfield replaced with the content ofrs2to the memory location[base, base + CLENBYTES). -
For
i = 1, 2, …, 31, load the content ofx[i](thei-th general-purpose register) to the memory location[base + i * CLENBYTES, base + (i + 1) * CLENBYTES). -
Set the
typefield of the capability inrs1to4(sealed), and write the capability to the exception handler registerceh.
5.3. A World Switching Extension for TransCapstone
In TransCapstone, a pair of extra instructions, i.e., CAPENTER and CAPEXIT, is added to support switching between the secure world and the normal world. The CAPENTER instruction causes an entry into the secure world from the normal world, and the CAPEXIT instruction causes an exit from the secure world into the normal world.
The CAPENTER instruction can only be used in the normal world, whereas the CAPEXIT instruction can only be used in the secure world. In addition, the CAPEXIT instruction can only be used when an exit capability is provided. Attempting to use those instructions in the wrong world or without the required capability will cause an exception. The behaviours of those instructions roughly correspond to the CALL and RETURN instructions respectively.
5.3.1. CAPENTER
An exception is raised when any of the following conditions are met:
-
cwrldis1(secure world). -
rs1does not contain a capability. -
The
validfield of the capability inrs1is0(invalid). -
The
typefield of the capability inrs1is not4(sealed).
If no exception is raised:
-
Load the content at the memory location
[base, base + CLENBYTES), wherebaseis thebasefield of the capability inrs1, to the program counter (pc). -
Store the old
pcvalue tonormal_pc, and the oldspvalue tonormal_sp. -
Set the
typefield of the capability inrs1to5(sealed-return), and write the capability to the registerswitch_cap. -
Write
rs1to the registerswitch_reg. -
Create a capability of
type = 6(exit) incra. -
Set
exit_regtord. -
Set
cwrldto1(secure world).
The rd register will be set to a value indicating the cause of exit when
the CPU core exits from the secure world.
5.3.2. CAPEXIT
An exception is raised when any of the following conditions are met:
-
cwrldis0(normal world). -
rs1does not contain a capability. -
The
validfield of the capability inrs1is0(invalid). -
The
typefield of the capability inrs1is not6(exit). -
rs2does not contain an integer. -
The
validfield of the capability inswitch_capis0(invalid).
If no exception is raised:
-
Write the content of
normal_pcandnormal_sptopcandsprespectively. -
Write the old
pccontent with thecursorfield replaced with the content ofrs2to the memory location[base, base + CLENBYTES), wherebaseis thebasefield of the capability inswitch_cap. -
Set the
typefield ofswitch_capto4(sealed) and write it tox[switch_reg]. -
Set the register
x[exit_reg]to0(normal exit). -
Set
cwrldto0(normal world).
6. Adjustments to Existing Instructions
For most existing instructions in the RISC-V ISA, the adjustments are straightforward.
Their behaviour is unchanged, and an exception is raised if any of the operands
(i.e., rs1, rs2 or rd) contains a capability.
For control flow instructions and memory access instructions, however, the
behaviour is slightly changed to be capability-aware.
6.1. Control Flow Instructions
In RISC-V, a set of instructions are used to control the flow of execution.
These instructions include conditional branch instructions (i.e., beq, bne, blt, bge, bltu, and bgeu),
and unconditional jump instructions (i.e., jal and jalr).
In Capstone, adjustments are made to these instructions to support capability-aware execution.
The following adjustments are made to these instructions:
-
Pure Capstone
-
An exception is raised if
rs1,rs2orrdcontains a capability. -
The
cursorfield of the capability inpc, instead ofpcitself, is changed by the instruction. -
If the instruction is
jalorjalr, thecursorfield of the capability inpc, which contains the address of the next instruction, is written tord.
-
-
TransCapstone
-
An exception is raised if
rs1,rs2orrdcontains a capability. -
If
cwldis1(secure world), thecursorfield of the capability inpc, instead ofpcitself, is changed by the instruction. -
If
cwldis1(secure world) and the instruction isjalorjalr, thecursorfield of the capability inpc, which contains the address of the next instruction, is written tord.
-
6.2. Memory Access Instructions
In RISC-V, memory access instructions include load instructions (i.e., lb, lh, lw, lbu, lhu,
lwu, ld, and fld), and store instructions (i.e., sb, sh, sw, sd, and fsd).
As the Capstone-RISC-V ISA extends each of the 32 general-purpose registers, instructions that take
these registers as operands are also extended. These instructions (i.e., lb, lh, lw, lbu, lhu,
lwu, ld, sb, sh, sw, and sd) take an integer as a raw address, and load or store a value
from or to this address. In Capstone, adjustments are made to these instructions to support capability-aware
memory access.
The following adjustments are made to these instructions:
-
Pure Capstone
-
An exception is raised if any of these instructions is executed.
-
-
TransCapstone
-
An exception is raised if any of these instructions is executed when
cwldis1(secure world). -
An exception is raised if
rs1,rs2orrdcontains a capability. -
An exception is raised if the address to be accessed is within the range
(SBASE-size, SEND)(i.e.addr = x[rs1] + sext(imm)andSBASE-size < addr < SEND), wheresizeis the size (in bytes) of the integer to be loaded or stored.
-
7. Interrupts and Exceptions
TODO: add support for nesting
7.1. Exception and Exit Codes
The exception code is what the exception handler domain receives as an argument when an exception occurs on pure Capstone or in TransCapstone secure world. It is an integer value that indicates what the type of the exception is. TransCapstone also has exit codes, which are the values returned to the CAPENTER instruction in case the exception cannot be handled in the secure world. We define the exception code and the exit code for each type of exception below. It aligns with the exception codes defined in RISC-V 64, where applicable, for ease of implementation and interoperability.
| Exception | Exception code | TransCapstone exit code |
|---|---|---|
Instruction address misaligned |
0 |
1 |
Instruction access fault |
1 |
1 |
Illegal instruction |
2 |
1 |
Breakpoint |
3 |
1 |
Load address misaligned |
4 |
1 |
Load access fault |
5 |
1 |
Store/AMO address misaligned |
6 |
1 |
Store/AMO access fault |
7 |
1 |
Unexpected operand type |
8 |
1 |
Invalid capability |
9 |
1 |
7.2. Pure Capstone
For pure Capstone, the handling of interrupts and exceptions is relatively
straightforward. Regardless of whether the event is an interrupt or an
exception, or what the type of the interrupt or exception is, the processor
core will always transfer the control flow to the exception handler domain
specified in the ceh register.
The current
context is saved and sealed in a sealed-return capability which
is then supplied to the
exception handler domain as an argument. When exception handling is complete,
the exception handler domain can use the RETURN instruction to resume the
execution of the excepted domain. This process resembles that of a CALL-RETURN
pair, except that it is asynchronous, rather than synchronous,
to the execution of the original domain.
TODO: specify what "panics" means here
TODO: specify what happens if any of the involved memory accesses fails
The CPU core panics if any of the following conditions is met:
-
The
cehregister does not contain a capability. -
The capability in
cehis invalid (valid = 0). -
The capability in
cehis not a sealed capability (type != 4).
Otherwise:
-
Load the program counter
pcfrom memory location[ceh.base, ceh.base + CLENBYTES). -
For
i = 1, 2, …, 31, load the content of thei-th general-purpose register from memory location[ceh.base + i * CLENBYTES, ceh.base + (i + 1) * CLENBYTES). -
Scrub the other general-purpose registers.
-
Store the original program counter
pcto the memory location[ceh.base + CLENBYTES, ceh.base + 2 * CLENBYTES). -
For
i = 1, 2, …, 31, store the original content of thei-th general-purpose register to memory location[ceh.base + i * CLENBYTES, ceh.base + (i + 1) * CLENBYTES). -
Set the
typefield ofcehto5(sealed-return),regfield ofcehto0(asynchronous), andasyncfield ofcehto1(asynchronous). -
Write the content of
cehto the registerc1. -
Write the exception code to the register
x10.
7.3. TransCapstone
TransCapstone retains the same interrupt and exception handling mechanims for the normal world as in RISC-V 64.
For the secure world in TransCapstone, the handling of interrupts and exceptions is more complex, and it becomes relevant whether the event is an interrupt or an exception.
For interrupts, in order to prevent denial-of-service attacks by the secure world, the processor core needs to transfer the control back to the normal world safely. The interrupt will be translated to one in the normal world that occurs at the CAPENTER instruction used to enter the secure world. Since interrupts are typically relevant only to the management of system resources, the interrupt should be transparent to both the secure world and the user process. In other words, the secure world will simply resume execution from where it was interrupted after the interrupt is handled by the normal-world OS.
For exceptions, we want to give the secure world the chance handle
them first. If the secure world manages to handle the exception, the
normal world will not be involved. The end result is that the whole
exception or its handling is not even visible to the normal world.
If the secure world fails to handle an exeption (i.e., when
it would end up panicking in the case of pure Capstone, such as when
ceh is not a valid sealed capability), however,
the normal world will take over. The exception will not be translated into
an exception in the normal world, but instead indicated in the exit code
that the CAPENTER instruction in the user process receives.
The user process can then decide what to do based on the exit code (e.g.,
terminate the domain in the secure world).
Below we discuss the details of the handling of interrupts and exceptions generated in the secure world.
7.3.1. Handling of Secure-World Interrupts
When an interrupt occurs in the secure world, the processor core directly saves the full context, scrubs it, and exits to the normal world. It then generates a corresponding interrupt in the normal world, and and follows the normal-world interrupt handling process thereafter.
If the content in switch_reg is a valid sealed capability:
-
Store the current value of the program counter (
pc) to the memory location[switch_cap.base, switch_cap.base + CLENBYTES). -
For
i = 1, 2, …, 31, store the content of thei-th general purpose to the memory location[switch_cap.base + i * CLENBYTES, switch_cap.base + (i + 1) * CLENBYTES). -
Set the
asyncfield ofswitch_capto1(asynchronous). -
Write the content of
switch_capto the registerx[switch_reg]. -
Load the program counter
pcand the stack pointerspfromnormal_pcandnormal_sprespectively. -
Scrub the other general-purpose registers.
-
Set the
cwrldregister to0(normal world). -
Trigger an interrupt in the normal world.
Otherwise:
-
Write the content of
cnullto the registerx[switch_reg]. -
Load the program counter
pcand the stack pointerspfromnormal_pcandnormal_sprespectively. -
Scrub the other general-purpose registers.
-
Set the
cwrldregister to0(normal world). -
Trigger an interrupt in the normal world.
Note that in this case, there will be another exception in the normal world
when the user process resumes execution after the interrupt has been handled
by the OS, due to the invalid switch_cap value written to the CAPENTER
operand.
7.3.2. Handling of Secure-World Exceptions
When an exception occurs, the processor core first attempts to handle the
exception in the secure world, in the similar way as in pure Capstone.
If this fails (ceh is not valid), the processor core saves
the full context if it can and exits to the normal
world with a proper error code.
If the content in ceh is a valid sealed capability:
-
Load the program counter
pcfrom memory location[ceh.base, ceh.base + CLENBYTES). -
For
i = 1, 2, …, 31, load the content of thei-th general-purpose register from memory location[ceh.base + i * CLENBYTES, ceh.base + (i + 1) * CLENBYTES). -
Store the original program counter
pcto the memory location[ceh.base + CLENBYTES, ceh.base + 2 * CLENBYTES). -
For
i = 1, 2, …, 31, store the original content of thei-th general-purpose register to memory location[ceh.base + i * CLENBYTES, ceh.base + (i + 1) * CLENBYTES). -
Set the
typefield ofcehto5(sealed-return), andregfield ofcehto0(asynchronous). -
Write the content of
cehto the registerc1. -
Write the exception code to the register
x10.
Note that this is exactly the same as the handling of exceptions in pure Capstone.
Otherwise:
If the content in switch_reg is a valid sealed capability:
-
Store the current value of the program counter (
pc) to the memory location[switch_cap.base, switch_cap.base + CLENBYTES). -
For
i = 1, 2, …, 31, store the content of thei-th general purpose to the memory location[switch_cap.base + i * CLENBYTES, switch_cap.base + (i + 1) * CLENBYTES). -
Set the
asyncfield ofswitch_capto1(asynchronous). -
Write the content of
switch_capto the registerx[switch_reg]. -
Load the program counter
pcand the stack pointerspfromnormal_pcandnormal_sprespectively. -
Write the exit code to the register
x[exit_reg]. -
Set the
cwrldregister to0(normal world).
Otherwise:
-
Write the content of
cnullto the registerx[switch_reg]. -
Load the program counter
pcand the stack pointerspfromnormal_pcandnormal_sprespectively. -
Write the exit code to the register
x[exit_reg]. -
Set the
cwrldregister to0(normal world).
8. Memory Consistency Model
TODO
Appendix A: Debugging Instructions (Non-Normative)
A.1. World Switching
The instructions SETWORLD and ONPARTITION are related to world switching in TransCapstone-RISC-V.
The instructions load their operands from the register rs1, which expects
an integer.
SETWORLD directly sets the core to the specified
world (0 for normal world and non-zero for secure world).
The program counter will also be made into a capability or an integer
correspondingly while retaining the cursor value.
ONPARTITION switches on (non-zero) or off (0) the world partitioning checks
in memory.
The instructions make it easy to set up the environment for testing either pure Capstone or TransCapstone:
-
Pure Capstone: secure world, world partitioning checks off
-
TransCapstone: normal world, world partitioning checks on
A.2. Exception Handling
The instructions SETEH and ONNORMALEH affect the behaviours of interrupt and exception handling.
The SETEH instruction sets the secure-world
exception handler domain (i.e., ceh) to the specified capability in rs1.
The ONNORMALEH instruction checks the integer value in rs1 and switches on (non-zero) or off (0) normal world handling of secure-world exceptions.
When this is on, an exception that occurs in the secure world will trap to the normal world
first before being handled by the secure-world exception handler (ceh), which is the
expected behaviour in TransCapstone.
When it is off, the exception will be directly handled by the secure-world exception handler,
as is expected in pure Capstone.
Appendix B: Instruction Listing
| Mnemonic | Format | Func3 | Func7 | rs1 | rs2 | rd | imm[11:0] | World | Variant |
|---|---|---|---|---|---|---|---|---|---|
QUERY |
R |
|
|
I |
- |
- |
- |
* |
* |
RCUPDATE |
R |
|
|
I |
- |
I |
- |
* |
* |
ALLOC |
R |
|
|
I |
- |
I |
- |
* |
* |
REV |
R |
|
|
I |
- |
- |
- |
* |
* |
CAPCREATE |
R |
|
|
- |
- |
C |
- |
* |
* |
CAPTYPE |
R |
|
|
I |
- |
C |
- |
* |
* |
CAPNODE |
R |
|
|
I |
- |
C |
- |
* |
* |
CAPPERM |
R |
|
|
I |
- |
C |
- |
* |
* |
CAPBOUND |
R |
|
|
I |
I |
C |
- |
* |
* |
CAPPRINT |
R |
|
|
I |
- |
- |
- |
* |
* |
TAGSET |
R |
|
|
I |
I |
- |
- |
* |
* |
TAGGET |
R |
|
|
I |
- |
I |
- |
* |
* |
R |
|
|
I |
- |
- |
- |
* |
T |
|
R |
|
|
I |
- |
- |
- |
* |
T |
|
R |
|
|
C |
- |
- |
- |
* |
T |
|
R |
|
|
I |
- |
- |
- |
* |
T |
| Mnemonic | Format | Func3 | Func7 | rs1 | rs2 | rd | imm[11:0] | World | Variant |
|---|---|---|---|---|---|---|---|---|---|
R |
|
|
C |
- |
- |
- |
* |
* |
|
R |
|
|
I |
I |
C |
- |
* |
* |
|
R |
|
|
I |
- |
C |
- |
* |
* |
|
R |
|
|
- |
- |
C |
- |
* |
* |
|
R |
|
|
C |
- |
I |
- |
* |
* |
|
R |
|
|
I |
- |
C |
- |
* |
* |
|
R |
|
|
C |
I |
C |
- |
* |
* |
|
R |
|
|
- |
- |
C |
- |
* |
* |
|
R |
|
|
C |
- |
C |
- |
* |
* |
|
R |
|
|
- |
- |
C |
- |
* |
* |
|
R |
|
|
C |
- |
C |
- |
* |
* |
|
R |
|
|
C |
- |
- |
- |
* |
* |
|
CAPGET |
R |
|
|
- |
- |
C |
- |
N |
* |
R |
|
|
C |
I |
C |
- |
* |
* |
|
I |
|
- |
C |
- |
C |
S |
* |
* |
| Mnemonic | Format | Func3 | Func7 | rs1 | rs2 | rd | imm[11:0] | World | Variant |
|---|---|---|---|---|---|---|---|---|---|
R |
|
|
C |
- |
C |
- |
* |
* |
|
R |
|
|
C |
C |
- |
- |
* |
* |
|
R |
|
|
C |
- |
I |
- |
* |
* |
|
R |
|
|
C |
I |
- |
- |
* |
* |
|
R |
|
|
C |
- |
I |
- |
* |
* |
|
R |
|
|
C |
I |
- |
- |
* |
* |
|
R |
|
|
C |
- |
I |
- |
* |
* |
|
R |
|
|
C |
I |
- |
- |
* |
* |
|
R |
|
|
C |
- |
I |
- |
* |
* |
|
R |
|
|
C |
I |
- |
- |
* |
* |
|
R |
|
|
I |
- |
C |
- |
N |
T |
|
R |
|
|
I |
C |
- |
- |
N |
T |
| Mnemonic | Format | Func3 | Func7 | rs1 | rs2 | rd | imm[11:0] | World | Variant |
|---|---|---|---|---|---|---|---|---|---|
R |
|
|
C |
- |
- |
- |
S |
* |
|
R |
|
|
C |
I |
- |
- |
S |
* |
|
R |
|
|
C |
- |
C |
- |
S |
* |
|
R |
|
|
C |
I |
- |
- |
S |
* |
|
R |
|
|
C |
- |
I |
- |
N |
T |
|
R |
|
|
C |
I |
- |
- |
S |
T |
Appendix C: Assembly Code Examples
TODO
Appendix D: Abstract Binary Interface (Non-Normative)
TODO