Blame opae-libs/libbitstream/bitstream.c

Packit 534379
// Copyright(c) 2018-2020, Intel Corporation
Packit 534379
//
Packit 534379
// Redistribution  and  use  in source  and  binary  forms,  with  or  without
Packit 534379
// modification, are permitted provided that the following conditions are met:
Packit 534379
//
Packit 534379
// * Redistributions of  source code  must retain the  above copyright notice,
Packit 534379
//   this list of conditions and the following disclaimer.
Packit 534379
// * Redistributions in binary form must reproduce the above copyright notice,
Packit 534379
//   this list of conditions and the following disclaimer in the documentation
Packit 534379
//   and/or other materials provided with the distribution.
Packit 534379
// * Neither the name  of Intel Corporation  nor the names of its contributors
Packit 534379
//   may be used to  endorse or promote  products derived  from this  software
Packit 534379
//   without specific prior written permission.
Packit 534379
//
Packit 534379
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
Packit 534379
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING,  BUT NOT LIMITED TO,  THE
Packit 534379
// IMPLIED WARRANTIES OF  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
Packit 534379
// ARE DISCLAIMED.  IN NO EVENT  SHALL THE COPYRIGHT OWNER  OR CONTRIBUTORS BE
Packit 534379
// LIABLE  FOR  ANY  DIRECT,  INDIRECT,  INCIDENTAL,  SPECIAL,  EXEMPLARY,  OR
Packit 534379
// CONSEQUENTIAL  DAMAGES  (INCLUDING,  BUT  NOT LIMITED  TO,  PROCUREMENT  OF
Packit 534379
// SUBSTITUTE GOODS OR SERVICES;  LOSS OF USE,  DATA, OR PROFITS;  OR BUSINESS
Packit 534379
// INTERRUPTION)  HOWEVER CAUSED  AND ON ANY THEORY  OF LIABILITY,  WHETHER IN
Packit 534379
// CONTRACT,  STRICT LIABILITY,  OR TORT  (INCLUDING NEGLIGENCE  OR OTHERWISE)
Packit 534379
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,  EVEN IF ADVISED OF THE
Packit 534379
// POSSIBILITY OF SUCH DAMAGE.
Packit 534379
Packit 534379
#ifdef HAVE_CONFIG_H
Packit 534379
#include <config.h>
Packit 534379
#endif // HAVE_CONFIG_H
Packit 534379
Packit 534379
#include <stdio.h>
Packit 534379
#include <errno.h>
Packit 534379
#include <sys/types.h>
Packit 534379
#include <sys/stat.h>
Packit 534379
#include <unistd.h>
Packit 534379
Packit 534379
#include <uuid/uuid.h>
Packit 534379
#include <json-c/json.h>
Packit 534379
#include "bitstream.h"
Packit 534379
#include "bits_utils.h"
Packit 534379
#include "metadatav1.h"
Packit 534379
Packit 534379
#include <opae/log.h>
Packit 534379
#include <opae/properties.h>
Packit 534379
#include <opae/sysobject.h>
Packit 534379
Packit 534379
STATIC fpga_result opae_bitstream_read_file(const char *file,
Packit 534379
					    uint8_t **buf,
Packit 534379
					    size_t *len)
Packit 534379
{
Packit 534379
	FILE *fp;
Packit 534379
	fpga_result res = FPGA_EXCEPTION;
Packit 534379
	long pos;
Packit 534379
	size_t sz;
Packit 534379
Packit 534379
	fp = fopen(file, "rb");
Packit 534379
	if (!fp) {
Packit 534379
		OPAE_ERR("fopen failed");
Packit 534379
		return FPGA_EXCEPTION;
Packit 534379
	}
Packit 534379
Packit 534379
	if (fseek(fp, 0, SEEK_END) < 0) {
Packit 534379
		OPAE_ERR("fseek failed");
Packit 534379
		goto out_close;
Packit 534379
	}
Packit 534379
Packit 534379
	pos = ftell(fp);
Packit 534379
	if (pos < 0) {
Packit 534379
		OPAE_ERR("ftell failed");
Packit 534379
		goto out_close;
Packit 534379
	}
Packit 534379
Packit 534379
	*len = (size_t)pos;
Packit 534379
Packit 534379
	*buf = (uint8_t *)malloc(*len);
Packit 534379
	if (!*buf) {
Packit 534379
		OPAE_ERR("malloc failed");
Packit 534379
		res = FPGA_NO_MEMORY;
Packit 534379
		*len = 0;
Packit 534379
		goto out_close;
Packit 534379
	}
Packit 534379
Packit 534379
	if (fseek(fp, 0, SEEK_SET) < 0) {
Packit 534379
		OPAE_ERR("fseek failed");
Packit 534379
		goto out_free;
Packit 534379
	}
Packit 534379
Packit 534379
	sz = fread(*buf, 1, *len, fp);
Packit 534379
	if (ferror(fp)) {
Packit 534379
		OPAE_ERR("ferror after read");
Packit 534379
		goto out_free;
Packit 534379
	}
Packit 534379
Packit 534379
	if (sz != *len) {
Packit 534379
		OPAE_ERR("file size and number "
Packit 534379
			 "of bytes read mismatch");
Packit 534379
		goto out_free;
Packit 534379
	}
Packit 534379
Packit 534379
	fclose(fp);
Packit 534379
	return FPGA_OK;
Packit 534379
Packit 534379
out_free:
Packit 534379
	free(*buf);
Packit 534379
	*buf = NULL;
Packit 534379
	*len = 0;
Packit 534379
out_close:
Packit 534379
	fclose(fp);
Packit 534379
	return res;
Packit 534379
}
Packit 534379
Packit 534379
bool opae_is_legacy_bitstream(opae_bitstream_info *info)
Packit 534379
{
Packit 534379
	opae_legacy_bitstream_header *hdr;
Packit 534379
Packit 534379
	if (info->data_len < sizeof(opae_legacy_bitstream_header))
Packit 534379
		return false;
Packit 534379
Packit 534379
	hdr = (opae_legacy_bitstream_header *)info->data;
Packit 534379
	if (hdr->legacy_magic == OPAE_LEGACY_BITSTREAM_MAGIC)
Packit 534379
		return true;
Packit 534379
Packit 534379
	return false;
Packit 534379
}
Packit 534379
Packit 534379
STATIC void opae_resolve_legacy_bitstream(opae_bitstream_info *info)
Packit 534379
{
Packit 534379
	opae_legacy_bitstream_header *hdr =
Packit 534379
		(opae_legacy_bitstream_header *)info->data;
Packit 534379
	uint8_t *p = &hdr->legacy_pr_ifc_id[15];
Packit 534379
	int i = 0;
Packit 534379
Packit 534379
	// The guid is encoded backwards.
Packit 534379
	// Reverse it.
Packit 534379
	while (p >= hdr->legacy_pr_ifc_id) {
Packit 534379
		info->pr_interface_id[i++] = *p--;
Packit 534379
	}
Packit 534379
Packit 534379
	info->rbf_data = info->data + sizeof(opae_legacy_bitstream_header);
Packit 534379
	info->rbf_len = info->data_len - sizeof(opae_legacy_bitstream_header);
Packit 534379
}
Packit 534379
Packit 534379
STATIC void *opae_bitstream_parse_metadata(const char *metadata,
Packit 534379
					   fpga_guid pr_interface_id,
Packit 534379
					   int *version)
Packit 534379
{
Packit 534379
	json_object *root = NULL;
Packit 534379
	json_object *j_version = NULL;
Packit 534379
	enum json_tokener_error j_err = json_tokener_success;
Packit 534379
	void *parsed = NULL;
Packit 534379
Packit 534379
	root = json_tokener_parse_verbose(metadata, &j_err);
Packit 534379
	if (!root) {
Packit 534379
		OPAE_ERR("invalid JSON metadata: %s",
Packit 534379
			 json_tokener_error_desc(j_err));
Packit 534379
		return NULL;
Packit 534379
	}
Packit 534379
Packit 534379
	if (!json_object_object_get_ex(root,
Packit 534379
				       "version",
Packit 534379
				       &j_version)) {
Packit 534379
		OPAE_ERR("metadata: failed to find \"version\" key");
Packit 534379
		goto out_put;
Packit 534379
	}
Packit 534379
Packit 534379
	if (!json_object_is_type(j_version, json_type_int)) {
Packit 534379
		OPAE_ERR("metadata: \"version\" key not integer");
Packit 534379
		goto out_put;
Packit 534379
	}
Packit 534379
Packit 534379
	*version = json_object_get_int(j_version);
Packit 534379
Packit 534379
	switch (*version) {
Packit 534379
Packit 534379
	// Some invalid GBS's around the BBS 6.4.0 and
Packit 534379
	// BBS 6.5.0 eras incorrectly set the metadata
Packit 534379
	// version to 640/650 respectively.
Packit 534379
	// Allow 640/650 to serve as an alias for 1.
Packit 534379
	case 650:
Packit 534379
	case 640:
Packit 534379
		*version = 1; /* FALLTHROUGH */
Packit 534379
	case 1:
Packit 534379
		parsed = opae_bitstream_parse_metadata_v1(root,
Packit 534379
							  pr_interface_id);
Packit 534379
	break;
Packit 534379
Packit 534379
	default:
Packit 534379
		OPAE_ERR("metadata: unsupported version: %d", *version);
Packit 534379
	}
Packit 534379
Packit 534379
out_put:
Packit 534379
	json_object_put(root);
Packit 534379
Packit 534379
	return parsed;
Packit 534379
}
Packit 534379
Packit 534379
STATIC fpga_guid valid_GBS_guid = {
Packit 534379
0x58, 0x65, 0x6f, 0x6e,
Packit 534379
0x46, 0x50,
Packit 534379
0x47, 0x41,
Packit 534379
0xb7, 0x47,
Packit 534379
0x42, 0x53, 0x76, 0x30, 0x30, 0x31
Packit 534379
};
Packit 534379
STATIC fpga_result opae_resolve_bitstream(opae_bitstream_info *info)
Packit 534379
{
Packit 534379
	opae_bitstream_header *hdr;
Packit 534379
	size_t sz;
Packit 534379
	char *buf;
Packit 534379
Packit 534379
	if (info->data_len < sizeof(opae_bitstream_header)) {
Packit 534379
		OPAE_ERR("file length smaller than bitstream header: "
Packit 534379
			 "\"%s\"", info->filename);
Packit 534379
		return FPGA_INVALID_PARAM;
Packit 534379
	}
Packit 534379
Packit 534379
	hdr = (opae_bitstream_header *)info->data;
Packit 534379
Packit 534379
	if (uuid_compare(hdr->valid_gbs_guid, valid_GBS_guid) != 0) {
Packit 534379
		OPAE_ERR("GBS guid is invalid: \"%s\"", info->filename);
Packit 534379
		return FPGA_INVALID_PARAM;
Packit 534379
	}
Packit 534379
Packit 534379
	// Check that metadata_length makes sense
Packit 534379
	// given that we know the total file size.
Packit 534379
Packit 534379
	sz = sizeof(fpga_guid) + sizeof(uint32_t);
Packit 534379
	sz += (size_t)hdr->metadata_length;
Packit 534379
Packit 534379
	if (sz > info->data_len) {
Packit 534379
		OPAE_ERR("invalid metadata length in \"%s\"", info->filename);
Packit 534379
		return FPGA_INVALID_PARAM;
Packit 534379
	}
Packit 534379
Packit 534379
	info->rbf_data = info->data + sz;
Packit 534379
	info->rbf_len = info->data_len - sz;
Packit 534379
Packit 534379
	buf = (char *)malloc(hdr->metadata_length + 1);
Packit 534379
	if (!buf) {
Packit 534379
		OPAE_ERR("malloc failed");
Packit 534379
		return FPGA_NO_MEMORY;
Packit 534379
	}
Packit 534379
Packit 534379
	memcpy(buf, hdr->metadata, hdr->metadata_length);
Packit 534379
	buf[hdr->metadata_length] = '\0';
Packit 534379
Packit 534379
	info->parsed_metadata =
Packit 534379
		opae_bitstream_parse_metadata(buf,
Packit 534379
					      info->pr_interface_id,
Packit 534379
					      &info->metadata_version);
Packit 534379
Packit 534379
	free(buf);
Packit 534379
Packit 534379
	return info->parsed_metadata ? FPGA_OK : FPGA_EXCEPTION;
Packit 534379
}
Packit 534379
Packit 534379
fpga_result opae_load_bitstream(const char *file, opae_bitstream_info *info)
Packit 534379
{
Packit 534379
	fpga_result res;
Packit 534379
Packit 534379
	if (!file || !info)
Packit 534379
		return FPGA_INVALID_PARAM;
Packit 534379
Packit 534379
	if (!opae_bitstream_path_is_valid(file,
Packit 534379
					  OPAE_BITSTREAM_PATH_NO_SYMLINK)) {
Packit 534379
		OPAE_ERR("invalid bitstream path \"%s\"", file);
Packit 534379
		return FPGA_INVALID_PARAM;
Packit 534379
	}
Packit 534379
Packit 534379
	memset(info, 0, sizeof(opae_bitstream_info));
Packit 534379
Packit 534379
	res = opae_bitstream_read_file(file, &info->data, &info->data_len);
Packit 534379
	if (res != FPGA_OK) {
Packit 534379
		OPAE_ERR("error loading \"%s\"", file);
Packit 534379
		return res;
Packit 534379
	}
Packit 534379
Packit 534379
	info->filename = file;
Packit 534379
Packit 534379
	if (opae_is_legacy_bitstream(info)) {
Packit 534379
		opae_resolve_legacy_bitstream(info);
Packit 534379
		OPAE_MSG("Legacy bitstream (GBS) format detected.");
Packit 534379
		OPAE_MSG("Legacy GBS support is deprecated "
Packit 534379
			 "and will be removed in a future release.");
Packit 534379
		return FPGA_OK;
Packit 534379
	}
Packit 534379
Packit 534379
	return opae_resolve_bitstream(info);
Packit 534379
}
Packit 534379
Packit 534379
fpga_result opae_unload_bitstream(opae_bitstream_info *info)
Packit 534379
{
Packit 534379
	fpga_result res = FPGA_OK;
Packit 534379
Packit 534379
	if (!info)
Packit 534379
		return FPGA_INVALID_PARAM;
Packit 534379
Packit 534379
	if (info->data)
Packit 534379
		free(info->data);
Packit 534379
Packit 534379
	if (info->parsed_metadata) {
Packit 534379
Packit 534379
		switch (info->metadata_version) {
Packit 534379
Packit 534379
		case 1:
Packit 534379
			opae_bitstream_release_metadata_v1(
Packit 534379
			(opae_bitstream_metadata_v1 *)info->parsed_metadata);
Packit 534379
		break;
Packit 534379
Packit 534379
		default:
Packit 534379
			OPAE_ERR("metadata: unsupported version: %d",
Packit 534379
				 info->metadata_version);
Packit 534379
			res = FPGA_EXCEPTION;
Packit 534379
		}
Packit 534379
Packit 534379
	}
Packit 534379
Packit 534379
	memset(info, 0, sizeof(opae_bitstream_info));
Packit 534379
Packit 534379
	return res;
Packit 534379
}