Skip to content
This repository has been archived by the owner on Jun 8, 2021. It is now read-only.

Latest commit

 

History

History
567 lines (472 loc) · 13.7 KB

DOCUMENTATION.md

File metadata and controls

567 lines (472 loc) · 13.7 KB

The uVisor API Documentation

Here you can find detailed documentation for:

  1. Configuration macros, to configure a secure box and protect data and peripherals.
  2. Secure function calls, to execute code in the context of a secure box.
  3. Box Identity, to retrieve a box-specific ID or the namespace of the current or calling box.
  4. Low level APIs, to access uVisor functions that are not available to unprivileged code (interrupts, restricted system registers).
  5. Type definitions.
  6. Error codes.

Configuration macros

UVISOR_BOX_CONFIG(box_name
                  const UvBoxAclItem *module_acl_list,
                  uint32_t module_stack_size,
                  [struct __your_context])
Description Secure box configuration
Type C/C++ pre-processor macro (pseudo-function)
Parameters
box_name
Secure box name
const UvBoxAclItem *module_acl_list
List of ACLs for the module
uint32_t module_stack_size
Required stack size for the secure box
struct __your_context
[optional] Type definition of the struct hosting the box context data

Example:

#include "uvisor-lib/uvisor-lib.h"

/* Required stack size */
#define BOX_STACK_SIZE 0x100

/* Define the box context. */
typedef struct {
    uint8_t secret[SECRET_SIZE];
    bool initialized;
    State_t current_state
} BoxContext;

/* Create the ACL list for the module. */
static const UvBoxAclItem g_box_acl[] = {
    {PORTB,  sizeof(*PORTB),  UVISOR_TACLDEF_PERIPH},
    {RTC,    sizeof(*RTC),    UVISOR_TACLDEF_PERIPH},
    {LPTMR0, sizeof(*LPTMR0), UVISOR_TACLDEF_PERIPH},
};

/* Configure the secure box compartment. */
UVISOR_BOX_NAMESPACE("com.example.my-box-name");
UVISOR_BOX_CONFIG(my_box_name, g_box_acl, BOX_STACK_SIZE, BoxContext);

UVISOR_SET_MODE(uvisor_mode);
Description [temporary] Set mode for the uVisor
Type C/C++ pre-processor macro (object declaration)
Parameters
uvisor_mode
UVISOR_DISABLED = disabled [default]
UVISOR_PERMISSIVE = permissive [currently n.a.]
UVISOR_ENABLED = enabled

Example:

#include "uvisor-lib/uvisor-lib.h"

/* Set the uVisor mode. */
UVISOR_SET_MODE(UVISOR_ENABLED);

Note:

  1. This macro is only needed temporarily (uVisor disabled by default) and will be removed in the future.

  2. This macro must be used only once in the top level yotta executable.


UVISOR_SET_MODE_ACL(uvisor_mode, const UvBoxAcl *main_box_acl_list);
Description [temporary] Set mode for the uVisor and provide background ACLs for the main box
Type C/C++ pre-processor macro (object declaration)
Parameters
uvisor_mode
UVISOR_DISABLED = disabled [default]
UVISOR_PERMISSIVE = permissive [currently n.a.]
UVISOR_ENABLED = enabled
const UvBoxAclItem *main_box_acl_list
List of ACLs for the main box (background ACLs)

Example:

#include "uvisor-lib/uvisor-lib.h"

/* Create background ACLs for the main box. */
static const UvBoxAclItem g_background_acl[] = {
    {UART0,       sizeof(*UART0), UVISOR_TACL_PERIPHERAL},
    {UART1,       sizeof(*UART1), UVISOR_TACL_PERIPHERAL},
    {PIT,         sizeof(*PIT),   UVISOR_TACL_PERIPHERAL},
};

/* Set the uVisor mode. */
UVISOR_SET_MODE_ACL(UVISOR_ENABLED, g_background_acl);

Note:

  1. This macro is only needed temporarily (uVisor disabled by default) and will be removed in the future.

  2. This macro must be used only once in the top level yotta executable.


UVISOR_BOX_NAMESPACE(static const char const namespace[])
Description

Specify the namespace for a box.

  <p>The namespace of the box must be a null-terminated string no longer than <code>MAX_BOX_NAMESPACE_LENGTH</code> (including the terminating null). The namespace must also be stored in public flash. uVisor will verify that the namespace is null-terminated and stored in public flash at boot-time, and will halt if the namespace fails this verification.</p>

  <p>For now, use a reverse domain name for the box namespace. If you don't have a reverse domain name, use a GUID string identifier. We currently don't verify that the namespace is globally unique, but we will perform this validation in the future.</p>

  <p>Use of this configuration macro before <code>UVISOR_BOX_CONFIG</code> is required. If you do not wish to give your box a namespace, specify <code>NULL</code> as the namespace to create an anonymous box.</p>
Type C/C++ pre-processor macro (pseudo-function)
Parameters namespace The namespace of the box

Example:

#include "uvisor-lib/uvisor-lib.h"

/* Configure the secure box. */
UVISOR_BOX_NAMESPACE("com.example.my-box-name");
UVISOR_BOX_CONFIG(my_box_name, UVISOR_BOX_STACK_SIZE);

Secure function call

uint32_t secure_gateway(box_name, uint32_t target_fn, ...)
Description Call a function using the context of a secure box
Type C/C++ pre-processor macro (pseudo-function)
Return value [optional] A maximum of one 32bit value
Parameters
box_name
Secure box name
uint32_t target_fn
Function to execute in the secure context
...
A maximum of four 32bit arguments

Example:

/* The box is configured here. */
...

/* The actual function implementation */
extern "C" uint32_t __secure_sum(uint32_t op1, uint32_t op2)
{
    return op1 + op2;op3 + op4;
}

/* The entry point to the actual function implementation */
uint32_t secure_sum(uint32_t op1, uint32_t op2)
{
    return secure_gateway(my_box_name, __secure_sum, op1, op2)
}

Box Identity

A box identity identifies a security domain uniquely and globally.

The box identity API can be used to determine the source box of an inbound secure gateway call. This can be useful for implementing complex authorization logic between mutually distrustful security domains.

uVisor provides the ability to retrieve the box ID of the current box (uvisor_box_id_self), or of the box that most recently called the current box through a secure gateway (uvisor_box_id_caller).

The box ID number is not constant and can change between reboots. But, the box ID number can be used as a token to retrieve a constant string identifier, known as the box namespace.

A box namespace is a static, box-specific string, that can help identify which box has which ID at run-time. In the future, the box namespace will be guaranteed to be globally unique.

A full example using this API is available at example-uvisor-box-id.

int uvisor_box_id_self(void)
Description Get the ID of the current box
Return value The ID of the current box

int uvisor_box_id_caller(void)
Description Get the ID of the box that is calling the current box through the most recent secure gateway
Return value The ID of the caller box, or -1 if there is no secure gateway calling box

int uvisor_box_namespace(int box_id, char *box_namespace, size_t length)
Description Copy the namespace of the specified box to the provided buffer.
Return value Return how many bytes were copied into box_namespace. Return UVISOR_ERROR_INVALID_BOX_ID if the provided box ID is invalid. Return UVISOR_ERROR_BUFFER_TOO_SMALL if the provided box_namespace is too small to hold MAX_BOX_NAMESPACE_LENGTH bytes. Return UVISOR_ERROR_BOX_NAMESPACE_ANONYMOUS if the box is anonymous.
Parameters int box_id The ID of the box you want to retrieve the namespace of
char *box_namespace The buffer where the box namespace will be copied to
size_t length The length in bytes of the provided box_namespace buffer

Low-level APIs

Currently the following low level operations are permitted:

  1. Interrupt management.

Interrupt management

void vIRQ_SetVector(uint32_t irqn, uint32_t vector)
Description Register an ISR to the currently active box
Parameters
uint32_t irqn
IRQn
uint32_t vector
Interrupt handler; if 0 the IRQn slot is de-registered for the current box

uint32_t vIRQ_GetVector(uint32_t irqn)
Description Get the ISR registered for IRQn
Return value The ISR registered for IRQn, if present; 0 otherwise
Parameters
uint32_t irqn
IRQn

void vIRQ_EnableIRQ(uint32_t irqn)
Description Enable IRQn for the currently active box
Parameters
uint32_t irqn
IRQn

void vIRQ_DisableIRQ(uint32_t irqn)
Description Disable IRQn for the currently active box
Parameters
uint32_t irqn
IRQn

void vIRQ_ClearPendingIRQ(uint32_t irqn)
Description Clear pending status of IRQn
Parameters
uint32_t irqn
IRQn

void vIRQ_SetPendingIRQ(uint32_t irqn)
Description Set pending status of IRQn
Parameters
uint32_t irqn
IRQn

uint32_t vIRQ_GetPendingIRQ(uint32_t irqn)
Description Get pending status of IRQn
Parameters
uint32_t irqn
IRQn

void vIRQ_SetPriority(uint32_t irqn, uint32_t priority)
Description Set priority level of IRQn
Parameters
uint32_t irqn
IRQn
uint32_t priority
Priority level (minimum: 1)

uint32_t vIRQ_GetPriority(uint32_t irqn)
Description Get priority level of IRQn
Return value The priority level of IRQn, if available; 0 otherwise
Parameters
uint32_t irqn
IRQn

int vIRQ_GetLevel(void)
Description Get level of currently active IRQn, if any
Return value The priority level of the currently active IRQn, if any; -1 otherwise

Type definitions

typedef uint32_t UvisroBoxAcl;    /* Permssion mask */

typedef struct
{
    const volatile void* start;   /* Start address of the protected area */
    uint32_t length;              /* Size of the protected area */
    UvisorBoxAcl acl;             /* Permission mask for the protected area */
} UvisorBoxAclItem;

Error codes

Error reason Error code
PERMISSION_DENIED 1
SANITY_CHECK_FAILED 2
NOT_IMPLEMENTED 3
NOT_ALLOWED 4
FAULT_MEMMANAGE 5
FAULT_BUS 6
FAULT_USAGE 7
FAULT_HARD 8
FAULT_DEBUG 9