#include <sys/types.h>
#include <sys/ioctl.h>
#include <dev/ic/pspvar.h>
#include <errno.h>
#include <fcntl.h>
#include <string.h>
#include "vmd.h"
extern struct vmd *env;
#define GPOL_NODBG (1ULL << 0)
#define GPOL_NOKS (1ULL << 1)
#define GPOL_ES (1ULL << 2)
#define GPOL_NOSEND (1ULL << 3)
#define GPOL_DOMAIN (1ULL << 4)
#define GPOL_SEV (1ULL << 5)
int
psp_get_pstate(uint16_t *state, uint8_t *major, uint8_t *minor,
uint8_t *build, uint8_t *seves)
{
struct psp_platform_status pst;
if (ioctl(env->vmd_psp_fd, PSP_IOC_GET_PSTATUS, &pst) < 0) {
log_warn("%s: ioctl", __func__);
return (-1);
}
if (state)
*state = pst.state;
if (major)
*major = pst.api_major;
if (minor)
*minor = pst.api_minor;
if (build)
*build = (pst.cfges_build >> 24) & 0xff;
if (seves)
*seves = pst.cfges_build & 0x1;
return (0);
}
int
psp_df_flush(void)
{
if (ioctl(env->vmd_psp_fd, PSP_IOC_DF_FLUSH) < 0) {
log_warn("%s: ioctl", __func__);
return (-1);
}
return (0);
}
int
psp_get_gstate(uint32_t handle, uint32_t *policy, uint32_t *asid,
uint8_t *state)
{
struct psp_guest_status gst;
memset(&gst, 0, sizeof(gst));
gst.handle = handle;
if (ioctl(env->vmd_psp_fd, PSP_IOC_GET_GSTATUS, &gst) < 0) {
log_warn("%s: ioctl", __func__);
return (-1);
}
if (policy)
*policy = gst.policy;
if (asid)
*asid = gst.asid;
if (state)
*state = gst.state;
return (0);
}
int
psp_launch_start(uint32_t *handle, int seves)
{
struct psp_launch_start ls;
memset(&ls, 0, sizeof(ls));
ls.policy = (GPOL_NODBG | GPOL_NOKS | GPOL_NOSEND | GPOL_DOMAIN |
GPOL_SEV);
if (seves)
ls.policy |= GPOL_ES;
if (ioctl(env->vmd_psp_fd, PSP_IOC_LAUNCH_START, &ls) < 0) {
log_warn("%s: ioctl", __func__);
return (-1);
}
if (handle)
*handle = ls.handle;
return (0);
}
int
psp_launch_update(uint32_t handle, vaddr_t v, size_t len)
{
struct psp_launch_update_data lud;
memset(&lud, 0, sizeof(lud));
lud.handle = handle;
lud.paddr = v;
lud.length = len;
if (ioctl(env->vmd_psp_fd, PSP_IOC_LAUNCH_UPDATE_DATA, &lud) < 0) {
log_warn("%s: ioctl", __func__);
return (-1);
}
return (0);
}
int
psp_encrypt_state(uint32_t handle, uint32_t asid, uint32_t vmid,
uint32_t vcpuid)
{
struct psp_encrypt_state es;
memset(&es, 0, sizeof(es));
es.handle = handle;
es.asid = asid;
es.vmid = vmid;
es.vcpuid = vcpuid;
if (ioctl(env->vmd_psp_fd, PSP_IOC_ENCRYPT_STATE, &es) < 0) {
log_warn("%s: ioctl", __func__);
return (-1);
}
return (0);
}
int
psp_launch_measure(uint32_t handle)
{
struct psp_launch_measure lm;
char *p, buf[256];
size_t len;
unsigned int i;
memset(&lm, 0, sizeof(lm));
lm.handle = handle;
lm.measure_len = sizeof(lm.psp_measure);
memset(lm.measure, 0, sizeof(lm.measure));
memset(lm.measure_nonce, 0, sizeof(lm.measure_nonce));
if (ioctl(env->vmd_psp_fd, PSP_IOC_LAUNCH_MEASURE, &lm) < 0) {
log_warn("%s: ioctl", __func__);
return (-1);
}
len = sizeof(buf);
memset(buf, 0, len);
p = buf;
for (i = 0; i < sizeof(lm.measure) && len >= 2;
i++, p += 2, len -= 2) {
snprintf(p, len, "%02x", lm.measure[i]);
}
log_info("%s: measurement 0x%s", __func__, buf);
len = sizeof(buf);
memset(buf, 0, len);
p = buf;
for (i = 0; i < sizeof(lm.measure_nonce) && len >= 2;
i++, p += 2, len -= 2) {
snprintf(p, len, "%02x", lm.measure_nonce[i]);
}
log_info("%s: nonce 0x%s", __func__, buf);
return (0);
}
int
psp_launch_finish(uint32_t handle)
{
struct psp_launch_finish lf;
lf.handle = handle;
if (ioctl(env->vmd_psp_fd, PSP_IOC_LAUNCH_FINISH, &lf) < 0) {
log_warn("%s: ioctl", __func__);
return (-1);
}
return (0);
}
int
psp_activate(uint32_t handle, uint32_t asid)
{
struct psp_activate act;
act.handle = handle;
act.asid = asid;
if (ioctl(env->vmd_psp_fd, PSP_IOC_ACTIVATE, &act) < 0) {
log_warn("%s: ioctl", __func__);
return (-1);
}
return (0);
}
int
psp_guest_shutdown(uint32_t handle)
{
struct psp_guest_shutdown gshutdown;
gshutdown.handle = handle;
if (ioctl(env->vmd_psp_fd, PSP_IOC_GUEST_SHUTDOWN, &gshutdown) < 0) {
log_warn("%s: ioctl", __func__);
return (-1);
}
return (0);
}
static int
psp_init(void)
{
if (ioctl(env->vmd_psp_fd, PSP_IOC_INIT) < 0) {
log_warn("%s: ioctl", __func__);
return (-1);
}
return (0);
}
static int
psp_shutdown(void)
{
if (ioctl(env->vmd_psp_fd, PSP_IOC_SHUTDOWN) < 0) {
log_warn("%s: ioctl", __func__);
return (-1);
}
return (0);
}
static int
psp_reset(void)
{
int ret;
if ((ret = psp_shutdown()) < 0 || (ret = psp_init()) < 0)
return (ret);
return (0);
}
void
psp_setup(void)
{
uint8_t major, minor, build;
env->vmd_psp_fd = open(PSP_NODE, O_RDWR);
if (env->vmd_psp_fd == -1) {
if (errno != ENXIO)
log_debug("%s: failed to open %s", __func__, PSP_NODE);
return;
}
if (psp_reset() < 0)
fatalx("%s: failed to reset PSP", __func__);
if (psp_get_pstate(NULL, &major, &minor, &build, NULL) < 0)
fatalx("%s: failed to get platform state", __func__);
log_info("PSP api %hhu.%hhu, build %hhu", major, minor, build);
}