[虚拟化/云][全栈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
diff --git a/hw/watchdog/Makefile.objs b/hw/watchdog/Makefile.objs
index 4b0374a..8f34e78
--- a/hw/watchdog/Makefile.objs
+++ b/hw/watchdog/Makefile.objs
@@ -, +, @@
-common-obj-y += watchdog.o
+common-obj-y += watchdog.o cstl-watchdog.o
common-obj-$(CONFIG_WDT_IB6300ESB) += wdt_i6300esb.o
common-obj-$(CONFIG_WDT_IB700) += wdt_ib700.o
diff --git a/hw/watchdog/cstl-watchdog.c b/hw/watchdog/cstl-watchdog.c
new file mode
index ..3ce043a
--- /dev/null
+++ b/hw/watchdog/cstl-watchdog.c
@@ -, +, @@
+/*
+ * Watch Dog Timer Demo
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ *
+ */
+
+#include "qemu/timer.h"
+#include "hw/hw.h"
+#include "hw/pci/pci.h"
+#include "sysemu/sysemu.h"
+
+typedef struct CSTLWatchdogState {
+ PCIDevice dev;
+
+ uint8_t activated;
+
+ uint8_t triggered;
+
+ uint32_t missed_ticks;
+
+ QEMUTimer *watchdog_timer;
+
+ uint32_t expiration_ticks;
+
+ MemoryRegion io;
+} CSTLWatchdogState;
+#define TYPE_CSTL_WATCHDOG "cstl-watchdog"
+#define CSTL_WATCHDOG(obj) \
+ OBJECT_CHECK(CSTLWatchdogState, (obj), TYPE_CSTL_WATCHDOG)
+
+static void cwd_timer_event(void *opaque)
+{
+ CSTLWatchdogState *s = CSTL_WATCHDOG(opaque);
+
+ (void)s;
+
+ printf("watch dog fire!\n");
+ if (!s->triggered) {
+ s->missed_ticks++;
+ }
+
+ s->triggered = ;
+
+ if (s->missed_ticks > ) {
+ printf("WARNING: missed watchdog tick\n");
+ }
+
+ if (s->missed_ticks > s->expiration_ticks) {
+ printf("Watchdog expired!\n");
+ qemu_system_reset_request();
+ }
+
+
+ if (s->activated) {
+ timer_mod(s->watchdog_timer,
+ qemu_clock_get_ms(QEMU_CLOCK_REALTIME) + );
+ }
+}
+
+static uint64_t cwd_io_read(void *opaque, hwaddr addr,
+ unsigned size)
+{
+ CSTLWatchdogState *s = CSTL_WATCHDOG(opaque);
+
+ switch (addr) {
+ case 0x00:
+ return 0x42;
+ case 0x01:
+ return s->activated;
+ default:
+ break;
+ }
+
+ return ;
+}
+
+static void cwd_io_write(void *opaque, hwaddr addr,
+ uint64_t val, unsigned size)
+{
+ CSTLWatchdogState *s = CSTL_WATCHDOG(opaque);
+
+ switch (addr) {
+ case 0x00:
+ /* read-only */
+ break;
+ case 0x01:
+ s->activated = !!val;
+
+ if (s->activated) {
+ printf("Activated!\n");
+ cwd_timer_event(s);
+ } else {
+ printf("Deactivated!\n");
+ timer_del(s->watchdog_timer);
+ }
+ break;
+ case 0x02:
+ s->triggered = ;
+ s->missed_ticks = ;
+ break;
+ default:
+ break;
+ }
+}
+
+static const MemoryRegionOps cwd_io_ops = {
+ .read = cwd_io_read,
+ .write = cwd_io_write,
+ .endianness = DEVICE_LITTLE_ENDIAN,
+};
+
+static const VMStateDescription vmstate_cwd = {
+ .name = TYPE_CSTL_WATCHDOG,
+ .version_id = ,
+ .fields = (VMStateField []) {
+ VMSTATE_PCI_DEVICE(dev, CSTLWatchdogState),
+ VMSTATE_UINT8(activated, CSTLWatchdogState),
+ VMSTATE_TIMER(watchdog_timer, CSTLWatchdogState),
+ VMSTATE_UINT8(triggered, CSTLWatchdogState),
+ VMSTATE_UINT32(missed_ticks, CSTLWatchdogState),
+ VMSTATE_END_OF_LIST()
+ }
+};
+
+static void cwd_unrealize(PCIDevice *dev)
+{
+}
+
+static int cwd_realize(PCIDevice *pci_dev)
+{
+ CSTLWatchdogState *s = CSTL_WATCHDOG(pci_dev);
+
+ pci_register_bar(pci_dev, , PCI_BASE_ADDRESS_SPACE_IO, &s->io);
+
+ return ;
+}
+
+static void cwd_reset(DeviceState *dev)
+{
+ CSTLWatchdogState *s = CSTL_WATCHDOG(dev);
+
+ s->activated = ;
+ s->triggered = ;
+ s->missed_ticks = ;
+}
+
+static void cwd_initfn(Object *obj)
+{
+ CSTLWatchdogState *s = CSTL_WATCHDOG(obj);
+
+ memory_region_init_io(&s->io, OBJECT(s), &cwd_io_ops, s, "cstl-watchdog-io", );
+
+ s->watchdog_timer = timer_new_ms(QEMU_CLOCK_REALTIME, cwd_timer_event, s);
+}
+
+static Property cwd_properties[] = {
+ DEFINE_PROP_UINT32("expiration-ticks", CSTLWatchdogState,
+ expiration_ticks, ),
+ DEFINE_PROP_END_OF_LIST(),
+};
+
+static void cwd_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
+
+ k->init = cwd_realize;
+ k->exit = cwd_unrealize;
+ k->vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET;
+ k->device_id = 0x0101;
+ k->revision = 0x01;
+ k->class_id = PCI_CLASS_SYSTEM_OTHER;
+ dc->reset = cwd_reset;
+ dc->vmsd = &vmstate_cwd;
+ dc->props = cwd_properties;
+}
+
+static TypeInfo cstl_watchdog_info = {
+ .name = TYPE_CSTL_WATCHDOG,
+ .parent = TYPE_PCI_DEVICE,
+ .instance_init = cwd_initfn,
+ .instance_size = sizeof(CSTLWatchdogState),
+ .class_init = cwd_class_init,
+};
+
+static void register_types(void)
+{
+ type_register_static(&cstl_watchdog_info);
+}
+
+type_init(register_types)
2. watchdog_testcase.patch
diff --git a/tests/Makefile b/tests/Makefile
index 471b4c8..0a8f2cd
--- a/tests/Makefile
+++ b/tests/Makefile
@@ -, +, @@ gcov-files-i386-y += hw/block/hd-geometry.c
check-qtest-i386-y += tests/boot-order-test$(EXESUF)
check-qtest-i386-y += tests/acpi-test$(EXESUF)
check-qtest-i386-y += tests/rtc-test$(EXESUF)
+check-qtest-i386-y += tests/cwd-test$(EXESUF)
check-qtest-i386-y += tests/i440fx-test$(EXESUF)
check-qtest-i386-y += tests/fw_cfg-test$(EXESUF)
check-qtest-i386-y += tests/blockdev-test$(EXESUF)
@@ -, +, @@ libqos-pc-obj-y += tests/libqos/malloc-pc.o
libqos-omap-obj-y = $(libqos-obj-y) tests/libqos/i2c-omap.o tests/rtc-test$(EXESUF): tests/rtc-test.o
+tests/cwd-test$(EXESUF): tests/cwd-test.o
tests/m48t59-test$(EXESUF): tests/m48t59-test.o
tests/endianness-test$(EXESUF): tests/endianness-test.o
tests/spapr-phb-test$(EXESUF): tests/spapr-phb-test.o $(libqos-obj-y)
diff --git a/tests/cwd-test.c b/tests/cwd-test.c
new file mode
index ..380a313
--- /dev/null
+++ b/tests/cwd-test.c
@@ -, +, @@
+/*
+ * QTest testcase for the CSTL Watchdog
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ *
+ */
+#include "libqtest.h"
+#include "hw/pci/pci_ids.h"
+#include "hw/pci/pci_regs.h"
+
+#include <glib.h>
+#include <unistd.h>
+
+static uint32_t pci_config_read(uint8_t bus, uint8_t devfn,
+ uint8_t addr, int size)
+{
+ outl(0xcf8, (bus << ) | (devfn << ) | addr | (1u << ));
+ if (size == ) {
+ return inb(0xcfc);
+ } else if (size == ) {
+ return inw(0xcfc);
+ }
+ return inl(0xcfc);
+}
+
+static void pci_config_write(uint8_t bus, uint8_t devfn,
+ uint32_t addr, int size, uint32_t value)
+{
+ outl(0xcf8, (bus << ) | (devfn << ) | addr | (1u << ));
+ if (size == ) {
+ outb(0xcfc, value);
+ } else if (size == ) {
+ outw(0xcfc, value);
+ } else {
+ outl(0xcfc, value);
+ }
+}
+
+static void cwd_probe(uint8_t bus, uint8_t devfn)
+{
+ uint32_t bar0 = 0xc000;
+ int i;
+
+ pci_config_write(bus, devfn, PCI_COMMAND, ,
+ (PCI_COMMAND_IO | PCI_COMMAND_MEMORY));
+ pci_config_write(bus, devfn, PCI_BASE_ADDRESS_0, , bar0);
+
+ g_assert_cmpint(inb(bar0 + 0x00), ==, 0x42);
+
+ outb(bar0 + 0x01, 0x03); // activate device
+ g_assert_cmpint(inb(bar0 + 0x01), ==, 0x01); // confirm activation
+
+ for (i = ; i < * ; i++) {
+ outb(bar0 + 0x02, 0x32);
+ g_usleep();
+ }
+
+ outb(bar0 + 0x01, 0x00); // deactivate device
+}
+
+static void basic_init(void)
+{
+ int slot;
+
+ for (slot = ; slot < ; slot++) {
+ uint8_t fn;
+
+ for (fn = ; fn < ; fn++) {
+ uint8_t devfn = (slot << ) | fn;
+ uint16_t device_id;
+ uint16_t vendor_id;
+
+ vendor_id = pci_config_read(, devfn, PCI_VENDOR_ID, );
+ device_id = pci_config_read(, devfn, PCI_DEVICE_ID, );
+
+ if (vendor_id == 0xFFFF || device_id == 0xFFFF) {
+ break;
+ }
+
+ if (vendor_id == 0x1af4 && device_id == 0x0101) {
+ cwd_probe(, devfn);
+ return;
+ }
+ }
+ }
+
+ g_assert_not_reached();
+}
+
+int main(int argc, char **argv)
+{
+ QTestState *s = NULL;
+ char *cmd;
+ int ret;
+
+ g_test_init(&argc, &argv, NULL);
+
+ cmd = g_strdup_printf("-device cstl-watchdog,expiration-ticks=%d",
+ g_test_rand_int_range(, ));
+
+ s = qtest_start(cmd);
+
+ g_free(cmd);
+
+ qtest_add_func("/basic/init", basic_init);
+
+ ret = g_test_run();
+
+ if (s) {
+ qtest_quit(s);
+ }
+
+ return ret;
+}
[虚拟化/云][全栈demo] 为qemu增加一个PCI的watchdog外设(二)的更多相关文章
- [虚拟化/云][全栈demo] 为qemu增加一个PCI的watchdog外设(九)
目的 1. 使用verilog/vhdl设计一个PCI的watchdog设备. 2. 通过systemverilog 写testbench. 很久之前研究过AC97的verilog代码.但是很久没用v ...
- [虚拟化/云][全栈demo] 为qemu增加一个PCI的watchdog外设(四)
通过前面的操作,我们已经可以创建一个带有我们自己的PCI的watchdog外设qemu 虚拟机了. 目的: 1. 了解我们的外设情况. 2. 为在guest中开发我们自己的linux PCI驱动程序做 ...
- [虚拟化/云][全栈demo] 为qemu增加一个PCI的watchdog外设(一)
目的: 结合现在比较流行的技术,通过一个demo 展示一个全栈式设计的各种技能. 一个全栈式的工程师,应该能设计通过verilog/VHDL做logical设计.能写内核驱动,能架站. 要熟悉veri ...
- [虚拟化/云][全栈demo] 为qemu增加一个PCI的watchdog外设(六)
目的: 1. 为我们自己的watchdog写一个驱动 步骤: 通过之前的介绍,我们很容易猜想到写我们基于PCI的watchdog驱动,可以分2个步骤. 1. 探测加载PCI设备 这部分代码跟我们的设备 ...
- [虚拟化/云][全栈demo] 为qemu增加一个PCI的watchdog外设(八)
目的: 1. 通过网页读取watchdog的信息 2. 通过网页设置watchdog 准备工作: 1. 选择一个web框架,选用 cherrypy $ sudo apt-get install pyt ...
- [虚拟化/云][全栈demo] 为qemu增加一个PCI的watchdog外设(五)
目的: 1. 了解PCI的基本知识,为完成watchdog的设备做准备. 准备知识: 简单的说,PCI 设备分3个空间. 配置空间,IO空间,内存地址空间. PCI设备厂家决定了外设是使用IO空间还是 ...
- [虚拟化/云][全栈demo] 为qemu增加一个PCI的watchdog外设(七)
目标: 1. 完成最终的设备驱动,增加具体的watchdog设备操作的代码. 测试代码: 代码最终实现见cwd_demo.c 代码只实现了read与write. 没有实现ioctl. 因此,我们可以 ...
- [虚拟化/云][全栈demo] 为qemu增加一个PCI的watchdog外设(三)
我们已经设计了一个基于qemu的watchdog了.下一步工作就是创建一个含有我们的watchdog的虚拟计算机器了. 准备工作: 1. 使用virt-manager或者virsh创建一个虚拟机器. ...
- 《全栈营销之如何制作个人博客》之二:php环境安装及个人博客后台搭建 让你的博客跑起来
上一节我们讲了个人博客用什么开发语言,用什么CMS系统,从这一节我们就开始真正的干货,这一节我们讨论一下PHP环境的安装,及个人博客后台的搭建,让你的博客在正常的PHP环境中运行起来,你就可以进行后台 ...
随机推荐
- IBM developerWorks 的Ajax系列教程
掌握 Ajax,第 1 部分: Ajax 入门简介 http://www.ibm.com/developerworks/cn/xml/wa-ajaxintro1.html?csrf-799150205 ...
- QtQml 应用程序的性能考虑与建议(来自小V的翻译)
QtQml 应用程序的性能考虑与建议 原文:csdn aidear_evo QtQml应用程序的性能考虑与建议 本文翻译自Qt官网文档:http://doc.qt.io/qt-5/qtquick-pe ...
- 同步Flex Chart的数据提示
原文 http://www.riafan.com/sync-datatips-for-flex-chart/ 图表数据提示的同步不仅包含单个图表内多个系列的数据提示的同步,也包含多个图表的数据提示的同 ...
- oralce DBA 培训_lesson06
控制文件 -小型二进制文件 -定义物理数据库的当前状态 -丢失控制文件须要修复 -维护数据库的完整性 -要求: 1.在启动数据库时处于mount状态 2.可以操作数据库 -仅仅链接至一个数据库 -最初 ...
- poj 1064 Cable master ,二分 精度!!!
给出n根绳子,求把它们分割成K条等长的绳子的最大长度是多少? 二分 用 for(int i=0; i<100; ++i) 取代 while(r-l>eps) 循环100次精度能达到1e ...
- SQL Server 2008如何导出带数据的脚本文件
第一步,选中需要导出脚本的数据库,右键选中 第二步,选取弹出菜单中的任务-生成脚本选项(会弹出一SQL生成脚本的向导) 第三步,在向导中点击下一步,弹出选择数据库界面(默认是自己之前选中的数据库),把 ...
- App.config和Web.config配置文件的自定义配置节点
前言 昨天修改代码发现了一个问题,由于自己要在WCF服务接口中添加了一个方法,那么在相应调用的地方进行更新服务就可以了,不料意外发生了,竟然无法更新.左查右查终于发现了问题.App.config配置文 ...
- scrapy爬虫初体验
scrapy是一个python的爬虫框架,用于提取结构性数据.在这次宝贝计划1的项目中要用到一些数据.但四处联系后各方可能因为一些隐私问题不愿提供数据信息.这样我们只能自己爬取,存入数据库,再进行调用 ...
- C#之多线程编程
一.进程与线程 进程(Process)是对一段静态指令序列(程序)的动态执行过程,是系统进行资源分配和调度的一个基本单位.与进程相关的信息包括进程的用户标识,正在执行的已经编译好的程序,进程程序和数据 ...
- 关闭浏览器输入框自动补齐 兼容IE,FF,Chrome等主流浏览器
这篇文章主要介绍了关闭浏览器输入框自动补齐 兼容IE,FF,Chrome等主流浏览器,需要的朋友可以参考下.希望对大家有所帮助 Firefox 和 IE 的浏览器各自实现了input历史记录的功能 ...