loongarch queue

-----BEGIN PGP SIGNATURE-----
 
 iHUEABYKAB0WIQQNhkKjomWfgLCz0aQfewwSUazn0QUCZ39pJgAKCRAfewwSUazn
 0YpMAQCNV9KJJ8f8EaXAw5a87mnmlcP0vRi5gZiyv1ZV9gRqPgEAhzCn/rnzpzd+
 H3B1fRlD1xmaQ8IqRugQ4vfDBd9CyQY=
 =OG4d
 -----END PGP SIGNATURE-----

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>
This commit is contained in:
Stefan Hajnoczi 2025-01-09 08:34:01 -05:00
commit c10ed2fac2
12 changed files with 142 additions and 33 deletions

View File

@ -857,7 +857,7 @@ static uint64_t load_aarch64_image(const char *filename, hwaddr mem_base,
hwaddr kernel_load_offset = KERNEL64_LOAD_ADDR; hwaddr kernel_load_offset = KERNEL64_LOAD_ADDR;
uint64_t kernel_size = 0; uint64_t kernel_size = 0;
uint8_t *buffer; uint8_t *buffer;
int size; ssize_t size;
/* On aarch64, it's the bootloader's job to uncompress the kernel. */ /* On aarch64, it's the bootloader's job to uncompress the kernel. */
size = load_image_gzipped_buffer(filename, LOAD_IMAGE_MAX_GUNZIP_BYTES, size = load_image_gzipped_buffer(filename, LOAD_IMAGE_MAX_GUNZIP_BYTES,

View File

@ -886,11 +886,11 @@ struct linux_efi_zboot_header {
* *
* If the image is not a Linux EFI zboot image, do nothing and return success. * 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; const struct linux_efi_zboot_header *header;
uint8_t *data = NULL; uint8_t *data = NULL;
int ploff, plsize; ssize_t ploff, plsize;
ssize_t bytes; ssize_t bytes;
/* ignore if this is too small to be a EFI zboot image */ /* ignore if this is too small to be a EFI zboot image */

View File

@ -15,6 +15,23 @@
#include "hw/intc/loongarch_extioi.h" #include "hw/intc/loongarch_extioi.h"
#include "trace.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) 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, static inline void extioi_update_sw_coremap(LoongArchExtIOICommonState *s,
int irq, uint64_t val, bool notify) int irq, uint64_t val, bool notify)
{ {
int i, cpu; int i, cpu, cpuid;
/* /*
* loongarch only support little endian, * loongarch only support little endian,
@ -134,12 +151,17 @@ static inline void extioi_update_sw_coremap(LoongArchExtIOICommonState *s,
val = cpu_to_le64(val); val = cpu_to_le64(val);
for (i = 0; i < 4; i++) { for (i = 0; i < 4; i++) {
cpu = val & 0xff; cpuid = val & 0xff;
val = val >> 8; val = val >> 8;
if (!(s->status & BIT(EXTIOI_ENABLE_CPU_ENCODE))) { if (!(s->status & BIT(EXTIOI_ENABLE_CPU_ENCODE))) {
cpu = ctz32(cpu); cpuid = ctz32(cpuid);
cpu = (cpu >= 4) ? 0 : cpu; cpuid = (cpuid >= 4) ? 0 : cpuid;
}
cpu = extioi_get_index_from_archid(s, cpuid);
if (cpu < 0) {
continue;
} }
if (s->sw_coremap[irq + i] == cpu) { 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->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 (i = 0; i < s->num_cpu; i++) {
for (pin = 0; pin < LS3A_INTC_IP; pin++) { for (pin = 0; pin < LS3A_INTC_IP; pin++) {
qdev_init_gpio_out(dev, &s->cpu[i].parent_irq[pin], 1); qdev_init_gpio_out(dev, &s->cpu[i].parent_irq[pin], 1);

View File

@ -13,11 +13,24 @@
static void loongarch_extioi_common_realize(DeviceState *dev, Error **errp) static void loongarch_extioi_common_realize(DeviceState *dev, Error **errp)
{ {
LoongArchExtIOICommonState *s = (LoongArchExtIOICommonState *)dev; 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) { assert(mc->possible_cpu_arch_ids);
error_setg(errp, "num-cpu must be at least 1"); 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; 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) static int loongarch_extioi_common_pre_save(void *opaque)
@ -82,7 +95,6 @@ static const VMStateDescription vmstate_loongarch_extioi = {
}; };
static const Property extioi_properties[] = { static const Property extioi_properties[] = {
DEFINE_PROP_UINT32("num-cpu", LoongArchExtIOICommonState, num_cpu, 1),
DEFINE_PROP_BIT("has-virtualization-extension", LoongArchExtIOICommonState, DEFINE_PROP_BIT("has-virtualization-extension", LoongArchExtIOICommonState,
features, EXTIOI_HAS_VIRT_EXTENSION, 0), features, EXTIOI_HAS_VIRT_EXTENSION, 0),
}; };

View File

@ -15,6 +15,26 @@
#include "system/reset.h" #include "system/reset.h"
#include "system/qtest.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; struct memmap_entry *memmap_table;
unsigned memmap_entries; 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); 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) static int64_t load_kernel_info(struct loongarch_boot_info *info)
{ {
uint64_t kernel_entry, kernel_low, kernel_high; 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_entry, &kernel_low,
&kernel_high, NULL, 0, &kernel_high, NULL, 0,
EM_LOONGARCH, 1, 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) { if (kernel_size < 0) {
error_report("could not load kernel '%s': %s", error_report("could not load kernel '%s': %s",

View File

@ -921,7 +921,6 @@ static void virt_irq_init(LoongArchVirtMachineState *lvms)
/* Create EXTIOI device */ /* Create EXTIOI device */
extioi = qdev_new(TYPE_LOONGARCH_EXTIOI); extioi = qdev_new(TYPE_LOONGARCH_EXTIOI);
qdev_prop_set_uint32(extioi, "num-cpu", ms->smp.cpus);
if (virt_is_veiointc_enabled(lvms)) { if (virt_is_veiointc_enabled(lvms)) {
qdev_prop_set_bit(extioi, "has-virtualization-extension", true); qdev_prop_set_bit(extioi, "has-virtualization-extension", true);
} }

View File

@ -65,6 +65,8 @@ typedef struct ExtIOICore {
uint32_t coreisr[EXTIOI_IRQS_GROUP_COUNT]; uint32_t coreisr[EXTIOI_IRQS_GROUP_COUNT];
DECLARE_BITMAP(sw_isr[LS3A_INTC_IP], EXTIOI_IRQS); DECLARE_BITMAP(sw_isr[LS3A_INTC_IP], EXTIOI_IRQS);
qemu_irq parent_irq[LS3A_INTC_IP]; qemu_irq parent_irq[LS3A_INTC_IP];
uint64_t arch_id;
CPUState *cpu;
} ExtIOICore; } ExtIOICore;
struct LoongArchExtIOICommonState { struct LoongArchExtIOICommonState {

View File

@ -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 * Returns the size of the decompressed payload if decompression was performed
* successfully. * 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_FAILED -1
#define ELF_LOAD_NOT_ELF -2 #define ELF_LOAD_NOT_ELF -2

View File

@ -104,6 +104,7 @@ DEF_HELPER_2(csrwr_estat, i64, env, tl)
DEF_HELPER_2(csrwr_asid, i64, env, tl) DEF_HELPER_2(csrwr_asid, i64, env, tl)
DEF_HELPER_2(csrwr_tcfg, i64, env, tl) DEF_HELPER_2(csrwr_tcfg, i64, env, tl)
DEF_HELPER_2(csrwr_ticlr, 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_b, i64, env, tl)
DEF_HELPER_2(iocsrrd_h, i64, env, tl) DEF_HELPER_2(iocsrrd_h, i64, env, tl)
DEF_HELPER_2(iocsrrd_w, i64, env, tl) DEF_HELPER_2(iocsrrd_w, i64, env, tl)

View File

@ -6,6 +6,7 @@
*/ */
#include "qemu/osdep.h" #include "qemu/osdep.h"
#include "qemu/log.h"
#include "qemu/main-loop.h" #include "qemu/main-loop.h"
#include "cpu.h" #include "cpu.h"
#include "internals.h" #include "internals.h"
@ -95,3 +96,23 @@ target_ulong helper_csrwr_ticlr(CPULoongArchState *env, target_ulong val)
} }
return old_v; 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;
}

View File

@ -95,7 +95,7 @@ static const CSRInfo csr_info[] = {
CSR_OFF(PGDL), CSR_OFF(PGDL),
CSR_OFF(PGDH), CSR_OFF(PGDH),
CSR_OFF_FUNCS(PGD, CSRFL_READONLY, gen_helper_csrrd_pgd, NULL), 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(PWCH),
CSR_OFF(STLBPS), CSR_OFF(STLBPS),
CSR_OFF(RVACFG), CSR_OFF(RVACFG),

View File

@ -512,7 +512,6 @@ target_ulong helper_lddir(CPULoongArchState *env, target_ulong base,
{ {
CPUState *cs = env_cpu(env); CPUState *cs = env_cpu(env);
target_ulong badvaddr, index, phys, ret; target_ulong badvaddr, index, phys, ret;
int shift;
uint64_t dir_base, dir_width; uint64_t dir_base, dir_width;
if (unlikely((level == 0) || (level > 4))) { if (unlikely((level == 0) || (level > 4))) {
@ -537,14 +536,9 @@ target_ulong helper_lddir(CPULoongArchState *env, target_ulong base,
badvaddr = env->CSR_TLBRBADV; badvaddr = env->CSR_TLBRBADV;
base = base & TARGET_PHYS_MASK; 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); get_dir_base_width(env, &dir_base, &dir_width, level);
index = (badvaddr >> dir_base) & ((1 << dir_width) - 1); 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; ret = ldq_phys(cs->as, phys) & TARGET_PHYS_MASK;
return ret; return ret;
} }
@ -554,7 +548,6 @@ void helper_ldpte(CPULoongArchState *env, target_ulong base, target_ulong odd,
{ {
CPUState *cs = env_cpu(env); CPUState *cs = env_cpu(env);
target_ulong phys, tmp0, ptindex, ptoffset0, ptoffset1, ps, badv; target_ulong phys, tmp0, ptindex, ptoffset0, ptoffset1, ps, badv;
int shift;
uint64_t ptbase = FIELD_EX64(env->CSR_PWCL, CSR_PWCL, PTBASE); uint64_t ptbase = FIELD_EX64(env->CSR_PWCL, CSR_PWCL, PTBASE);
uint64_t ptwidth = FIELD_EX64(env->CSR_PWCL, CSR_PWCL, PTWIDTH); uint64_t ptwidth = FIELD_EX64(env->CSR_PWCL, CSR_PWCL, PTWIDTH);
uint64_t dir_base, dir_width; 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); tmp0 += MAKE_64BIT_MASK(ps, 1);
} }
} else { } 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; badv = env->CSR_TLBRBADV;
ptindex = (badv >> ptbase) & ((1 << ptwidth) - 1); ptindex = (badv >> ptbase) & ((1 << ptwidth) - 1);
ptindex = ptindex & ~0x1; /* clear bit 0 */ ptindex = ptindex & ~0x1; /* clear bit 0 */
ptoffset0 = ptindex << shift; ptoffset0 = ptindex << 3;
ptoffset1 = (ptindex + 1) << shift; ptoffset1 = (ptindex + 1) << 3;
phys = base | (odd ? ptoffset1 : ptoffset0); phys = base | (odd ? ptoffset1 : ptoffset0);
tmp0 = ldq_phys(cs->as, phys) & TARGET_PHYS_MASK; tmp0 = ldq_phys(cs->as, phys) & TARGET_PHYS_MASK;
ps = ptbase; ps = ptbase;