|
| 1 | +diff --git a/accel/kvm/kvm-all.c b/accel/kvm/kvm-all.c |
| 2 | +index b472301637..c39c09b16b 100644 |
| 3 | +--- a/accel/kvm/kvm-all.c |
| 4 | ++++ b/accel/kvm/kvm-all.c |
| 5 | +@@ -2527,6 +2527,13 @@ static int kvm_init(MachineState *ms) |
| 6 | + type = kvm_arch_get_default_type(ms); |
| 7 | + } |
| 8 | + |
| 9 | ++ if (object_property_find(OBJECT(current_machine), "cove")) { |
| 10 | ++ if (object_property_get_bool(OBJECT(current_machine), "cove", &error_abort)) { |
| 11 | ++ type = 1UL << 10; |
| 12 | ++ warn_report("Creating CoVE TVM"); |
| 13 | ++ } |
| 14 | ++ } |
| 15 | ++ |
| 16 | + do { |
| 17 | + ret = kvm_ioctl(s, KVM_CREATE_VM, type); |
| 18 | + } while (ret == -EINTR); |
| 19 | +diff --git a/hw/riscv/boot.c b/hw/riscv/boot.c |
| 20 | +index 52bf8e67de..7f4550bbf1 100644 |
| 21 | +--- a/hw/riscv/boot.c |
| 22 | ++++ b/hw/riscv/boot.c |
| 23 | +@@ -16,7 +16,7 @@ |
| 24 | + * You should have received a copy of the GNU General Public License along with |
| 25 | + * this program. If not, see <http://www.gnu.org/licenses/>. |
| 26 | + */ |
| 27 | +- |
| 28 | ++#include <linux/kvm.h> |
| 29 | + #include "qemu/osdep.h" |
| 30 | + #include "qemu/datadir.h" |
| 31 | + #include "qemu/units.h" |
| 32 | +@@ -205,6 +205,18 @@ static void riscv_load_initrd(MachineState *machine, uint64_t kernel_entry) |
| 33 | + } |
| 34 | + } |
| 35 | + |
| 36 | ++ #if defined(CONFIG_KVM) |
| 37 | ++ struct kvm_riscv_cove_measure_region mr = { |
| 38 | ++ .user_addr = 0, |
| 39 | ++ .gpa = start, |
| 40 | ++ .size = size, |
| 41 | ++ .type = KVM_RISCV_COVE_REGION_INITRD, |
| 42 | ++ }; |
| 43 | ++ warn_report("Register initrd region %lx %ld", start, size); |
| 44 | ++ KVMState *s = KVM_STATE(machine->accelerator); |
| 45 | ++ kvm_vm_ioctl(s, KVM_RISCV_COVE_MEASURE_REGION, &mr); |
| 46 | ++ #endif |
| 47 | ++ |
| 48 | + /* Some RISC-V machines (e.g. opentitan) don't have a fdt. */ |
| 49 | + if (fdt) { |
| 50 | + end = start + size; |
| 51 | +@@ -222,6 +234,7 @@ target_ulong riscv_load_kernel(MachineState *machine, |
| 52 | + const char *kernel_filename = machine->kernel_filename; |
| 53 | + uint64_t kernel_load_base, kernel_entry; |
| 54 | + void *fdt = machine->fdt; |
| 55 | ++ ssize_t kernel_size; |
| 56 | + |
| 57 | + g_assert(kernel_filename != NULL); |
| 58 | + |
| 59 | +@@ -232,20 +245,23 @@ target_ulong riscv_load_kernel(MachineState *machine, |
| 60 | + * the (expected) load address load address. This allows kernels to have |
| 61 | + * separate SBI and ELF entry points (used by FreeBSD, for example). |
| 62 | + */ |
| 63 | +- if (load_elf_ram_sym(kernel_filename, NULL, NULL, NULL, |
| 64 | ++ kernel_size = load_elf_ram_sym(kernel_filename, NULL, NULL, NULL, |
| 65 | + NULL, &kernel_load_base, NULL, NULL, 0, |
| 66 | +- EM_RISCV, 1, 0, NULL, true, sym_cb) > 0) { |
| 67 | ++ EM_RISCV, 1, 0, NULL, true, sym_cb) > 0; |
| 68 | ++ if (kernel_size > 0) { |
| 69 | + kernel_entry = kernel_load_base; |
| 70 | + goto out; |
| 71 | + } |
| 72 | + |
| 73 | +- if (load_uimage_as(kernel_filename, &kernel_entry, NULL, NULL, |
| 74 | +- NULL, NULL, NULL) > 0) { |
| 75 | ++ kernel_size = load_uimage_as(kernel_filename, &kernel_entry, NULL, NULL, |
| 76 | ++ NULL, NULL, NULL); |
| 77 | ++ if (kernel_size > 0) { |
| 78 | + goto out; |
| 79 | + } |
| 80 | + |
| 81 | +- if (load_image_targphys_as(kernel_filename, kernel_start_addr, |
| 82 | +- current_machine->ram_size, NULL) > 0) { |
| 83 | ++ kernel_size = load_image_targphys_as(kernel_filename, kernel_start_addr, |
| 84 | ++ current_machine->ram_size, NULL); |
| 85 | ++ if (kernel_size > 0) { |
| 86 | + kernel_entry = kernel_start_addr; |
| 87 | + goto out; |
| 88 | + } |
| 89 | +@@ -262,6 +278,35 @@ out: |
| 90 | + kernel_entry = extract64(kernel_entry, 0, 32); |
| 91 | + } |
| 92 | + |
| 93 | ++ #if defined(CONFIG_KVM) |
| 94 | ++ struct kvm_riscv_cove_measure_region mr = { |
| 95 | ++ .user_addr = 0, |
| 96 | ++ .gpa = kernel_entry, |
| 97 | ++ .size = kernel_size, |
| 98 | ++ .type = KVM_RISCV_COVE_REGION_KERNEL, |
| 99 | ++ }; |
| 100 | ++ warn_report("Register kernel region %lx %ld", kernel_entry, kernel_size); |
| 101 | ++ KVMState *s = KVM_STATE(machine->accelerator); |
| 102 | ++ kvm_vm_ioctl(s, KVM_RISCV_COVE_MEASURE_REGION, &mr); |
| 103 | ++ |
| 104 | ++ if (object_property_find(OBJECT(current_machine), "cove-tap-filename")) { |
| 105 | ++ const char * tap_filename = object_property_get_str(OBJECT(current_machine), "cove-tap-filename", NULL); |
| 106 | ++ hwaddr tap_addr = (kernel_entry+kernel_size); |
| 107 | ++ tap_addr = ((4096-1) & tap_addr) ? ((tap_addr+4096) & ~(4096-1)) : tap_addr; |
| 108 | ++ error_report("Loading CoVE TAP %s %lx", tap_filename, tap_addr); |
| 109 | ++ if (load_image_targphys(tap_filename, tap_addr, 4096) <= 0) { |
| 110 | ++ error_report("Loading CoVE TAP failed"); |
| 111 | ++ } |
| 112 | ++ struct kvm_riscv_cove_measure_region mr = { |
| 113 | ++ .user_addr = 0, |
| 114 | ++ .gpa = tap_addr, |
| 115 | ++ .size = 4096, |
| 116 | ++ .type = KVM_RISCV_COVE_REGION_COVE_TAP, |
| 117 | ++ }; |
| 118 | ++ kvm_vm_ioctl(KVM_STATE(machine->accelerator), KVM_RISCV_COVE_MEASURE_REGION, &mr); |
| 119 | ++ } |
| 120 | ++ #endif |
| 121 | ++ |
| 122 | + if (load_initrd && machine->initrd_filename) { |
| 123 | + riscv_load_initrd(machine, kernel_entry); |
| 124 | + } |
| 125 | +diff --git a/hw/riscv/virt.c b/hw/riscv/virt.c |
| 126 | +index 505a36dff6..40a41eb9ee 100644 |
| 127 | +--- a/hw/riscv/virt.c |
| 128 | ++++ b/hw/riscv/virt.c |
| 129 | +@@ -17,7 +17,8 @@ |
| 130 | + * You should have received a copy of the GNU General Public License along with |
| 131 | + * this program. If not, see <http://www.gnu.org/licenses/>. |
| 132 | + */ |
| 133 | +- |
| 134 | ++#include <linux/kvm.h> |
| 135 | ++#include <libfdt.h> |
| 136 | + #include "qemu/osdep.h" |
| 137 | + #include "qemu/units.h" |
| 138 | + #include "qemu/error-report.h" |
| 139 | +@@ -1312,6 +1313,17 @@ static void virt_machine_done(Notifier *notifier, void *data) |
| 140 | + machine); |
| 141 | + riscv_load_fdt(fdt_load_addr, machine->fdt); |
| 142 | + |
| 143 | ++ #if defined(CONFIG_KVM) |
| 144 | ++ uint32_t fdtsize = fdt_totalsize(machine->fdt); |
| 145 | ++ struct kvm_riscv_cove_measure_region mr = { |
| 146 | ++ .user_addr = 0, |
| 147 | ++ .gpa = fdt_load_addr, |
| 148 | ++ .size = fdtsize, |
| 149 | ++ .type = KVM_RISCV_COVE_REGION_FDT, |
| 150 | ++ }; |
| 151 | ++ kvm_vm_ioctl(KVM_STATE(machine->accelerator), KVM_RISCV_COVE_MEASURE_REGION, &mr); |
| 152 | ++ #endif |
| 153 | ++ |
| 154 | + /* load the reset vector */ |
| 155 | + riscv_setup_rom_reset_vec(machine, &s->soc[0], start_addr, |
| 156 | + virt_memmap[VIRT_MROM].base, |
| 157 | +@@ -1330,6 +1342,12 @@ static void virt_machine_done(Notifier *notifier, void *data) |
| 158 | + if (virt_is_acpi_enabled(s)) { |
| 159 | + virt_acpi_setup(s); |
| 160 | + } |
| 161 | ++ |
| 162 | ++ #if defined(CONFIG_KVM) |
| 163 | ++ struct kvm_riscv_cove_vm_finalize finalize = { |
| 164 | ++ }; |
| 165 | ++ kvm_vm_ioctl(KVM_STATE(machine->accelerator), KVM_RISCV_COVE_VM_FINALIZE, &finalize); |
| 166 | ++ #endif |
| 167 | + } |
| 168 | + |
| 169 | + static void virt_machine_init(MachineState *machine) |
| 170 | +@@ -1540,6 +1558,33 @@ static void virt_machine_instance_init(Object *obj) |
| 171 | + s->acpi = ON_OFF_AUTO_AUTO; |
| 172 | + } |
| 173 | + |
| 174 | ++static bool virt_get_cove(Object *obj, Error **errp) |
| 175 | ++{ |
| 176 | ++ RISCVVirtState *s = RISCV_VIRT_MACHINE(obj); |
| 177 | ++ |
| 178 | ++ return s->cove; |
| 179 | ++} |
| 180 | ++ |
| 181 | ++static void virt_set_cove(Object *obj, bool value, Error **errp) |
| 182 | ++{ |
| 183 | ++ RISCVVirtState *s = RISCV_VIRT_MACHINE(obj); |
| 184 | ++ |
| 185 | ++ s->cove = value; |
| 186 | ++} |
| 187 | ++ |
| 188 | ++static char *virt_get_cove_tap_filename(Object *obj, Error **errp) |
| 189 | ++{ |
| 190 | ++ RISCVVirtState *s = RISCV_VIRT_MACHINE(obj); |
| 191 | ++ return g_strdup(s->cove_tap_filename); |
| 192 | ++} |
| 193 | ++ |
| 194 | ++static void virt_set_cove_tap_filename(Object *obj, const char *val, Error **errp) |
| 195 | ++{ |
| 196 | ++ RISCVVirtState *s = RISCV_VIRT_MACHINE(obj); |
| 197 | ++ g_free(s->cove_tap_filename); |
| 198 | ++ s->cove_tap_filename = g_strdup(val); |
| 199 | ++} |
| 200 | ++ |
| 201 | + static char *virt_get_aia_guests(Object *obj, Error **errp) |
| 202 | + { |
| 203 | + RISCVVirtState *s = RISCV_VIRT_MACHINE(obj); |
| 204 | +@@ -1714,6 +1759,10 @@ static void virt_machine_class_init(ObjectClass *oc, void *data) |
| 205 | + NULL, NULL); |
| 206 | + object_class_property_set_description(oc, "acpi", |
| 207 | + "Enable ACPI"); |
| 208 | ++ object_class_property_add_bool(oc, "cove", virt_get_cove, |
| 209 | ++ virt_set_cove); |
| 210 | ++ object_class_property_add_str(oc, "cove-tap-filename", virt_get_cove_tap_filename, |
| 211 | ++ virt_set_cove_tap_filename); |
| 212 | + } |
| 213 | + |
| 214 | + static const TypeInfo virt_machine_typeinfo = { |
| 215 | +diff --git a/include/hw/riscv/virt.h b/include/hw/riscv/virt.h |
| 216 | +index e5c474b26e..c01e733b34 100644 |
| 217 | +--- a/include/hw/riscv/virt.h |
| 218 | ++++ b/include/hw/riscv/virt.h |
| 219 | +@@ -60,6 +60,8 @@ struct RISCVVirtState { |
| 220 | + char *oem_table_id; |
| 221 | + OnOffAuto acpi; |
| 222 | + const MemMapEntry *memmap; |
| 223 | ++ bool cove; |
| 224 | ++ char *cove_tap_filename; |
| 225 | + }; |
| 226 | + |
| 227 | + enum { |
| 228 | +diff --git a/linux-headers/linux/kvm.h b/linux-headers/linux/kvm.h |
| 229 | +index 1f3f3333a4..9dc12996ef 100644 |
| 230 | +--- a/linux-headers/linux/kvm.h |
| 231 | ++++ b/linux-headers/linux/kvm.h |
| 232 | +@@ -2245,4 +2245,24 @@ struct kvm_s390_zpci_op { |
| 233 | + /* flags for kvm_s390_zpci_op->u.reg_aen.flags */ |
| 234 | + #define KVM_S390_ZPCIOP_REGAEN_HOST (1 << 0) |
| 235 | + |
| 236 | ++enum KVM_RISCV_COVE_REGION { |
| 237 | ++ KVM_RISCV_COVE_REGION_FIRMWARE = 0, |
| 238 | ++ KVM_RISCV_COVE_REGION_KERNEL, |
| 239 | ++ KVM_RISCV_COVE_REGION_FDT, |
| 240 | ++ KVM_RISCV_COVE_REGION_INITRD, |
| 241 | ++ KVM_RISCV_COVE_REGION_COVE_TAP, |
| 242 | ++}; |
| 243 | ++ |
| 244 | ++struct kvm_riscv_cove_measure_region { |
| 245 | ++ unsigned long user_addr; |
| 246 | ++ unsigned long gpa; |
| 247 | ++ unsigned long size; |
| 248 | ++ enum KVM_RISCV_COVE_REGION type; |
| 249 | ++}; |
| 250 | ++ |
| 251 | ++struct kvm_riscv_cove_vm_finalize {}; |
| 252 | ++ |
| 253 | ++#define KVM_RISCV_COVE_MEASURE_REGION _IOR(KVMIO, 0xb6, struct kvm_riscv_cove_measure_region) |
| 254 | ++#define KVM_RISCV_COVE_VM_FINALIZE _IOR(KVMIO, 0xb7, struct kvm_riscv_cove_vm_finalize) |
| 255 | ++ |
| 256 | + #endif /* __LINUX_KVM_H */ |
0 commit comments