qemu/hw/cxl/cxl-cdat.c
<<
>>
Prefs
   1/*
   2 * CXL CDAT Structure
   3 *
   4 * Copyright (C) 2021 Avery Design Systems, Inc.
   5 *
   6 * This work is licensed under the terms of the GNU GPL, version 2 or later.
   7 * See the COPYING file in the top-level directory.
   8 */
   9
  10#include "qemu/osdep.h"
  11#include "hw/pci/pci.h"
  12#include "hw/cxl/cxl.h"
  13#include "qapi/error.h"
  14#include "qemu/error-report.h"
  15
  16static void cdat_len_check(CDATSubHeader *hdr, Error **errp)
  17{
  18    assert(hdr->length);
  19    assert(hdr->reserved == 0);
  20
  21    switch (hdr->type) {
  22    case CDAT_TYPE_DSMAS:
  23        assert(hdr->length == sizeof(CDATDsmas));
  24        break;
  25    case CDAT_TYPE_DSLBIS:
  26        assert(hdr->length == sizeof(CDATDslbis));
  27        break;
  28    case CDAT_TYPE_DSMSCIS:
  29        assert(hdr->length == sizeof(CDATDsmscis));
  30        break;
  31    case CDAT_TYPE_DSIS:
  32        assert(hdr->length == sizeof(CDATDsis));
  33        break;
  34    case CDAT_TYPE_DSEMTS:
  35        assert(hdr->length == sizeof(CDATDsemts));
  36        break;
  37    case CDAT_TYPE_SSLBIS:
  38        assert(hdr->length >= sizeof(CDATSslbisHeader));
  39        assert((hdr->length - sizeof(CDATSslbisHeader)) %
  40               sizeof(CDATSslbe) == 0);
  41        break;
  42    default:
  43        error_setg(errp, "Type %d is reserved", hdr->type);
  44    }
  45}
  46
  47static void ct3_build_cdat(CDATObject *cdat, Error **errp)
  48{
  49    g_autofree CDATTableHeader *cdat_header = NULL;
  50    g_autofree CDATEntry *cdat_st = NULL;
  51    uint8_t sum = 0;
  52    int ent, i;
  53
  54    /* Use default table if fopen == NULL */
  55    assert(cdat->build_cdat_table);
  56
  57    cdat_header = g_malloc0(sizeof(*cdat_header));
  58    if (!cdat_header) {
  59        error_setg(errp, "Failed to allocate CDAT header");
  60        return;
  61    }
  62
  63    cdat->built_buf_len = cdat->build_cdat_table(&cdat->built_buf, cdat->private);
  64
  65    if (!cdat->built_buf_len) {
  66        /* Build later as not all data available yet */
  67        cdat->to_update = true;
  68        return;
  69    }
  70    cdat->to_update = false;
  71
  72    cdat_st = g_malloc0(sizeof(*cdat_st) * (cdat->built_buf_len + 1));
  73    if (!cdat_st) {
  74        error_setg(errp, "Failed to allocate CDAT entry array");
  75        return;
  76    }
  77
  78    /* Entry 0 for CDAT header, starts with Entry 1 */
  79    for (ent = 1; ent < cdat->built_buf_len + 1; ent++) {
  80        CDATSubHeader *hdr = cdat->built_buf[ent - 1];
  81        uint8_t *buf = (uint8_t *)cdat->built_buf[ent - 1];
  82
  83        cdat_st[ent].base = hdr;
  84        cdat_st[ent].length = hdr->length;
  85
  86        cdat_header->length += hdr->length;
  87        for (i = 0; i < hdr->length; i++) {
  88            sum += buf[i];
  89        }
  90    }
  91
  92    /* CDAT header */
  93    cdat_header->revision = CXL_CDAT_REV;
  94    /* For now, no runtime updates */
  95    cdat_header->sequence = 0;
  96    cdat_header->length += sizeof(CDATTableHeader);
  97    sum += cdat_header->revision + cdat_header->sequence +
  98        cdat_header->length;
  99    /* Sum of all bytes including checksum must be 0 */
 100    cdat_header->checksum = ~sum + 1;
 101
 102    cdat_st[0].base = g_steal_pointer(&cdat_header);
 103    cdat_st[0].length = sizeof(*cdat_header);
 104    cdat->entry_len = 1 + cdat->built_buf_len;
 105    cdat->entry = g_steal_pointer(&cdat_st);
 106}
 107
 108static void ct3_load_cdat(CDATObject *cdat, Error **errp)
 109{
 110    g_autofree CDATEntry *cdat_st = NULL;
 111    uint8_t sum = 0;
 112    int num_ent;
 113    int i = 0, ent = 1, file_size = 0;
 114    CDATSubHeader *hdr;
 115    FILE *fp = NULL;
 116
 117    /* Read CDAT file and create its cache */
 118    fp = fopen(cdat->filename, "r");
 119    if (!fp) {
 120        error_setg(errp, "CDAT: Unable to open file");
 121        return;
 122    }
 123
 124    fseek(fp, 0, SEEK_END);
 125    file_size = ftell(fp);
 126    fseek(fp, 0, SEEK_SET);
 127    cdat->buf = g_malloc0(file_size);
 128
 129    if (fread(cdat->buf, file_size, 1, fp) == 0) {
 130        error_setg(errp, "CDAT: File read failed");
 131        return;
 132    }
 133
 134    fclose(fp);
 135
 136    if (file_size < sizeof(CDATTableHeader)) {
 137        error_setg(errp, "CDAT: File too short");
 138        return;
 139    }
 140    i = sizeof(CDATTableHeader);
 141    num_ent = 1;
 142    while (i < file_size) {
 143        hdr = (CDATSubHeader *)(cdat->buf + i);
 144        cdat_len_check(hdr, errp);
 145        i += hdr->length;
 146        num_ent++;
 147    }
 148    if (i != file_size) {
 149        error_setg(errp, "CDAT: File length missmatch");
 150        return;
 151    }
 152
 153    cdat_st = g_malloc0(sizeof(*cdat_st) * num_ent);
 154    if (!cdat_st) {
 155        error_setg(errp, "CDAT: Failed to allocate entry array");
 156        return;
 157    }
 158
 159    /* Set CDAT header, Entry = 0 */
 160    cdat_st[0].base = cdat->buf;
 161    cdat_st[0].length = sizeof(CDATTableHeader);
 162    i = 0;
 163
 164    while (i < cdat_st[0].length) {
 165        sum += cdat->buf[i++];
 166    }
 167
 168    /* Read CDAT structures */
 169    while (i < file_size) {
 170        hdr = (CDATSubHeader *)(cdat->buf + i);
 171        cdat_len_check(hdr, errp);
 172
 173        cdat_st[ent].base = hdr;
 174        cdat_st[ent].length = hdr->length;
 175
 176        while (cdat->buf + i <
 177               (uint8_t *)cdat_st[ent].base + cdat_st[ent].length) {
 178            assert(i < file_size);
 179            sum += cdat->buf[i++];
 180        }
 181
 182        ent++;
 183    }
 184
 185    if (sum != 0) {
 186        warn_report("CDAT: Found checksum mismatch in %s", cdat->filename);
 187    }
 188    cdat->entry_len = num_ent;
 189    cdat->entry = g_steal_pointer(&cdat_st);
 190}
 191
 192void cxl_doe_cdat_init(CXLComponentState *cxl_cstate, Error **errp)
 193{
 194    CDATObject *cdat = &cxl_cstate->cdat;
 195
 196    if (cdat->filename) {
 197        ct3_load_cdat(cdat, errp);
 198    } else {
 199        ct3_build_cdat(cdat, errp);
 200    }
 201}
 202
 203void cxl_doe_cdat_update(CXLComponentState *cxl_cstate, Error **errp)
 204{
 205    CDATObject *cdat = &cxl_cstate->cdat;
 206
 207    if (cdat->to_update) {
 208        ct3_build_cdat(cdat, errp);
 209    }
 210}
 211
 212void cxl_doe_cdat_release(CXLComponentState *cxl_cstate)
 213{
 214    CDATObject *cdat = &cxl_cstate->cdat;
 215
 216    free(cdat->entry);
 217    if (cdat->built_buf) {
 218        cdat->free_cdat_table(cdat->built_buf, cdat->built_buf_len,
 219                              cdat->private);
 220    }
 221    if (cdat->buf) {
 222        free(cdat->buf);
 223    }
 224}
 225