mirror of
https://github.com/izzy2lost/xemu.git
synced 2026-07-06 00:20:22 -07:00
Merge tag 'for_upstream' of https://git.kernel.org/pub/scm/virt/kvm/mst/qemu into staging
pci,pc,virtio: features, tests, fixes, cleanups lots of acpi rework first version of biosbits infrastructure ASID support in vhost-vdpa core_count2 support in smbios PCIe DOE emulation virtio vq reset HMAT support part of infrastructure for viommu support in vhost-vdpa VTD PASID support fixes, tests all over the place Signed-off-by: Michael S. Tsirkin <mst@redhat.com> # -----BEGIN PGP SIGNATURE----- # # iQFDBAABCAAtFiEEXQn9CHHI+FuUyooNKB8NuNKNVGkFAmNpXDkPHG1zdEByZWRo # YXQuY29tAAoJECgfDbjSjVRpD0AH/2G8ZPrgrxJC9y3uD5/5J6QRzO+TsDYbg5ut # uBf4rKSHHzcu6zdyAfsrhbAKKzyD4HrEGNXZrBjnKM1xCiB/SGBcDIWntwrca2+s # 5Dpbi4xvd4tg6tVD4b47XNDCcn2uUbeI0e2M5QIbtCmzdi/xKbFAfl5G8DQp431X # Kmz79G4CdKWyjVlM0HoYmdCw/4FxkdjD02tE/Uc5YMrePNaEg5Bw4hjCHbx1b6ur # 6gjeXAtncm9s4sO0l+sIdyiqlxiTry9FSr35WaQ0qPU+Og5zaf1EiWfdl8TRo4qU # EAATw5A4hyw11GfOGp7oOVkTGvcNB/H7aIxD7emdWZV8+BMRPKo= # =zTCn # -----END PGP SIGNATURE----- # gpg: Signature made Mon 07 Nov 2022 14:27:53 EST # gpg: using RSA key 5D09FD0871C8F85B94CA8A0D281F0DB8D28D5469 # gpg: issuer "mst@redhat.com" # gpg: Good signature from "Michael S. Tsirkin <mst@kernel.org>" [full] # gpg: aka "Michael S. Tsirkin <mst@redhat.com>" [full] # Primary key fingerprint: 0270 606B 6F3C DF3D 0B17 0970 C350 3912 AFBE 8E67 # Subkey fingerprint: 5D09 FD08 71C8 F85B 94CA 8A0D 281F 0DB8 D28D 5469 * tag 'for_upstream' of https://git.kernel.org/pub/scm/virt/kvm/mst/qemu: (83 commits) checkpatch: better pattern for inline comments hw/virtio: introduce virtio_device_should_start tests/acpi: update tables for new core count test bios-tables-test: add test for number of cores > 255 tests/acpi: allow changes for core_count2 test bios-tables-test: teach test to use smbios 3.0 tables hw/smbios: add core_count2 to smbios table type 4 vhost-user: Support vhost_dev_start vhost: Change the sequence of device start intel-iommu: PASID support intel-iommu: convert VTD_PE_GET_FPD_ERR() to be a function intel-iommu: drop VTDBus intel-iommu: don't warn guest errors when getting rid2pasid entry vfio: move implement of vfio_get_xlat_addr() to memory.c tests: virt: Update expected *.acpihmatvirt tables tests: acpi: aarch64/virt: add a test for hmat nodes with no initiators hw/arm/virt: Enable HMAT on arm virt machine tests: Add HMAT AArch64/virt empty table files tests: acpi: q35: update expected blobs *.hmat-noinitiators expected HMAT: tests: acpi: q35: add test for hmat nodes without initiators ... Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
This commit is contained in:
+15
@@ -1835,6 +1835,13 @@ F: qapi/pci.json
|
||||
F: docs/pci*
|
||||
F: docs/specs/*pci*
|
||||
|
||||
PCIE DOE
|
||||
M: Huai-Cheng Kuo <hchkuo@avery-design.com.tw>
|
||||
M: Chris Browy <cbrowy@avery-design.com>
|
||||
S: Supported
|
||||
F: include/hw/pci/pcie_doe.h
|
||||
F: hw/pci/pcie_doe.c
|
||||
|
||||
ACPI/SMBIOS
|
||||
M: Michael S. Tsirkin <mst@redhat.com>
|
||||
M: Igor Mammedov <imammedo@redhat.com>
|
||||
@@ -1862,6 +1869,13 @@ S: Supported
|
||||
F: hw/acpi/viot.c
|
||||
F: hw/acpi/viot.h
|
||||
|
||||
ACPI/AVOCADO/BIOSBITS
|
||||
M: Ani Sinha <ani@anisinha.ca>
|
||||
S: Supported
|
||||
F: tests/avocado/acpi-bits/*
|
||||
F: tests/avocado/acpi-bits.py
|
||||
F: docs/devel/acpi-bits.rst
|
||||
|
||||
ACPI/HEST/GHES
|
||||
R: Dongjiu Geng <gengdongjiu1@gmail.com>
|
||||
L: qemu-arm@nongnu.org
|
||||
@@ -2003,6 +2017,7 @@ S: Supported
|
||||
F: hw/*/virtio*
|
||||
F: hw/virtio/Makefile.objs
|
||||
F: hw/virtio/trace-events
|
||||
F: qapi/virtio.json
|
||||
F: net/vhost-user.c
|
||||
F: include/hw/virtio/
|
||||
|
||||
|
||||
@@ -355,42 +355,62 @@ static int cryptodev_builtin_create_akcipher_session(
|
||||
return index;
|
||||
}
|
||||
|
||||
static int64_t cryptodev_builtin_create_session(
|
||||
static int cryptodev_builtin_create_session(
|
||||
CryptoDevBackend *backend,
|
||||
CryptoDevBackendSessionInfo *sess_info,
|
||||
uint32_t queue_index, Error **errp)
|
||||
uint32_t queue_index,
|
||||
CryptoDevCompletionFunc cb,
|
||||
void *opaque)
|
||||
{
|
||||
CryptoDevBackendBuiltin *builtin =
|
||||
CRYPTODEV_BACKEND_BUILTIN(backend);
|
||||
CryptoDevBackendSymSessionInfo *sym_sess_info;
|
||||
CryptoDevBackendAsymSessionInfo *asym_sess_info;
|
||||
int ret, status;
|
||||
Error *local_error = NULL;
|
||||
|
||||
switch (sess_info->op_code) {
|
||||
case VIRTIO_CRYPTO_CIPHER_CREATE_SESSION:
|
||||
sym_sess_info = &sess_info->u.sym_sess_info;
|
||||
return cryptodev_builtin_create_cipher_session(
|
||||
builtin, sym_sess_info, errp);
|
||||
ret = cryptodev_builtin_create_cipher_session(
|
||||
builtin, sym_sess_info, &local_error);
|
||||
break;
|
||||
|
||||
case VIRTIO_CRYPTO_AKCIPHER_CREATE_SESSION:
|
||||
asym_sess_info = &sess_info->u.asym_sess_info;
|
||||
return cryptodev_builtin_create_akcipher_session(
|
||||
builtin, asym_sess_info, errp);
|
||||
ret = cryptodev_builtin_create_akcipher_session(
|
||||
builtin, asym_sess_info, &local_error);
|
||||
break;
|
||||
|
||||
case VIRTIO_CRYPTO_HASH_CREATE_SESSION:
|
||||
case VIRTIO_CRYPTO_MAC_CREATE_SESSION:
|
||||
default:
|
||||
error_setg(errp, "Unsupported opcode :%" PRIu32 "",
|
||||
error_setg(&local_error, "Unsupported opcode :%" PRIu32 "",
|
||||
sess_info->op_code);
|
||||
return -1;
|
||||
return -VIRTIO_CRYPTO_NOTSUPP;
|
||||
}
|
||||
|
||||
return -1;
|
||||
if (local_error) {
|
||||
error_report_err(local_error);
|
||||
}
|
||||
if (ret < 0) {
|
||||
status = -VIRTIO_CRYPTO_ERR;
|
||||
} else {
|
||||
sess_info->session_id = ret;
|
||||
status = VIRTIO_CRYPTO_OK;
|
||||
}
|
||||
if (cb) {
|
||||
cb(opaque, status);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cryptodev_builtin_close_session(
|
||||
CryptoDevBackend *backend,
|
||||
uint64_t session_id,
|
||||
uint32_t queue_index, Error **errp)
|
||||
uint32_t queue_index,
|
||||
CryptoDevCompletionFunc cb,
|
||||
void *opaque)
|
||||
{
|
||||
CryptoDevBackendBuiltin *builtin =
|
||||
CRYPTODEV_BACKEND_BUILTIN(backend);
|
||||
@@ -407,6 +427,9 @@ static int cryptodev_builtin_close_session(
|
||||
|
||||
g_free(session);
|
||||
builtin->sessions[session_id] = NULL;
|
||||
if (cb) {
|
||||
cb(opaque, VIRTIO_CRYPTO_OK);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -506,7 +529,9 @@ static int cryptodev_builtin_asym_operation(
|
||||
static int cryptodev_builtin_operation(
|
||||
CryptoDevBackend *backend,
|
||||
CryptoDevBackendOpInfo *op_info,
|
||||
uint32_t queue_index, Error **errp)
|
||||
uint32_t queue_index,
|
||||
CryptoDevCompletionFunc cb,
|
||||
void *opaque)
|
||||
{
|
||||
CryptoDevBackendBuiltin *builtin =
|
||||
CRYPTODEV_BACKEND_BUILTIN(backend);
|
||||
@@ -514,11 +539,12 @@ static int cryptodev_builtin_operation(
|
||||
CryptoDevBackendSymOpInfo *sym_op_info;
|
||||
CryptoDevBackendAsymOpInfo *asym_op_info;
|
||||
enum CryptoDevBackendAlgType algtype = op_info->algtype;
|
||||
int ret = -VIRTIO_CRYPTO_ERR;
|
||||
int status = -VIRTIO_CRYPTO_ERR;
|
||||
Error *local_error = NULL;
|
||||
|
||||
if (op_info->session_id >= MAX_NUM_SESSIONS ||
|
||||
builtin->sessions[op_info->session_id] == NULL) {
|
||||
error_setg(errp, "Cannot find a valid session id: %" PRIu64 "",
|
||||
error_setg(&local_error, "Cannot find a valid session id: %" PRIu64 "",
|
||||
op_info->session_id);
|
||||
return -VIRTIO_CRYPTO_INVSESS;
|
||||
}
|
||||
@@ -526,14 +552,21 @@ static int cryptodev_builtin_operation(
|
||||
sess = builtin->sessions[op_info->session_id];
|
||||
if (algtype == CRYPTODEV_BACKEND_ALG_SYM) {
|
||||
sym_op_info = op_info->u.sym_op_info;
|
||||
ret = cryptodev_builtin_sym_operation(sess, sym_op_info, errp);
|
||||
status = cryptodev_builtin_sym_operation(sess, sym_op_info,
|
||||
&local_error);
|
||||
} else if (algtype == CRYPTODEV_BACKEND_ALG_ASYM) {
|
||||
asym_op_info = op_info->u.asym_op_info;
|
||||
ret = cryptodev_builtin_asym_operation(sess, op_info->op_code,
|
||||
asym_op_info, errp);
|
||||
status = cryptodev_builtin_asym_operation(sess, op_info->op_code,
|
||||
asym_op_info, &local_error);
|
||||
}
|
||||
|
||||
return ret;
|
||||
if (local_error) {
|
||||
error_report_err(local_error);
|
||||
}
|
||||
if (cb) {
|
||||
cb(opaque, status);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void cryptodev_builtin_cleanup(
|
||||
@@ -548,7 +581,7 @@ static void cryptodev_builtin_cleanup(
|
||||
|
||||
for (i = 0; i < MAX_NUM_SESSIONS; i++) {
|
||||
if (builtin->sessions[i] != NULL) {
|
||||
cryptodev_builtin_close_session(backend, i, 0, &error_abort);
|
||||
cryptodev_builtin_close_session(backend, i, 0, NULL, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -259,13 +259,18 @@ static int64_t cryptodev_vhost_user_sym_create_session(
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int64_t cryptodev_vhost_user_create_session(
|
||||
static int cryptodev_vhost_user_create_session(
|
||||
CryptoDevBackend *backend,
|
||||
CryptoDevBackendSessionInfo *sess_info,
|
||||
uint32_t queue_index, Error **errp)
|
||||
uint32_t queue_index,
|
||||
CryptoDevCompletionFunc cb,
|
||||
void *opaque)
|
||||
{
|
||||
uint32_t op_code = sess_info->op_code;
|
||||
CryptoDevBackendSymSessionInfo *sym_sess_info;
|
||||
int64_t ret;
|
||||
Error *local_error = NULL;
|
||||
int status;
|
||||
|
||||
switch (op_code) {
|
||||
case VIRTIO_CRYPTO_CIPHER_CREATE_SESSION:
|
||||
@@ -273,27 +278,42 @@ static int64_t cryptodev_vhost_user_create_session(
|
||||
case VIRTIO_CRYPTO_MAC_CREATE_SESSION:
|
||||
case VIRTIO_CRYPTO_AEAD_CREATE_SESSION:
|
||||
sym_sess_info = &sess_info->u.sym_sess_info;
|
||||
return cryptodev_vhost_user_sym_create_session(backend, sym_sess_info,
|
||||
queue_index, errp);
|
||||
default:
|
||||
error_setg(errp, "Unsupported opcode :%" PRIu32 "",
|
||||
sess_info->op_code);
|
||||
return -1;
|
||||
ret = cryptodev_vhost_user_sym_create_session(backend, sym_sess_info,
|
||||
queue_index, &local_error);
|
||||
break;
|
||||
|
||||
default:
|
||||
error_setg(&local_error, "Unsupported opcode :%" PRIu32 "",
|
||||
sess_info->op_code);
|
||||
return -VIRTIO_CRYPTO_NOTSUPP;
|
||||
}
|
||||
|
||||
return -1;
|
||||
if (local_error) {
|
||||
error_report_err(local_error);
|
||||
}
|
||||
if (ret < 0) {
|
||||
status = -VIRTIO_CRYPTO_ERR;
|
||||
} else {
|
||||
sess_info->session_id = ret;
|
||||
status = VIRTIO_CRYPTO_OK;
|
||||
}
|
||||
if (cb) {
|
||||
cb(opaque, status);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cryptodev_vhost_user_close_session(
|
||||
CryptoDevBackend *backend,
|
||||
uint64_t session_id,
|
||||
uint32_t queue_index, Error **errp)
|
||||
uint32_t queue_index,
|
||||
CryptoDevCompletionFunc cb,
|
||||
void *opaque)
|
||||
{
|
||||
CryptoDevBackendClient *cc =
|
||||
backend->conf.peers.ccs[queue_index];
|
||||
CryptoDevBackendVhost *vhost_crypto;
|
||||
int ret;
|
||||
int ret = -1, status;
|
||||
|
||||
vhost_crypto = cryptodev_vhost_user_get_vhost(cc, backend, queue_index);
|
||||
if (vhost_crypto) {
|
||||
@@ -301,12 +321,17 @@ static int cryptodev_vhost_user_close_session(
|
||||
ret = dev->vhost_ops->vhost_crypto_close_session(dev,
|
||||
session_id);
|
||||
if (ret < 0) {
|
||||
return -1;
|
||||
status = -VIRTIO_CRYPTO_ERR;
|
||||
} else {
|
||||
return 0;
|
||||
status = VIRTIO_CRYPTO_OK;
|
||||
}
|
||||
} else {
|
||||
status = -VIRTIO_CRYPTO_NOTSUPP;
|
||||
}
|
||||
return -1;
|
||||
if (cb) {
|
||||
cb(opaque, status);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void cryptodev_vhost_user_cleanup(
|
||||
|
||||
+24
-20
@@ -26,6 +26,7 @@
|
||||
#include "qapi/error.h"
|
||||
#include "qapi/visitor.h"
|
||||
#include "qemu/config-file.h"
|
||||
#include "qemu/error-report.h"
|
||||
#include "qom/object_interfaces.h"
|
||||
#include "hw/virtio/virtio-crypto.h"
|
||||
|
||||
@@ -72,69 +73,72 @@ void cryptodev_backend_cleanup(
|
||||
}
|
||||
}
|
||||
|
||||
int64_t cryptodev_backend_create_session(
|
||||
int cryptodev_backend_create_session(
|
||||
CryptoDevBackend *backend,
|
||||
CryptoDevBackendSessionInfo *sess_info,
|
||||
uint32_t queue_index, Error **errp)
|
||||
uint32_t queue_index,
|
||||
CryptoDevCompletionFunc cb,
|
||||
void *opaque)
|
||||
{
|
||||
CryptoDevBackendClass *bc =
|
||||
CRYPTODEV_BACKEND_GET_CLASS(backend);
|
||||
|
||||
if (bc->create_session) {
|
||||
return bc->create_session(backend, sess_info, queue_index, errp);
|
||||
return bc->create_session(backend, sess_info, queue_index, cb, opaque);
|
||||
}
|
||||
|
||||
return -1;
|
||||
return -VIRTIO_CRYPTO_NOTSUPP;
|
||||
}
|
||||
|
||||
int cryptodev_backend_close_session(
|
||||
CryptoDevBackend *backend,
|
||||
uint64_t session_id,
|
||||
uint32_t queue_index, Error **errp)
|
||||
uint32_t queue_index,
|
||||
CryptoDevCompletionFunc cb,
|
||||
void *opaque)
|
||||
{
|
||||
CryptoDevBackendClass *bc =
|
||||
CRYPTODEV_BACKEND_GET_CLASS(backend);
|
||||
|
||||
if (bc->close_session) {
|
||||
return bc->close_session(backend, session_id, queue_index, errp);
|
||||
return bc->close_session(backend, session_id, queue_index, cb, opaque);
|
||||
}
|
||||
|
||||
return -1;
|
||||
return -VIRTIO_CRYPTO_NOTSUPP;
|
||||
}
|
||||
|
||||
static int cryptodev_backend_operation(
|
||||
CryptoDevBackend *backend,
|
||||
CryptoDevBackendOpInfo *op_info,
|
||||
uint32_t queue_index, Error **errp)
|
||||
uint32_t queue_index,
|
||||
CryptoDevCompletionFunc cb,
|
||||
void *opaque)
|
||||
{
|
||||
CryptoDevBackendClass *bc =
|
||||
CRYPTODEV_BACKEND_GET_CLASS(backend);
|
||||
|
||||
if (bc->do_op) {
|
||||
return bc->do_op(backend, op_info, queue_index, errp);
|
||||
return bc->do_op(backend, op_info, queue_index, cb, opaque);
|
||||
}
|
||||
|
||||
return -VIRTIO_CRYPTO_ERR;
|
||||
return -VIRTIO_CRYPTO_NOTSUPP;
|
||||
}
|
||||
|
||||
int cryptodev_backend_crypto_operation(
|
||||
CryptoDevBackend *backend,
|
||||
void *opaque,
|
||||
uint32_t queue_index, Error **errp)
|
||||
void *opaque1,
|
||||
uint32_t queue_index,
|
||||
CryptoDevCompletionFunc cb, void *opaque2)
|
||||
{
|
||||
VirtIOCryptoReq *req = opaque;
|
||||
VirtIOCryptoReq *req = opaque1;
|
||||
CryptoDevBackendOpInfo *op_info = &req->op_info;
|
||||
enum CryptoDevBackendAlgType algtype = req->flags;
|
||||
|
||||
if ((algtype != CRYPTODEV_BACKEND_ALG_SYM)
|
||||
&& (algtype != CRYPTODEV_BACKEND_ALG_ASYM)) {
|
||||
error_setg(errp, "Unsupported cryptodev alg type: %" PRIu32 "",
|
||||
algtype);
|
||||
|
||||
error_report("Unsupported cryptodev alg type: %" PRIu32 "", algtype);
|
||||
return -VIRTIO_CRYPTO_NOTSUPP;
|
||||
}
|
||||
|
||||
return cryptodev_backend_operation(backend, op_info, queue_index, errp);
|
||||
return cryptodev_backend_operation(backend, op_info, queue_index,
|
||||
cb, opaque2);
|
||||
}
|
||||
|
||||
static void
|
||||
|
||||
@@ -12,6 +12,9 @@ softmmu_ss.add([files(
|
||||
softmmu_ss.add(when: 'CONFIG_POSIX', if_true: files('rng-random.c'))
|
||||
softmmu_ss.add(when: 'CONFIG_POSIX', if_true: files('hostmem-file.c'))
|
||||
softmmu_ss.add(when: 'CONFIG_LINUX', if_true: files('hostmem-memfd.c'))
|
||||
if keyutils.found()
|
||||
softmmu_ss.add(keyutils, files('cryptodev-lkcf.c'))
|
||||
endif
|
||||
if have_vhost_user
|
||||
softmmu_ss.add(when: 'CONFIG_VIRTIO', if_true: files('vhost-user.c'))
|
||||
endif
|
||||
|
||||
@@ -22,6 +22,8 @@
|
||||
#include "qemu/osdep.h"
|
||||
#include "crypto/akcipher.h"
|
||||
#include "akcipherpriv.h"
|
||||
#include "der.h"
|
||||
#include "rsakey.h"
|
||||
|
||||
#if defined(CONFIG_GCRYPT)
|
||||
#include "akcipher-gcrypt.c.inc"
|
||||
@@ -106,3 +108,19 @@ void qcrypto_akcipher_free(QCryptoAkCipher *akcipher)
|
||||
|
||||
drv->free(akcipher);
|
||||
}
|
||||
|
||||
int qcrypto_akcipher_export_p8info(const QCryptoAkCipherOptions *opts,
|
||||
uint8_t *key, size_t keylen,
|
||||
uint8_t **dst, size_t *dst_len,
|
||||
Error **errp)
|
||||
{
|
||||
switch (opts->alg) {
|
||||
case QCRYPTO_AKCIPHER_ALG_RSA:
|
||||
qcrypto_akcipher_rsakey_export_p8info(key, keylen, dst, dst_len);
|
||||
return 0;
|
||||
|
||||
default:
|
||||
error_setg(errp, "Unsupported algorithm: %u", opts->alg);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
+286
-23
@@ -22,20 +22,93 @@
|
||||
#include "qemu/osdep.h"
|
||||
#include "crypto/der.h"
|
||||
|
||||
typedef struct QCryptoDerEncodeNode {
|
||||
uint8_t tag;
|
||||
struct QCryptoDerEncodeNode *parent;
|
||||
struct QCryptoDerEncodeNode *next;
|
||||
/* for constructed type, data is null */
|
||||
const uint8_t *data;
|
||||
size_t dlen;
|
||||
} QCryptoDerEncodeNode;
|
||||
|
||||
typedef struct QCryptoEncodeContext {
|
||||
QCryptoDerEncodeNode root;
|
||||
QCryptoDerEncodeNode *current_parent;
|
||||
QCryptoDerEncodeNode *tail;
|
||||
} QCryptoEncodeContext;
|
||||
|
||||
enum QCryptoDERTypeTag {
|
||||
QCRYPTO_DER_TYPE_TAG_BOOL = 0x1,
|
||||
QCRYPTO_DER_TYPE_TAG_INT = 0x2,
|
||||
QCRYPTO_DER_TYPE_TAG_BIT_STR = 0x3,
|
||||
QCRYPTO_DER_TYPE_TAG_OCT_STR = 0x4,
|
||||
QCRYPTO_DER_TYPE_TAG_OCT_NULL = 0x5,
|
||||
QCRYPTO_DER_TYPE_TAG_OCT_OID = 0x6,
|
||||
QCRYPTO_DER_TYPE_TAG_NULL = 0x5,
|
||||
QCRYPTO_DER_TYPE_TAG_OID = 0x6,
|
||||
QCRYPTO_DER_TYPE_TAG_SEQ = 0x10,
|
||||
QCRYPTO_DER_TYPE_TAG_SET = 0x11,
|
||||
};
|
||||
|
||||
#define QCRYPTO_DER_CONSTRUCTED_MASK 0x20
|
||||
enum QCryptoDERTagClass {
|
||||
QCRYPTO_DER_TAG_CLASS_UNIV = 0x0,
|
||||
QCRYPTO_DER_TAG_CLASS_APPL = 0x1,
|
||||
QCRYPTO_DER_TAG_CLASS_CONT = 0x2,
|
||||
QCRYPTO_DER_TAG_CLASS_PRIV = 0x3,
|
||||
};
|
||||
|
||||
enum QCryptoDERTagEnc {
|
||||
QCRYPTO_DER_TAG_ENC_PRIM = 0x0,
|
||||
QCRYPTO_DER_TAG_ENC_CONS = 0x1,
|
||||
};
|
||||
|
||||
#define QCRYPTO_DER_TAG_ENC_MASK 0x20
|
||||
#define QCRYPTO_DER_TAG_ENC_SHIFT 5
|
||||
|
||||
#define QCRYPTO_DER_TAG_CLASS_MASK 0xc0
|
||||
#define QCRYPTO_DER_TAG_CLASS_SHIFT 6
|
||||
|
||||
#define QCRYPTO_DER_TAG_VAL_MASK 0x1f
|
||||
#define QCRYPTO_DER_SHORT_LEN_MASK 0x80
|
||||
|
||||
#define QCRYPTO_DER_TAG(class, enc, val) \
|
||||
(((class) << QCRYPTO_DER_TAG_CLASS_SHIFT) | \
|
||||
((enc) << QCRYPTO_DER_TAG_ENC_SHIFT) | (val))
|
||||
|
||||
/**
|
||||
* qcrypto_der_encode_length:
|
||||
* @src_len: the length of source data
|
||||
* @dst: distination to save the encoded 'length', if dst is NULL, only compute
|
||||
* the expected buffer size in bytes.
|
||||
* @dst_len: output parameter, indicates how many bytes wrote.
|
||||
*
|
||||
* Encode the 'length' part of TLV tuple.
|
||||
*/
|
||||
static void qcrypto_der_encode_length(size_t src_len,
|
||||
uint8_t *dst, size_t *dst_len)
|
||||
{
|
||||
size_t max_length = 0xFF;
|
||||
uint8_t length_bytes = 0, header_byte;
|
||||
|
||||
if (src_len < QCRYPTO_DER_SHORT_LEN_MASK) {
|
||||
header_byte = src_len;
|
||||
*dst_len = 1;
|
||||
} else {
|
||||
for (length_bytes = 1; max_length < src_len; length_bytes++) {
|
||||
max_length = (max_length << 8) + max_length;
|
||||
}
|
||||
header_byte = length_bytes;
|
||||
header_byte |= QCRYPTO_DER_SHORT_LEN_MASK;
|
||||
*dst_len = length_bytes + 1;
|
||||
}
|
||||
if (!dst) {
|
||||
return;
|
||||
}
|
||||
*dst++ = header_byte;
|
||||
/* Bigendian length bytes */
|
||||
for (; length_bytes > 0; length_bytes--) {
|
||||
*dst++ = ((src_len >> (length_bytes - 1) * 8) & 0xFF);
|
||||
}
|
||||
}
|
||||
|
||||
static uint8_t qcrypto_der_peek_byte(const uint8_t **data, size_t *dlen)
|
||||
{
|
||||
return **data;
|
||||
@@ -150,40 +223,230 @@ static int qcrypto_der_extract_data(const uint8_t **data, size_t *dlen,
|
||||
return qcrypto_der_extract_definite_data(data, dlen, cb, ctx, errp);
|
||||
}
|
||||
|
||||
int qcrypto_der_decode_int(const uint8_t **data, size_t *dlen,
|
||||
QCryptoDERDecodeCb cb, void *ctx, Error **errp)
|
||||
static int qcrypto_der_decode_tlv(const uint8_t expected_tag,
|
||||
const uint8_t **data, size_t *dlen,
|
||||
QCryptoDERDecodeCb cb,
|
||||
void *ctx, Error **errp)
|
||||
{
|
||||
const uint8_t *saved_data = *data;
|
||||
size_t saved_dlen = *dlen;
|
||||
uint8_t tag;
|
||||
int data_length;
|
||||
|
||||
if (*dlen < 1) {
|
||||
error_setg(errp, "Need more data");
|
||||
return -1;
|
||||
}
|
||||
tag = qcrypto_der_cut_byte(data, dlen);
|
||||
|
||||
/* INTEGER must encoded in primitive-form */
|
||||
if (tag != QCRYPTO_DER_TYPE_TAG_INT) {
|
||||
error_setg(errp, "Invalid integer type tag: %u", tag);
|
||||
return -1;
|
||||
if (tag != expected_tag) {
|
||||
error_setg(errp, "Unexpected tag: expected: %u, actual: %u",
|
||||
expected_tag, tag);
|
||||
goto error;
|
||||
}
|
||||
|
||||
return qcrypto_der_extract_data(data, dlen, cb, ctx, errp);
|
||||
data_length = qcrypto_der_extract_data(data, dlen, cb, ctx, errp);
|
||||
if (data_length < 0) {
|
||||
goto error;
|
||||
}
|
||||
return data_length;
|
||||
|
||||
error:
|
||||
*data = saved_data;
|
||||
*dlen = saved_dlen;
|
||||
return -1;
|
||||
}
|
||||
|
||||
int qcrypto_der_decode_int(const uint8_t **data, size_t *dlen,
|
||||
QCryptoDERDecodeCb cb, void *ctx, Error **errp)
|
||||
{
|
||||
const uint8_t tag = QCRYPTO_DER_TAG(QCRYPTO_DER_TAG_CLASS_UNIV,
|
||||
QCRYPTO_DER_TAG_ENC_PRIM,
|
||||
QCRYPTO_DER_TYPE_TAG_INT);
|
||||
return qcrypto_der_decode_tlv(tag, data, dlen, cb, ctx, errp);
|
||||
}
|
||||
|
||||
int qcrypto_der_decode_seq(const uint8_t **data, size_t *dlen,
|
||||
QCryptoDERDecodeCb cb, void *ctx, Error **errp)
|
||||
{
|
||||
uint8_t tag;
|
||||
if (*dlen < 1) {
|
||||
error_setg(errp, "Need more data");
|
||||
return -1;
|
||||
}
|
||||
tag = qcrypto_der_cut_byte(data, dlen);
|
||||
uint8_t tag = QCRYPTO_DER_TAG(QCRYPTO_DER_TAG_CLASS_UNIV,
|
||||
QCRYPTO_DER_TAG_ENC_CONS,
|
||||
QCRYPTO_DER_TYPE_TAG_SEQ);
|
||||
return qcrypto_der_decode_tlv(tag, data, dlen, cb, ctx, errp);
|
||||
}
|
||||
|
||||
int qcrypto_der_decode_octet_str(const uint8_t **data, size_t *dlen,
|
||||
QCryptoDERDecodeCb cb, void *ctx, Error **errp)
|
||||
{
|
||||
uint8_t tag = QCRYPTO_DER_TAG(QCRYPTO_DER_TAG_CLASS_UNIV,
|
||||
QCRYPTO_DER_TAG_ENC_PRIM,
|
||||
QCRYPTO_DER_TYPE_TAG_OCT_STR);
|
||||
return qcrypto_der_decode_tlv(tag, data, dlen, cb, ctx, errp);
|
||||
}
|
||||
|
||||
int qcrypto_der_decode_bit_str(const uint8_t **data, size_t *dlen,
|
||||
QCryptoDERDecodeCb cb, void *ctx, Error **errp)
|
||||
{
|
||||
uint8_t tag = QCRYPTO_DER_TAG(QCRYPTO_DER_TAG_CLASS_UNIV,
|
||||
QCRYPTO_DER_TAG_ENC_PRIM,
|
||||
QCRYPTO_DER_TYPE_TAG_BIT_STR);
|
||||
return qcrypto_der_decode_tlv(tag, data, dlen, cb, ctx, errp);
|
||||
}
|
||||
|
||||
int qcrypto_der_decode_oid(const uint8_t **data, size_t *dlen,
|
||||
QCryptoDERDecodeCb cb, void *ctx, Error **errp)
|
||||
{
|
||||
uint8_t tag = QCRYPTO_DER_TAG(QCRYPTO_DER_TAG_CLASS_UNIV,
|
||||
QCRYPTO_DER_TAG_ENC_PRIM,
|
||||
QCRYPTO_DER_TYPE_TAG_OID);
|
||||
return qcrypto_der_decode_tlv(tag, data, dlen, cb, ctx, errp);
|
||||
}
|
||||
|
||||
int qcrypto_der_decode_ctx_tag(const uint8_t **data, size_t *dlen, int tag_id,
|
||||
QCryptoDERDecodeCb cb, void *ctx, Error **errp)
|
||||
{
|
||||
uint8_t tag = QCRYPTO_DER_TAG(QCRYPTO_DER_TAG_CLASS_CONT,
|
||||
QCRYPTO_DER_TAG_ENC_CONS,
|
||||
tag_id);
|
||||
return qcrypto_der_decode_tlv(tag, data, dlen, cb, ctx, errp);
|
||||
}
|
||||
|
||||
static void qcrypto_der_encode_prim(QCryptoEncodeContext *ctx, uint8_t tag,
|
||||
const uint8_t *data, size_t dlen)
|
||||
{
|
||||
QCryptoDerEncodeNode *node = g_new0(QCryptoDerEncodeNode, 1);
|
||||
size_t nbytes_len;
|
||||
|
||||
node->tag = tag;
|
||||
node->data = data;
|
||||
node->dlen = dlen;
|
||||
node->parent = ctx->current_parent;
|
||||
|
||||
qcrypto_der_encode_length(dlen, NULL, &nbytes_len);
|
||||
/* 1 byte for Tag, nbyte_len for Length, and dlen for Value */
|
||||
node->parent->dlen += 1 + nbytes_len + dlen;
|
||||
|
||||
ctx->tail->next = node;
|
||||
ctx->tail = node;
|
||||
}
|
||||
|
||||
QCryptoEncodeContext *qcrypto_der_encode_ctx_new(void)
|
||||
{
|
||||
QCryptoEncodeContext *ctx = g_new0(QCryptoEncodeContext, 1);
|
||||
ctx->current_parent = &ctx->root;
|
||||
ctx->tail = &ctx->root;
|
||||
return ctx;
|
||||
}
|
||||
|
||||
static void qcrypto_der_encode_cons_begin(QCryptoEncodeContext *ctx,
|
||||
uint8_t tag)
|
||||
{
|
||||
QCryptoDerEncodeNode *node = g_new0(QCryptoDerEncodeNode, 1);
|
||||
|
||||
node->tag = tag;
|
||||
node->parent = ctx->current_parent;
|
||||
ctx->current_parent = node;
|
||||
ctx->tail->next = node;
|
||||
ctx->tail = node;
|
||||
}
|
||||
|
||||
static void qcrypto_der_encode_cons_end(QCryptoEncodeContext *ctx)
|
||||
{
|
||||
QCryptoDerEncodeNode *cons_node = ctx->current_parent;
|
||||
size_t nbytes_len;
|
||||
|
||||
qcrypto_der_encode_length(cons_node->dlen, NULL, &nbytes_len);
|
||||
/* 1 byte for Tag, nbyte_len for Length, and dlen for Value */
|
||||
cons_node->parent->dlen += 1 + nbytes_len + cons_node->dlen;
|
||||
ctx->current_parent = cons_node->parent;
|
||||
}
|
||||
|
||||
void qcrypto_der_encode_seq_begin(QCryptoEncodeContext *ctx)
|
||||
{
|
||||
uint8_t tag = QCRYPTO_DER_TAG(QCRYPTO_DER_TAG_CLASS_UNIV,
|
||||
QCRYPTO_DER_TAG_ENC_CONS,
|
||||
QCRYPTO_DER_TYPE_TAG_SEQ);
|
||||
qcrypto_der_encode_cons_begin(ctx, tag);
|
||||
}
|
||||
|
||||
void qcrypto_der_encode_seq_end(QCryptoEncodeContext *ctx)
|
||||
{
|
||||
qcrypto_der_encode_cons_end(ctx);
|
||||
}
|
||||
|
||||
void qcrypto_der_encode_oid(QCryptoEncodeContext *ctx,
|
||||
const uint8_t *src, size_t src_len)
|
||||
{
|
||||
uint8_t tag = QCRYPTO_DER_TAG(QCRYPTO_DER_TAG_CLASS_UNIV,
|
||||
QCRYPTO_DER_TAG_ENC_PRIM,
|
||||
QCRYPTO_DER_TYPE_TAG_OID);
|
||||
qcrypto_der_encode_prim(ctx, tag, src, src_len);
|
||||
}
|
||||
|
||||
void qcrypto_der_encode_int(QCryptoEncodeContext *ctx,
|
||||
const uint8_t *src, size_t src_len)
|
||||
{
|
||||
uint8_t tag = QCRYPTO_DER_TAG(QCRYPTO_DER_TAG_CLASS_UNIV,
|
||||
QCRYPTO_DER_TAG_ENC_PRIM,
|
||||
QCRYPTO_DER_TYPE_TAG_INT);
|
||||
qcrypto_der_encode_prim(ctx, tag, src, src_len);
|
||||
}
|
||||
|
||||
void qcrypto_der_encode_null(QCryptoEncodeContext *ctx)
|
||||
{
|
||||
uint8_t tag = QCRYPTO_DER_TAG(QCRYPTO_DER_TAG_CLASS_UNIV,
|
||||
QCRYPTO_DER_TAG_ENC_PRIM,
|
||||
QCRYPTO_DER_TYPE_TAG_NULL);
|
||||
qcrypto_der_encode_prim(ctx, tag, NULL, 0);
|
||||
}
|
||||
|
||||
void qcrypto_der_encode_octet_str(QCryptoEncodeContext *ctx,
|
||||
const uint8_t *src, size_t src_len)
|
||||
{
|
||||
uint8_t tag = QCRYPTO_DER_TAG(QCRYPTO_DER_TAG_CLASS_UNIV,
|
||||
QCRYPTO_DER_TAG_ENC_PRIM,
|
||||
QCRYPTO_DER_TYPE_TAG_OCT_STR);
|
||||
qcrypto_der_encode_prim(ctx, tag, src, src_len);
|
||||
}
|
||||
|
||||
void qcrypto_der_encode_octet_str_begin(QCryptoEncodeContext *ctx)
|
||||
{
|
||||
uint8_t tag = QCRYPTO_DER_TAG(QCRYPTO_DER_TAG_CLASS_UNIV,
|
||||
QCRYPTO_DER_TAG_ENC_PRIM,
|
||||
QCRYPTO_DER_TYPE_TAG_OCT_STR);
|
||||
qcrypto_der_encode_cons_begin(ctx, tag);
|
||||
}
|
||||
|
||||
void qcrypto_der_encode_octet_str_end(QCryptoEncodeContext *ctx)
|
||||
{
|
||||
qcrypto_der_encode_cons_end(ctx);
|
||||
}
|
||||
|
||||
size_t qcrypto_der_encode_ctx_buffer_len(QCryptoEncodeContext *ctx)
|
||||
{
|
||||
return ctx->root.dlen;
|
||||
}
|
||||
|
||||
void qcrypto_der_encode_ctx_flush_and_free(QCryptoEncodeContext *ctx,
|
||||
uint8_t *dst)
|
||||
{
|
||||
QCryptoDerEncodeNode *node, *prev;
|
||||
size_t len;
|
||||
|
||||
for (prev = &ctx->root;
|
||||
(node = prev->next) && (prev->next = node->next, 1);) {
|
||||
/* Tag */
|
||||
*dst++ = node->tag;
|
||||
|
||||
/* Length */
|
||||
qcrypto_der_encode_length(node->dlen, dst, &len);
|
||||
dst += len;
|
||||
|
||||
/* SEQUENCE must use constructed form */
|
||||
if (tag != (QCRYPTO_DER_TYPE_TAG_SEQ | QCRYPTO_DER_CONSTRUCTED_MASK)) {
|
||||
error_setg(errp, "Invalid type sequence tag: %u", tag);
|
||||
return -1;
|
||||
/* Value */
|
||||
if (node->data) {
|
||||
memcpy(dst, node->data, node->dlen);
|
||||
dst += node->dlen;
|
||||
}
|
||||
g_free(node);
|
||||
}
|
||||
|
||||
return qcrypto_der_extract_data(data, dlen, cb, ctx, errp);
|
||||
g_free(ctx);
|
||||
}
|
||||
|
||||
+208
-3
@@ -22,6 +22,11 @@
|
||||
|
||||
#include "qapi/error.h"
|
||||
|
||||
typedef struct QCryptoEncodeContext QCryptoEncodeContext;
|
||||
|
||||
/* rsaEncryption: 1.2.840.113549.1.1.1 */
|
||||
#define QCRYPTO_OID_rsaEncryption "\x2A\x86\x48\x86\xF7\x0D\x01\x01\x01"
|
||||
|
||||
/* Simple decoder used to parse DER encoded rsa keys. */
|
||||
|
||||
/**
|
||||
@@ -47,14 +52,13 @@ typedef int (*QCryptoDERDecodeCb) (void *opaque, const uint8_t *value,
|
||||
* will be set to the rest length of data, if cb is not NULL, must
|
||||
* return 0 to make decode success, at last, the length of the data
|
||||
* part of the decoded INTEGER will be returned. Otherwise, -1 is
|
||||
* returned.
|
||||
* returned and the valued of *data and *dlen keep unchanged.
|
||||
*/
|
||||
int qcrypto_der_decode_int(const uint8_t **data,
|
||||
size_t *dlen,
|
||||
QCryptoDERDecodeCb cb,
|
||||
void *opaque,
|
||||
Error **errp);
|
||||
|
||||
/**
|
||||
* qcrypto_der_decode_seq:
|
||||
*
|
||||
@@ -70,7 +74,7 @@ int qcrypto_der_decode_int(const uint8_t **data,
|
||||
* will be set to the rest length of data, if cb is not NULL, must
|
||||
* return 0 to make decode success, at last, the length of the data
|
||||
* part of the decoded SEQUENCE will be returned. Otherwise, -1 is
|
||||
* returned.
|
||||
* returned and the valued of *data and *dlen keep unchanged.
|
||||
*/
|
||||
int qcrypto_der_decode_seq(const uint8_t **data,
|
||||
size_t *dlen,
|
||||
@@ -78,4 +82,205 @@ int qcrypto_der_decode_seq(const uint8_t **data,
|
||||
void *opaque,
|
||||
Error **errp);
|
||||
|
||||
/**
|
||||
* qcrypto_der_decode_oid:
|
||||
*
|
||||
* Decode OID from DER-encoded data, similar with der_decode_int.
|
||||
*
|
||||
* @data: pointer to address of input data
|
||||
* @dlen: pointer to length of input data
|
||||
* @cb: callback invoked when decode succeed, if cb equals NULL, no
|
||||
* callback will be invoked
|
||||
* @opaque: parameter passed to cb
|
||||
*
|
||||
* Returns: On success, *data points to rest data, and *dlen
|
||||
* will be set to the rest length of data, if cb is not NULL, must
|
||||
* return 0 to make decode success, at last, the length of the data
|
||||
* part of the decoded OID will be returned. Otherwise, -1 is
|
||||
* returned and the valued of *data and *dlen keep unchanged.
|
||||
*/
|
||||
int qcrypto_der_decode_oid(const uint8_t **data,
|
||||
size_t *dlen,
|
||||
QCryptoDERDecodeCb cb,
|
||||
void *opaque,
|
||||
Error **errp);
|
||||
|
||||
/**
|
||||
* qcrypto_der_decode_octet_str:
|
||||
*
|
||||
* Decode OCTET STRING from DER-encoded data, similar with der_decode_int.
|
||||
*
|
||||
* @data: pointer to address of input data
|
||||
* @dlen: pointer to length of input data
|
||||
* @cb: callback invoked when decode succeed, if cb equals NULL, no
|
||||
* callback will be invoked
|
||||
* @opaque: parameter passed to cb
|
||||
*
|
||||
* Returns: On success, *data points to rest data, and *dlen
|
||||
* will be set to the rest length of data, if cb is not NULL, must
|
||||
* return 0 to make decode success, at last, the length of the data
|
||||
* part of the decoded OCTET STRING will be returned. Otherwise, -1 is
|
||||
* returned and the valued of *data and *dlen keep unchanged.
|
||||
*/
|
||||
int qcrypto_der_decode_octet_str(const uint8_t **data,
|
||||
size_t *dlen,
|
||||
QCryptoDERDecodeCb cb,
|
||||
void *opaque,
|
||||
Error **errp);
|
||||
|
||||
/**
|
||||
* qcrypto_der_decode_bit_str:
|
||||
*
|
||||
* Decode BIT STRING from DER-encoded data, similar with der_decode_int.
|
||||
*
|
||||
* @data: pointer to address of input data
|
||||
* @dlen: pointer to length of input data
|
||||
* @cb: callback invoked when decode succeed, if cb equals NULL, no
|
||||
* callback will be invoked
|
||||
* @opaque: parameter passed to cb
|
||||
*
|
||||
* Returns: On success, *data points to rest data, and *dlen
|
||||
* will be set to the rest length of data, if cb is not NULL, must
|
||||
* return 0 to make decode success, at last, the length of the data
|
||||
* part of the decoded BIT STRING will be returned. Otherwise, -1 is
|
||||
* returned and the valued of *data and *dlen keep unchanged.
|
||||
*/
|
||||
int qcrypto_der_decode_bit_str(const uint8_t **data,
|
||||
size_t *dlen,
|
||||
QCryptoDERDecodeCb cb,
|
||||
void *opaque,
|
||||
Error **errp);
|
||||
|
||||
|
||||
/**
|
||||
* qcrypto_der_decode_ctx_tag:
|
||||
*
|
||||
* Decode context specific tag
|
||||
*
|
||||
* @data: pointer to address of input data
|
||||
* @dlen: pointer to length of input data
|
||||
* @tag: expected value of context specific tag
|
||||
* @cb: callback invoked when decode succeed, if cb equals NULL, no
|
||||
* callback will be invoked
|
||||
* @opaque: parameter passed to cb
|
||||
*
|
||||
* Returns: On success, *data points to rest data, and *dlen
|
||||
* will be set to the rest length of data, if cb is not NULL, must
|
||||
* return 0 to make decode success, at last, the length of the data
|
||||
* part of the decoded BIT STRING will be returned. Otherwise, -1 is
|
||||
* returned and the valued of *data and *dlen keep unchanged.
|
||||
*/
|
||||
int qcrypto_der_decode_ctx_tag(const uint8_t **data,
|
||||
size_t *dlen, int tag_id,
|
||||
QCryptoDERDecodeCb cb,
|
||||
void *opaque,
|
||||
Error **errp);
|
||||
|
||||
/**
|
||||
* qcrypto_der_encode_ctx_new:
|
||||
*
|
||||
* Allocate a context used for der encoding.
|
||||
*/
|
||||
QCryptoEncodeContext *qcrypto_der_encode_ctx_new(void);
|
||||
|
||||
/**
|
||||
* qcrypto_der_encode_seq_begin:
|
||||
* @ctx: the encode context.
|
||||
*
|
||||
* Start encoding a SEQUENCE for ctx.
|
||||
*
|
||||
*/
|
||||
void qcrypto_der_encode_seq_begin(QCryptoEncodeContext *ctx);
|
||||
|
||||
/**
|
||||
* qcrypto_der_encode_seq_begin:
|
||||
* @ctx: the encode context.
|
||||
*
|
||||
* Finish uencoding a SEQUENCE for ctx.
|
||||
*
|
||||
*/
|
||||
void qcrypto_der_encode_seq_end(QCryptoEncodeContext *ctx);
|
||||
|
||||
|
||||
/**
|
||||
* qcrypto_der_encode_oid:
|
||||
* @ctx: the encode context.
|
||||
* @src: the source data of oid, note it should be already encoded, this
|
||||
* function only add tag and length part for it.
|
||||
*
|
||||
* Encode an oid into ctx.
|
||||
*/
|
||||
void qcrypto_der_encode_oid(QCryptoEncodeContext *ctx,
|
||||
const uint8_t *src, size_t src_len);
|
||||
|
||||
/**
|
||||
* qcrypto_der_encode_int:
|
||||
* @ctx: the encode context.
|
||||
* @src: the source data of integer, note it should be already encoded, this
|
||||
* function only add tag and length part for it.
|
||||
*
|
||||
* Encode an integer into ctx.
|
||||
*/
|
||||
void qcrypto_der_encode_int(QCryptoEncodeContext *ctx,
|
||||
const uint8_t *src, size_t src_len);
|
||||
|
||||
/**
|
||||
* qcrypto_der_encode_null:
|
||||
* @ctx: the encode context.
|
||||
*
|
||||
* Encode a null into ctx.
|
||||
*/
|
||||
void qcrypto_der_encode_null(QCryptoEncodeContext *ctx);
|
||||
|
||||
/**
|
||||
* qcrypto_der_encode_octet_str:
|
||||
* @ctx: the encode context.
|
||||
* @src: the source data of the octet string.
|
||||
*
|
||||
* Encode a octet string into ctx.
|
||||
*/
|
||||
void qcrypto_der_encode_octet_str(QCryptoEncodeContext *ctx,
|
||||
const uint8_t *src, size_t src_len);
|
||||
|
||||
/**
|
||||
* qcrypto_der_encode_octet_str_begin:
|
||||
* @ctx: the encode context.
|
||||
*
|
||||
* Start encoding a octet string, All fields between
|
||||
* qcrypto_der_encode_octet_str_begin and qcrypto_der_encode_octet_str_end
|
||||
* are encoded as an octet string. This is useful when we need to encode a
|
||||
* encoded SEQUNCE as OCTET STRING.
|
||||
*/
|
||||
void qcrypto_der_encode_octet_str_begin(QCryptoEncodeContext *ctx);
|
||||
|
||||
/**
|
||||
* qcrypto_der_encode_octet_str_end:
|
||||
* @ctx: the encode context.
|
||||
*
|
||||
* Finish encoding a octet string, All fields between
|
||||
* qcrypto_der_encode_octet_str_begin and qcrypto_der_encode_octet_str_end
|
||||
* are encoded as an octet string. This is useful when we need to encode a
|
||||
* encoded SEQUNCE as OCTET STRING.
|
||||
*/
|
||||
void qcrypto_der_encode_octet_str_end(QCryptoEncodeContext *ctx);
|
||||
|
||||
/**
|
||||
* qcrypto_der_encode_ctx_buffer_len:
|
||||
* @ctx: the encode context.
|
||||
*
|
||||
* Compute the expected buffer size to save all encoded things.
|
||||
*/
|
||||
size_t qcrypto_der_encode_ctx_buffer_len(QCryptoEncodeContext *ctx);
|
||||
|
||||
/**
|
||||
* qcrypto_der_encode_ctx_flush_and_free:
|
||||
* @ctx: the encode context.
|
||||
* @dst: the distination to save the encoded data, the length of dst should
|
||||
* not less than qcrypto_der_encode_cxt_buffer_len
|
||||
*
|
||||
* Flush all encoded data into dst, then free ctx.
|
||||
*/
|
||||
void qcrypto_der_encode_ctx_flush_and_free(QCryptoEncodeContext *ctx,
|
||||
uint8_t *dst);
|
||||
|
||||
#endif /* QCRYPTO_ASN1_DECODER_H */
|
||||
|
||||
@@ -19,6 +19,8 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "der.h"
|
||||
#include "rsakey.h"
|
||||
|
||||
void qcrypto_akcipher_rsakey_free(QCryptoAkCipherRSAKey *rsa_key)
|
||||
@@ -37,6 +39,46 @@ void qcrypto_akcipher_rsakey_free(QCryptoAkCipherRSAKey *rsa_key)
|
||||
g_free(rsa_key);
|
||||
}
|
||||
|
||||
/**
|
||||
* PKCS#8 private key info for RSA
|
||||
*
|
||||
* PrivateKeyInfo ::= SEQUENCE {
|
||||
* version INTEGER,
|
||||
* privateKeyAlgorithm PrivateKeyAlgorithmIdentifier,
|
||||
* privateKey OCTET STRING,
|
||||
* attributes [0] IMPLICIT Attributes OPTIONAL
|
||||
* }
|
||||
*/
|
||||
void qcrypto_akcipher_rsakey_export_p8info(const uint8_t *key,
|
||||
size_t keylen,
|
||||
uint8_t **dst,
|
||||
size_t *dlen)
|
||||
{
|
||||
QCryptoEncodeContext *ctx = qcrypto_der_encode_ctx_new();
|
||||
uint8_t version = 0;
|
||||
|
||||
qcrypto_der_encode_seq_begin(ctx);
|
||||
|
||||
/* version */
|
||||
qcrypto_der_encode_int(ctx, &version, sizeof(version));
|
||||
|
||||
/* algorithm identifier */
|
||||
qcrypto_der_encode_seq_begin(ctx);
|
||||
qcrypto_der_encode_oid(ctx, (uint8_t *)QCRYPTO_OID_rsaEncryption,
|
||||
sizeof(QCRYPTO_OID_rsaEncryption) - 1);
|
||||
qcrypto_der_encode_null(ctx);
|
||||
qcrypto_der_encode_seq_end(ctx);
|
||||
|
||||
/* RSA private key */
|
||||
qcrypto_der_encode_octet_str(ctx, key, keylen);
|
||||
|
||||
qcrypto_der_encode_seq_end(ctx);
|
||||
|
||||
*dlen = qcrypto_der_encode_ctx_buffer_len(ctx);
|
||||
*dst = g_malloc(*dlen);
|
||||
qcrypto_der_encode_ctx_flush_and_free(ctx, *dst);
|
||||
}
|
||||
|
||||
#if defined(CONFIG_NETTLE) && defined(CONFIG_HOGWEED)
|
||||
#include "rsakey-nettle.c.inc"
|
||||
#else
|
||||
|
||||
+10
-1
@@ -22,7 +22,6 @@
|
||||
#ifndef QCRYPTO_RSAKEY_H
|
||||
#define QCRYPTO_RSAKEY_H
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "qemu/host-utils.h"
|
||||
#include "crypto/akcipher.h"
|
||||
|
||||
@@ -84,6 +83,16 @@ QCryptoAkCipherRSAKey *qcrypto_akcipher_rsakey_parse(
|
||||
QCryptoAkCipherKeyType type,
|
||||
const uint8_t *key, size_t keylen, Error **errp);
|
||||
|
||||
/**
|
||||
* qcrypto_akcipher_rsakey_export_as_p8info:
|
||||
*
|
||||
* Export RSA private key to PKCS#8 private key info.
|
||||
*/
|
||||
void qcrypto_akcipher_rsakey_export_p8info(const uint8_t *key,
|
||||
size_t keylen,
|
||||
uint8_t **dst,
|
||||
size_t *dlen);
|
||||
|
||||
void qcrypto_akcipher_rsakey_free(QCryptoAkCipherRSAKey *key);
|
||||
|
||||
G_DEFINE_AUTOPTR_CLEANUP_FUNC(QCryptoAkCipherRSAKey,
|
||||
|
||||
@@ -0,0 +1,145 @@
|
||||
=============================================================================
|
||||
ACPI/SMBIOS avocado tests using biosbits
|
||||
=============================================================================
|
||||
|
||||
Biosbits is a software written by Josh Triplett that can be downloaded
|
||||
from https://biosbits.org/. The github codebase can be found
|
||||
`here <https://github.com/biosbits/bits/tree/master>`__. It is a software that executes
|
||||
the bios components such as acpi and smbios tables directly through acpica
|
||||
bios interpreter (a freely available C based library written by Intel,
|
||||
downloadable from https://acpica.org/ and is included with biosbits) without an
|
||||
operating system getting involved in between.
|
||||
There are several advantages to directly testing the bios in a real physical
|
||||
machine or VM as opposed to indirectly discovering bios issues through the
|
||||
operating system. For one thing, the OSes tend to hide bios problems from the
|
||||
end user. The other is that we have more control of what we wanted to test
|
||||
and how by directly using acpica interpreter on top of the bios on a running
|
||||
system. More details on the inspiration for developing biosbits and its real
|
||||
life uses can be found in [#a]_ and [#b]_.
|
||||
This directory contains tests written in python using avocado framework that
|
||||
exercises the QEMU bios components using biosbits and reports test failures.
|
||||
For QEMU, we maintain a fork of bios bits in gitlab along with all the
|
||||
dependent submodules:
|
||||
https://gitlab.com/qemu-project/biosbits-bits
|
||||
This fork contains numerous fixes, a newer acpica and changes specific to
|
||||
running this avocado QEMU tests using bits. The author of this document
|
||||
is the sole maintainer of the QEMU fork of bios bits repo.
|
||||
|
||||
Under the directory ``tests/avocado/``, ``acpi-bits.py`` is a QEMU avocado
|
||||
test that drives all this.
|
||||
|
||||
A brief description of the various test files follows.
|
||||
|
||||
Under ``tests/avocado/`` as the root we have:
|
||||
|
||||
::
|
||||
|
||||
├── acpi-bits
|
||||
│ ├── bits-config
|
||||
│ │ └── bits-cfg.txt
|
||||
│ ├── bits-tests
|
||||
│ │ ├── smbios.py2
|
||||
│ │ ├── testacpi.py2
|
||||
│ │ └── testcpuid.py2
|
||||
│ └── README
|
||||
├── acpi-bits.py
|
||||
|
||||
* ``tests/avocado``:
|
||||
|
||||
``acpi-bits.py``:
|
||||
This is the main python avocado test script that generates a
|
||||
biosbits iso. It then spawns a QEMU VM with it, collects the log and reports
|
||||
test failures. This is the script one would be interested in if they wanted
|
||||
to add or change some component of the log parsing, add a new command line
|
||||
to alter how QEMU is spawned etc. Test writers typically would not need to
|
||||
modify this script unless they wanted to enhance or change the log parsing
|
||||
for their tests. In order to enable debugging, you can set **V=1**
|
||||
environment variable. This enables verbose mode for the test and also dumps
|
||||
the entire log from bios bits and more information in case failure happens.
|
||||
|
||||
In order to run this test, please perform the following steps from the QEMU
|
||||
build directory:
|
||||
::
|
||||
|
||||
$ make check-venv (needed only the first time to create the venv)
|
||||
$ ./tests/venv/bin/avocado run -t acpi tests/avocado
|
||||
|
||||
The above will run all acpi avocado tests including this one.
|
||||
In order to run the individual tests, perform the following:
|
||||
::
|
||||
|
||||
$ ./tests/venv/bin/avocado run tests/avocado/acpi-bits.py --tap -
|
||||
|
||||
The above will produce output in tap format. You can omit "--tap -" in the
|
||||
end and it will produce output like the following:
|
||||
::
|
||||
|
||||
$ ./tests/venv/bin/avocado run tests/avocado/acpi-bits.py
|
||||
Fetching asset from tests/avocado/acpi-bits.py:AcpiBitsTest.test_acpi_smbios_bits
|
||||
JOB ID : eab225724da7b64c012c65705dc2fa14ab1defef
|
||||
JOB LOG : /home/anisinha/avocado/job-results/job-2022-10-10T17.58-eab2257/job.log
|
||||
(1/1) tests/avocado/acpi-bits.py:AcpiBitsTest.test_acpi_smbios_bits: PASS (33.09 s)
|
||||
RESULTS : PASS 1 | ERROR 0 | FAIL 0 | SKIP 0 | WARN 0 | INTERRUPT 0 | CANCEL 0
|
||||
JOB TIME : 39.22 s
|
||||
|
||||
You can inspect the log file for more information about the run or in order
|
||||
to diagnoze issues. If you pass V=1 in the environment, more diagnostic logs
|
||||
would be found in the test log.
|
||||
|
||||
* ``tests/avocado/acpi-bits/bits-config``:
|
||||
|
||||
This location contains biosbits configuration files that determine how the
|
||||
software runs the tests.
|
||||
|
||||
``bits-config.txt``:
|
||||
This is the biosbits config file that determines what tests
|
||||
or actions are performed by bits. The description of the config options are
|
||||
provided in the file itself.
|
||||
|
||||
* ``tests/avocado/acpi-bits/bits-tests``:
|
||||
|
||||
This directory contains biosbits python based tests that are run from within
|
||||
the biosbits environment in the spawned VM. New additions of test cases can
|
||||
be made in the appropriate test file. For example, new acpi tests can go
|
||||
into testacpi.py2 and one would call testsuite.add_test() to register the new
|
||||
test so that it gets executed as a part of the ACPI tests.
|
||||
It might be occasionally necessary to disable some subtests or add a new
|
||||
test that belongs to a test suite not already present in this directory. To
|
||||
do this, please clone the bits source from
|
||||
https://gitlab.com/qemu-project/biosbits-bits/-/tree/qemu-bits.
|
||||
Note that this is the "qemu-bits" branch and not the "bits" branch of the
|
||||
repository. "qemu-bits" is the branch where we have made all the QEMU
|
||||
specific enhancements and we must use the source from this branch only.
|
||||
Copy the test suite/script that needs modification (addition of new tests
|
||||
or disabling them) from python directory into this directory. For
|
||||
example, in order to change cpuid related tests, copy the following
|
||||
file into this directory and rename it with .py2 extension:
|
||||
https://gitlab.com/qemu-project/biosbits-bits/-/blob/qemu-bits/python/testcpuid.py
|
||||
Then make your additions and changes here. Therefore, the steps are:
|
||||
|
||||
(a) Copy unmodified test script to this directory from bits source.
|
||||
(b) Add a SPDX license header.
|
||||
(c) Perform modifications to the test.
|
||||
|
||||
Commits (a), (b) and (c) should go under separate commits so that the original
|
||||
test script and the changes we have made are separated and clear.
|
||||
|
||||
The test framework will then use your modified test script to run the test.
|
||||
No further changes would be needed. Please check the logs to make sure that
|
||||
appropriate changes have taken effect.
|
||||
|
||||
The tests have an extension .py2 in order to indicate that:
|
||||
|
||||
(a) They are python2.7 based scripts and not python 3 scripts.
|
||||
(b) They are run from within the bios bits VM and is not subjected to QEMU
|
||||
build/test python script maintainance and dependency resolutions.
|
||||
(c) They need not be loaded by avocado framework when running tests.
|
||||
|
||||
|
||||
Author: Ani Sinha <ani@anisinha.ca>
|
||||
|
||||
References:
|
||||
-----------
|
||||
.. [#a] https://blog.linuxplumbersconf.org/2011/ocw/system/presentations/867/original/bits.pdf
|
||||
.. [#b] https://www.youtube.com/watch?v=36QIepyUuhg
|
||||
|
||||
@@ -11,6 +11,7 @@ the basics if you are adding new files and targets to the build.
|
||||
build-system
|
||||
kconfig
|
||||
testing
|
||||
acpi-bits
|
||||
qtest
|
||||
ci
|
||||
qapi-code-gen
|
||||
|
||||
@@ -26,6 +26,16 @@ void aml_append(Aml *parent_ctx, Aml *child)
|
||||
{
|
||||
}
|
||||
|
||||
Aml *aml_return(Aml *val)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
Aml *aml_method(const char *name, int arg_count, AmlSerializeFlag sflag)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
Aml *aml_resource_template(void)
|
||||
{
|
||||
return NULL;
|
||||
|
||||
+10
-3
@@ -2070,7 +2070,7 @@ void build_pptt(GArray *table_data, BIOSLinker *linker, MachineState *ms,
|
||||
acpi_table_end(linker, &table);
|
||||
}
|
||||
|
||||
/* build rev1/rev3/rev5.1 FADT */
|
||||
/* build rev1/rev3/rev5.1/rev6.0 FADT */
|
||||
void build_fadt(GArray *tbl, BIOSLinker *linker, const AcpiFadtData *f,
|
||||
const char *oem_id, const char *oem_table_id)
|
||||
{
|
||||
@@ -2193,8 +2193,15 @@ void build_fadt(GArray *tbl, BIOSLinker *linker, const AcpiFadtData *f,
|
||||
/* SLEEP_STATUS_REG */
|
||||
build_append_gas_from_struct(tbl, &f->sleep_sts);
|
||||
|
||||
/* TODO: extra fields need to be added to support revisions above rev5 */
|
||||
assert(f->rev == 5);
|
||||
if (f->rev == 5) {
|
||||
goto done;
|
||||
}
|
||||
|
||||
/* Hypervisor Vendor Identity */
|
||||
build_append_padded_str(tbl, "QEMU", 8, '\0');
|
||||
|
||||
/* TODO: extra fields need to be added to support revisions above rev6 */
|
||||
assert(f->rev == 6);
|
||||
|
||||
done:
|
||||
acpi_table_end(linker, &table);
|
||||
|
||||
+3
-3
@@ -635,7 +635,7 @@ static unsigned read_erst_record(ERSTDeviceState *s)
|
||||
if (record_length < UEFI_CPER_RECORD_MIN_SIZE) {
|
||||
rc = STATUS_FAILED;
|
||||
}
|
||||
if ((s->record_offset + record_length) > exchange_length) {
|
||||
if (record_length > exchange_length - s->record_offset) {
|
||||
rc = STATUS_FAILED;
|
||||
}
|
||||
/* If all is ok, copy the record to the exchange buffer */
|
||||
@@ -684,7 +684,7 @@ static unsigned write_erst_record(ERSTDeviceState *s)
|
||||
if (record_length < UEFI_CPER_RECORD_MIN_SIZE) {
|
||||
return STATUS_FAILED;
|
||||
}
|
||||
if ((s->record_offset + record_length) > exchange_length) {
|
||||
if (record_length > exchange_length - s->record_offset) {
|
||||
return STATUS_FAILED;
|
||||
}
|
||||
|
||||
@@ -716,7 +716,7 @@ static unsigned write_erst_record(ERSTDeviceState *s)
|
||||
if (nvram) {
|
||||
/* Write the record into the slot */
|
||||
memcpy(nvram, exchange, record_length);
|
||||
memset(nvram + record_length, exchange_length - record_length, 0xFF);
|
||||
memset(nvram + record_length, 0xFF, exchange_length - record_length);
|
||||
/* If a new record, increment the record_count */
|
||||
if (!record_found) {
|
||||
uint32_t record_count;
|
||||
|
||||
+100
-6
@@ -922,6 +922,7 @@ void nvdimm_init_acpi_state(NVDIMMState *state, MemoryRegion *io,
|
||||
#define NVDIMM_DSM_RFIT_STATUS "RSTA"
|
||||
|
||||
#define NVDIMM_QEMU_RSVD_UUID "648B9CF2-CDA1-4312-8AD9-49C4AF32BD62"
|
||||
#define NVDIMM_DEVICE_DSM_UUID "4309AC30-0D11-11E4-9191-0800200C9A66"
|
||||
|
||||
static void nvdimm_build_common_dsm(Aml *dev,
|
||||
NVDIMMState *nvdimm_state)
|
||||
@@ -1029,15 +1030,14 @@ static void nvdimm_build_common_dsm(Aml *dev,
|
||||
/* UUID for QEMU internal use */), expected_uuid));
|
||||
aml_append(elsectx, ifctx);
|
||||
elsectx2 = aml_else();
|
||||
aml_append(elsectx2, aml_store(
|
||||
aml_touuid("4309AC30-0D11-11E4-9191-0800200C9A66")
|
||||
aml_append(elsectx2, aml_store(aml_touuid(NVDIMM_DEVICE_DSM_UUID)
|
||||
/* UUID for NVDIMM Devices */, expected_uuid));
|
||||
aml_append(elsectx, elsectx2);
|
||||
aml_append(method, elsectx);
|
||||
|
||||
uuid_invalid = aml_lnot(aml_equal(uuid, expected_uuid));
|
||||
|
||||
unsupport = aml_if(aml_or(unpatched, uuid_invalid, NULL));
|
||||
unsupport = aml_if(aml_lor(unpatched, uuid_invalid));
|
||||
|
||||
/*
|
||||
* function 0 is called to inquire what functions are supported by
|
||||
@@ -1069,10 +1069,9 @@ static void nvdimm_build_common_dsm(Aml *dev,
|
||||
* in the DSM Spec.
|
||||
*/
|
||||
pckg = aml_arg(3);
|
||||
ifctx = aml_if(aml_and(aml_equal(aml_object_type(pckg),
|
||||
ifctx = aml_if(aml_land(aml_equal(aml_object_type(pckg),
|
||||
aml_int(4 /* Package */)) /* It is a Package? */,
|
||||
aml_equal(aml_sizeof(pckg), aml_int(1)) /* 1 element? */,
|
||||
NULL));
|
||||
aml_equal(aml_sizeof(pckg), aml_int(1)) /* 1 element? */));
|
||||
|
||||
pckg_index = aml_local(2);
|
||||
pckg_buf = aml_local(3);
|
||||
@@ -1244,6 +1243,7 @@ static void nvdimm_build_fit(Aml *dev)
|
||||
static void nvdimm_build_nvdimm_devices(Aml *root_dev, uint32_t ram_slots)
|
||||
{
|
||||
uint32_t slot;
|
||||
Aml *method, *pkg, *field, *com_call;
|
||||
|
||||
for (slot = 0; slot < ram_slots; slot++) {
|
||||
uint32_t handle = nvdimm_slot_to_handle(slot);
|
||||
@@ -1261,6 +1261,100 @@ static void nvdimm_build_nvdimm_devices(Aml *root_dev, uint32_t ram_slots)
|
||||
*/
|
||||
aml_append(nvdimm_dev, aml_name_decl("_ADR", aml_int(handle)));
|
||||
|
||||
/*
|
||||
* ACPI v6.4: Section 6.5.10 NVDIMM Label Methods
|
||||
*/
|
||||
/* _LSI */
|
||||
method = aml_method("_LSI", 0, AML_SERIALIZED);
|
||||
com_call = aml_call5(NVDIMM_COMMON_DSM,
|
||||
aml_touuid(NVDIMM_DEVICE_DSM_UUID),
|
||||
aml_int(1), aml_int(4), aml_int(0),
|
||||
aml_int(handle));
|
||||
aml_append(method, aml_store(com_call, aml_local(0)));
|
||||
|
||||
aml_append(method, aml_create_dword_field(aml_local(0),
|
||||
aml_int(0), "STTS"));
|
||||
aml_append(method, aml_create_dword_field(aml_local(0), aml_int(4),
|
||||
"SLSA"));
|
||||
aml_append(method, aml_create_dword_field(aml_local(0), aml_int(8),
|
||||
"MAXT"));
|
||||
|
||||
pkg = aml_package(3);
|
||||
aml_append(pkg, aml_name("STTS"));
|
||||
aml_append(pkg, aml_name("SLSA"));
|
||||
aml_append(pkg, aml_name("MAXT"));
|
||||
aml_append(method, aml_store(pkg, aml_local(1)));
|
||||
aml_append(method, aml_return(aml_local(1)));
|
||||
|
||||
aml_append(nvdimm_dev, method);
|
||||
|
||||
/* _LSR */
|
||||
method = aml_method("_LSR", 2, AML_SERIALIZED);
|
||||
aml_append(method, aml_name_decl("INPT", aml_buffer(8, NULL)));
|
||||
|
||||
aml_append(method, aml_create_dword_field(aml_name("INPT"),
|
||||
aml_int(0), "OFST"));
|
||||
aml_append(method, aml_create_dword_field(aml_name("INPT"),
|
||||
aml_int(4), "LEN"));
|
||||
aml_append(method, aml_store(aml_arg(0), aml_name("OFST")));
|
||||
aml_append(method, aml_store(aml_arg(1), aml_name("LEN")));
|
||||
|
||||
pkg = aml_package(1);
|
||||
aml_append(pkg, aml_name("INPT"));
|
||||
aml_append(method, aml_store(pkg, aml_local(0)));
|
||||
|
||||
com_call = aml_call5(NVDIMM_COMMON_DSM,
|
||||
aml_touuid(NVDIMM_DEVICE_DSM_UUID),
|
||||
aml_int(1), aml_int(5), aml_local(0),
|
||||
aml_int(handle));
|
||||
aml_append(method, aml_store(com_call, aml_local(3)));
|
||||
field = aml_create_dword_field(aml_local(3), aml_int(0), "STTS");
|
||||
aml_append(method, field);
|
||||
field = aml_create_field(aml_local(3), aml_int(32),
|
||||
aml_shiftleft(aml_name("LEN"), aml_int(3)),
|
||||
"LDAT");
|
||||
aml_append(method, field);
|
||||
aml_append(method, aml_name_decl("LSA", aml_buffer(0, NULL)));
|
||||
aml_append(method, aml_to_buffer(aml_name("LDAT"), aml_name("LSA")));
|
||||
|
||||
pkg = aml_package(2);
|
||||
aml_append(pkg, aml_name("STTS"));
|
||||
aml_append(pkg, aml_name("LSA"));
|
||||
|
||||
aml_append(method, aml_store(pkg, aml_local(1)));
|
||||
aml_append(method, aml_return(aml_local(1)));
|
||||
|
||||
aml_append(nvdimm_dev, method);
|
||||
|
||||
/* _LSW */
|
||||
method = aml_method("_LSW", 3, AML_SERIALIZED);
|
||||
aml_append(method, aml_store(aml_arg(2), aml_local(2)));
|
||||
aml_append(method, aml_name_decl("INPT", aml_buffer(8, NULL)));
|
||||
field = aml_create_dword_field(aml_name("INPT"),
|
||||
aml_int(0), "OFST");
|
||||
aml_append(method, field);
|
||||
field = aml_create_dword_field(aml_name("INPT"),
|
||||
aml_int(4), "TLEN");
|
||||
aml_append(method, field);
|
||||
aml_append(method, aml_store(aml_arg(0), aml_name("OFST")));
|
||||
aml_append(method, aml_store(aml_arg(1), aml_name("TLEN")));
|
||||
|
||||
aml_append(method, aml_concatenate(aml_name("INPT"), aml_local(2),
|
||||
aml_name("INPT")));
|
||||
pkg = aml_package(1);
|
||||
aml_append(pkg, aml_name("INPT"));
|
||||
aml_append(method, aml_store(pkg, aml_local(0)));
|
||||
com_call = aml_call5(NVDIMM_COMMON_DSM,
|
||||
aml_touuid(NVDIMM_DEVICE_DSM_UUID),
|
||||
aml_int(1), aml_int(6), aml_local(0),
|
||||
aml_int(handle));
|
||||
aml_append(method, aml_store(com_call, aml_local(3)));
|
||||
field = aml_create_dword_field(aml_local(3), aml_int(0), "STTS");
|
||||
aml_append(method, field);
|
||||
aml_append(method, aml_return(aml_name("STTS")));
|
||||
|
||||
aml_append(nvdimm_dev, method);
|
||||
|
||||
nvdimm_build_device_dsm(nvdimm_dev, handle);
|
||||
aml_append(root_dev, nvdimm_dev);
|
||||
}
|
||||
|
||||
@@ -30,6 +30,7 @@ config ARM_VIRT
|
||||
select ACPI_VIOT
|
||||
select VIRTIO_MEM_SUPPORTED
|
||||
select ACPI_CXL
|
||||
select ACPI_HMAT
|
||||
|
||||
config CHEETAH
|
||||
bool
|
||||
|
||||
+19
-14
@@ -42,6 +42,7 @@
|
||||
#include "hw/acpi/memory_hotplug.h"
|
||||
#include "hw/acpi/generic_event_device.h"
|
||||
#include "hw/acpi/tpm.h"
|
||||
#include "hw/acpi/hmat.h"
|
||||
#include "hw/pci/pcie_host.h"
|
||||
#include "hw/pci/pci.h"
|
||||
#include "hw/pci/pci_bus.h"
|
||||
@@ -685,7 +686,7 @@ build_dbg2(GArray *table_data, BIOSLinker *linker, VirtMachineState *vms)
|
||||
};
|
||||
|
||||
/*
|
||||
* ACPI spec, Revision 5.1 Errata A
|
||||
* ACPI spec, Revision 6.0 Errata A
|
||||
* 5.2.12 Multiple APIC Description Table (MADT)
|
||||
*/
|
||||
static void build_append_gicr(GArray *table_data, uint64_t base, uint32_t size)
|
||||
@@ -704,7 +705,7 @@ build_madt(GArray *table_data, BIOSLinker *linker, VirtMachineState *vms)
|
||||
int i;
|
||||
VirtMachineClass *vmc = VIRT_MACHINE_GET_CLASS(vms);
|
||||
const MemMapEntry *memmap = vms->memmap;
|
||||
AcpiTable table = { .sig = "APIC", .rev = 3, .oem_id = vms->oem_id,
|
||||
AcpiTable table = { .sig = "APIC", .rev = 4, .oem_id = vms->oem_id,
|
||||
.oem_table_id = vms->oem_table_id };
|
||||
|
||||
acpi_table_begin(&table, table_data);
|
||||
@@ -739,7 +740,7 @@ build_madt(GArray *table_data, BIOSLinker *linker, VirtMachineState *vms)
|
||||
|
||||
/* 5.2.12.14 GIC Structure */
|
||||
build_append_int_noprefix(table_data, 0xB, 1); /* Type */
|
||||
build_append_int_noprefix(table_data, 76, 1); /* Length */
|
||||
build_append_int_noprefix(table_data, 80, 1); /* Length */
|
||||
build_append_int_noprefix(table_data, 0, 2); /* Reserved */
|
||||
build_append_int_noprefix(table_data, i, 4); /* GIC ID */
|
||||
build_append_int_noprefix(table_data, i, 4); /* ACPI Processor UID */
|
||||
@@ -759,6 +760,10 @@ build_madt(GArray *table_data, BIOSLinker *linker, VirtMachineState *vms)
|
||||
build_append_int_noprefix(table_data, 0, 8); /* GICR Base Address*/
|
||||
/* MPIDR */
|
||||
build_append_int_noprefix(table_data, armcpu->mp_affinity, 8);
|
||||
/* Processor Power Efficiency Class */
|
||||
build_append_int_noprefix(table_data, 0, 1);
|
||||
/* Reserved */
|
||||
build_append_int_noprefix(table_data, 0, 3);
|
||||
}
|
||||
|
||||
if (vms->gic_version != VIRT_GIC_VERSION_2) {
|
||||
@@ -770,12 +775,6 @@ build_madt(GArray *table_data, BIOSLinker *linker, VirtMachineState *vms)
|
||||
}
|
||||
|
||||
if (its_class_name() && !vmc->no_its) {
|
||||
/*
|
||||
* FIXME: Structure is from Revision 6.0 where 'GIC Structure'
|
||||
* has additional fields on top of implemented 5.1 Errata A,
|
||||
* to make it consistent with v6.0 we need to bump everything
|
||||
* to v6.0
|
||||
*/
|
||||
/*
|
||||
* ACPI spec, Revision 6.0 Errata A
|
||||
* (original 6.0 definition has invalid Length)
|
||||
@@ -808,13 +807,13 @@ build_madt(GArray *table_data, BIOSLinker *linker, VirtMachineState *vms)
|
||||
}
|
||||
|
||||
/* FADT */
|
||||
static void build_fadt_rev5(GArray *table_data, BIOSLinker *linker,
|
||||
static void build_fadt_rev6(GArray *table_data, BIOSLinker *linker,
|
||||
VirtMachineState *vms, unsigned dsdt_tbl_offset)
|
||||
{
|
||||
/* ACPI v5.1 */
|
||||
/* ACPI v6.0 */
|
||||
AcpiFadtData fadt = {
|
||||
.rev = 5,
|
||||
.minor_ver = 1,
|
||||
.rev = 6,
|
||||
.minor_ver = 0,
|
||||
.flags = 1 << ACPI_FADT_F_HW_REDUCED_ACPI,
|
||||
.xdsdt_tbl_offset = &dsdt_tbl_offset,
|
||||
};
|
||||
@@ -944,7 +943,7 @@ void virt_acpi_build(VirtMachineState *vms, AcpiBuildTables *tables)
|
||||
|
||||
/* FADT MADT PPTT GTDT MCFG SPCR DBG2 pointed to by RSDT */
|
||||
acpi_add_table(table_offsets, tables_blob);
|
||||
build_fadt_rev5(tables_blob, tables->linker, vms, dsdt);
|
||||
build_fadt_rev6(tables_blob, tables->linker, vms, dsdt);
|
||||
|
||||
acpi_add_table(table_offsets, tables_blob);
|
||||
build_madt(tables_blob, tables->linker, vms);
|
||||
@@ -989,6 +988,12 @@ void virt_acpi_build(VirtMachineState *vms, AcpiBuildTables *tables)
|
||||
build_slit(tables_blob, tables->linker, ms, vms->oem_id,
|
||||
vms->oem_table_id);
|
||||
}
|
||||
|
||||
if (ms->numa_state->hmat_enabled) {
|
||||
acpi_add_table(table_offsets, tables_blob);
|
||||
build_hmat(tables_blob, tables->linker, ms->numa_state,
|
||||
vms->oem_id, vms->oem_table_id);
|
||||
}
|
||||
}
|
||||
|
||||
if (ms->nvdimms_state->is_enabled) {
|
||||
|
||||
+12
-12
@@ -168,13 +168,6 @@ static int vhost_user_blk_start(VirtIODevice *vdev, Error **errp)
|
||||
goto err_guest_notifiers;
|
||||
}
|
||||
|
||||
ret = vhost_dev_start(&s->dev, vdev);
|
||||
if (ret < 0) {
|
||||
error_setg_errno(errp, -ret, "Error starting vhost");
|
||||
goto err_guest_notifiers;
|
||||
}
|
||||
s->started_vu = true;
|
||||
|
||||
/* guest_notifier_mask/pending not used yet, so just unmask
|
||||
* everything here. virtio-pci will do the right thing by
|
||||
* enabling/disabling irqfd.
|
||||
@@ -183,9 +176,20 @@ static int vhost_user_blk_start(VirtIODevice *vdev, Error **errp)
|
||||
vhost_virtqueue_mask(&s->dev, vdev, i, false);
|
||||
}
|
||||
|
||||
s->dev.vq_index_end = s->dev.nvqs;
|
||||
ret = vhost_dev_start(&s->dev, vdev);
|
||||
if (ret < 0) {
|
||||
error_setg_errno(errp, -ret, "Error starting vhost");
|
||||
goto err_guest_notifiers;
|
||||
}
|
||||
s->started_vu = true;
|
||||
|
||||
return ret;
|
||||
|
||||
err_guest_notifiers:
|
||||
for (i = 0; i < s->dev.nvqs; i++) {
|
||||
vhost_virtqueue_mask(&s->dev, vdev, i, true);
|
||||
}
|
||||
k->set_guest_notifiers(qbus->parent, s->dev.nvqs, false);
|
||||
err_host_notifiers:
|
||||
vhost_dev_disable_notifiers(&s->dev, vdev);
|
||||
@@ -222,14 +226,10 @@ static void vhost_user_blk_stop(VirtIODevice *vdev)
|
||||
static void vhost_user_blk_set_status(VirtIODevice *vdev, uint8_t status)
|
||||
{
|
||||
VHostUserBlk *s = VHOST_USER_BLK(vdev);
|
||||
bool should_start = virtio_device_started(vdev, status);
|
||||
bool should_start = virtio_device_should_start(vdev, status);
|
||||
Error *local_err = NULL;
|
||||
int ret;
|
||||
|
||||
if (!vdev->vm_running) {
|
||||
should_start = false;
|
||||
}
|
||||
|
||||
if (!s->connected) {
|
||||
return;
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user