root/sys/arch/amd64/include/ghcb.h
/*      $OpenBSD: ghcb.h,v 1.7 2026/02/16 15:06:03 hshoexer Exp $       */

/*
 * Copyright (c) 2024, 2025 Hans-Joerg Hoexer <hshoexer@genua.de>
 *
 * Permission to use, copy, modify, and distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice appear in all copies.
 *
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 */

#ifndef _MACHINE_GHCB_H_
#define _MACHINE_GHCB_H_

#ifndef _LOCORE

#include <sys/systm.h>

#include <machine/frame.h>

#define GHCB_OFFSET(m)                  ((m) / 8)
#define GHCB_IDX(m)                     (GHCB_OFFSET((m)) / 8)
#define GHCB_BIT(m)                     (GHCB_OFFSET((m)) % 8)

#define GHCB_XSS                        0x140
#define GHCB_RAX                        0x1F8
#define GHCB_RBX                        0x318
#define GHCB_RCX                        0x308
#define GHCB_RDX                        0x310
#define GHCB_SW_EXITCODE                0x390
#define GHCB_SW_EXITINFO1               0x398
#define GHCB_SW_EXITINFO2               0x3A0
#define GHCB_SW_SCRATCH                 0x3A8
#define GHCB_XCR0                       0x3E8

#define GHCB_MAX                        0xFFF

struct ghcb_sa {
        uint8_t                 v_pad0[0xcb];           /* 000h-0CAh */
        uint8_t                 v_cpl;                  /* 0CBh */
        uint8_t                 v_pad1[0x74];           /* 0CCh-13Fh */
        uint64_t                v_xss;                  /* 140h */
        uint8_t                 v_pad2[0x18];           /* 148h-15Fh */
        uint64_t                v_dr7;                  /* 160h */
        uint8_t                 v_pad3[0x10];           /* 168h-177h */
        uint64_t                v_rip;                  /* 178h */
        uint8_t                 v_pad4[0x58];           /* 180h-1D7h */
        uint64_t                v_rsp;                  /* 1D8h */
        uint8_t                 v_pad5[0x18];           /* 1E0h-1F7h */
        uint64_t                v_rax;                  /* 1F8h */
        uint8_t                 v_pad6[0x108];          /* 200h-307h */
        uint64_t                v_rcx;                  /* 308h */
        uint64_t                v_rdx;                  /* 310h */
        uint64_t                v_rbx;                  /* 318h */
        uint8_t                 v_pad7[0x8];            /* 320h-327h */
        uint64_t                v_rbp;                  /* 328h */
        uint64_t                v_rsi;                  /* 330h */
        uint64_t                v_rdi;                  /* 338h */
        uint64_t                v_r8;                   /* 340h */
        uint64_t                v_r9;                   /* 348h */
        uint64_t                v_r10;                  /* 350h */
        uint64_t                v_r11;                  /* 358h */
        uint64_t                v_r12;                  /* 360h */
        uint64_t                v_r13;                  /* 368h */
        uint64_t                v_r14;                  /* 370h */
        uint64_t                v_r15;                  /* 378h */
        uint8_t                 v_pad8[0x10];           /* 380h-38Fh */
        uint64_t                v_sw_exitcode;          /* 390h */
        uint64_t                v_sw_exitinfo1;         /* 398h */
        uint64_t                v_sw_exitinfo2;         /* 3a0h */
        uint64_t                v_sw_scratch;           /* 3a8h */
        uint8_t                 v_pad9[0x38];           /* 3B0h-3E7h */
        uint64_t                v_xcr0;                 /* 3E8h */
#define GHCB_VB_SZ      0x10
        uint8_t                 valid_bitmap[GHCB_VB_SZ];
                                                        /* 3F0h-3FFh */
        uint64_t                v_x87_state_gpa;        /* 400h */
        uint8_t                 v_pad10[0x3f8];         /* 408h-7FFh */
        uint8_t                 v_sharedbuf[0x7f0];     /* 800h-FEFh */
        uint8_t                 v_pad11[0xa];           /* FF0h-FF9h */
        uint16_t                v_ghcb_proto_version;   /* FFAh-FFBh */
        uint32_t                v_ghcb_usage;           /* FFCh-FFFh */
};

#define GHCB_SZ8        0
#define GHCB_SZ16       1
#define GHCB_SZ32       2
#define GHCB_SZ64       3

struct ghcb_sync {
        uint8_t                 valid_bitmap[GHCB_VB_SZ];

        int                     sz_a;
        int                     sz_b;
        int                     sz_c;
        int                     sz_d;
};
#endif /* !_LOCORE */

/* Definitions used with the MSR protocol */
#define MSR_PROTO_CPUID_REQ     0x4
#define MSR_PROTO_CPUID_RESP    0x5
#define MSR_PROTO_TERMINATE     0x100

#ifndef _LOCORE

extern vaddr_t ghcb_vaddr;
extern paddr_t ghcb_paddr;

struct ghcb_extra_regs {
        uint64_t         exitcode;
        uint64_t         exitinfo1;
        uint64_t         exitinfo2;
        uint64_t         scratch;
        void            *data;
        size_t           data_sz;
};

void    ghcb_clear(struct ghcb_sa *);
int     ghcb_valbm_set(uint8_t *, int);
int     ghcb_valbm_isset(uint8_t *, int);
int     ghcb_verify_bm(uint8_t *, uint8_t *);
int     ghcb_valid(struct ghcb_sa *);
int     ghcb_empty(struct ghcb_sa *);

void    ghcb_sync_val(int, int, struct ghcb_sync *);
void    ghcb_sync_out(struct trapframe *, const struct ghcb_extra_regs *,
            struct ghcb_sa *, struct ghcb_sync *);
void    ghcb_sync_in(struct trapframe *, struct ghcb_extra_regs *,
            struct ghcb_sa *, struct ghcb_sync *);
void    _ghcb_mem_rw(vaddr_t, int, void *, bool);
void    _ghcb_io_rw(uint16_t, int, uint32_t *, bool);

static inline uint8_t
ghcb_mem_read_1(vaddr_t addr)
{
        uint8_t val;

        _ghcb_mem_rw(addr, GHCB_SZ8, &val, true);
        return val;
}

static inline uint16_t
ghcb_mem_read_2(vaddr_t addr)
{
        uint16_t val;

        _ghcb_mem_rw(addr, GHCB_SZ16, &val, true);
        return val;
}

static inline uint32_t
ghcb_mem_read_4(vaddr_t addr)
{
        uint32_t val;

        _ghcb_mem_rw(addr, GHCB_SZ32, &val, true);
        return val;
}

static inline uint64_t
ghcb_mem_read_8(vaddr_t addr)
{
        uint64_t val;

        _ghcb_mem_rw(addr, GHCB_SZ64, &val, true);
        return val;
}

static inline void
ghcb_mem_write_1(vaddr_t addr, uint8_t v)
{
        _ghcb_mem_rw(addr, GHCB_SZ8, &v, false);
}

static inline void
ghcb_mem_write_2(vaddr_t addr, uint16_t v)
{
        _ghcb_mem_rw(addr, GHCB_SZ16, &v, false);
}

static inline void
ghcb_mem_write_4(vaddr_t addr, uint32_t v)
{
        _ghcb_mem_rw(addr, GHCB_SZ32, &v, false);
}

static inline void
ghcb_mem_write_8(vaddr_t addr, uint64_t v)
{
        _ghcb_mem_rw(addr, GHCB_SZ64, &v, false);
}

static inline uint8_t
ghcb_io_read_1(uint16_t port)
{
        uint32_t val;

        _ghcb_io_rw(port, GHCB_SZ8, &val, true);
        return val;
}

static inline uint16_t
ghcb_io_read_2(uint16_t port)
{
        uint32_t val;

        _ghcb_io_rw(port, GHCB_SZ16, &val, true);
        return val;
}

static inline uint32_t
ghcb_io_read_4(uint16_t port)
{
        uint32_t val;

        _ghcb_io_rw(port, GHCB_SZ32, &val, true);
        return val;
}

static inline void
ghcb_io_write_1(uint16_t port, uint8_t v)
{
        uint32_t val = v;

        _ghcb_io_rw(port, GHCB_SZ8, &val, false);
}

static inline void
ghcb_io_write_2(uint16_t port, uint16_t v)
{
        uint32_t val = v;

        _ghcb_io_rw(port, GHCB_SZ16, &val, false);
}

static inline void
ghcb_io_write_4(uint16_t port, uint32_t v)
{
        _ghcb_io_rw(port, GHCB_SZ32, &v, false);
}

#endif /* !_LOCORE */

#endif /* !_MACHINE_GHCB_H_ */