diff options
author | Stefan Hajnoczi <stefanha@redhat.com> | 2025-01-09 08:34:01 -0500 |
---|---|---|
committer | Stefan Hajnoczi <stefanha@redhat.com> | 2025-01-09 08:34:01 -0500 |
commit | c10ed2fac295d77370c4c81091af5deb3859e35d (patch) | |
tree | 1852464e74e5d245124598f4237dd88b97dc768f | |
parent | 3f8bcbba3b320c610689576fc47595f1076198dd (diff) | |
parent | c3afa714bcea4c8b014fec99881bd0bdbe8262b8 (diff) | |
download | qemu-c10ed2fac295d77370c4c81091af5deb3859e35d.zip qemu-c10ed2fac295d77370c4c81091af5deb3859e35d.tar.gz qemu-c10ed2fac295d77370c4c81091af5deb3859e35d.tar.bz2 |
Merge tag 'pull-loongarch-20250109' of https://gitlab.com/bibo-mao/qemu into staging
loongarch queue
# -----BEGIN PGP SIGNATURE-----
#
# iHUEABYKAB0WIQQNhkKjomWfgLCz0aQfewwSUazn0QUCZ39pJgAKCRAfewwSUazn
# 0YpMAQCNV9KJJ8f8EaXAw5a87mnmlcP0vRi5gZiyv1ZV9gRqPgEAhzCn/rnzpzd+
# H3B1fRlD1xmaQ8IqRugQ4vfDBd9CyQY=
# =OG4d
# -----END PGP SIGNATURE-----
# gpg: Signature made Thu 09 Jan 2025 01:13:58 EST
# gpg: using EDDSA key 0D8642A3A2659F80B0B3D1A41F7B0C1251ACE7D1
# gpg: Good signature from "bibo mao <maobibo@loongson.cn>" [unknown]
# gpg: WARNING: This key is not certified with a trusted signature!
# gpg: There is no indication that the signature belongs to the owner.
# Primary key fingerprint: 7044 3A00 19C0 E97A 31C7 13C4 8E86 8FB7 A176 9D4C
# Subkey fingerprint: 0D86 42A3 A265 9F80 B0B3 D1A4 1F7B 0C12 51AC E7D1
* tag 'pull-loongarch-20250109' of https://gitlab.com/bibo-mao/qemu:
hw/intc/loongarch_extioi: Add irq routing support from physical id
hw/intc/loongarch_extioi: Remove num-cpu property
hw/intc/loongarch_extioi: Get cpu number from possible_cpu_arch_ids
target/loongarch: Only support 64bit pte width
hw/loongarch/boot: Support Linux raw boot image
hw/core/loader: Use ssize_t for efi zboot unpacker
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
-rw-r--r-- | hw/arm/boot.c | 2 | ||||
-rw-r--r-- | hw/core/loader.c | 4 | ||||
-rw-r--r-- | hw/intc/loongarch_extioi.c | 36 | ||||
-rw-r--r-- | hw/intc/loongarch_extioi_common.c | 18 | ||||
-rw-r--r-- | hw/loongarch/boot.c | 69 | ||||
-rw-r--r-- | hw/loongarch/virt.c | 1 | ||||
-rw-r--r-- | include/hw/intc/loongarch_extioi_common.h | 2 | ||||
-rw-r--r-- | include/hw/loader.h | 2 | ||||
-rw-r--r-- | target/loongarch/helper.h | 1 | ||||
-rw-r--r-- | target/loongarch/tcg/csr_helper.c | 21 | ||||
-rw-r--r-- | target/loongarch/tcg/insn_trans/trans_privileged.c.inc | 2 | ||||
-rw-r--r-- | target/loongarch/tcg/tlb_helper.c | 17 |
12 files changed, 142 insertions, 33 deletions
diff --git a/hw/arm/boot.c b/hw/arm/boot.c index 68fe865..b44bea8 100644 --- a/hw/arm/boot.c +++ b/hw/arm/boot.c @@ -857,7 +857,7 @@ static uint64_t load_aarch64_image(const char *filename, hwaddr mem_base, hwaddr kernel_load_offset = KERNEL64_LOAD_ADDR; uint64_t kernel_size = 0; uint8_t *buffer; - int size; + ssize_t size; /* On aarch64, it's the bootloader's job to uncompress the kernel. */ size = load_image_gzipped_buffer(filename, LOAD_IMAGE_MAX_GUNZIP_BYTES, diff --git a/hw/core/loader.c b/hw/core/loader.c index c0407e2..4dfdb02 100644 --- a/hw/core/loader.c +++ b/hw/core/loader.c @@ -886,11 +886,11 @@ struct linux_efi_zboot_header { * * If the image is not a Linux EFI zboot image, do nothing and return success. */ -ssize_t unpack_efi_zboot_image(uint8_t **buffer, int *size) +ssize_t unpack_efi_zboot_image(uint8_t **buffer, ssize_t *size) { const struct linux_efi_zboot_header *header; uint8_t *data = NULL; - int ploff, plsize; + ssize_t ploff, plsize; ssize_t bytes; /* ignore if this is too small to be a EFI zboot image */ diff --git a/hw/intc/loongarch_extioi.c b/hw/intc/loongarch_extioi.c index 4a1a7c3..f3055ec 100644 --- a/hw/intc/loongarch_extioi.c +++ b/hw/intc/loongarch_extioi.c @@ -15,6 +15,23 @@ #include "hw/intc/loongarch_extioi.h" #include "trace.h" +static int extioi_get_index_from_archid(LoongArchExtIOICommonState *s, + uint64_t arch_id) +{ + int i; + + for (i = 0; i < s->num_cpu; i++) { + if (s->cpu[i].arch_id == arch_id) { + break; + } + } + + if ((i < s->num_cpu) && s->cpu[i].cpu) { + return i; + } + + return -1; +} static void extioi_update_irq(LoongArchExtIOICommonState *s, int irq, int level) { @@ -125,7 +142,7 @@ static inline void extioi_enable_irq(LoongArchExtIOICommonState *s, int index,\ static inline void extioi_update_sw_coremap(LoongArchExtIOICommonState *s, int irq, uint64_t val, bool notify) { - int i, cpu; + int i, cpu, cpuid; /* * loongarch only support little endian, @@ -134,12 +151,17 @@ static inline void extioi_update_sw_coremap(LoongArchExtIOICommonState *s, val = cpu_to_le64(val); for (i = 0; i < 4; i++) { - cpu = val & 0xff; + cpuid = val & 0xff; val = val >> 8; if (!(s->status & BIT(EXTIOI_ENABLE_CPU_ENCODE))) { - cpu = ctz32(cpu); - cpu = (cpu >= 4) ? 0 : cpu; + cpuid = ctz32(cpuid); + cpuid = (cpuid >= 4) ? 0 : cpuid; + } + + cpu = extioi_get_index_from_archid(s, cpuid); + if (cpu < 0) { + continue; } if (s->sw_coremap[irq + i] == cpu) { @@ -347,12 +369,6 @@ static void loongarch_extioi_realize(DeviceState *dev, Error **errp) s->status |= BIT(EXTIOI_ENABLE); } - s->cpu = g_new0(ExtIOICore, s->num_cpu); - if (s->cpu == NULL) { - error_setg(errp, "Memory allocation for ExtIOICore faile"); - return; - } - for (i = 0; i < s->num_cpu; i++) { for (pin = 0; pin < LS3A_INTC_IP; pin++) { qdev_init_gpio_out(dev, &s->cpu[i].parent_irq[pin], 1); diff --git a/hw/intc/loongarch_extioi_common.c b/hw/intc/loongarch_extioi_common.c index e4c1cc3..fd56253 100644 --- a/hw/intc/loongarch_extioi_common.c +++ b/hw/intc/loongarch_extioi_common.c @@ -13,11 +13,24 @@ static void loongarch_extioi_common_realize(DeviceState *dev, Error **errp) { LoongArchExtIOICommonState *s = (LoongArchExtIOICommonState *)dev; + MachineState *machine = MACHINE(qdev_get_machine()); + MachineClass *mc = MACHINE_GET_CLASS(machine); + const CPUArchIdList *id_list; + int i; - if (s->num_cpu == 0) { - error_setg(errp, "num-cpu must be at least 1"); + assert(mc->possible_cpu_arch_ids); + id_list = mc->possible_cpu_arch_ids(machine); + s->num_cpu = id_list->len; + s->cpu = g_new0(ExtIOICore, s->num_cpu); + if (s->cpu == NULL) { + error_setg(errp, "Memory allocation for ExtIOICore faile"); return; } + + for (i = 0; i < s->num_cpu; i++) { + s->cpu[i].arch_id = id_list->cpus[i].arch_id; + s->cpu[i].cpu = CPU(id_list->cpus[i].cpu); + } } static int loongarch_extioi_common_pre_save(void *opaque) @@ -82,7 +95,6 @@ static const VMStateDescription vmstate_loongarch_extioi = { }; static const Property extioi_properties[] = { - DEFINE_PROP_UINT32("num-cpu", LoongArchExtIOICommonState, num_cpu, 1), DEFINE_PROP_BIT("has-virtualization-extension", LoongArchExtIOICommonState, features, EXTIOI_HAS_VIRT_EXTENSION, 0), }; diff --git a/hw/loongarch/boot.c b/hw/loongarch/boot.c index 48154cd..241c0ee 100644 --- a/hw/loongarch/boot.c +++ b/hw/loongarch/boot.c @@ -15,6 +15,26 @@ #include "system/reset.h" #include "system/qtest.h" +/* + * Linux Image Format + * https://docs.kernel.org/arch/loongarch/booting.html + */ +#define LINUX_PE_MAGIC 0x818223cd +#define MZ_MAGIC 0x5a4d /* "MZ" */ + +struct loongarch_linux_hdr { + uint32_t mz_magic; + uint32_t res0; + uint64_t kernel_entry; + uint64_t kernel_size; + uint64_t load_offset; + uint64_t res1; + uint64_t res2; + uint64_t res3; + uint32_t linux_pe_magic; + uint32_t pe_header_offset; +} QEMU_PACKED; + struct memmap_entry *memmap_table; unsigned memmap_entries; @@ -171,6 +191,50 @@ 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 int64_t load_loongarch_linux_image(const char *filename, + uint64_t *kernel_entry, + uint64_t *kernel_low, + uint64_t *kernel_high) +{ + gsize len; + ssize_t size; + uint8_t *buffer; + struct loongarch_linux_hdr *hdr; + + /* Load as raw file otherwise */ + if (!g_file_get_contents(filename, (char **)&buffer, &len, NULL)) { + return -1; + } + size = len; + + /* Unpack the image if it is a EFI zboot image */ + if (unpack_efi_zboot_image(&buffer, &size) < 0) { + g_free(buffer); + return -1; + } + + hdr = (struct loongarch_linux_hdr *)buffer; + + if (extract32(le32_to_cpu(hdr->mz_magic), 0, 16) != MZ_MAGIC || + le32_to_cpu(hdr->linux_pe_magic) != LINUX_PE_MAGIC) { + g_free(buffer); + return -1; + } + + /* Early kernel versions may have those fields in virtual address */ + *kernel_entry = extract64(le64_to_cpu(hdr->kernel_entry), + 0, TARGET_PHYS_ADDR_SPACE_BITS); + *kernel_low = extract64(le64_to_cpu(hdr->load_offset), + 0, TARGET_PHYS_ADDR_SPACE_BITS); + *kernel_high = *kernel_low + size; + + rom_add_blob_fixed(filename, buffer, size, *kernel_low); + + g_free(buffer); + + return size; +} + static int64_t load_kernel_info(struct loongarch_boot_info *info) { uint64_t kernel_entry, kernel_low, kernel_high; @@ -181,6 +245,11 @@ static int64_t load_kernel_info(struct loongarch_boot_info *info) &kernel_entry, &kernel_low, &kernel_high, NULL, 0, EM_LOONGARCH, 1, 0); + if (kernel_size < 0) { + kernel_size = load_loongarch_linux_image(info->kernel_filename, + &kernel_entry, &kernel_low, + &kernel_high); + } if (kernel_size < 0) { error_report("could not load kernel '%s': %s", diff --git a/hw/loongarch/virt.c b/hw/loongarch/virt.c index 60bd4dc..df56d75 100644 --- a/hw/loongarch/virt.c +++ b/hw/loongarch/virt.c @@ -921,7 +921,6 @@ static void virt_irq_init(LoongArchVirtMachineState *lvms) /* Create EXTIOI device */ extioi = qdev_new(TYPE_LOONGARCH_EXTIOI); - qdev_prop_set_uint32(extioi, "num-cpu", ms->smp.cpus); if (virt_is_veiointc_enabled(lvms)) { qdev_prop_set_bit(extioi, "has-virtualization-extension", true); } diff --git a/include/hw/intc/loongarch_extioi_common.h b/include/hw/intc/loongarch_extioi_common.h index f6bc778..22d7880 100644 --- a/include/hw/intc/loongarch_extioi_common.h +++ b/include/hw/intc/loongarch_extioi_common.h @@ -65,6 +65,8 @@ typedef struct ExtIOICore { uint32_t coreisr[EXTIOI_IRQS_GROUP_COUNT]; DECLARE_BITMAP(sw_isr[LS3A_INTC_IP], EXTIOI_IRQS); qemu_irq parent_irq[LS3A_INTC_IP]; + uint64_t arch_id; + CPUState *cpu; } ExtIOICore; struct LoongArchExtIOICommonState { diff --git a/include/hw/loader.h b/include/hw/loader.h index 7f6d06b..8985046 100644 --- a/include/hw/loader.h +++ b/include/hw/loader.h @@ -101,7 +101,7 @@ ssize_t load_image_gzipped_buffer(const char *filename, uint64_t max_sz, * Returns the size of the decompressed payload if decompression was performed * successfully. */ -ssize_t unpack_efi_zboot_image(uint8_t **buffer, int *size); +ssize_t unpack_efi_zboot_image(uint8_t **buffer, ssize_t *size); #define ELF_LOAD_FAILED -1 #define ELF_LOAD_NOT_ELF -2 diff --git a/target/loongarch/helper.h b/target/loongarch/helper.h index b3b64a0..943517b 100644 --- a/target/loongarch/helper.h +++ b/target/loongarch/helper.h @@ -104,6 +104,7 @@ DEF_HELPER_2(csrwr_estat, i64, env, tl) DEF_HELPER_2(csrwr_asid, i64, env, tl) DEF_HELPER_2(csrwr_tcfg, i64, env, tl) DEF_HELPER_2(csrwr_ticlr, i64, env, tl) +DEF_HELPER_2(csrwr_pwcl, i64, env, tl) DEF_HELPER_2(iocsrrd_b, i64, env, tl) DEF_HELPER_2(iocsrrd_h, i64, env, tl) DEF_HELPER_2(iocsrrd_w, i64, env, tl) diff --git a/target/loongarch/tcg/csr_helper.c b/target/loongarch/tcg/csr_helper.c index 15f94ca..6c95be9 100644 --- a/target/loongarch/tcg/csr_helper.c +++ b/target/loongarch/tcg/csr_helper.c @@ -6,6 +6,7 @@ */ #include "qemu/osdep.h" +#include "qemu/log.h" #include "qemu/main-loop.h" #include "cpu.h" #include "internals.h" @@ -95,3 +96,23 @@ target_ulong helper_csrwr_ticlr(CPULoongArchState *env, target_ulong val) } return old_v; } + +target_ulong helper_csrwr_pwcl(CPULoongArchState *env, target_ulong val) +{ + int shift; + int64_t old_v = env->CSR_PWCL; + + /* + * The real hardware only supports 64bit PTE width now, 128bit or others + * treated as illegal. + */ + shift = FIELD_EX64(val, CSR_PWCL, PTEWIDTH); + if (shift) { + qemu_log_mask(LOG_GUEST_ERROR, + "Attempted set pte width with %d bit\n", 64 << shift); + val = FIELD_DP64(val, CSR_PWCL, PTEWIDTH, 0); + } + + env->CSR_PWCL = val; + return old_v; +} diff --git a/target/loongarch/tcg/insn_trans/trans_privileged.c.inc b/target/loongarch/tcg/insn_trans/trans_privileged.c.inc index 7e4ec93..30f9b83 100644 --- a/target/loongarch/tcg/insn_trans/trans_privileged.c.inc +++ b/target/loongarch/tcg/insn_trans/trans_privileged.c.inc @@ -95,7 +95,7 @@ static const CSRInfo csr_info[] = { CSR_OFF(PGDL), CSR_OFF(PGDH), CSR_OFF_FUNCS(PGD, CSRFL_READONLY, gen_helper_csrrd_pgd, NULL), - CSR_OFF(PWCL), + CSR_OFF_FUNCS(PWCL, 0, NULL, gen_helper_csrwr_pwcl), CSR_OFF(PWCH), CSR_OFF(STLBPS), CSR_OFF(RVACFG), diff --git a/target/loongarch/tcg/tlb_helper.c b/target/loongarch/tcg/tlb_helper.c index 97f38fc..8c61fe7 100644 --- a/target/loongarch/tcg/tlb_helper.c +++ b/target/loongarch/tcg/tlb_helper.c @@ -512,7 +512,6 @@ target_ulong helper_lddir(CPULoongArchState *env, target_ulong base, { CPUState *cs = env_cpu(env); target_ulong badvaddr, index, phys, ret; - int shift; uint64_t dir_base, dir_width; if (unlikely((level == 0) || (level > 4))) { @@ -537,14 +536,9 @@ target_ulong helper_lddir(CPULoongArchState *env, target_ulong base, badvaddr = env->CSR_TLBRBADV; base = base & TARGET_PHYS_MASK; - - /* 0:64bit, 1:128bit, 2:192bit, 3:256bit */ - shift = FIELD_EX64(env->CSR_PWCL, CSR_PWCL, PTEWIDTH); - shift = (shift + 1) * 3; - get_dir_base_width(env, &dir_base, &dir_width, level); index = (badvaddr >> dir_base) & ((1 << dir_width) - 1); - phys = base | index << shift; + phys = base | index << 3; ret = ldq_phys(cs->as, phys) & TARGET_PHYS_MASK; return ret; } @@ -554,7 +548,6 @@ void helper_ldpte(CPULoongArchState *env, target_ulong base, target_ulong odd, { CPUState *cs = env_cpu(env); target_ulong phys, tmp0, ptindex, ptoffset0, ptoffset1, ps, badv; - int shift; uint64_t ptbase = FIELD_EX64(env->CSR_PWCL, CSR_PWCL, PTBASE); uint64_t ptwidth = FIELD_EX64(env->CSR_PWCL, CSR_PWCL, PTWIDTH); uint64_t dir_base, dir_width; @@ -595,16 +588,12 @@ void helper_ldpte(CPULoongArchState *env, target_ulong base, target_ulong odd, tmp0 += MAKE_64BIT_MASK(ps, 1); } } else { - /* 0:64bit, 1:128bit, 2:192bit, 3:256bit */ - shift = FIELD_EX64(env->CSR_PWCL, CSR_PWCL, PTEWIDTH); - shift = (shift + 1) * 3; badv = env->CSR_TLBRBADV; ptindex = (badv >> ptbase) & ((1 << ptwidth) - 1); ptindex = ptindex & ~0x1; /* clear bit 0 */ - ptoffset0 = ptindex << shift; - ptoffset1 = (ptindex + 1) << shift; - + ptoffset0 = ptindex << 3; + ptoffset1 = (ptindex + 1) << 3; phys = base | (odd ? ptoffset1 : ptoffset0); tmp0 = ldq_phys(cs->as, phys) & TARGET_PHYS_MASK; ps = ptbase; |