return ((val / 10) << 4) + val % 10;
}
-static bool cmos_ram_data_in(struct kvm *kvm, u16 port, void *data, int size, u32 count)
+static bool cmos_ram_data_in(struct ioport *ioport, struct kvm *kvm, u16 port, void *data, int size, u32 count)
{
struct tm *tm;
time_t ti;
return true;
}
-static bool cmos_ram_data_out(struct kvm *kvm, u16 port, void *data, int size, u32 count)
+static bool cmos_ram_data_out(struct ioport *ioport, struct kvm *kvm, u16 port, void *data, int size, u32 count)
{
return true;
}
.io_in = cmos_ram_data_in,
};
-static bool cmos_ram_index_out(struct kvm *kvm, u16 port, void *data, int size, u32 count)
+static bool cmos_ram_index_out(struct ioport *ioport, struct kvm *kvm, u16 port, void *data, int size, u32 count)
{
u8 value;
void rtc__init(void)
{
/* PORT 0070-007F - CMOS RAM/RTC (REAL TIME CLOCK) */
- ioport__register(0x0070, &cmos_ram_index_ioport_ops, 1);
- ioport__register(0x0071, &cmos_ram_data_ioport_ops, 1);
+ ioport__register(0x0070, &cmos_ram_index_ioport_ops, 1, NULL);
+ ioport__register(0x0071, &cmos_ram_data_ioport_ops, 1, NULL);
}
return NULL;
}
-static bool serial8250_out(struct kvm *kvm, u16 port, void *data, int size, u32 count)
+static bool serial8250_out(struct ioport *ioport, struct kvm *kvm, u16 port, void *data, int size, u32 count)
{
struct serial8250_device *dev;
u16 offset;
return ret;
}
-static bool serial8250_in(struct kvm *kvm, u16 port, void *data, int size, u32 count)
+static bool serial8250_in(struct ioport *ioport, struct kvm *kvm, u16 port, void *data, int size, u32 count)
{
struct serial8250_device *dev;
u16 offset;
static void serial8250__device_init(struct kvm *kvm, struct serial8250_device *dev)
{
- ioport__register(dev->iobase, &serial8250_ops, 8);
+ ioport__register(dev->iobase, &serial8250_ops, 8, NULL);
kvm__irq_line(kvm, dev->irq, 0);
}
static char videomem[VESA_MEM_SIZE];
-static bool vesa_pci_io_in(struct kvm *kvm, u16 port, void *data, int size, u32 count)
+static bool vesa_pci_io_in(struct ioport *ioport, struct kvm *kvm, u16 port, void *data, int size, u32 count)
{
return true;
}
-static bool vesa_pci_io_out(struct kvm *kvm, u16 port, void *data, int size, u32 count)
+static bool vesa_pci_io_out(struct ioport *ioport, struct kvm *kvm, u16 port, void *data, int size, u32 count)
{
return true;
}
pci__register(&vesa_pci_device, dev);
- ioport__register(IOPORT_VESA, &vesa_io_ops, IOPORT_VESA_SIZE);
+ ioport__register(IOPORT_VESA, &vesa_io_ops, IOPORT_VESA_SIZE, NULL);
kvm__register_mmio(VESA_MEM_ADDR, VESA_MEM_SIZE, &vesa_mmio_callback);
#ifndef KVM__IOPORT_H
#define KVM__IOPORT_H
+#include "kvm/rbtree-interval.h"
+
#include <stdbool.h>
#include <asm/types.h>
#include <linux/types.h>
struct kvm;
+struct ioport {
+ struct rb_int_node node;
+ struct ioport_operations *ops;
+ void *priv;
+};
+
struct ioport_operations {
- bool (*io_in)(struct kvm *kvm, u16 port, void *data, int size, u32 count);
- bool (*io_out)(struct kvm *kvm, u16 port, void *data, int size, u32 count);
+ bool (*io_in)(struct ioport *ioport, struct kvm *kvm, u16 port, void *data, int size, u32 count);
+ bool (*io_out)(struct ioport *ioport, struct kvm *kvm, u16 port, void *data, int size, u32 count);
};
void ioport__setup_legacy(void);
-void ioport__register(u16 port, struct ioport_operations *ops, int count);
+void ioport__register(u16 port, struct ioport_operations *ops, int count, void *param);
static inline u8 ioport__read8(u8 *data)
{
#include "kvm/kvm.h"
#include "kvm/util.h"
-#include "kvm/rbtree-interval.h"
#include <linux/kvm.h> /* for KVM_EXIT_* */
#include <linux/types.h>
#include <stdlib.h>
#include <stdio.h>
-#define ioport_node(n) rb_entry(n, struct ioport_entry, node)
-
-struct ioport_entry {
- struct rb_int_node node;
- struct ioport_operations *ops;
-};
+#define ioport_node(n) rb_entry(n, struct ioport, node)
static struct rb_root ioport_tree = RB_ROOT;
bool ioport_debug;
-static struct ioport_entry *ioport_search(struct rb_root *root, u64 addr)
+static struct ioport *ioport_search(struct rb_root *root, u64 addr)
{
struct rb_int_node *node;
return ioport_node(node);
}
-static int ioport_insert(struct rb_root *root, struct ioport_entry *data)
+static int ioport_insert(struct rb_root *root, struct ioport *data)
{
return rb_int_insert(root, &data->node);
}
-static bool debug_io_out(struct kvm *kvm, u16 port, void *data, int size, u32 count)
+static bool debug_io_out(struct ioport *ioport, struct kvm *kvm, u16 port, void *data, int size, u32 count)
{
exit(EXIT_SUCCESS);
}
.io_out = debug_io_out,
};
-static bool dummy_io_in(struct kvm *kvm, u16 port, void *data, int size, u32 count)
+static bool dummy_io_in(struct ioport *ioport, struct kvm *kvm, u16 port, void *data, int size, u32 count)
{
return true;
}
-static bool dummy_io_out(struct kvm *kvm, u16 port, void *data, int size, u32 count)
+static bool dummy_io_out(struct ioport *ioport, struct kvm *kvm, u16 port, void *data, int size, u32 count)
{
return true;
}
.io_out = dummy_io_out,
};
-void ioport__register(u16 port, struct ioport_operations *ops, int count)
+void ioport__register(u16 port, struct ioport_operations *ops, int count, void *param)
{
- struct ioport_entry *entry;
+ struct ioport *entry;
entry = ioport_search(&ioport_tree, port);
if (entry) {
if (entry == NULL)
die("Failed allocating new ioport entry");
- *entry = (struct ioport_entry) {
+ *entry = (struct ioport) {
.node = RB_INT_INIT(port, port + count),
.ops = ops,
+ .priv = param,
};
ioport_insert(&ioport_tree, entry);
bool kvm__emulate_io(struct kvm *kvm, u16 port, void *data, int direction, int size, u32 count)
{
struct ioport_operations *ops;
- bool ret;
- struct ioport_entry *entry;
+ bool ret = false;
+ struct ioport *entry;
entry = ioport_search(&ioport_tree, port);
if (!entry)
goto error;
- ops = entry->ops;
+ ops = entry->ops;
if (direction == KVM_EXIT_IO_IN) {
- if (!ops->io_in)
- goto error;
-
- ret = ops->io_in(kvm, port, data, size, count);
- if (!ret)
- goto error;
+ if (ops->io_in)
+ ret = ops->io_in(entry, kvm, port, data, size, count);
} else {
- if (!ops->io_out)
- goto error;
-
- ret = ops->io_out(kvm, port, data, size, count);
- if (!ret)
- goto error;
+ if (ops->io_out)
+ ret = ops->io_out(entry, kvm, port, data, size, count);
}
+
+ if (!ret)
+ goto error;
+
return true;
error:
if (ioport_debug)
void ioport__setup_legacy(void)
{
/* 0x0020 - 0x003F - 8259A PIC 1 */
- ioport__register(0x0020, &dummy_read_write_ioport_ops, 2);
+ ioport__register(0x0020, &dummy_read_write_ioport_ops, 2, NULL);
/* PORT 0040-005F - PIT - PROGRAMMABLE INTERVAL TIMER (8253, 8254) */
- ioport__register(0x0040, &dummy_read_write_ioport_ops, 4);
+ ioport__register(0x0040, &dummy_read_write_ioport_ops, 4, NULL);
/* PORT 0060-006F - KEYBOARD CONTROLLER 804x (8041, 8042) (or PPI (8255) on PC,XT) */
- ioport__register(0x0060, &dummy_read_write_ioport_ops, 2);
- ioport__register(0x0064, &dummy_read_write_ioport_ops, 1);
+ ioport__register(0x0060, &dummy_read_write_ioport_ops, 2, NULL);
+ ioport__register(0x0064, &dummy_read_write_ioport_ops, 1, NULL);
/* 0x00A0 - 0x00AF - 8259A PIC 2 */
- ioport__register(0x00A0, &dummy_read_write_ioport_ops, 2);
+ ioport__register(0x00A0, &dummy_read_write_ioport_ops, 2, NULL);
/* PORT 00E0-00EF are 'motherboard specific' so we use them for our
internal debugging purposes. */
- ioport__register(IOPORT_DBG, &debug_ops, 1);
+ ioport__register(IOPORT_DBG, &debug_ops, 1, NULL);
/* PORT 00ED - DUMMY PORT FOR DELAY??? */
- ioport__register(0x00ED, &dummy_write_only_ioport_ops, 1);
+ ioport__register(0x00ED, &dummy_write_only_ioport_ops, 1, NULL);
/* 0x00F0 - 0x00FF - Math co-processor */
- ioport__register(0x00F0, &dummy_write_only_ioport_ops, 2);
+ ioport__register(0x00F0, &dummy_write_only_ioport_ops, 2, NULL);
/* PORT 03D4-03D5 - COLOR VIDEO - CRT CONTROL REGISTERS */
- ioport__register(0x03D4, &dummy_read_write_ioport_ops, 1);
- ioport__register(0x03D5, &dummy_write_only_ioport_ops, 1);
+ ioport__register(0x03D4, &dummy_read_write_ioport_ops, 1, NULL);
+ ioport__register(0x03D5, &dummy_write_only_ioport_ops, 1, NULL);
}
return base + offset;
}
-static bool pci_config_address_out(struct kvm *kvm, u16 port, void *data, int size, u32 count)
+static bool pci_config_address_out(struct ioport *ioport, struct kvm *kvm, u16 port, void *data, int size, u32 count)
{
void *p = pci_config_address_ptr(port);
return true;
}
-static bool pci_config_address_in(struct kvm *kvm, u16 port, void *data, int size, u32 count)
+static bool pci_config_address_in(struct ioport *ioport, struct kvm *kvm, u16 port, void *data, int size, u32 count)
{
void *p = pci_config_address_ptr(port);
.io_out = pci_config_address_out,
};
-static bool pci_config_data_out(struct kvm *kvm, u16 port, void *data, int size, u32 count)
+static bool pci_config_data_out(struct ioport *ioport, struct kvm *kvm, u16 port, void *data, int size, u32 count)
{
return true;
}
return dev != NULL;
}
-static bool pci_config_data_in(struct kvm *kvm, u16 port, void *data, int size, u32 count)
+static bool pci_config_data_in(struct ioport *ioport, struct kvm *kvm, u16 port, void *data, int size, u32 count)
{
unsigned long start;
u8 dev_num;
void pci__init(void)
{
- ioport__register(PCI_CONFIG_DATA + 0, &pci_config_data_ops, 4);
- ioport__register(PCI_CONFIG_ADDRESS + 0, &pci_config_address_ops, 4);
+ ioport__register(PCI_CONFIG_DATA + 0, &pci_config_data_ops, 4, NULL);
+ ioport__register(PCI_CONFIG_ADDRESS + 0, &pci_config_address_ops, 4, NULL);
}
return true;
}
-static bool virtio_p9_pci_io_in(struct kvm *kvm, u16 port, void *data, int size, u32 count)
+static bool virtio_p9_pci_io_in(struct ioport *ioport, struct kvm *kvm, u16 port, void *data, int size, u32 count)
{
unsigned long offset;
bool ret = true;
}
}
-static bool virtio_p9_pci_io_out(struct kvm *kvm, u16 port, void *data, int size, u32 count)
+static bool virtio_p9_pci_io_out(struct ioport *ioport, struct kvm *kvm, u16 port, void *data, int size, u32 count)
{
unsigned long offset;
bool ret = true;
virtio_p9_pci_device.irq_line = line;
pci__register(&virtio_p9_pci_device, dev);
- ioport__register(IOPORT_VIRTIO_P9, &virtio_p9_io_ops, IOPORT_VIRTIO_P9_SIZE);
+ ioport__register(IOPORT_VIRTIO_P9, &virtio_p9_io_ops, IOPORT_VIRTIO_P9_SIZE, NULL);
}
*offset = port - (base + *dev_idx * size);
}
-static bool virtio_blk_pci_io_in(struct kvm *kvm, u16 port, void *data, int size, u32 count)
+static bool virtio_blk_pci_io_in(struct ioport *ioport, struct kvm *kvm, u16 port, void *data, int size, u32 count)
{
struct blk_dev *bdev;
u16 offset, dev_idx;
virt_queue__trigger_irq(vq, bdev->pci_hdr.irq_line, &bdev->isr, kvm);
}
-static bool virtio_blk_pci_io_out(struct kvm *kvm, u16 port, void *data, int size, u32 count)
+static bool virtio_blk_pci_io_out(struct ioport *ioport, struct kvm *kvm, u16 port, void *data, int size, u32 count)
{
struct blk_dev *bdev;
u16 offset, dev_idx;
pci__register(&bdev->pci_hdr, dev);
- ioport__register(blk_dev_base_addr, &virtio_blk_io_ops, IOPORT_VIRTIO_BLK_SIZE);
+ ioport__register(blk_dev_base_addr, &virtio_blk_io_ops, IOPORT_VIRTIO_BLK_SIZE, NULL);
}
void virtio_blk__init_all(struct kvm *kvm)
return true;
}
-static bool virtio_console_pci_io_in(struct kvm *kvm, u16 port, void *data, int size, u32 count)
+static bool virtio_console_pci_io_in(struct ioport *ioport, struct kvm *kvm, u16 port, void *data, int size, u32 count)
{
unsigned long offset = port - IOPORT_VIRTIO_CONSOLE;
bool ret = true;
}
-static bool virtio_console_pci_io_out(struct kvm *kvm, u16 port, void *data, int size, u32 count)
+static bool virtio_console_pci_io_out(struct ioport *ioport, struct kvm *kvm, u16 port, void *data, int size, u32 count)
{
unsigned long offset = port - IOPORT_VIRTIO_CONSOLE;
bool ret = true;
virtio_console_pci_device.irq_pin = pin;
virtio_console_pci_device.irq_line = line;
pci__register(&virtio_console_pci_device, dev);
- ioport__register(IOPORT_VIRTIO_CONSOLE, &virtio_console_io_ops, IOPORT_VIRTIO_CONSOLE_SIZE);
+ ioport__register(IOPORT_VIRTIO_CONSOLE, &virtio_console_io_ops, IOPORT_VIRTIO_CONSOLE_SIZE, NULL);
}
return true;
}
-static bool virtio_net_pci_io_in(struct kvm *kvm, u16 port, void *data, int size, u32 count)
+static bool virtio_net_pci_io_in(struct ioport *ioport, struct kvm *kvm, u16 port, void *data, int size, u32 count)
{
unsigned long offset = port - IOPORT_VIRTIO_NET;
bool ret = true;
}
}
-static bool virtio_net_pci_io_out(struct kvm *kvm, u16 port, void *data, int size, u32 count)
+static bool virtio_net_pci_io_out(struct ioport *ioport, struct kvm *kvm, u16 port, void *data, int size, u32 count)
{
unsigned long offset = port - IOPORT_VIRTIO_NET;
bool ret = true;
pci_header.irq_pin = pin;
pci_header.irq_line = line;
pci__register(&pci_header, dev);
- ioport__register(IOPORT_VIRTIO_NET, &virtio_net_io_ops, IOPORT_VIRTIO_NET_SIZE);
+ ioport__register(IOPORT_VIRTIO_NET, &virtio_net_io_ops, IOPORT_VIRTIO_NET_SIZE, NULL);
virtio_net__io_thread_init(params->kvm);
}
static struct rng_dev rdev;
-static bool virtio_rng_pci_io_in(struct kvm *kvm, u16 port, void *data, int size, u32 count)
+static bool virtio_rng_pci_io_in(struct ioport *ioport, struct kvm *kvm, u16 port, void *data, int size, u32 count)
{
unsigned long offset;
bool ret = true;
}
}
-static bool virtio_rng_pci_io_out(struct kvm *kvm, u16 port, void *data, int size, u32 count)
+static bool virtio_rng_pci_io_out(struct ioport *ioport, struct kvm *kvm, u16 port, void *data, int size, u32 count)
{
unsigned long offset;
bool ret = true;
virtio_rng_pci_device.irq_line = line;
pci__register(&virtio_rng_pci_device, dev);
- ioport__register(IOPORT_VIRTIO_RNG, &virtio_rng_io_ops, IOPORT_VIRTIO_RNG_SIZE);
+ ioport__register(IOPORT_VIRTIO_RNG, &virtio_rng_io_ops, IOPORT_VIRTIO_RNG_SIZE, NULL);
}