diff --git a/hw/intc/loongarch_extioi_kvm.c b/hw/intc/loongarch_extioi_kvm.c index f5bbc3325556903e6482d8517bed23ae0b861e8e..e7699ad2ea0be46fe0b0a0b49c207acf5e9ebe5f 100644 --- a/hw/intc/loongarch_extioi_kvm.c +++ b/hw/intc/loongarch_extioi_kvm.c @@ -22,6 +22,30 @@ static void kvm_extioi_access_regs(int fd, uint64_t addr, addr, val, is_write, &error_abort); } +static void kvm_extioi_access_sw_status(int fd, uint64_t addr, + void *val, bool is_write) +{ + kvm_device_access(fd, KVM_DEV_LOONGARCH_EXTIOI_GRP_SW_STATUS, + addr, val, is_write, &error_abort); +} + +static void kvm_extioi_save_load_sw_status(void *opaque, bool is_write) +{ + KVMLoongArchExtIOI *s = (KVMLoongArchExtIOI *)opaque; + KVMLoongArchExtIOIClass *class = KVM_LOONGARCH_EXTIOI_GET_CLASS(s); + int fd = class->dev_fd; + int addr; + + addr = KVM_DEV_LOONGARCH_EXTIOI_SW_STATUS_NUM_CPU; + kvm_extioi_access_sw_status(fd, addr, (void *)&s->num_cpu, is_write); + + addr = KVM_DEV_LOONGARCH_EXTIOI_SW_STATUS_FEATURE; + kvm_extioi_access_sw_status(fd, addr, (void *)&s->features, is_write); + + addr = KVM_DEV_LOONGARCH_EXTIOI_SW_STATUS_STATE; + kvm_extioi_access_sw_status(fd, addr, (void *)&s->status, is_write); +} + static int kvm_loongarch_extioi_pre_save(void *opaque) { KVMLoongArchExtIOI *s = (KVMLoongArchExtIOI *)opaque; @@ -41,6 +65,8 @@ static int kvm_loongarch_extioi_pre_save(void *opaque) kvm_extioi_access_regs(fd, EXTIOI_COREISR_START, (void *)s->coreisr, false); + kvm_extioi_save_load_sw_status(opaque, false); + return 0; } @@ -61,12 +87,19 @@ static int kvm_loongarch_extioi_post_load(void *opaque, int version_id) (void *)s->sw_coremap, true); kvm_extioi_access_regs(fd, EXTIOI_COREISR_START, (void *)s->coreisr, true); + kvm_extioi_save_load_sw_status(opaque, true); + + kvm_device_access(fd, KVM_DEV_LOONGARCH_EXTIOI_GRP_CTRL, + KVM_DEV_LOONGARCH_EXTIOI_CTRL_LOAD_FINISHED, + NULL, true, &error_abort); + return 0; } static void kvm_loongarch_extioi_realize(DeviceState *dev, Error **errp) { KVMLoongArchExtIOIClass *extioi_class = KVM_LOONGARCH_EXTIOI_GET_CLASS(dev); + KVMLoongArchExtIOI *s = KVM_LOONGARCH_EXTIOI(dev); struct kvm_create_device cd = {0}; Error *err = NULL; int ret,i; @@ -77,6 +110,10 @@ static void kvm_loongarch_extioi_realize(DeviceState *dev, Error **errp) return; } + if (s->features & BIT(EXTIOI_HAS_VIRT_EXTENSION)) { + s->features |= EXTIOI_VIRT_HAS_FEATURES; + } + if (!extioi_class->is_created) { cd.type = KVM_DEV_TYPE_LA_EXTIOI; ret = kvm_vm_ioctl(kvm_state, KVM_CREATE_DEVICE, &cd); @@ -87,6 +124,15 @@ static void kvm_loongarch_extioi_realize(DeviceState *dev, Error **errp) } extioi_class->is_created = true; extioi_class->dev_fd = cd.fd; + + kvm_device_access(cd.fd, KVM_DEV_LOONGARCH_EXTIOI_GRP_CTRL, + KVM_DEV_LOONGARCH_EXTIOI_CTRL_INIT_NUM_CPU, + &s->num_cpu, true, NULL); + + kvm_device_access(cd.fd, KVM_DEV_LOONGARCH_EXTIOI_GRP_CTRL, + KVM_DEV_LOONGARCH_EXTIOI_CTRL_INIT_FEATURE, + &s->features, true, NULL); + fprintf(stdout, "Create LoongArch extioi irqchip in KVM done!\n"); } @@ -102,8 +148,8 @@ static void kvm_loongarch_extioi_realize(DeviceState *dev, Error **errp) static const VMStateDescription vmstate_kvm_extioi_core = { .name = "kvm-extioi-single", - .version_id = 1, - .minimum_version_id = 1, + .version_id = 2, + .minimum_version_id = 2, .pre_save = kvm_loongarch_extioi_pre_save, .post_load = kvm_loongarch_extioi_post_load, .fields = (VMStateField[]) { @@ -119,10 +165,20 @@ static const VMStateDescription vmstate_kvm_extioi_core = { EXTIOI_IRQS_IPMAP_SIZE / 4), VMSTATE_UINT32_ARRAY(coremap, KVMLoongArchExtIOI, EXTIOI_IRQS / 4), VMSTATE_UINT8_ARRAY(sw_coremap, KVMLoongArchExtIOI, EXTIOI_IRQS), + VMSTATE_UINT32(num_cpu, KVMLoongArchExtIOI), + VMSTATE_UINT32(features, KVMLoongArchExtIOI), + VMSTATE_UINT32(status, KVMLoongArchExtIOI), VMSTATE_END_OF_LIST() } }; +static Property extioi_properties[] = { + DEFINE_PROP_UINT32("num-cpu", KVMLoongArchExtIOI, num_cpu, 1), + DEFINE_PROP_BIT("has-virtualization-extension", KVMLoongArchExtIOI, + features, EXTIOI_HAS_VIRT_EXTENSION, 0), + DEFINE_PROP_END_OF_LIST(), +}; + static void kvm_loongarch_extioi_class_init(ObjectClass *oc, void *data) { DeviceClass *dc = DEVICE_CLASS(oc); @@ -131,6 +187,7 @@ static void kvm_loongarch_extioi_class_init(ObjectClass *oc, void *data) extioi_class->parent_realize = dc->realize; dc->realize = kvm_loongarch_extioi_realize; extioi_class->is_created = false; + device_class_set_props(dc, extioi_properties); dc->vmsd = &vmstate_kvm_extioi_core; } diff --git a/hw/loongarch/boot.c b/hw/loongarch/boot.c index 53dcefbb55a7a932b5cc0a5b26c9a32886fb07a6..13f0c37659e3502513020bf050ad3a38a7fd8a9b 100644 --- a/hw/loongarch/boot.c +++ b/hw/loongarch/boot.c @@ -171,6 +171,48 @@ static uint64_t cpu_loongarch_virt_to_phys(void *opaque, uint64_t addr) return addr & MAKE_64BIT_MASK(0, TARGET_PHYS_ADDR_SPACE_BITS); } +static void find_initrd_loadoffset(struct loongarch_boot_info *info, + uint64_t kernel_high, ssize_t kernel_size) +{ + hwaddr base, size, gap, low_end; + ram_addr_t initrd_end, initrd_start; + + base = VIRT_LOWMEM_BASE; + gap = VIRT_LOWMEM_SIZE; + initrd_start = ROUND_UP(kernel_high + 4 * kernel_size, 64 * KiB); + initrd_end = initrd_start + initrd_size; + + size = info->ram_size; + low_end = base + MIN(size, gap); + if (initrd_end <= low_end) { + initrd_offset = initrd_start; + return ; + } + + if (size <= gap) { + error_report("The low memory too small for initial ram disk '%s'," + "You need to expand the memory space", + info->initrd_filename); + exit(1); + } + + /* + * Try to load initrd in the high memory + */ + size -= gap; + base = VIRT_HIGHMEM_BASE; + initrd_start = ROUND_UP(base, 64 * KiB); + if (initrd_size <= size) { + initrd_offset = initrd_start; + return ; + } + + error_report("The high memory too small for initial ram disk '%s'," + "You need to expand the memory space", + info->initrd_filename); + exit(1); +} + static int64_t load_kernel_info(struct loongarch_boot_info *info) { uint64_t kernel_entry, kernel_low, kernel_high; @@ -192,16 +234,9 @@ static int64_t load_kernel_info(struct loongarch_boot_info *info) if (info->initrd_filename) { initrd_size = get_image_size(info->initrd_filename); if (initrd_size > 0) { - initrd_offset = ROUND_UP(kernel_high + 4 * kernel_size, 64 * KiB); - - if (initrd_offset + initrd_size > info->ram_size) { - error_report("memory too small for initial ram disk '%s'", - info->initrd_filename); - exit(1); - } - + find_initrd_loadoffset(info, kernel_high, kernel_size); initrd_size = load_image_targphys(info->initrd_filename, initrd_offset, - info->ram_size - initrd_offset); + initrd_size); } if (initrd_size == (target_ulong)-1) { diff --git a/hw/loongarch/virt.c b/hw/loongarch/virt.c index d165c238010fda2dd9c3929d63a5c140f5bf906d..f1953b9f82df838da0aab5612ae5214b6e10e1ed 100644 --- a/hw/loongarch/virt.c +++ b/hw/loongarch/virt.c @@ -890,6 +890,8 @@ static void virt_irq_init(LoongArchVirtMachineState *lvms) if (kvm_enabled() && kvm_irqchip_in_kernel()) { extioi = qdev_new(TYPE_KVM_LOONGARCH_EXTIOI); + qdev_prop_set_uint32(extioi, "num-cpu", ms->smp.max_cpus); + qdev_prop_set_bit(extioi, "has-virtualization-extension", true); sysbus_realize_and_unref(SYS_BUS_DEVICE(extioi), &error_fatal); } else { extioi = qdev_new(TYPE_LOONGARCH_EXTIOI); diff --git a/include/hw/intc/loongarch_extioi.h b/include/hw/intc/loongarch_extioi.h index e8378f6083090d58f6a797619879f19911c2d7d8..e77cd752cfe7b7b83b97ae2337ad88be666c049f 100644 --- a/include/hw/intc/loongarch_extioi.h +++ b/include/hw/intc/loongarch_extioi.h @@ -92,6 +92,10 @@ struct LoongArchExtIOI { struct KVMLoongArchExtIOI { SysBusDevice parent_obj; + uint32_t num_cpu; + uint32_t features; + uint32_t status; + /* hardware state */ uint32_t nodetype[EXTIOI_IRQS_NODETYPE_COUNT / 2]; uint32_t bounce[EXTIOI_IRQS_GROUP_COUNT]; diff --git a/linux-headers/asm-loongarch/kvm.h b/linux-headers/asm-loongarch/kvm.h index f109ed42d9b6c819313da33919f5b0d33a37f104..c23c16f3ae6da5bd7d5a7ec331e238f341baa637 100644 --- a/linux-headers/asm-loongarch/kvm.h +++ b/linux-headers/asm-loongarch/kvm.h @@ -142,16 +142,16 @@ struct kvm_iocsr_entry { #define KVM_DEV_LOONGARCH_EXTIOI_GRP_REGS 0x40000003 -#define KVM_DEV_LOONGARCH_PCH_PIC_GRP_CTRL 0x40000004 -#define KVM_DEV_LOONGARCH_PCH_PIC_CTRL_INIT 0 - -#define KVM_DEV_LOONGARCH_PCH_PIC_GRP_REGS 0x40000005 +#define KVM_DEV_LOONGARCH_EXTIOI_GRP_SW_STATUS 0x40000006 +#define KVM_DEV_LOONGARCH_EXTIOI_SW_STATUS_NUM_CPU 0x0 +#define KVM_DEV_LOONGARCH_EXTIOI_SW_STATUS_FEATURE 0x1 +#define KVM_DEV_LOONGARCH_EXTIOI_SW_STATUS_STATE 0x2 -#define KVM_LOONGARCH_VM_HAVE_IRQCHIP 0x40000001 - -#define KVM_DEV_LOONGARCH_IPI_GRP_REGS 0x40000002 +#define KVM_DEV_LOONGARCH_EXTIOI_GRP_CTRL 0x40000007 +#define KVM_DEV_LOONGARCH_EXTIOI_CTRL_INIT_NUM_CPU 0x0 +#define KVM_DEV_LOONGARCH_EXTIOI_CTRL_INIT_FEATURE 0x1 +#define KVM_DEV_LOONGARCH_EXTIOI_CTRL_LOAD_FINISHED 0x3 -#define KVM_DEV_LOONGARCH_EXTIOI_GRP_REGS 0x40000003 #define KVM_DEV_LOONGARCH_PCH_PIC_GRP_CTRL 0x40000004 #define KVM_DEV_LOONGARCH_PCH_PIC_CTRL_INIT 0 diff --git a/target/loongarch/cpu.c b/target/loongarch/cpu.c index bfc7df3044c964bffaa1fa4f4ae0f6b37a185231..626d891dd5e6225d35f42ab3e0e3f8e94915938a 100644 --- a/target/loongarch/cpu.c +++ b/target/loongarch/cpu.c @@ -563,7 +563,7 @@ static void loongarch_cpu_reset_hold(Object *obj) env->CSR_ECFG = FIELD_DP64(env->CSR_ECFG, CSR_ECFG, VS, 0); env->CSR_ECFG = FIELD_DP64(env->CSR_ECFG, CSR_ECFG, LIE, 0); - env->CSR_ESTAT = env->CSR_ESTAT & (~MAKE_64BIT_MASK(0, 2)); + env->CSR_ESTAT = 0; env->CSR_RVACFG = FIELD_DP64(env->CSR_RVACFG, CSR_RVACFG, RBITS, 0); env->CSR_CPUID = cs->cpu_index; env->CSR_TCFG = FIELD_DP64(env->CSR_TCFG, CSR_TCFG, EN, 0); @@ -628,8 +628,8 @@ static void loongarch_cpu_realizefn(DeviceState *dev, Error **errp) loongarch_cpu_register_gdb_regs_for_features(cs); - cpu_reset(cs); qemu_init_vcpu(cs); + cpu_reset(cs); lacc->parent_realize(dev, errp); } diff --git a/target/loongarch/cpu.h b/target/loongarch/cpu.h index 9afa831e4529a9327c716052a5b3c37e0293764e..8f7c02cfed2857f0fac84d191fa13a6531d7dd60 100644 --- a/target/loongarch/cpu.h +++ b/target/loongarch/cpu.h @@ -422,6 +422,7 @@ struct ArchCPU { const char *dtb_compatible; /* used by KVM_REG_LOONGARCH_COUNTER ioctl to access guest time counters */ uint64_t kvm_state_counter; + VMChangeStateEntry *vmsentry; }; /** diff --git a/target/loongarch/kvm/kvm.c b/target/loongarch/kvm/kvm.c index 719d6c29892d7e1ec6affb1c6c66d7f31e9aa036..22177b6220cc86c3ec43a7babd6a5f917afc411b 100644 --- a/target/loongarch/kvm/kvm.c +++ b/target/loongarch/kvm/kvm.c @@ -590,9 +590,16 @@ static int kvm_loongarch_get_lbt(CPUState *cs) void kvm_arch_reset_vcpu(CPUState *cs) { CPULoongArchState *env = cpu_env(cs); + int ret = 0; + uint64_t unused = 0; env->mp_state = KVM_MP_STATE_RUNNABLE; - kvm_set_one_reg(cs, KVM_REG_LOONGARCH_VCPU_RESET, 0); + ret = kvm_set_one_reg(cs, KVM_REG_LOONGARCH_VCPU_RESET, &unused); + if (ret) { + error_report("Failed to set KVM_REG_LOONGARCH_VCPU_RESET: %s", + strerror(errno)); + exit(EXIT_FAILURE); + } } static int kvm_loongarch_get_mpstate(CPUState *cs) @@ -898,9 +905,10 @@ int kvm_arch_init_vcpu(CPUState *cs) uint64_t val; int ret; Error *local_err = NULL; + LoongArchCPU *cpu = LOONGARCH_CPU(cs); ret = 0; - qemu_add_vm_change_state_handler(kvm_loongarch_vm_stage_change, cs); + cpu->vmsentry = qemu_add_vm_change_state_handler(kvm_loongarch_vm_stage_change, cs); if (!kvm_get_one_reg(cs, KVM_REG_LOONGARCH_DEBUG_INST, &val)) { brk_insn = val; @@ -921,6 +929,8 @@ int kvm_arch_init_vcpu(CPUState *cs) int kvm_arch_destroy_vcpu(CPUState *cs) { + LoongArchCPU *cpu = LOONGARCH_CPU(cs); + qemu_del_vm_change_state_handler(cpu->vmsentry); return 0; }