【QEMU系统分析之TPM篇(三)】

本文以QEMU 8.2.2为例,分析其TPM-emulator模块实现,并为QEMU添加Windows平台TPM模拟器支持。介绍了TPM-emulator概念,详细分析其代码,包括与swtpm建立数据通道的过程。指出因Windows系统不支持相关功能,可利用其UNIX本地套接字支持建立数据通道。

系列文章目录

第一章 QEMU系统仿真 TPM 设备实例

第二章 QEMU系统 TPM-TIS 设备源码分析

第三章 QEMU系统 TPM-emulator 设备源码分析(上)

第四章 QEMU系统添加 Windows 主机软件 TPM 设备支持



前言

本文以 QEMU 8.2.2 为例,分析其 TPM-emulator 模块的实现,并为 QEMU 添加 Windows 平台的TPM 模拟器的支持。
本文读者需要具备一定的 QEMU 使用经验,并对 C 语言编程有一定了解。

在 QEMU 启动时需要提供如下参数完成 TPM-emulator 的设置:

-chardev  "socket,id=chrtpm,path=swtpm-sock" 
-tpmdev "emulator,id=tpm0,chardev=chrtpm" 
-device "tpm-tis,tpmdev=tpm0"

本文将分析 TPM-emulator 模块实现部分中与 swtpm 软件 TPM 程序建立控制通道(ctrlchannel)的部分代码,这部分代码是 TPM-emulator 创建时需首先完成的工作。


一、TPM-emulator是什么?

QEMU 支持对 TPM 设备的仿真,在没有硬件支持的环境中,我们可以使用 swtpm 来替代 TPM 硬件设备,为系统提供 TPM 支持。
在 QEMU 启动时需要提供如下参数完成 TPM-emulator 的设置:

-chardev  "socket,id=chrtpm,path=swtpm-sock" 
-tpmdev "emulator,id=tpm0,chardev=chrtpm" 
-device "tpm-tis,tpmdev=tpm0"

二、QEMU 中 TPM-emulator 的实现

1.代码分析

TPM-emulator 的代码位于 backend/tpm/tpm_emulator.c 中

首先,设备申明代码如下:

type_init(tpm_emulator_register)

函数 tpm_emulator_register() 为设备的注册函数,代码如下:

static void tpm_emulator_register(void)
{
   
   
    type_register_static(&tpm_emulator_info);
}

结构体 tpm_emulator_info 定义为:

static const TypeInfo tpm_emulator_info = {
   
   
    .name = TYPE_TPM_EMULATOR,
    .parent = TYPE_TPM_BACKEND,
    .instance_size = sizeof(TPMEmulator),
    .class_init = tpm_emulator_class_init,
    .instance_init = tpm_emulator_inst_init,
    .instance_finalize = tpm_emulator_inst_finalize,
};

根据设备在系统中注册的过程,首先需要注册设备类,然后完成设备实例的初始化,因此我们首先进入设备类初始化函数 tpm_emulator_class_init()

    .class_init = tpm_emulator_class_init,
};

函数 tpm_emulator_class_init()代码如下:

static void tpm_emulator_class_init(ObjectClass *klass, void *data)
{
   
   
    TPMBackendClass *tbc = TPM_BACKEND_CLASS(klass);

    tbc->type = TPM_TYPE_EMULATOR;
    tbc->opts = tpm_emulator_cmdline_opts;
    tbc->desc = "TPM emulator backend driver";
    tbc->create = tpm_emulator_create;
    tbc->startup_tpm = tpm_emulator_startup_tpm;
    tbc->cancel_cmd = tpm_emulator_cancel_cmd;
    tbc->get_tpm_established_flag = tpm_emulator_get_tpm_established_flag;
    tbc->reset_tpm_established_flag = tpm_emulator_reset_tpm_established_flag;
    tbc->get_tpm_version = tpm_emulator_get_tpm_version;
    tbc->get_buffer_size = tpm_emulator_get_buffer_size;
    tbc->get_tpm_options = tpm_emulator_get_tpm_options;

    tbc->handle_request = tpm_emulator_handle_request;
}

系统运行首先需要创建设备类,因此我们查看 tpm_emulator_create() 函数

static TPMBackend *tpm_emulator_create(QemuOpts *opts)
{
   
   
    TPMBackend *tb = TPM_BACKEND(object_new(TYPE_TPM_EMULATOR));

    if (tpm_emulator_handle_device_opts(TPM_EMULATOR(tb), opts)) {
   
   
        object_unref(OBJECT(tb));
        return NULL;
    }

    return tb;
}

tpm_emulator_create() 函数首先通过 tpm_emulator_handle_device_opts() 注册该设备类的各个操作函数

static int tpm_emulator_handle_device_opts(TPMEmulator *tpm_emu, QemuOpts *opts)
{
   
   
    const char *value;
    Error *err = NULL;
    Chardev *dev;

    value = qemu_opt_get(opts, "chardev");
    if (!value) {
   
   
        error_report("tpm-emulator: parameter 'chardev' is missing");
        goto err;
    }

    dev = qemu_chr_find(value);
    if (!dev) {
   
   
        error_report("tpm-emulator: tpm chardev '%s' not found", value);
        goto err;
    }

    if (!qemu_chr_fe_init(&tpm_emu->ctrl_chr, dev, &err)) {
   
   
        error_prepend(&err, "tpm-emulator: No valid chardev found at '%s':",
                      value);
        error_report_err(err);
        goto err;
    }

    tpm_emu->options->chardev = g_strdup(value);

    if (tpm_emulator_prepare_data_fd(tpm_emu) < 0) {
   
   
        goto err;
    }

    /* FIXME: tpm_util_test_tpmdev() accepts only on socket fd, as it also used
     * by passthrough driver, which not yet using GIOChannel.
     */
    if (tpm_util_test_tpmdev(QIO_CHANNEL_SOCKET(tpm_emu->data_ioc)->fd,
                             &tpm_emu->tpm_version)) {
   
   
        error_report("'%s' is not emulating TPM device. Error: %s",
                      tpm_emu->options->chardev, strerror(errno));
        goto err;
    }

    switch (tpm_emu->tpm_version) {
   
   
    case TPM_VERSION_1_2:
        trace_tpm_emulator_handle_device_opts_tpm12();
        break;
    case TPM_VERSION_2_0:
        trace_tpm_emulator_handle_device_opts_tpm2();
        break;
    default:
        trace_tpm_emulator_handle_device_opts_unspec();
    }

    if (tpm_emulator_probe_caps
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值