summaryrefslogtreecommitdiff
path: root/tools/libs/guest/xg_sr_common.c
blob: 7ccdc3b1f6aaea3b4e6e3495eb089f91007f82d9 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
#include <assert.h>

#include "xg_sr_common.h"

#include <xen-tools/common-macros.h>

static const char *const dhdr_types[] =
{
    [DHDR_TYPE_X86_PV]  = "x86 PV",
    [DHDR_TYPE_X86_HVM] = "x86 HVM",
};

const char *dhdr_type_to_str(uint32_t type)
{
    if ( type < ARRAY_SIZE(dhdr_types) && dhdr_types[type] )
        return dhdr_types[type];

    return "Reserved";
}

static const char *const mandatory_rec_types[] =
{
    [REC_TYPE_END]                          = "End",
    [REC_TYPE_PAGE_DATA]                    = "Page data",
    [REC_TYPE_X86_PV_INFO]                  = "x86 PV info",
    [REC_TYPE_X86_PV_P2M_FRAMES]            = "x86 PV P2M frames",
    [REC_TYPE_X86_PV_VCPU_BASIC]            = "x86 PV vcpu basic",
    [REC_TYPE_X86_PV_VCPU_EXTENDED]         = "x86 PV vcpu extended",
    [REC_TYPE_X86_PV_VCPU_XSAVE]            = "x86 PV vcpu xsave",
    [REC_TYPE_SHARED_INFO]                  = "Shared info",
    [REC_TYPE_X86_TSC_INFO]                 = "x86 TSC info",
    [REC_TYPE_HVM_CONTEXT]                  = "HVM context",
    [REC_TYPE_HVM_PARAMS]                   = "HVM params",
    [REC_TYPE_TOOLSTACK]                    = "Toolstack",
    [REC_TYPE_X86_PV_VCPU_MSRS]             = "x86 PV vcpu msrs",
    [REC_TYPE_VERIFY]                       = "Verify",
    [REC_TYPE_CHECKPOINT]                   = "Checkpoint",
    [REC_TYPE_CHECKPOINT_DIRTY_PFN_LIST]    = "Checkpoint dirty pfn list",
    [REC_TYPE_STATIC_DATA_END]              = "Static data end",
    [REC_TYPE_X86_CPUID_POLICY]             = "x86 CPUID policy",
    [REC_TYPE_X86_MSR_POLICY]               = "x86 MSR policy",
};

const char *rec_type_to_str(uint32_t type)
{
    if ( !(type & REC_TYPE_OPTIONAL) )
    {
        if ( (type < ARRAY_SIZE(mandatory_rec_types)) &&
             (mandatory_rec_types[type]) )
            return mandatory_rec_types[type];
    }

    return "Reserved";
}

int write_split_record(struct xc_sr_context *ctx, struct xc_sr_record *rec,
                       void *buf, size_t sz)
{
    static const char zeroes[(1u << REC_ALIGN_ORDER) - 1] = { 0 };

    xc_interface *xch = ctx->xch;
    typeof(rec->length) combined_length = rec->length + sz;
    size_t record_length = ROUNDUP(combined_length, REC_ALIGN_ORDER);
    struct iovec parts[] = {
        { &rec->type,       sizeof(rec->type) },
        { &combined_length, sizeof(combined_length) },
        { rec->data,        rec->length },
        { buf,              sz },
        { (void *)zeroes,   record_length - combined_length },
    };

    if ( record_length > REC_LENGTH_MAX )
    {
        ERROR("Record (0x%08x, %s) length %#zx exceeds max (%#x)", rec->type,
              rec_type_to_str(rec->type), record_length, REC_LENGTH_MAX);
        return -1;
    }

    if ( rec->length )
        assert(rec->data);
    if ( sz )
        assert(buf);

    if ( writev_exact(ctx->fd, parts, ARRAY_SIZE(parts)) )
        goto err;

    return 0;

 err:
    PERROR("Unable to write record to stream");
    return -1;
}

int read_record(struct xc_sr_context *ctx, int fd, struct xc_sr_record *rec)
{
    xc_interface *xch = ctx->xch;
    struct xc_sr_rhdr rhdr;
    size_t datasz;

    if ( read_exact(fd, &rhdr, sizeof(rhdr)) )
    {
        PERROR("Failed to read Record Header from stream");
        return -1;
    }

    if ( rhdr.length > REC_LENGTH_MAX )
    {
        ERROR("Record (0x%08x, %s) length %#x exceeds max (%#x)", rhdr.type,
              rec_type_to_str(rhdr.type), rhdr.length, REC_LENGTH_MAX);
        return -1;
    }

    datasz = ROUNDUP(rhdr.length, REC_ALIGN_ORDER);

    if ( datasz )
    {
        rec->data = malloc(datasz);

        if ( !rec->data )
        {
            ERROR("Unable to allocate %zu bytes for record data (0x%08x, %s)",
                  datasz, rhdr.type, rec_type_to_str(rhdr.type));
            return -1;
        }

        if ( read_exact(fd, rec->data, datasz) )
        {
            free(rec->data);
            rec->data = NULL;
            PERROR("Failed to read %zu bytes of data for record (0x%08x, %s)",
                   datasz, rhdr.type, rec_type_to_str(rhdr.type));
            return -1;
        }
    }
    else
        rec->data = NULL;

    rec->type   = rhdr.type;
    rec->length = rhdr.length;

    return 0;
};

static void __attribute__((unused)) build_assertions(void)
{
    BUILD_BUG_ON(sizeof(struct xc_sr_ihdr) != 24);
    BUILD_BUG_ON(sizeof(struct xc_sr_dhdr) != 16);
    BUILD_BUG_ON(sizeof(struct xc_sr_rhdr) != 8);

    BUILD_BUG_ON(sizeof(struct xc_sr_rec_page_data_header)  != 8);
    BUILD_BUG_ON(sizeof(struct xc_sr_rec_x86_pv_info)       != 8);
    BUILD_BUG_ON(sizeof(struct xc_sr_rec_x86_pv_p2m_frames) != 8);
    BUILD_BUG_ON(sizeof(struct xc_sr_rec_x86_pv_vcpu_hdr)   != 8);
    BUILD_BUG_ON(sizeof(struct xc_sr_rec_x86_tsc_info)      != 24);
    BUILD_BUG_ON(sizeof(struct xc_sr_rec_hvm_params_entry)  != 16);
    BUILD_BUG_ON(sizeof(struct xc_sr_rec_hvm_params)        != 8);
}

/*
 * Local variables:
 * mode: C
 * c-file-style: "BSD"
 * c-basic-offset: 4
 * tab-width: 4
 * indent-tabs-mode: nil
 * End:
 */