[虚拟化/云][全栈demo] 为qemu增加一个PCI的watchdog外设(二)

这篇文章的理解,需要一些专业知识了。

我们可以创建模拟自己的外设吗?

我们已经知道什么是qemu了,我们可以通过qmeu的提供的外设,DIY一个计算机了。

但是我们可能还不满足,我们可以自己制造一个外设吗?

答案是可以的。而且这是了解计算机体系结构的一个很好的实践活动。

watchdog 外设

watchdog, 即看门狗。 如果狗饿了,便会”咬人“(CPU),让CPU重新启动。 为了不让狗狗”咬人“,我们需要不停的喂他。

我们将创建一个最简单的PCI的外设watchdog。如果你是一个硬件工程师或集成电路工程师,那么你肯定知道watchdog是什么东西, 并且可以很轻松的自行设计一个watchdog了。

但是我们这里创建的watchdog,是基于qemu架构的软件模拟的设备。

预备知识:

1. git 基本操作。

2. C 语言。

3. PCI的一些知识。

4. 阅读qemu 的文档 http://wiki.qemu.org/Manual

开发平台:

linux

 实践:

1. clone一个qemu的仓库 http://wiki.qemu.org/Download

$ git clone git://git.qemu.org/qemu.git

2. 切换到一个新分支,一定从5d92c74 检出(checkout

$ git checkout -b watchdog 5d92c74

 3. 写源代码。

将下面的代码watchdog_source.patch(见代码目录)保存到本地, 注意去掉代码前面的行好。 现在不分析代码。以后会分析。这个代码已经测试过是可以运行的。

然后应用到qemu中。

$ git apply watchdog_source.patch

4. 配置qemu  http://wiki.qemu.org/Documentation/9psetup

$ ./configure '--target-list=x86_64-softmmu' '--enable-debug' '--enable-kvm' '--enable-spice' '--prefix=/home/shhfeng/qemu/'

4. 编译源代码。 http://wiki.qemu.org/Hosts/Linux

$ make

5. 测试代码 http://wiki.qemu.org/Documentation/QemuIoTests

将下面的代码watchdog_testcase.patch(见代码目录)保存到本地, 注意去掉代码前面的行好。 现在不分析代码。以后会分析。这个代码已经测试过是可以运行的。

然后应用到qemu中。

$ git apply watchdog_testcase.patch

$ make check-qtest-x86_64

6. 启动qemu with cstl-watchdog

$ x86_64-softmmu/qemu-system-x86_64 -device cstl-watchdog

注意:这里不能使用: $ x86_64-softmmu/qemu-system-x86_64 -watchdog cstl-watchdog

是因为没有在cstl-watchdog.c 中定义: WatchdogTimerModel

此外watchdog没有支持中断, 请参考 http://www.cnblogs.com/lihuidashen/p/4462220.html

代码目录:

1. watchdog_source.patch

  1 diff --git a/hw/watchdog/Makefile.objs b/hw/watchdog/Makefile.objs

  2 index 4b0374a..8f34e78 100644

  3 --- a/hw/watchdog/Makefile.objs

  4 +++ b/hw/watchdog/Makefile.objs

  5 @@ -1,3 +1,3 @@

  6 -common-obj-y += watchdog.o

  7 +common-obj-y += watchdog.o cstl-watchdog.o

  8  common-obj-$(CONFIG_WDT_IB6300ESB) += wdt_i6300esb.o

  9  common-obj-$(CONFIG_WDT_IB700) += wdt_ib700.o

 10 diff --git a/hw/watchdog/cstl-watchdog.c b/hw/watchdog/cstl-watchdog.c

 11 new file mode 100644

 12 index 0000000..3ce043a

 13 --- /dev/null

 14 +++ b/hw/watchdog/cstl-watchdog.c

 15 @@ -0,0 +1,197 @@

 16 +/*

 17 + * Watch Dog Timer Demo

 18 + *

 19 + * This work is licensed under the terms of the GNU GPL, version 2 or later.

 20 + * See the COPYING file in the top-level directory.

 21 + *

 22 + */

 23 +

 24 +#include "qemu/timer.h"

 25 +#include "hw/hw.h"

 26 +#include "hw/pci/pci.h"

 27 +#include "sysemu/sysemu.h"

 28 +

 29 +typedef struct CSTLWatchdogState {

 30 +    PCIDevice dev;

 31 +

 32 +    uint8_t activated;

 33 +

 34 +    uint8_t triggered;

 35 +

 36 +    uint32_t missed_ticks;

 37 +

 38 +    QEMUTimer *watchdog_timer;

 39 +

 40 +    uint32_t expiration_ticks;

 41 +

 42 +    MemoryRegion io;

 43 +} CSTLWatchdogState;

 44 +#define TYPE_CSTL_WATCHDOG "cstl-watchdog"

 45 +#define CSTL_WATCHDOG(obj) \

 46 +    OBJECT_CHECK(CSTLWatchdogState, (obj), TYPE_CSTL_WATCHDOG)

 47 +

 48 +static void cwd_timer_event(void *opaque)

 49 +{

 50 +    CSTLWatchdogState *s = CSTL_WATCHDOG(opaque);

 51 +

 52 +    (void)s;

 53 +

 54 +    printf("watch dog fire!\n");

 55 +    if (!s->triggered) {

 56 +        s->missed_ticks++;

 57 +    }

 58 +

 59 +    s->triggered = 0;

 60 +

 61 +    if (s->missed_ticks > 1) {

 62 +        printf("WARNING: missed watchdog tick\n");

 63 +    }

 64 +

 65 +    if (s->missed_ticks > s->expiration_ticks) {

 66 +        printf("Watchdog expired!\n");

 67 +        qemu_system_reset_request();

 68 +    }

 69 +

 70 +

 71 +    if (s->activated) {

 72 +        timer_mod(s->watchdog_timer,

 73 +                  qemu_clock_get_ms(QEMU_CLOCK_REALTIME) + 1000);

 74 +    }

 75 +}

 76 +

 77 +static uint64_t cwd_io_read(void *opaque, hwaddr addr,

 78 +                            unsigned size)

 79 +{

 80 +    CSTLWatchdogState *s = CSTL_WATCHDOG(opaque);

 81 +

 82 +    switch (addr) {

 83 +    case 0x00:

 84 +        return 0x42;

 85 +    case 0x01:

 86 +        return s->activated;

 87 +    default:

 88 +        break;

 89 +    }

 90 +

 91 +    return 0;

 92 +}

 93 +

 94 +static void cwd_io_write(void *opaque, hwaddr addr,

 95 +                         uint64_t val, unsigned size)

 96 +{

 97 +    CSTLWatchdogState *s = CSTL_WATCHDOG(opaque);

 98 +

 99 +    switch (addr) {

100 +    case 0x00:

101 +        /* read-only */

102 +        break;

103 +    case 0x01:

104 +        s->activated = !!val;

105 +

106 +        if (s->activated) {

107 +            printf("Activated!\n");

108 +            cwd_timer_event(s);

109 +        } else {

110 +            printf("Deactivated!\n");

111 +            timer_del(s->watchdog_timer);

112 +        }

113 +        break;

114 +    case 0x02:

115 +        s->triggered = 1;

116 +        s->missed_ticks = 0;

117 +        break;

118 +    default:

119 +        break;

120 +    }

121 +}

122 +

123 +static const MemoryRegionOps cwd_io_ops = {

124 +    .read = cwd_io_read,

125 +    .write = cwd_io_write,

126 +    .endianness = DEVICE_LITTLE_ENDIAN,

127 +};

128 +

129 +static const VMStateDescription vmstate_cwd = {

130 +    .name = TYPE_CSTL_WATCHDOG,

131 +    .version_id = 1,

132 +    .fields      = (VMStateField []) {

133 +        VMSTATE_PCI_DEVICE(dev, CSTLWatchdogState),

134 +        VMSTATE_UINT8(activated, CSTLWatchdogState),

135 +        VMSTATE_TIMER(watchdog_timer, CSTLWatchdogState),

136 +        VMSTATE_UINT8(triggered, CSTLWatchdogState),

137 +        VMSTATE_UINT32(missed_ticks, CSTLWatchdogState),

138 +        VMSTATE_END_OF_LIST()

139 +    }

140 +};

141 +

142 +static void cwd_unrealize(PCIDevice *dev)

143 +{

144 +}

145 +

146 +static int cwd_realize(PCIDevice *pci_dev)

147 +{

148 +    CSTLWatchdogState *s = CSTL_WATCHDOG(pci_dev);

149 +

150 +    pci_register_bar(pci_dev, 0, PCI_BASE_ADDRESS_SPACE_IO, &s->io);

151 +

152 +    return 0;

153 +}

154 +

155 +static void cwd_reset(DeviceState *dev)

156 +{

157 +    CSTLWatchdogState *s = CSTL_WATCHDOG(dev);

158 +

159 +    s->activated = 0;

160 +    s->triggered = 0;

161 +    s->missed_ticks = 0;

162 +}

163 +

164 +static void cwd_initfn(Object *obj)

165 +{

166 +    CSTLWatchdogState *s = CSTL_WATCHDOG(obj);

167 +

168 +    memory_region_init_io(&s->io, OBJECT(s), &cwd_io_ops, s, "cstl-watchdog-io", 16);

169 +

170 +    s->watchdog_timer = timer_new_ms(QEMU_CLOCK_REALTIME, cwd_timer_event, s);

171 +}

172 +

173 +static Property cwd_properties[] = {

174 +    DEFINE_PROP_UINT32("expiration-ticks", CSTLWatchdogState,

175 +                       expiration_ticks, 10),

176 +    DEFINE_PROP_END_OF_LIST(),

177 +};

178 +

179 +static void cwd_class_init(ObjectClass *klass, void *data)

180 +{

181 +    DeviceClass *dc = DEVICE_CLASS(klass);

182 +    PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);

183 +

184 +    k->init = cwd_realize;

185 +    k->exit = cwd_unrealize;

186 +    k->vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET;

187 +    k->device_id = 0x0101;

188 +    k->revision = 0x01;

189 +    k->class_id = PCI_CLASS_SYSTEM_OTHER;

190 +    dc->reset = cwd_reset;

191 +    dc->vmsd = &vmstate_cwd;

192 +    dc->props = cwd_properties;

193 +}

194 +

195 +static TypeInfo cstl_watchdog_info = {

196 +    .name          = TYPE_CSTL_WATCHDOG,

197 +    .parent        = TYPE_PCI_DEVICE,

198 +    .instance_init = cwd_initfn,

199 +    .instance_size = sizeof(CSTLWatchdogState),

200 +    .class_init    = cwd_class_init,

201 +};

202 +

203 +static void register_types(void)

204 +{

205 +    type_register_static(&cstl_watchdog_info);

206 +}

207 +

208 +type_init(register_types)
View Code

 

 2. watchdog_testcase.patch

  1 diff --git a/tests/Makefile b/tests/Makefile

  2 index 471b4c8..0a8f2cd 100644

  3 --- a/tests/Makefile

  4 +++ b/tests/Makefile

  5 @@ -116,6 +116,7 @@ gcov-files-i386-y += hw/block/hd-geometry.c

  6  check-qtest-i386-y += tests/boot-order-test$(EXESUF)

  7  check-qtest-i386-y += tests/acpi-test$(EXESUF)

  8  check-qtest-i386-y += tests/rtc-test$(EXESUF)

  9 +check-qtest-i386-y += tests/cwd-test$(EXESUF)

 10  check-qtest-i386-y += tests/i440fx-test$(EXESUF)

 11  check-qtest-i386-y += tests/fw_cfg-test$(EXESUF)

 12  check-qtest-i386-y += tests/blockdev-test$(EXESUF)

 13 @@ -242,6 +243,7 @@ libqos-pc-obj-y += tests/libqos/malloc-pc.o

 14  libqos-omap-obj-y = $(libqos-obj-y) tests/libqos/i2c-omap.o

 15  

 16  tests/rtc-test$(EXESUF): tests/rtc-test.o

 17 +tests/cwd-test$(EXESUF): tests/cwd-test.o

 18  tests/m48t59-test$(EXESUF): tests/m48t59-test.o

 19  tests/endianness-test$(EXESUF): tests/endianness-test.o

 20  tests/spapr-phb-test$(EXESUF): tests/spapr-phb-test.o $(libqos-obj-y)

 21 diff --git a/tests/cwd-test.c b/tests/cwd-test.c

 22 new file mode 100644

 23 index 0000000..380a313

 24 --- /dev/null

 25 +++ b/tests/cwd-test.c

 26 @@ -0,0 +1,120 @@

 27 +/*

 28 + * QTest testcase for the CSTL Watchdog

 29 + *

 30 + * This work is licensed under the terms of the GNU GPL, version 2 or later.

 31 + * See the COPYING file in the top-level directory.

 32 + *

 33 + */

 34 +#include "libqtest.h"

 35 +#include "hw/pci/pci_ids.h"

 36 +#include "hw/pci/pci_regs.h"

 37 +

 38 +#include <glib.h>

 39 +#include <unistd.h>

 40 +

 41 +static uint32_t pci_config_read(uint8_t bus, uint8_t devfn,

 42 +                                uint8_t addr, int size)

 43 +{

 44 +    outl(0xcf8, (bus << 16) | (devfn << 8) | addr | (1u << 31));

 45 +    if (size == 1) {

 46 +        return inb(0xcfc);

 47 +    } else if (size == 2) {

 48 +        return inw(0xcfc);

 49 +    }

 50 +    return inl(0xcfc);

 51 +}

 52 +

 53 +static void pci_config_write(uint8_t bus, uint8_t devfn,

 54 +                             uint32_t addr, int size, uint32_t value)

 55 +{

 56 +    outl(0xcf8, (bus << 16) | (devfn << 8) | addr | (1u << 31));

 57 +    if (size == 1) {

 58 +        outb(0xcfc, value);

 59 +    } else if (size == 2) {

 60 +        outw(0xcfc, value);

 61 +    } else {

 62 +        outl(0xcfc, value);

 63 +    }

 64 +}

 65 +

 66 +static void cwd_probe(uint8_t bus, uint8_t devfn)

 67 +{

 68 +    uint32_t bar0 = 0xc000;

 69 +    int i;

 70 +

 71 +    pci_config_write(bus, devfn, PCI_COMMAND, 2,

 72 +                     (PCI_COMMAND_IO | PCI_COMMAND_MEMORY));

 73 +    pci_config_write(bus, devfn, PCI_BASE_ADDRESS_0, 4, bar0);

 74 +

 75 +    g_assert_cmpint(inb(bar0 + 0x00), ==, 0x42);

 76 +

 77 +    outb(bar0 + 0x01, 0x03); // activate device

 78 +    g_assert_cmpint(inb(bar0 + 0x01), ==, 0x01); // confirm activation

 79 +

 80 +    for (i = 0; i < 2 * 10; i++) {

 81 +        outb(bar0 + 0x02, 0x32);

 82 +        g_usleep(500000);

 83 +    }

 84 +

 85 +    outb(bar0 + 0x01, 0x00); // deactivate device

 86 +}

 87 +

 88 +static void basic_init(void)

 89 +{

 90 +    int slot;

 91 +

 92 +    for (slot = 0; slot < 32; slot++) {

 93 +        uint8_t fn;

 94 +

 95 +        for (fn = 0; fn < 8; fn++) {

 96 +            uint8_t devfn = (slot << 3) | fn;

 97 +            uint16_t device_id;

 98 +            uint16_t vendor_id;

 99 +

100 +            vendor_id = pci_config_read(0, devfn, PCI_VENDOR_ID, 2);

101 +            device_id = pci_config_read(0, devfn, PCI_DEVICE_ID, 2);

102 +

103 +            if (vendor_id == 0xFFFF || device_id == 0xFFFF) {

104 +                break;

105 +            }

106 +

107 +            if (vendor_id == 0x1af4 && device_id == 0x0101) {

108 +                cwd_probe(0, devfn);

109 +                return;

110 +            }

111 +        }

112 +    }

113 +

114 +    g_assert_not_reached();

115 +}

116 +

117 +int main(int argc, char **argv)

118 +{

119 +    QTestState *s = NULL;

120 +    char *cmd;

121 +    int ret;

122 +

123 +    g_test_init(&argc, &argv, NULL);

124 +

125 +    cmd = g_strdup_printf("-device cstl-watchdog,expiration-ticks=%d",

126 +                          g_test_rand_int_range(2, 11));

127 +

128 +    s = qtest_start(cmd);

129 +

130 +    g_free(cmd);

131 +

132 +    qtest_add_func("/basic/init", basic_init);

133 +

134 +    ret = g_test_run();

135 +

136 +    if (s) {

137 +        qtest_quit(s);

138 +    }

139 +

140 +    return ret;

141 +}
View Code

 

你可能感兴趣的:(demo)