@@ -34,7 +34,7 @@ void kvm__init_ram(struct kvm *kvm)
phys_size = kvm->ram_size;
host_mem = kvm->ram_start;
- err = kvm__register_mem(kvm, phys_start, phys_size, host_mem);
+ err = kvm__register_ram(kvm, phys_start, phys_size, host_mem);
if (err)
die("Failed to register %lld bytes of memory at physical "
"address 0x%llx [err %d]", phys_size, phys_start, err);
@@ -387,8 +387,8 @@ int pci_shmem__init(struct kvm *kvm)
if (mem == NULL)
return -EINVAL;
- kvm__register_mem(kvm, shmem_region->phys_addr, shmem_region->size,
- mem);
+ kvm__register_dev_mem(kvm, shmem_region->phys_addr, shmem_region->size,
+ mem);
return 0;
}
dev_init(pci_shmem__init);
@@ -73,7 +73,7 @@ struct framebuffer *vesa__init(struct kvm *kvm)
if (mem == MAP_FAILED)
ERR_PTR(-errno);
- kvm__register_mem(kvm, VESA_MEM_ADDR, VESA_MEM_SIZE, mem);
+ kvm__register_dev_mem(kvm, VESA_MEM_ADDR, VESA_MEM_SIZE, mem);
vesafb = (struct framebuffer) {
.width = VESA_WIDTH,
@@ -34,6 +34,14 @@ enum {
KVM_VMSTATE_PAUSED,
};
+enum kvm_mem_type {
+ KVM_MEM_TYPE_RAM = 1 << 1,
+ KVM_MEM_TYPE_DEVICE = 1 << 2,
+
+ KVM_MEM_TYPE_ALL = KVM_MEM_TYPE_RAM
+ | KVM_MEM_TYPE_DEVICE
+};
+
struct kvm_ext {
const char *name;
int code;
@@ -44,6 +52,7 @@ struct kvm_mem_bank {
u64 guest_phys_addr;
void *host_addr;
u64 size;
+ enum kvm_mem_type type;
};
struct kvm {
@@ -90,7 +99,22 @@ void kvm__irq_line(struct kvm *kvm, int irq, int level);
void kvm__irq_trigger(struct kvm *kvm, int irq);
bool kvm__emulate_io(struct kvm_cpu *vcpu, u16 port, void *data, int direction, int size, u32 count);
bool kvm__emulate_mmio(struct kvm_cpu *vcpu, u64 phys_addr, u8 *data, u32 len, u8 is_write);
-int kvm__register_mem(struct kvm *kvm, u64 guest_phys, u64 size, void *userspace_addr);
+int kvm__register_mem(struct kvm *kvm, u64 guest_phys, u64 size, void *userspace_addr,
+ enum kvm_mem_type type);
+static inline int kvm__register_ram(struct kvm *kvm, u64 guest_phys, u64 size,
+ void *userspace_addr)
+{
+ return kvm__register_mem(kvm, guest_phys, size, userspace_addr,
+ KVM_MEM_TYPE_RAM);
+}
+
+static inline int kvm__register_dev_mem(struct kvm *kvm, u64 guest_phys,
+ u64 size, void *userspace_addr)
+{
+ return kvm__register_mem(kvm, guest_phys, size, userspace_addr,
+ KVM_MEM_TYPE_DEVICE);
+}
+
int kvm__register_mmio(struct kvm *kvm, u64 phys_addr, u64 phys_addr_len, bool coalesce,
void (*mmio_fn)(struct kvm_cpu *vcpu, u64 addr, u8 *data, u32 len, u8 is_write, void *ptr),
void *ptr);
@@ -117,6 +141,24 @@ u64 host_to_guest_flat(struct kvm *kvm, void *ptr);
bool kvm__arch_load_kernel_image(struct kvm *kvm, int fd_kernel, int fd_initrd,
const char *kernel_cmdline);
+static inline const char *kvm_mem_type_to_string(enum kvm_mem_type type)
+{
+ switch (type) {
+ case KVM_MEM_TYPE_ALL:
+ return "(all)";
+ case KVM_MEM_TYPE_RAM:
+ return "RAM";
+ case KVM_MEM_TYPE_DEVICE:
+ return "device";
+ }
+
+ return "???";
+}
+
+int kvm__for_each_mem_bank(struct kvm *kvm, enum kvm_mem_type type,
+ int (*fun)(struct kvm *kvm, struct kvm_mem_bank *bank, void *data),
+ void *data);
+
/*
* Debugging
*/
@@ -182,7 +182,8 @@ core_exit(kvm__exit);
* memory regions to it. Therefore, be careful if you use this function for
* registering memory regions for emulating hardware.
*/
-int kvm__register_mem(struct kvm *kvm, u64 guest_phys, u64 size, void *userspace_addr)
+int kvm__register_mem(struct kvm *kvm, u64 guest_phys, u64 size,
+ void *userspace_addr, enum kvm_mem_type type)
{
struct kvm_userspace_memory_region mem;
struct kvm_mem_bank *bank;
@@ -196,6 +197,7 @@ int kvm__register_mem(struct kvm *kvm, u64 guest_phys, u64 size, void *userspace
bank->guest_phys_addr = guest_phys;
bank->host_addr = userspace_addr;
bank->size = size;
+ bank->type = type;
mem = (struct kvm_userspace_memory_region) {
.slot = kvm->mem_slots++,
@@ -245,6 +247,33 @@ u64 host_to_guest_flat(struct kvm *kvm, void *ptr)
return 0;
}
+/*
+ * Iterate over each registered memory bank. Call @fun for each bank with @data
+ * as argument. @type is a bitmask that allows to filter banks according to
+ * their type.
+ *
+ * If one call to @fun returns a non-zero value, stop iterating and return the
+ * value. Otherwise, return zero.
+ */
+int kvm__for_each_mem_bank(struct kvm *kvm, enum kvm_mem_type type,
+ int (*fun)(struct kvm *kvm, struct kvm_mem_bank *bank, void *data),
+ void *data)
+{
+ int ret;
+ struct kvm_mem_bank *bank;
+
+ list_for_each_entry(bank, &kvm->mem_banks, list) {
+ if (type != KVM_MEM_TYPE_ALL && !(bank->type & type))
+ continue;
+
+ ret = fun(kvm, bank, data);
+ if (ret)
+ break;
+ }
+
+ return ret;
+}
+
int kvm__recommended_cpus(struct kvm *kvm)
{
int ret;
@@ -28,21 +28,21 @@ void kvm__init_ram(struct kvm *kvm)
phys_size = kvm->ram_size;
host_mem = kvm->ram_start;
- kvm__register_mem(kvm, phys_start, phys_size, host_mem);
+ kvm__register_ram(kvm, phys_start, phys_size, host_mem);
} else {
/* one region for memory that fits below MMIO range */
phys_start = 0;
phys_size = KVM_MMIO_START;
host_mem = kvm->ram_start;
- kvm__register_mem(kvm, phys_start, phys_size, host_mem);
+ kvm__register_ram(kvm, phys_start, phys_size, host_mem);
/* one region for rest of memory */
phys_start = KVM_MMIO_START + KVM_MMIO_SIZE;
phys_size = kvm->ram_size - KVM_MMIO_START;
host_mem = kvm->ram_start + KVM_MMIO_START;
- kvm__register_mem(kvm, phys_start, phys_size, host_mem);
+ kvm__register_ram(kvm, phys_start, phys_size, host_mem);
}
}
@@ -79,7 +79,7 @@ void kvm__init_ram(struct kvm *kvm)
"overlaps MMIO!\n",
phys_size);
- kvm__register_mem(kvm, phys_start, phys_size, host_mem);
+ kvm__register_ram(kvm, phys_start, phys_size, host_mem);
}
void kvm__arch_set_cmdline(char *cmdline, bool video)
@@ -98,7 +98,7 @@ void kvm__init_ram(struct kvm *kvm)
phys_size = kvm->ram_size;
host_mem = kvm->ram_start;
- kvm__register_mem(kvm, phys_start, phys_size, host_mem);
+ kvm__register_ram(kvm, phys_start, phys_size, host_mem);
} else {
/* First RAM range from zero to the PCI gap: */
@@ -106,7 +106,7 @@ void kvm__init_ram(struct kvm *kvm)
phys_size = KVM_32BIT_GAP_START;
host_mem = kvm->ram_start;
- kvm__register_mem(kvm, phys_start, phys_size, host_mem);
+ kvm__register_ram(kvm, phys_start, phys_size, host_mem);
/* Second RAM range from 4GB to the end of RAM: */
@@ -114,7 +114,7 @@ void kvm__init_ram(struct kvm *kvm)
phys_size = kvm->ram_size - phys_start;
host_mem = kvm->ram_start + phys_start;
- kvm__register_mem(kvm, phys_start, phys_size, host_mem);
+ kvm__register_ram(kvm, phys_start, phys_size, host_mem);
}
}