diff options
author | Richard Henderson <richard.henderson@linaro.org> | 2022-07-04 16:37:13 +0530 |
---|---|---|
committer | Richard Henderson <richard.henderson@linaro.org> | 2022-07-04 16:37:13 +0530 |
commit | 1437479e5ee1a49ccd84cad9e7b010fb2ee9d805 (patch) | |
tree | 8ecd8a33779470649e7a3697d78d0b4d4f7ae810 | |
parent | dfe2382f0641f537fdd33399d579215077c8f68c (diff) | |
parent | eb1e9ff8bba91674b4321f2b075c55aa8d9948cc (diff) |
Merge tag 'pull-la-20220704' of https://gitlab.com/rth7680/qemu into staging
LoongArch patch queue:
Support linux-user.
Fixes for CSR BADV.
Fix ASRT{LE,GT} exception.
Fixes for LS7A RTC.
Fix for interrupt vector spacing.
# -----BEGIN PGP SIGNATURE-----
#
# iQFRBAABCgA7FiEEekgeeIaLTbaoWgXAZN846K9+IV8FAmLCs4gdHHJpY2hhcmQu
# aGVuZGVyc29uQGxpbmFyby5vcmcACgkQZN846K9+IV89IQgAsgGM117dgDlI48wP
# zRVRE9rmK9EE/YR8b4rejh5iFlH0kZTELWAaXmjxWSv9uyXwsApNdnxnthUH1CRD
# RbT8AOIUphH6MBMb2joy+zFyBkGBnJQbSxJWN0jDT/ie67I/O0qOIemXU9tETssn
# OLNCn+GuNFLiS8EytczkZHDmQjjt00PGZLsnCm+ZY+/ejNci0FV0NItBo6iWxDdj
# 8MPJU8pDkXyi+djJpExPc0hTxJ2qmH0FZtpjKwWnU8dbLSRD9IfYhFK5Tsh1oxYJ
# 9Er9ZS0RI2CqK3o2k7keYsJHMaIZbNZKhcoA3XiGs15T9YHe1Rc9FeYDasrQw4wQ
# 60FwkA==
# =i2CR
# -----END PGP SIGNATURE-----
# gpg: Signature made Mon 04 Jul 2022 03:01:52 PM +0530
# gpg: using RSA key 7A481E78868B4DB6A85A05C064DF38E8AF7E215F
# gpg: issuer "richard.henderson@linaro.org"
# gpg: Good signature from "Richard Henderson <richard.henderson@linaro.org>" [ultimate]
* tag 'pull-la-20220704' of https://gitlab.com/rth7680/qemu: (23 commits)
target/loongarch: Add lock when writing timer clear reg
target/loongarch: Fix the meaning of ECFG reg's VS field
hw/rtc/ls7a_rtc: Fix 'calculate' spelling errors
hw/rtc/ls7a_rtc: Use tm struct pointer as arguments in toy_time_to_val()
hw/rtc/ls7a_rtc: Fix rtc enable and disable function
hw/rtc/ls7a_rtc: Add reset function
hw/rtc/ls7a_rtc: Remove unimplemented device in realized function
hw/rtc/ls7a_rtc: Fix timer call back function
hw/rtc/ls7a_rtc: Fix uninitialied bugs and toymatch writing function
hw/intc/loongarch_pch_msi: Fix msi vector convertion
target/loongarch: Update README
default-configs: Add loongarch linux-user support
target/loongarch: Adjust functions and structure to support user-mode
target/loongarch: remove unused include hw/loader.h
target/loongarch: Fix helper_asrtle_d/asrtgt_d raise wrong exception
target/loongarch: Fix missing update CSR_BADV
target/loongarch: remove badaddr from CPULoongArch
scripts: add loongarch64 binfmt config
linux-user: Add LoongArch cpu_loop support
linux-user: Add LoongArch syscall support
...
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
32 files changed, 1226 insertions, 95 deletions
diff --git a/configs/targets/loongarch64-linux-user.mak b/configs/targets/loongarch64-linux-user.mak new file mode 100644 index 0000000000..7d1b964020 --- /dev/null +++ b/configs/targets/loongarch64-linux-user.mak @@ -0,0 +1,3 @@ +# Default configuration for loongarch64-linux-user +TARGET_ARCH=loongarch64 +TARGET_BASE_ARCH=loongarch diff --git a/hw/intc/loongarch_pch_msi.c b/hw/intc/loongarch_pch_msi.c index 74bcdbdb48..b36d6d76e4 100644 --- a/hw/intc/loongarch_pch_msi.c +++ b/hw/intc/loongarch_pch_msi.c @@ -23,9 +23,14 @@ static uint64_t loongarch_msi_mem_read(void *opaque, hwaddr addr, unsigned size) static void loongarch_msi_mem_write(void *opaque, hwaddr addr, uint64_t val, unsigned size) { - LoongArchPCHMSI *s = LOONGARCH_PCH_MSI(opaque); - int irq_num = val & 0xff; + LoongArchPCHMSI *s = (LoongArchPCHMSI *)opaque; + int irq_num; + /* + * vector number is irq number from upper extioi intc + * need subtract irq base to get msi vector offset + */ + irq_num = (val & 0xff) - s->irq_base; trace_loongarch_msi_set_irq(irq_num); assert(irq_num < PCH_MSI_IRQ_NUM); qemu_set_irq(s->pch_msi_irq[irq_num], 1); @@ -58,11 +63,24 @@ static void loongarch_pch_msi_init(Object *obj) qdev_init_gpio_in(DEVICE(obj), pch_msi_irq_handler, PCH_MSI_IRQ_NUM); } +static Property loongarch_msi_properties[] = { + DEFINE_PROP_UINT32("msi_irq_base", LoongArchPCHMSI, irq_base, 0), + DEFINE_PROP_END_OF_LIST(), +}; + +static void loongarch_pch_msi_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + + device_class_set_props(dc, loongarch_msi_properties); +} + static const TypeInfo loongarch_pch_msi_info = { .name = TYPE_LOONGARCH_PCH_MSI, .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(LoongArchPCHMSI), .instance_init = loongarch_pch_msi_init, + .class_init = loongarch_pch_msi_class_init, }; static void loongarch_pch_msi_register_types(void) diff --git a/hw/loongarch/loongson3.c b/hw/loongarch/loongson3.c index bd20ebbb78..403dd91e11 100644 --- a/hw/loongarch/loongson3.c +++ b/hw/loongarch/loongson3.c @@ -267,6 +267,7 @@ static void loongarch_irq_init(LoongArchMachineState *lams) } pch_msi = qdev_new(TYPE_LOONGARCH_PCH_MSI); + qdev_prop_set_uint32(pch_msi, "msi_irq_base", PCH_MSI_IRQ_START); d = SYS_BUS_DEVICE(pch_msi); sysbus_realize_and_unref(d, &error_fatal); sysbus_mmio_map(d, 0, LS7A_PCH_MSI_ADDR_LOW); diff --git a/hw/rtc/ls7a_rtc.c b/hw/rtc/ls7a_rtc.c index fe6710310f..e8b75701e4 100644 --- a/hw/rtc/ls7a_rtc.c +++ b/hw/rtc/ls7a_rtc.c @@ -72,9 +72,6 @@ struct LS7ARtcState { */ int64_t offset_toy; int64_t offset_rtc; - uint64_t save_toy_mon; - uint64_t save_toy_year; - uint64_t save_rtc; int64_t data; int tidx; uint32_t toymatch[3]; @@ -128,28 +125,21 @@ static inline void toy_val_to_time_year(uint64_t toy_year, struct tm *tm) } /* parse struct tm to toy value */ -static inline uint64_t toy_time_to_val_mon(struct tm tm) +static inline uint64_t toy_time_to_val_mon(struct tm *tm) { uint64_t val = 0; - val = FIELD_DP32(val, TOY, MON, tm.tm_mon + 1); - val = FIELD_DP32(val, TOY, DAY, tm.tm_mday); - val = FIELD_DP32(val, TOY, HOUR, tm.tm_hour); - val = FIELD_DP32(val, TOY, MIN, tm.tm_min); - val = FIELD_DP32(val, TOY, SEC, tm.tm_sec); + val = FIELD_DP32(val, TOY, MON, tm->tm_mon + 1); + val = FIELD_DP32(val, TOY, DAY, tm->tm_mday); + val = FIELD_DP32(val, TOY, HOUR, tm->tm_hour); + val = FIELD_DP32(val, TOY, MIN, tm->tm_min); + val = FIELD_DP32(val, TOY, SEC, tm->tm_sec); return val; } -static inline uint64_t toy_time_to_val_year(struct tm tm) -{ - uint64_t year; - - year = tm.tm_year; - return year; -} - -static inline void toymatch_val_to_time(uint64_t val, struct tm *tm) +static inline void toymatch_val_to_time(LS7ARtcState *s, uint64_t val, struct tm *tm) { + qemu_get_timedate(tm, s->offset_toy); tm->tm_sec = FIELD_EX32(val, TOY_MATCH, SEC); tm->tm_min = FIELD_EX32(val, TOY_MATCH, MIN); tm->tm_hour = FIELD_EX32(val, TOY_MATCH, HOUR); @@ -158,17 +148,18 @@ static inline void toymatch_val_to_time(uint64_t val, struct tm *tm) tm->tm_year += (FIELD_EX32(val, TOY_MATCH, YEAR) - (tm->tm_year & 0x3f)); } -static void toymatch_write(LS7ARtcState *s, struct tm *tm, uint64_t val, int num) +static void toymatch_write(LS7ARtcState *s, uint64_t val, int num) { int64_t now, expire_time; + struct tm tm = {}; /* it do not support write when toy disabled */ if (toy_enabled(s)) { s->toymatch[num] = val; - /* caculate expire time */ + /* calculate expire time */ now = qemu_clock_get_ms(rtc_clock); - toymatch_val_to_time(val, tm); - expire_time = now + (qemu_timedate_diff(tm) - s->offset_toy) * 1000; + toymatch_val_to_time(s, val, &tm); + expire_time = now + (qemu_timedate_diff(&tm) - s->offset_toy) * 1000; timer_mod(s->toy_timer[num], expire_time); } } @@ -180,7 +171,7 @@ static void rtcmatch_write(LS7ARtcState *s, uint64_t val, int num) /* it do not support write when toy disabled */ if (rtc_enabled(s)) { s->rtcmatch[num] = val; - /* caculate expire time */ + /* calculate expire time */ expire_ns = ticks_to_ns(val) - ticks_to_ns(s->offset_rtc); timer_mod_ns(s->rtc_timer[num], expire_ns); } @@ -189,16 +180,8 @@ static void rtcmatch_write(LS7ARtcState *s, uint64_t val, int num) static void ls7a_toy_stop(LS7ARtcState *s) { int i; - struct tm tm; - /* - * save time when disabled toy, - * because toy time not add counters. - */ - qemu_get_timedate(&tm, s->offset_toy); - s->save_toy_mon = toy_time_to_val_mon(tm); - s->save_toy_year = toy_time_to_val_year(tm); - /* delete timers, and when re-enabled, recaculate expire time */ + /* delete timers, and when re-enabled, recalculate expire time */ for (i = 0; i < TIMER_NUMS; i++) { timer_del(s->toy_timer[i]); } @@ -207,13 +190,8 @@ static void ls7a_toy_stop(LS7ARtcState *s) static void ls7a_rtc_stop(LS7ARtcState *s) { int i; - uint64_t time; - - /* save rtc time */ - time = ls7a_rtc_ticks() + s->offset_rtc; - s->save_rtc = time; - /* delete timers, and when re-enabled, recaculate expire time */ + /* delete timers, and when re-enabled, recalculate expire time */ for (i = 0; i < TIMER_NUMS; i++) { timer_del(s->rtc_timer[i]); } @@ -223,20 +201,13 @@ static void ls7a_toy_start(LS7ARtcState *s) { int i; uint64_t expire_time, now; - struct tm tm; - /* - * need to recaculate toy offset - * and expire time when enable it. - */ - toy_val_to_time_mon(s->save_toy_mon, &tm); - toy_val_to_time_year(s->save_toy_year, &tm); + struct tm tm = {}; - s->offset_toy = qemu_timedate_diff(&tm); now = qemu_clock_get_ms(rtc_clock); - /* recaculate expire time and enable timer */ + /* recalculate expire time and enable timer */ for (i = 0; i < TIMER_NUMS; i++) { - toymatch_val_to_time(s->toymatch[i], &tm); + toymatch_val_to_time(s, s->toymatch[i], &tm); expire_time = now + (qemu_timedate_diff(&tm) - s->offset_toy) * 1000; timer_mod(s->toy_timer[i], expire_time); } @@ -245,16 +216,9 @@ static void ls7a_toy_start(LS7ARtcState *s) static void ls7a_rtc_start(LS7ARtcState *s) { int i; - uint64_t expire_time, now; - - /* - * need to recaculate rtc offset - * and expire time when enable it. - */ - now = ls7a_rtc_ticks(); - s->offset_rtc = s->save_rtc - now; + uint64_t expire_time; - /* recaculate expire time and enable timer */ + /* recalculate expire time and enable timer */ for (i = 0; i < TIMER_NUMS; i++) { expire_time = ticks_to_ns(s->rtcmatch[i]) - ticks_to_ns(s->offset_rtc); timer_mod_ns(s->rtc_timer[i], expire_time); @@ -269,23 +233,21 @@ static uint64_t ls7a_rtc_read(void *opaque, hwaddr addr, unsigned size) switch (addr) { case SYS_TOYREAD0: - /* if toy disabled, read save toy time */ if (toy_enabled(s)) { qemu_get_timedate(&tm, s->offset_toy); - val = toy_time_to_val_mon(tm); + val = toy_time_to_val_mon(&tm); } else { - /* read save mon val */ - val = s->save_toy_mon; + /* return 0 when toy disabled */ + val = 0; } break; case SYS_TOYREAD1: - /* if toy disabled, read save toy time */ if (toy_enabled(s)) { qemu_get_timedate(&tm, s->offset_toy); val = tm.tm_year; } else { - /* read save year val */ - val = s->save_toy_year; + /* return 0 when toy disabled */ + val = 0; } break; case SYS_TOYMATCH0: @@ -301,11 +263,11 @@ static uint64_t ls7a_rtc_read(void *opaque, hwaddr addr, unsigned size) val = s->cntrctl; break; case SYS_RTCREAD0: - /* if rtc disabled, read save rtc time */ if (rtc_enabled(s)) { val = ls7a_rtc_ticks() + s->offset_rtc; } else { - val = s->save_rtc; + /* return 0 when rtc disabled */ + val = 0; } break; case SYS_RTCMATCH0: @@ -352,13 +314,13 @@ static void ls7a_rtc_write(void *opaque, hwaddr addr, } break; case SYS_TOYMATCH0: - toymatch_write(s, &tm, val, 0); + toymatch_write(s, val, 0); break; case SYS_TOYMATCH1: - toymatch_write(s, &tm, val, 1); + toymatch_write(s, val, 1); break; case SYS_TOYMATCH2: - toymatch_write(s, &tm, val, 2); + toymatch_write(s, val, 2); break; case SYS_RTCCTRL: /* get old ctrl */ @@ -423,7 +385,7 @@ static void toy_timer_cb(void *opaque) LS7ARtcState *s = opaque; if (toy_enabled(s)) { - qemu_irq_pulse(s->irq); + qemu_irq_raise(s->irq); } } @@ -432,7 +394,7 @@ static void rtc_timer_cb(void *opaque) LS7ARtcState *s = opaque; if (rtc_enabled(s)) { - qemu_irq_pulse(s->irq); + qemu_irq_raise(s->irq); } } @@ -455,11 +417,26 @@ static void ls7a_rtc_realize(DeviceState *dev, Error **errp) } d->offset_toy = 0; d->offset_rtc = 0; - d->save_toy_mon = 0; - d->save_toy_year = 0; - d->save_rtc = 0; - create_unimplemented_device("mmio fallback 1", 0x10013ffc, 0x4); +} + +/* delete timer and clear reg when reset */ +static void ls7a_rtc_reset(DeviceState *dev) +{ + int i; + SysBusDevice *sbd = SYS_BUS_DEVICE(dev); + LS7ARtcState *d = LS7A_RTC(sbd); + for (i = 0; i < TIMER_NUMS; i++) { + if (toy_enabled(d)) { + timer_del(d->toy_timer[i]); + } + if (rtc_enabled(d)) { + timer_del(d->rtc_timer[i]); + } + d->toymatch[i] = 0; + d->rtcmatch[i] = 0; + } + d->cntrctl = 0; } static int ls7a_rtc_pre_save(void *opaque) @@ -495,9 +472,6 @@ static const VMStateDescription vmstate_ls7a_rtc = { .fields = (VMStateField[]) { VMSTATE_INT64(offset_toy, LS7ARtcState), VMSTATE_INT64(offset_rtc, LS7ARtcState), - VMSTATE_UINT64(save_toy_mon, LS7ARtcState), - VMSTATE_UINT64(save_toy_year, LS7ARtcState), - VMSTATE_UINT64(save_rtc, LS7ARtcState), VMSTATE_UINT32_ARRAY(toymatch, LS7ARtcState, TIMER_NUMS), VMSTATE_UINT32_ARRAY(rtcmatch, LS7ARtcState, TIMER_NUMS), VMSTATE_UINT32(cntrctl, LS7ARtcState), @@ -510,6 +484,7 @@ static void ls7a_rtc_class_init(ObjectClass *klass, void *data) DeviceClass *dc = DEVICE_CLASS(klass); dc->vmsd = &vmstate_ls7a_rtc; dc->realize = ls7a_rtc_realize; + dc->reset = ls7a_rtc_reset; dc->desc = "ls7a rtc"; } diff --git a/include/hw/intc/loongarch_pch_msi.h b/include/hw/intc/loongarch_pch_msi.h index f668bfca7a..6d67560dea 100644 --- a/include/hw/intc/loongarch_pch_msi.h +++ b/include/hw/intc/loongarch_pch_msi.h @@ -17,4 +17,6 @@ struct LoongArchPCHMSI { SysBusDevice parent_obj; qemu_irq pch_msi_irq[PCH_MSI_IRQ_NUM]; MemoryRegion msi_mmio; + /* irq base passed to upper extioi intc */ + unsigned int irq_base; }; diff --git a/linux-user/elfload.c b/linux-user/elfload.c index 163fc8a1ee..1de77c7959 100644 --- a/linux-user/elfload.c +++ b/linux-user/elfload.c @@ -922,6 +922,97 @@ static void elf_core_copy_regs(target_elf_gregset_t *regs, const CPUPPCState *en #endif +#ifdef TARGET_LOONGARCH64 + +#define ELF_START_MMAP 0x80000000 + +#define ELF_CLASS ELFCLASS64 +#define ELF_ARCH EM_LOONGARCH + +#define elf_check_arch(x) ((x) == EM_LOONGARCH) + +static inline void init_thread(struct target_pt_regs *regs, + struct image_info *infop) +{ + /*Set crmd PG,DA = 1,0 */ + regs->csr.crmd = 2 << 3; + regs->csr.era = infop->entry; + regs->regs[3] = infop->start_stack; +} + +/* See linux kernel: arch/loongarch/include/asm/elf.h */ +#define ELF_NREG 45 +typedef target_elf_greg_t target_elf_gregset_t[ELF_NREG]; + +enum { + TARGET_EF_R0 = 0, + TARGET_EF_CSR_ERA = TARGET_EF_R0 + 33, + TARGET_EF_CSR_BADV = TARGET_EF_R0 + 34, +}; + +static void elf_core_copy_regs(target_elf_gregset_t *regs, + const CPULoongArchState *env) +{ + int i; + + (*regs)[TARGET_EF_R0] = 0; + + for (i = 1; i < ARRAY_SIZE(env->gpr); i++) { + (*regs)[TARGET_EF_R0 + i] = tswapreg(env->gpr[i]); + } + + (*regs)[TARGET_EF_CSR_ERA] = tswapreg(env->pc); + (*regs)[TARGET_EF_CSR_BADV] = tswapreg(env->CSR_BADV); +} + +#define USE_ELF_CORE_DUMP +#define ELF_EXEC_PAGESIZE 4096 + +#define ELF_HWCAP get_elf_hwcap() + +/* See arch/loongarch/include/uapi/asm/hwcap.h */ +enum { + HWCAP_LOONGARCH_CPUCFG = (1 << 0), + HWCAP_LOONGARCH_LAM = (1 << 1), + HWCAP_LOONGARCH_UAL = (1 << 2), + HWCAP_LOONGARCH_FPU = (1 << 3), + HWCAP_LOONGARCH_LSX = (1 << 4), + HWCAP_LOONGARCH_LASX = (1 << 5), + HWCAP_LOONGARCH_CRC32 = (1 << 6), + HWCAP_LOONGARCH_COMPLEX = (1 << 7), + HWCAP_LOONGARCH_CRYPTO = (1 << 8), + HWCAP_LOONGARCH_LVZ = (1 << 9), + HWCAP_LOONGARCH_LBT_X86 = (1 << 10), + HWCAP_LOONGARCH_LBT_ARM = (1 << 11), + HWCAP_LOONGARCH_LBT_MIPS = (1 << 12), +}; + +static uint32_t get_elf_hwcap(void) +{ + LoongArchCPU *cpu = LOONGARCH_CPU(thread_cpu); + uint32_t hwcaps = 0; + + hwcaps |= HWCAP_LOONGARCH_CRC32; + + if (FIELD_EX32(cpu->env.cpucfg[1], CPUCFG1, UAL)) { + hwcaps |= HWCAP_LOONGARCH_UAL; + } + + if (FIELD_EX32(cpu->env.cpucfg[2], CPUCFG2, FP)) { + hwcaps |= HWCAP_LOONGARCH_FPU; + } + + if (FIELD_EX32(cpu->env.cpucfg[2], CPUCFG2, LAM)) { + hwcaps |= HWCAP_LOONGARCH_LAM; + } + + return hwcaps; +} + +#define ELF_PLATFORM "loongarch" + +#endif /* TARGET_LOONGARCH64 */ + #ifdef TARGET_MIPS #define ELF_START_MMAP 0x80000000 diff --git a/linux-user/loongarch64/cpu_loop.c b/linux-user/loongarch64/cpu_loop.c new file mode 100644 index 0000000000..894fdd111a --- /dev/null +++ b/linux-user/loongarch64/cpu_loop.c @@ -0,0 +1,96 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * QEMU LoongArch user cpu_loop. + * + * Copyright (c) 2021 Loongson Technology Corporation Limited + */ + +#include "qemu/osdep.h" +#include "qemu.h" +#include "user-internals.h" +#include "cpu_loop-common.h" +#include "signal-common.h" + +void cpu_loop(CPULoongArchState *env) +{ + CPUState *cs = env_cpu(env); + int trapnr, si_code; + abi_long ret; + + for (;;) { + cpu_exec_start(cs); + trapnr = cpu_exec(cs); + cpu_exec_end(cs); + process_queued_cpu_work(cs); + + switch (trapnr) { + case EXCP_INTERRUPT: + /* just indicate that signals should be handled asap */ + break; + case EXCCODE_SYS: + env->pc += 4; + ret = do_syscall(env, env->gpr[11], + env->gpr[4], env->gpr[5], + env->gpr[6], env->gpr[7], + env->gpr[8], env->gpr[9], + -1, -1); + if (ret == -QEMU_ERESTARTSYS) { + env->pc -= 4; + break; + } + if (ret == -QEMU_ESIGRETURN) { + /* + * Returning from a successful sigreturn syscall. + * Avoid clobbering register state. + */ + break; + } + env->gpr[4] = ret; + break; + case EXCCODE_INE: + force_sig_fault(TARGET_SIGILL, 0, env->pc); + break; + case EXCCODE_FPE: + si_code = TARGET_FPE_FLTUNK; + if (GET_FP_CAUSE(env->fcsr0) & FP_INVALID) { + si_code = TARGET_FPE_FLTINV; + } else if (GET_FP_CAUSE(env->fcsr0) & FP_DIV0) { + si_code = TARGET_FPE_FLTDIV; + } else if (GET_FP_CAUSE(env->fcsr0) & FP_OVERFLOW) { + si_code = TARGET_FPE_FLTOVF; + } else if (GET_FP_CAUSE(env->fcsr0) & FP_UNDERFLOW) { + si_code = TARGET_FPE_FLTUND; + } else if (GET_FP_CAUSE(env->fcsr0) & FP_INEXACT) { + si_code = TARGET_FPE_FLTRES; + } + force_sig_fault(TARGET_SIGFPE, si_code, env->pc); + break; + case EXCP_DEBUG: + case EXCCODE_BRK: + force_sig_fault(TARGET_SIGTRAP, TARGET_TRAP_BRKPT, env->pc); + break; + case EXCCODE_BCE: + force_sig_fault(TARGET_SIGSYS, TARGET_SI_KERNEL, env->pc); + break; + case EXCP_ATOMIC: + cpu_exec_step_atomic(cs); + break; + default: + EXCP_DUMP(env, "qemu: unhandled CPU exception 0x%x - aborting\n", + trapnr); + exit(EXIT_FAILURE); + } + process_pending_signals(env); + } +} + +void target_cpu_copy_regs(CPUArchState *env, struct target_pt_regs *regs) +{ + int i; + + for (i = 0; i < 32; i++) { + env->gpr[i] = regs->regs[i]; + } + env->pc = regs->csr.era; + +} diff --git a/linux-user/loongarch64/signal.c b/linux-user/loongarch64/signal.c new file mode 100644 index 0000000000..65fd5f3857 --- /dev/null +++ b/linux-user/loongarch64/signal.c @@ -0,0 +1,335 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * LoongArch emulation of Linux signals + * + * Copyright (c) 2021 Loongson Technology Corporation Limited + */ + +#include "qemu/osdep.h" +#include "qemu.h" +#include "user-internals.h" +#include "signal-common.h" +#include "linux-user/trace.h" + +#include "target/loongarch/internals.h" + +/* FP context was used */ +#define SC_USED_FP (1 << 0) + +struct target_sigcontext { + uint64_t sc_pc; + uint64_t sc_regs[32]; + uint32_t sc_flags; + uint64_t sc_extcontext[0] QEMU_ALIGNED(16); +}; + + +#define FPU_CTX_MAGIC 0x46505501 +#define FPU_CTX_ALIGN 8 +struct target_fpu_context { + uint64_t regs[32]; + uint64_t fcc; + uint32_t fcsr; +} QEMU_ALIGNED(FPU_CTX_ALIGN); + +#define CONTEXT_INFO_ALIGN 16 +struct target_sctx_info { + uint32_t magic; + uint32_t size; + uint64_t padding; +} QEMU_ALIGNED(CONTEXT_INFO_ALIGN); + +struct target_ucontext { + abi_ulong tuc_flags; + abi_ptr tuc_link; + target_stack_t tuc_stack; + target_sigset_t tuc_sigmask; + uint8_t __unused[1024 / 8 - sizeof(target_sigset_t)]; + struct target_sigcontext tuc_mcontext; +}; + +struct target_rt_sigframe { + struct target_siginfo rs_info; + struct target_ucontext rs_uc; +}; + +/* + * These two structures are not present in guest memory, are private + * to the signal implementation, but are largely copied from the + * kernel's signal implementation. + */ +struct ctx_layout { + void *haddr; + abi_ptr gaddr; + unsigned int size; +}; + +struct extctx_layout { + unsigned int size; + unsigned int flags; + struct ctx_layout fpu; + struct ctx_layout end; +}; + +/* The kernel's sc_save_fcc macro is a sequence of MOVCF2GR+BSTRINS. */ +static uint64_t read_all_fcc(CPULoongArchState *env) +{ + uint64_t ret = 0; + + for (int i = 0; i < 8; ++i) { + ret |= (uint64_t)env->cf[i] << (i * 8); + } + + return ret; +} + +/* The kernel's sc_restore_fcc macro is a sequence of BSTRPICK+MOVGR2CF. */ +static void write_all_fcc(CPULoongArchState *env, uint64_t val) +{ + for (int i = 0; i < 8; ++i) { + env->cf[i] = (val >> (i * 8)) & 1; + } +} + +static abi_ptr extframe_alloc(struct extctx_layout *extctx, + struct ctx_layout *sctx, unsigned size, + unsigned align, abi_ptr orig_sp) +{ + abi_ptr sp = orig_sp; + + sp -= sizeof(struct target_sctx_info) + size; + align = MAX(align, CONTEXT_INFO_ALIGN); + sp = ROUND_DOWN(sp, align); + sctx->gaddr = sp; + + size = orig_sp - sp; + sctx->size = size; + extctx->size += size; + + return sp; +} + +static abi_ptr setup_extcontext(struct extctx_layout *extctx, abi_ptr sp) +{ + memset(extctx, 0, sizeof(struct extctx_layout)); + + /* Grow down, alloc "end" context info first. */ + sp = extframe_alloc(extctx, &extctx->end, 0, CONTEXT_INFO_ALIGN, sp); + + /* For qemu, there is no lazy fp context switch, so fp always present. */ + extctx->flags = SC_USED_FP; + sp = extframe_alloc(extctx, &extctx->fpu, + sizeof(struct target_rt_sigframe), FPU_CTX_ALIGN, sp); + + return sp; +} + +static void setup_sigframe(CPULoongArchState *env, + struct target_sigcontext *sc, + struct extctx_layout *extctx) +{ + struct target_sctx_info *info; + struct target_fpu_context *fpu_ctx; + int i; + + __put_user(extctx->flags, &sc->sc_flags); + __put_user(env->pc, &sc->sc_pc); + __put_user(0, &sc->sc_regs[0]); + for (i = 1; i < 32; ++i) { + __put_user(env->gpr[i], &sc->sc_regs[i]); + } + + /* + * Set fpu context + */ + info = extctx->fpu.haddr; + __put_user(FPU_CTX_MAGIC, &info->magic); + __put_user(extctx->fpu.size, &info->size); + + fpu_ctx = (struct target_fpu_context *)(info + 1); + for (i = 0; i < 32; ++i) { + __put_user(env->fpr[i], &fpu_ctx->regs[i]); + } + __put_user(read_all_fcc(env), &fpu_ctx->fcc); + __put_user(env->fcsr0, &fpu_ctx->fcsr); + + /* + * Set end context + */ + info = extctx->end.haddr; + __put_user(0, &info->magic); + __put_user(extctx->end.size, &info->size); +} + +static bool parse_extcontext(struct extctx_layout *extctx, abi_ptr frame) +{ + memset(extctx, 0, sizeof(*extctx)); + + while (1) { + uint32_t magic, size; + + if (get_user_u32(magic, frame) || get_user_u32(size, frame + 4)) { + return false; + } + + switch (magic) { + case 0: /* END */ + extctx->end.gaddr = frame; + extctx->end.size = size; + extctx->size += size; + return true; + + case FPU_CTX_MAGIC: + if (size < (sizeof(struct target_sctx_info) + + sizeof(struct target_fpu_context))) { + return false; + } + extctx->fpu.gaddr = frame; + extctx->fpu.size = size; + extctx->size += size; + break; + default: + return false; + } + + frame += size; + } +} + +static void restore_sigframe(CPULoongArchState *env, + struct target_sigcontext *sc, + struct extctx_layout *extctx) +{ + int i; + + __get_user(env->pc, &sc->sc_pc); + for (i = 1; i < 32; ++i) { + __get_user(env->gpr[i], &sc->sc_regs[i]); + } + + if (extctx->fpu.haddr) { + struct target_fpu_context *fpu_ctx = + extctx->fpu.haddr + sizeof(struct target_sctx_info); + uint64_t fcc; + + for (i = 0; i < 32; ++i) { + __get_user(env->fpr[i], &fpu_ctx->regs[i]); + } + __get_user(fcc, &fpu_ctx->fcc); + write_all_fcc(env, fcc); + __get_user(env->fcsr0, &fpu_ctx->fcsr); + restore_fp_status(env); + } +} + +/* + * Determine which stack to use. + */ +static abi_ptr get_sigframe(struct target_sigaction *ka, + CPULoongArchState *env, + struct extctx_layout *extctx) +{ + abi_ulong sp; + + sp = target_sigsp(get_sp_from_cpustate(env), ka); + sp = ROUND_DOWN(sp, 16); + sp = setup_extcontext(extctx, sp); + sp -= sizeof(struct target_rt_sigframe); + + assert(QEMU_IS_ALIGNED(sp, 16)); + + return sp; +} + +void setup_rt_frame(int sig, struct target_sigaction *ka, + target_siginfo_t *info, + target_sigset_t *set, CPULoongArchState *env) +{ + struct target_rt_sigframe *frame; + struct extctx_layout extctx; + abi_ptr frame_addr; + int i; + + frame_addr = get_sigframe(ka, env, &extctx); + trace_user_setup_rt_frame(env, frame_addr); + + frame = lock_user(VERIFY_WRITE, frame_addr, + sizeof(*frame) + extctx.size, 0); + if (!frame) { + force_sigsegv(sig); + return; + } + extctx.fpu.haddr = (void *)frame + (extctx.fpu.gaddr - frame_addr); + extctx.end.haddr = (void *)frame + (extctx.end.gaddr - frame_addr); + + tswap_siginfo(&frame->rs_info, info); + + __put_user(0, &frame->rs_uc.tuc_flags); + __put_user(0, &frame->rs_uc.tuc_link); + target_save_altstack(&frame->rs_uc.tuc_stack, env); + + setup_sigframe(env, &frame->rs_uc.tuc_mcontext, &extctx); + + for (i = 0; i < TARGET_NSIG_WORDS; i++) { + __put_user(set->sig[i], &frame->rs_uc.tuc_sigmask.sig[i]); + } + + env->gpr[4] = sig; + env->gpr[5] = frame_addr + offsetof(struct target_rt_sigframe, rs_info); + env->gpr[6] = frame_addr + offsetof(struct target_rt_sigframe, rs_uc); + env->gpr[3] = frame_addr; + env->gpr[1] = default_rt_sigreturn; + + env->pc = ka->_sa_handler; + unlock_user(frame, frame_addr, sizeof(*frame) + extctx.size); +} + +long do_rt_sigreturn(CPULoongArchState *env) +{ + struct target_rt_sigframe *frame; + struct extctx_layout extctx; + abi_ulong frame_addr; + sigset_t blocked; + + frame_addr = env->gpr[3]; + trace_user_do_rt_sigreturn(env, frame_addr); + + if (!parse_extcontext(&extctx, frame_addr + sizeof(*frame))) { + goto badframe; + } + + frame = lock_user(VERIFY_READ, frame_addr, + sizeof(*frame) + extctx.size, 1); + if (!frame) { + goto badframe; + } + if (extctx.fpu.gaddr) { + extctx.fpu.haddr = (void *)frame + (extctx.fpu.gaddr - frame_addr); + } + + target_to_host_sigset(&blocked, &frame->rs_uc.tuc_sigmask); + set_sigmask(&blocked); + + restore_sigframe(env, &frame->rs_uc.tuc_mcontext, &extctx); + + target_restore_altstack(&frame->rs_uc.tuc_stack, env); + + unlock_user(frame, frame_addr, 0); + return -QEMU_ESIGRETURN; + + badframe: + force_sig(TARGET_SIGSEGV); + return -QEMU_ESIGRETURN; +} + +void setup_sigtramp(abi_ulong sigtramp_page) +{ + uint32_t *tramp = lock_user(VERIFY_WRITE, sigtramp_page, 8, 0); + assert(tramp != NULL); + + __put_user(0x03822c0b, tramp + 0); /* ori a7, zero, 0x8b */ + __put_user(0x002b0000, tramp + 1); /* syscall 0 */ + + default_rt_sigreturn = sigtramp_page; + unlock_user(tramp, sigtramp_page, 8); +} diff --git a/linux-user/loongarch64/sockbits.h b/linux-user/loongarch64/sockbits.h new file mode 100644 index 0000000000..1cffcae120 --- /dev/null +++ b/linux-user/loongarch64/sockbits.h @@ -0,0 +1,11 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Copyright (c) 2021 Loongson Technology Corporation Limited + */ + +#ifndef LOONGARCH_TARGET_SOCKBITS_H +#define LOONGARCH_TARGET_SOCKBITS_H + +#include "../generic/sockbits.h" + +#endif diff --git a/linux-user/loongarch64/syscall_nr.h b/linux-user/loongarch64/syscall_nr.h new file mode 100644 index 0000000000..be00915adf --- /dev/null +++ b/linux-user/loongarch64/syscall_nr.h @@ -0,0 +1,312 @@ +/* + * This file contains the system call numbers. + * Do not modify. + * This file is generated by scripts/gensyscalls.sh + */ +#ifndef LINUX_USER_LOONGARCH_SYSCALL_NR_H +#define LINUX_USER_LOONGARCH_SYSCALL_NR_H + +#define TARGET_NR_io_setup 0 +#define TARGET_NR_io_destroy 1 +#define TARGET_NR_io_submit 2 +#define TARGET_NR_io_cancel 3 +#define TARGET_NR_io_getevents 4 +#define TARGET_NR_setxattr 5 +#define TARGET_NR_lsetxattr 6 +#define TARGET_NR_fsetxattr 7 +#define TARGET_NR_getxattr 8 +#define TARGET_NR_lgetxattr 9 +#define TARGET_NR_fgetxattr 10 +#define TARGET_NR_listxattr 11 +#define TARGET_NR_llistxattr 12 +#define TARGET_NR_flistxattr 13 +#define TARGET_NR_removexattr 14 +#define TARGET_NR_lremovexattr 15 +#define TARGET_NR_fremovexattr 16 +#define TARGET_NR_getcwd 17 +#define TARGET_NR_lookup_dcookie 18 +#define TARGET_NR_eventfd2 19 +#define TARGET_NR_epoll_create1 20 +#define TARGET_NR_epoll_ctl 21 +#define TARGET_NR_epoll_pwait 22 +#define TARGET_NR_dup 23 +#define TARGET_NR_dup3 24 +#define TARGET_NR_fcntl 25 +#define TARGET_NR_inotify_init1 26 +#define TARGET_NR_inotify_add_watch 27 +#define TARGET_NR_inotify_rm_watch 28 +#define TARGET_NR_ioctl 29 +#define TARGET_NR_ioprio_set 30 +#define TARGET_NR_ioprio_get 31 +#define TARGET_NR_flock 32 +#define TARGET_NR_mknodat 33 +#define TARGET_NR_mkdirat 34 +#define TARGET_NR_unlinkat 35 +#define TARGET_NR_symlinkat 36 +#define TARGET_NR_linkat 37 +#define TARGET_NR_umount2 39 +#define TARGET_NR_mount 40 +#define TARGET_NR_pivot_root 41 +#define TARGET_NR_nfsservctl 42 +#define TARGET_NR_statfs 43 +#define TARGET_NR_fstatfs 44 +#define TARGET_NR_truncate 45 +#define TARGET_NR_ftruncate 46 +#define TARGET_NR_fallocate 47 +#define TARGET_NR_faccessat 48 +#define TARGET_NR_chdir 49 +#define TARGET_NR_fchdir 50 +#define TARGET_NR_chroot 51 +#define TARGET_NR_fchmod 52 +#define TARGET_NR_fchmodat 53 +#define TARGET_NR_fchownat 54 +#define TARGET_NR_fchown 55 +#define TARGET_NR_openat 56 +#define TARGET_NR_close 57 +#define TARGET_NR_vhangup 58 +#define TARGET_NR_pipe2 59 +#define TARGET_NR_quotactl 60 +#define TARGET_NR_getdents64 61 +#define TARGET_NR_lseek 62 +#define TARGET_NR_read 63 +#define TARGET_NR_write 64 +#define TARGET_NR_readv 65 +#define TARGET_NR_writev 66 +#define TARGET_NR_pread64 67 +#define TARGET_NR_pwrite64 68 +#define TARGET_NR_preadv 69 +#define TARGET_NR_pwritev 70 +#define TARGET_NR_sendfile 71 +#define TARGET_NR_pselect6 72 +#define TARGET_NR_ppoll 73 +#define TARGET_NR_signalfd4 74 +#define TARGET_NR_vmsplice 75 +#define TARGET_NR_splice 76 +#define TARGET_NR_tee 77 +#define TARGET_NR_readlinkat 78 +#define TARGET_NR_sync 81 +#define TARGET_NR_fsync 82 +#define TARGET_NR_fdatasync 83 +#define TARGET_NR_sync_file_range 84 +#define TARGET_NR_timerfd_create 85 +#define TARGET_NR_timerfd_settime 86 +#define TARGET_NR_timerfd_gettime 87 +#define TARGET_NR_utimensat 88 +#define TARGET_NR_acct 89 +#define TARGET_NR_capget 90 +#define TARGET_NR_capset 91 +#define TARGET_NR_personality 92 +#define TARGET_NR_exit 93 +#define TARGET_NR_exit_group 94 +#define TARGET_NR_waitid 95 +#define TARGET_NR_set_tid_address 96 +#define TARGET_NR_unshare 97 +#define TARGET_NR_futex 98 +#define TARGET_NR_set_robust_list 99 +#define TARGET_NR_get_robust_list 100 +#define TARGET_NR_nanosleep 101 +#define TARGET_NR_getitimer 102 +#define TARGET_NR_setitimer 103 +#define TARGET_NR_kexec_load 104 +#define TARGET_NR_init_module 105 +#define TARGET_NR_delete_module 106 +#define TARGET_NR_timer_create 107 +#define TARGET_NR_timer_gettime 108 +#define TARGET_NR_timer_getoverrun 109 +#define TARGET_NR_timer_settime 110 +#define TARGET_NR_timer_delete 111 +#define TARGET_NR_clock_settime 112 +#define TARGET_NR_clock_gettime 113 +#define TARGET_NR_clock_getres 114 +#define TARGET_NR_clock_nanosleep 115 +#define TARGET_NR_syslog 116 +#define TARGET_NR_ptrace 117 +#define TARGET_NR_sched_setparam 118 +#define TARGET_NR_sched_setscheduler 119 +#define TARGET_NR_sched_getscheduler 120 +#define TARGET_NR_sched_getparam 121 +#define TARGET_NR_sched_setaffinity 122 +#define TARGET_NR_sched_getaffinity 123 +#define TARGET_NR_sched_yield 124 +#define TARGET_NR_sched_get_priority_max 125 +#define TARGET_NR_sched_get_priority_min 126 +#define TARGET_NR_sched_rr_get_interval 127 +#define TARGET_NR_restart_syscall 128 +#define TARGET_NR_kill 129 +#define TARGET_NR_tkill 130 +#define TARGET_NR_tgkill 131 +#define TARGET_NR_sigaltstack 132 +#define TARGET_NR_rt_sigsuspend 133 +#define TARGET_NR_rt_sigaction 134 +#define TARGET_NR_rt_sigprocmask 135 +#define TARGET_NR_rt_sigpending 136 +#define TARGET_NR_rt_sigtimedwait 137 +#define TARGET_NR_rt_sigqueueinfo 138 +#define TARGET_NR_rt_sigreturn 139 +#define TARGET_NR_setpriority 140 +#define TARGET_NR_getpriority 141 +#define TARGET_NR_reboot 142 +#define TARGET_NR_setregid 143 +#define TARGET_NR_setgid 144 +#define TARGET_NR_setreuid 145 +#define TARGET_NR_setuid 146 +#define TARGET_NR_setresuid 147 +#define TARGET_NR_getresuid 148 +#define TARGET_NR_setresgid 149 +#define TARGET_NR_getresgid 150 +#define TARGET_NR_setfsuid 151 +#define TARGET_NR_setfsgid 152 +#define TARGET_NR_times 153 +#define TARGET_NR_setpgid 154 +#define TARGET_NR_getpgid 155 +#define TARGET_NR_getsid 156 +#define TARGET_NR_setsid 157 +#define TARGET_NR_getgroups 158 +#define TARGET_NR_setgroups 159 +#define TARGET_NR_uname 160 +#define TARGET_NR_sethostname 161 +#define TARGET_NR_setdomainname 162 +#define TARGET_NR_getrusage 165 +#define TARGET_NR_umask 166 +#define TARGET_NR_prctl 167 +#define TARGET_NR_getcpu 168 +#define TARGET_NR_gettimeofday 169 +#define TARGET_NR_settimeofday 170 +#define TARGET_NR_adjtimex 171 +#define TARGET_NR_getpid 172 +#define TARGET_NR_getppid 173 +#define TARGET_NR_getuid 174 +#define TARGET_NR_geteuid 175 +#define TARGET_NR_getgid 176 +#define TARGET_NR_getegid 177 +#define TARGET_NR_gettid 178 +#define TARGET_NR_sysinfo 179 +#define TARGET_NR_mq_open 180 +#define TARGET_NR_mq_unlink 181 +#define TARGET_NR_mq_timedsend 182 +#define TARGET_NR_mq_timedreceive 183 +#define TARGET_NR_mq_notify 184 +#define TARGET_NR_mq_getsetattr 185 +#define TARGET_NR_msgget 186 +#define TARGET_NR_msgctl 187 +#define TARGET_NR_msgrcv 188 +#define TARGET_NR_msgsnd 189 +#define TARGET_NR_semget 190 +#define TARGET_NR_semctl 191 +#define TARGET_NR_semtimedop 192 +#define TARGET_NR_semop 193 +#define TARGET_NR_shmget 194 +#define TARGET_NR_shmctl 195 +#define TARGET_NR_shmat 196 +#define TARGET_NR_shmdt 197 +#define TARGET_NR_socket 198 +#define TARGET_NR_socketpair 199 +#define TARGET_NR_bind 200 +#define TARGET_NR_listen 201 +#define TARGET_NR_accept 202 +#define TARGET_NR_connect 203 +#define TARGET_NR_getsockname 204 +#define TARGET_NR_getpeername 205 +#define TARGET_NR_sendto 206 +#define TARGET_NR_recvfrom 207 +#define TARGET_NR_setsockopt 208 +#define TARGET_NR_getsockopt 209 +#define TARGET_NR_shutdown 210 +#define TARGET_NR_sendmsg 211 +#define TARGET_NR_recvmsg 212 +#define TARGET_NR_readahead 213 +#define TARGET_NR_brk 214 +#define TARGET_NR_munmap 215 +#define TARGET_NR_mremap 216 +#define TARGET_NR_add_key 217 +#define TARGET_NR_request_key 218 +#define TARGET_NR_keyctl 219 +#define TARGET_NR_clone 220 +#define TARGET_NR_execve 221 +#define TARGET_NR_mmap 222 +#define TARGET_NR_fadvise64 223 +#define TARGET_NR_swapon 224 +#define TARGET_NR_swapoff 225 +#define TARGET_NR_mprotect 226 +#define TARGET_NR_msync 227 +#define TARGET_NR_mlock 228 +#define TARGET_NR_munlock 229 +#define TARGET_NR_mlockall 230 +#define TARGET_NR_munlockall 231 +#define TARGET_NR_mincore 232 +#define TARGET_NR_madvise 233 +#define TARGET_NR_remap_file_pages 234 +#define TARGET_NR_mbind 235 +#define TARGET_NR_get_mempolicy 236 +#define TARGET_NR_set_mempolicy 237 +#define TARGET_NR_migrate_pages 238 +#define TARGET_NR_move_pages 239 +#define TARGET_NR_rt_tgsigqueueinfo 240 +#define TARGET_NR_perf_event_open 241 +#define TARGET_NR_accept4 242 +#define TARGET_NR_recvmmsg 243 +#define TARGET_NR_arch_specific_syscall 244 +#define TARGET_NR_wait4 260 +#define TARGET_NR_prlimit64 261 +#define TARGET_NR_fanotify_init 262 +#define TARGET_NR_fanotify_mark 263 +#define TARGET_NR_name_to_handle_at 264 +#define TARGET_NR_open_by_handle_at 265 +#define TARGET_NR_clock_adjtime 266 +#define TARGET_NR_syncfs 267 +#define TARGET_NR_setns 268 +#define TARGET_NR_sendmmsg 269 +#define TARGET_NR_process_vm_readv 270 +#define TARGET_NR_process_vm_writev 271 +#define TARGET_NR_kcmp 272 +#define TARGET_NR_finit_module 273 +#define TARGET_NR_sched_setattr 274 +#define TARGET_NR_sched_getattr 275 +#define TARGET_NR_renameat2 276 +#define TARGET_NR_seccomp 277 +#define TARGET_NR_getrandom 278 +#define TARGET_NR_memfd_create 279 +#define TARGET_NR_bpf 280 +#define TARGET_NR_execveat 281 +#define TARGET_NR_userfaultfd 282 +#define TARGET_NR_membarrier 283 +#define TARGET_NR_mlock2 284 +#define TARGET_NR_copy_file_range 285 +#define TARGET_NR_preadv2 286 +#define TARGET_NR_pwritev2 287 +#define TARGET_NR_pkey_mprotect 288 +#define TARGET_NR_pkey_alloc 289 +#define TARGET_NR_pkey_free 290 +#define TARGET_NR_statx 291 +#define TARGET_NR_io_pgetevents 292 +#define TARGET_NR_rseq 293 +#define TARGET_NR_kexec_file_load 294 +#define TARGET_NR_pidfd_send_signal 424 +#define TARGET_NR_io_uring_setup 425 +#define TARGET_NR_io_uring_enter 426 +#define TARGET_NR_io_uring_register 427 +#define TARGET_NR_open_tree 428 +#define TARGET_NR_move_mount 429 +#define TARGET_NR_fsopen 430 +#define TARGET_NR_fsconfig 431 +#define TARGET_NR_fsmount 432 +#define TARGET_NR_fspick 433 +#define TARGET_NR_pidfd_open 434 +#define TARGET_NR_clone3 435 +#define TARGET_NR_close_range 436 +#define TARGET_NR_openat2 437 +#define TARGET_NR_pidfd_getfd 438 +#define TARGET_NR_faccessat2 439 +#define TARGET_NR_process_madvise 440 +#define TARGET_NR_epoll_pwait2 441 +#define TARGET_NR_mount_setattr 442 +#define TARGET_NR_quotactl_fd 443 +#define TARGET_NR_landlock_create_ruleset 444 +#define TARGET_NR_landlock_add_rule 445 +#define TARGET_NR_landlock_restrict_self 446 +#define TARGET_NR_process_mrelease 448 +#define TARGET_NR_futex_waitv 449 +#define TARGET_NR_set_mempolicy_home_node 450 +#define TARGET_NR_syscalls 451 + +#endif /* LINUX_USER_LOONGARCH_SYSCALL_NR_H */ diff --git a/linux-user/loongarch64/target_cpu.h b/linux-user/loongarch64/target_cpu.h new file mode 100644 index 0000000000..a29af66156 --- /dev/null +++ b/linux-user/loongarch64/target_cpu.h @@ -0,0 +1,34 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * LoongArch specific CPU ABI and functions for linux-user + * + * Copyright (c) 2021 Loongson Technology Corporation Limited + */ + +#ifndef LOONGARCH_TARGET_CPU_H +#define LOONGARCH_TARGET_CPU_H + +static inline void cpu_clone_regs_child(CPULoongArchState *env, + target_ulong newsp, unsigned flags) +{ + if (newsp) { + env->gpr[3] = newsp; + } + env->gpr[4] = 0; +} + +static inline void cpu_clone_regs_parent(CPULoongArchState *env, + unsigned flags) +{ +} + +static inline void cpu_set_tls(CPULoongArchState *env, target_ulong newtls) +{ + env->gpr[2] = newtls; +} + +static inline abi_ulong get_sp_from_cpustate(CPULoongArchState *state) +{ + return state->gpr[3]; +} +#endif diff --git a/linux-user/loongarch64/target_elf.h b/linux-user/loongarch64/target_elf.h new file mode 100644 index 0000000000..95c3f05a46 --- /dev/null +++ b/linux-user/loongarch64/target_elf.h @@ -0,0 +1,12 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Copyright (c) 2021 Loongson Technology Corporation Limited + */ + +#ifndef LOONGARCH_TARGET_ELF_H +#define LOONGARCH_TARGET_ELF_H +static inline const char *cpu_get_model(uint32_t eflags) +{ + return "la464"; +} +#endif diff --git a/linux-user/loongarch64/target_errno_defs.h b/linux-user/loongarch64/target_errno_defs.h new file mode 100644 index 0000000000..c198b8aca9 --- /dev/null +++ b/linux-user/loongarch64/target_errno_defs.h @@ -0,0 +1,12 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Copyright (c) 2021 Loongson Technology Corporation Limited + */ + +#ifndef LOONGARCH_TARGET_ERRNO_DEFS_H +#define LOONGARCH_TARGET_ERRNO_DEFS_H + +/* Target uses generic errno */ +#include "../generic/target_errno_defs.h" + +#endif diff --git a/linux-user/loongarch64/target_fcntl.h b/linux-user/loongarch64/target_fcntl.h new file mode 100644 index 0000000000..99bf586854 --- /dev/null +++ b/linux-user/loongarch64/target_fcntl.h @@ -0,0 +1,11 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Copyright (c) 2021 Loongson Technology Corporation Limited + */ + +#ifndef LOONGARCH_TARGET_FCNTL_H +#define LOONGARCH_TARGET_FCNTL_H + +#include "../generic/fcntl.h" + +#endif diff --git a/linux-user/loongarch64/target_prctl.h b/linux-user/loongarch64/target_prctl.h new file mode 100644 index 0000000000..eb53b31ad5 --- /dev/null +++ b/linux-user/loongarch64/target_prctl.h @@ -0,0 +1 @@ +/* No special prctl support required. */ diff --git a/linux-user/loongarch64/target_resource.h b/linux-user/loongarch64/target_resource.h new file mode 100644 index 0000000000..0f86bf24ee --- /dev/null +++ b/linux-user/loongarch64/target_resource.h @@ -0,0 +1,11 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Copyright (c) 2021 Loongson Technology Corporation Limited + */ + +#ifndef LOONGARCH_TARGET_RESOURCE_H +#define LOONGARCH_TARGET_RESOURCE_H + +#include "../generic/target_resource.h" + +#endif diff --git a/linux-user/loongarch64/target_signal.h b/linux-user/loongarch64/target_signal.h new file mode 100644 index 0000000000..ad3aaffcb4 --- /dev/null +++ b/linux-user/loongarch64/target_signal.h @@ -0,0 +1,13 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Copyright (c) 2021 Loongson Technology Corporation Limited + */ + +#ifndef LOONGARCH_TARGET_SIGNAL_H +#define LOONGARCH_TARGET_SIGNAL_H + +#include "../generic/signal.h" + +#define TARGET_ARCH_HAS_SIGTRAMP_PAGE 1 + +#endif /* LOONGARCH_TARGET_SIGNAL_H */ diff --git a/linux-user/loongarch64/target_structs.h b/linux-user/loongarch64/target_structs.h new file mode 100644 index 0000000000..6041441e15 --- /dev/null +++ b/linux-user/loongarch64/target_structs.h @@ -0,0 +1,11 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Copyright (c) 2021 Loongson Technology Corporation Limited + */ + +#ifndef LOONGARCH_TARGET_STRUCTS_H +#define LOONGARCH_TARGET_STRUCTS_H + +#include "../generic/target_structs.h" + +#endif diff --git a/linux-user/loongarch64/target_syscall.h b/linux-user/loongarch64/target_syscall.h new file mode 100644 index 0000000000..8b5de52124 --- /dev/null +++ b/linux-user/loongarch64/target_syscall.h @@ -0,0 +1,48 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Copyright (c) 2021 Loongson Technology Corporation Limited + */ + +#ifndef LOONGARCH_TARGET_SYSCALL_H +#define LOONGARCH_TARGET_SYSCALL_H + +#include "qemu/units.h" + +/* + * this struct defines the way the registers are stored on the + * stack during a system call. + */ + +struct target_pt_regs { + /* Saved main processor registers. */ + target_ulong regs[32]; + + /* Saved special registers. */ + struct { + target_ulong era; + target_ulong badv; + target_ulong crmd; + target_ulong prmd; + target_ulong euen; + target_ulong ecfg; + target_ulong estat; + } csr; + target_ulong orig_a0; + target_ulong __last[0]; +}; + +#define UNAME_MACHINE "loongarch64" +#define UNAME_MINIMUM_RELEASE "5.19.0" + +#define TARGET_MCL_CURRENT 1 +#define TARGET_MCL_FUTURE 2 +#define TARGET_MCL_ONFAULT 4 + +#define TARGET_FORCE_SHMLBA + +static inline abi_ulong target_shmlba(CPULoongArchState *env) +{ + return 64 * KiB; +} + +#endif diff --git a/linux-user/loongarch64/termbits.h b/linux-user/loongarch64/termbits.h new file mode 100644 index 0000000000..d425db8748 --- /dev/null +++ b/linux-user/loongarch64/termbits.h @@ -0,0 +1,11 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Copyright (c) 2021 Loongson Technology Corporation Limited + */ + +#ifndef LOONGARCH_TARGET_TERMBITS_H +#define LOONGARCH_TARGET_TERMBITS_H + +#include "../generic/termbits.h" + +#endif diff --git a/linux-user/syscall_defs.h b/linux-user/syscall_defs.h index 4587b62ac9..85b0f33e91 100644 --- a/linux-user/syscall_defs.h +++ b/linux-user/syscall_defs.h @@ -74,7 +74,7 @@ || defined(TARGET_M68K) || defined(TARGET_CRIS) \ || defined(TARGET_S390X) || defined(TARGET_OPENRISC) \ || defined(TARGET_NIOS2) || defined(TARGET_RISCV) \ - || defined(TARGET_XTENSA) + || defined(TARGET_XTENSA) || defined(TARGET_LOONGARCH64) #define TARGET_IOC_SIZEBITS 14 #define TARGET_IOC_DIRBITS 2 @@ -2196,6 +2196,10 @@ struct target_stat64 { uint64_t st_ino; }; +#elif defined(TARGET_LOONGARCH64) + +/* LoongArch no newfstatat/fstat syscall. */ + #else #error unsupported CPU #endif diff --git a/scripts/gensyscalls.sh b/scripts/gensyscalls.sh index 8fb450e3c9..a2f7664b7b 100755 --- a/scripts/gensyscalls.sh +++ b/scripts/gensyscalls.sh @@ -44,6 +44,7 @@ read_includes() cpp -P -nostdinc -fdirectives-only \ -D_UAPI_ASM_$(upper ${arch})_BITSPERLONG_H \ + -D__ASM_$(upper ${arch})_BITSPERLONG_H \ -D__BITS_PER_LONG=${bits} \ -I${linux}/arch/${arch}/include/uapi/ \ -I${linux}/include/uapi \ @@ -99,4 +100,5 @@ generate_syscall_nr openrisc 32 "$output/linux-user/openrisc/syscall_nr.h" generate_syscall_nr riscv 32 "$output/linux-user/riscv/syscall32_nr.h" generate_syscall_nr riscv 64 "$output/linux-user/riscv/syscall64_nr.h" generate_syscall_nr hexagon 32 "$output/linux-user/hexagon/syscall_nr.h" +generate_syscall_nr loongarch 64 "$output/linux-user/loongarch64/syscall_nr.h" rm -fr "$TMP" diff --git a/scripts/qemu-binfmt-conf.sh b/scripts/qemu-binfmt-conf.sh index 9cb723f443..1f4e2cd19d 100755 --- a/scripts/qemu-binfmt-conf.sh +++ b/scripts/qemu-binfmt-conf.sh @@ -4,7 +4,7 @@ qemu_target_list="i386 i486 alpha arm armeb sparc sparc32plus sparc64 \ ppc ppc64 ppc64le m68k mips mipsel mipsn32 mipsn32el mips64 mips64el \ sh4 sh4eb s390x aarch64 aarch64_be hppa riscv32 riscv64 xtensa xtensaeb \ -microblaze microblazeel or1k x86_64 hexagon" +microblaze microblazeel or1k x86_64 hexagon loongarch64" i386_magic='\x7fELF\x01\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x03\x00' i386_mask='\xff\xff\xff\xff\xff\xfe\xfe\x00\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff\xff' @@ -140,6 +140,10 @@ hexagon_magic='\x7fELF\x01\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x hexagon_mask='\xff\xff\xff\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff\xff' hexagon_family=hexagon +loongarch64_magic='\x7fELF\x02\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x02\x01' +loongarch64_mask='\xff\xff\xff\xff\xff\xff\xff\xfc\x00\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff\xff' +loongarch64_family=loongarch + qemu_get_family() { cpu=${HOST_ARCH:-$(uname -m)} case "$cpu" in diff --git a/target/loongarch/README b/target/loongarch/README index 4dcd0f1682..9f5edd10c8 100644 --- a/target/loongarch/README +++ b/target/loongarch/README @@ -24,9 +24,9 @@ Download cross-tools. - wget https://github.com/loongson/build-tools/releases/latest/download/loongarch64-clfs-20211202-cross-tools.tar.xz + wget https://github.com/loongson/build-tools/releases/download/2022.05.29/loongarch64-clfs-5.0-cross-tools-gcc-full.tar.xz - tar -vxf loongarch64-clfs-20211202-cross-tools.tar.xz -C /opt + tar -vxf loongarch64-clfs-5.0-cross-tools-gcc-full.tar.xz -C /opt Config cross-tools env. @@ -60,5 +60,40 @@ ./build/qemu-system-loongarch64 -machine virt -m 4G -cpu Loongson-3A5000 -smp 1 -kernel build/tests/tcg/loongarch64-softmmu/hello -monitor none -display none -chardev file,path=hello.out,id=output -serial chardev:output +- Linux-user emulation + + We already support Linux user emulation. We can use LoongArch cross-tools to build LoongArch executables on X86 machines, + and We can also use qemu-loongarch64 to run LoongArch executables. + + 1. Config cross-tools env. + + see System emulation. + + 2. Test tests/tcg/multiarch. + + ./configure --static --prefix=/usr --disable-werror --target-list="loongarch64-linux-user" --enable-debug + + cd build + + make && make check-tcg + + 3. Run LoongArch system basic command with loongarch-clfs-system. + + - Config clfs env. + + wget https://github.com/loongson/build-tools/releases/download/2022.05.29/loongarch64-clfs-system-5.0.tar.bz2 + + tar -vxf loongarch64-clfs-system-5.0.tar.bz2 -C /opt/clfs + + cp /opt/clfs/lib64/ld-linux-loongarch-lp64d.so.1 /lib64 + + export LD_LIBRARY_PATH="/opt/clfs/lib64" + + - Run LoongArch system basic command. + + ./qemu-loongarch64 /opt/clfs/usr/bin/bash + ./qemu-loongarch64 /opt/clfs/usr/bin/ls + ./qemu-loongarch64 /opt/clfs/usr/bin/pwd + - Note. We can get the latest LoongArch documents or LoongArch tools at https://github.com/loongson/ diff --git a/target/loongarch/cpu.c b/target/loongarch/cpu.c index 4c8f96bc3a..d2d4667a34 100644 --- a/target/loongarch/cpu.c +++ b/target/loongarch/cpu.c @@ -18,7 +18,6 @@ #include "fpu/softfloat-helpers.h" #include "cpu-csr.h" #include "sysemu/reset.h" -#include "hw/loader.h" const char * const regnames[32] = { "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", @@ -51,6 +50,7 @@ static const char * const excp_names[] = { [EXCCODE_IPE] = "Instruction privilege error", [EXCCODE_FPE] = "Floating Point Exception", [EXCCODE_DBP] = "Debug breakpoint", + [EXCCODE_BCE] = "Bound Check Exception", }; const char *loongarch_exception_name(int32_t exception) @@ -82,6 +82,7 @@ static void loongarch_cpu_set_pc(CPUState *cs, vaddr value) env->pc = value; } +#ifndef CONFIG_USER_ONLY #include "hw/loongarch/virt.h" void loongarch_cpu_set_irq(void *opaque, int irq, int level) @@ -171,18 +172,21 @@ static void loongarch_cpu_do_interrupt(CPUState *cs) cause = cs->exception_index; update_badinstr = 0; break; - case EXCCODE_ADEM: case EXCCODE_SYS: case EXCCODE_BRK: + case EXCCODE_INE: + case EXCCODE_IPE: + case EXCCODE_FPE: + case EXCCODE_BCE: + env->CSR_BADV = env->pc; + QEMU_FALLTHROUGH; + case EXCCODE_ADEM: case EXCCODE_PIL: case EXCCODE_PIS: case EXCCODE_PME: case EXCCODE_PNR: case EXCCODE_PNX: case EXCCODE_PPI: - case EXCCODE_INE: - case EXCCODE_IPE: - case EXCCODE_FPE: cause = cs->exception_index; break; default: @@ -219,6 +223,10 @@ static void loongarch_cpu_do_interrupt(CPUState *cs) env->CSR_CRMD = FIELD_DP64(env->CSR_CRMD, CSR_CRMD, PLV, 0); env->CSR_CRMD = FIELD_DP64(env->CSR_CRMD, CSR_CRMD, IE, 0); + if (vec_size) { + vec_size = (1 << vec_size) * 4; + } + if (cs->exception_index == EXCCODE_INT) { /* Interrupt */ uint32_t vector = 0; @@ -292,6 +300,7 @@ static bool loongarch_cpu_exec_interrupt(CPUState *cs, int interrupt_request) } return false; } +#endif #ifdef CONFIG_TCG static void loongarch_cpu_synchronize_from_tb(CPUState *cs, @@ -306,6 +315,9 @@ static void loongarch_cpu_synchronize_from_tb(CPUState *cs, static bool loongarch_cpu_has_work(CPUState *cs) { +#ifdef CONFIG_USER_ONLY + return true; +#else LoongArchCPU *cpu = LOONGARCH_CPU(cs); CPULoongArchState *env = &cpu->env; bool has_work = false; @@ -316,6 +328,7 @@ static bool loongarch_cpu_has_work(CPUState *cs) } return has_work; +#endif } static void loongarch_la464_initfn(Object *obj) @@ -464,7 +477,9 @@ static void loongarch_cpu_reset(DeviceState *dev) env->CSR_DMW[n] = FIELD_DP64(env->CSR_DMW[n], CSR_DMW, PLV3, 0); } +#ifndef CONFIG_USER_ONLY env->pc = 0x1c000000; +#endif restore_fp_status(env); cs->exception_index = -1; @@ -495,6 +510,7 @@ static void loongarch_cpu_realizefn(DeviceState *dev, Error **errp) lacc->parent_realize(dev, errp); } +#ifndef CONFIG_USER_ONLY static void loongarch_qemu_write(void *opaque, hwaddr addr, uint64_t val, unsigned size) { @@ -529,13 +545,16 @@ static const MemoryRegionOps loongarch_qemu_ops = { .max_access_size = 8, }, }; +#endif static void loongarch_cpu_init(Object *obj) { LoongArchCPU *cpu = LOONGARCH_CPU(obj); - CPULoongArchState *env = &cpu->env; cpu_set_cpustate_pointers(cpu); + +#ifndef CONFIG_USER_ONLY + CPULoongArchState *env = &cpu->env; qdev_init_gpio_in(DEVICE(cpu), loongarch_cpu_set_irq, N_IRQS); timer_init_ns(&cpu->timer, QEMU_CLOCK_VIRTUAL, &loongarch_constant_timer_cb, cpu); @@ -545,6 +564,7 @@ static void loongarch_cpu_init(Object *obj) memory_region_init_io(&env->iocsr_mem, OBJECT(cpu), &loongarch_qemu_ops, NULL, "iocsr_misc", 0x428); memory_region_add_subregion(&env->system_iocsr, 0, &env->iocsr_mem); +#endif } static ObjectClass *loongarch_cpu_class_by_name(const char *cpu_model) @@ -612,18 +632,22 @@ static struct TCGCPUOps loongarch_tcg_ops = { .initialize = loongarch_translate_init, .synchronize_from_tb = loongarch_cpu_synchronize_from_tb, +#ifndef CONFIG_USER_ONLY .tlb_fill = loongarch_cpu_tlb_fill, .cpu_exec_interrupt = loongarch_cpu_exec_interrupt, .do_interrupt = loongarch_cpu_do_interrupt, .do_transaction_failed = loongarch_cpu_do_transaction_failed, +#endif }; #endif /* CONFIG_TCG */ +#ifndef CONFIG_USER_ONLY #include "hw/core/sysemu-cpu-ops.h" static const struct SysemuCPUOps loongarch_sysemu_ops = { .get_phys_page_debug = loongarch_cpu_get_phys_page_debug, }; +#endif static void loongarch_cpu_class_init(ObjectClass *c, void *data) { @@ -639,8 +663,10 @@ static void loongarch_cpu_class_init(ObjectClass *c, void *data) cc->has_work = loongarch_cpu_has_work; cc->dump_state = loongarch_cpu_dump_state; cc->set_pc = loongarch_cpu_set_pc; +#ifndef CONFIG_USER_ONLY dc->vmsd = &vmstate_loongarch_cpu; cc->sysemu_ops = &loongarch_sysemu_ops; +#endif cc->disas_set_info = loongarch_cpu_disas_set_info; cc->gdb_read_register = loongarch_cpu_gdb_read_register; cc->gdb_write_register = loongarch_cpu_gdb_write_register; diff --git a/target/loongarch/cpu.h b/target/loongarch/cpu.h index 71a5036c3c..d141ec9b5d 100644 --- a/target/loongarch/cpu.h +++ b/target/loongarch/cpu.h @@ -246,8 +246,6 @@ typedef struct CPUArchState { uint64_t lladdr; /* LL virtual address compared against SC */ uint64_t llval; - uint64_t badaddr; - /* LoongArch CSRs */ uint64_t CSR_CRMD; uint64_t CSR_PRMD; @@ -303,6 +301,7 @@ typedef struct CPUArchState { uint64_t CSR_DERA; uint64_t CSR_DSAVE; +#ifndef CONFIG_USER_ONLY LoongArchTLB tlb[LOONGARCH_TLB_MAX]; AddressSpace address_space_iocsr; @@ -310,6 +309,7 @@ typedef struct CPUArchState { MemoryRegion iocsr_mem; bool load_elf; uint64_t elf_address; +#endif } CPULoongArchState; /** @@ -360,12 +360,16 @@ struct LoongArchCPUClass { static inline int cpu_mmu_index(CPULoongArchState *env, bool ifetch) { +#ifdef CONFIG_USER_ONLY + return MMU_USER_IDX; +#else uint8_t pg = FIELD_EX64(env->CSR_CRMD, CSR_CRMD, PG); if (!pg) { return MMU_DA_IDX; } return FIELD_EX64(env->CSR_CRMD, CSR_CRMD, PLV); +#endif } static inline void cpu_get_tb_cpu_state(CPULoongArchState *env, diff --git a/target/loongarch/csr_helper.c b/target/loongarch/csr_helper.c index 24a9389364..7e02787895 100644 --- a/target/loongarch/csr_helper.c +++ b/target/loongarch/csr_helper.c @@ -81,7 +81,9 @@ target_ulong helper_csrwr_ticlr(CPULoongArchState *env, target_ulong val) int64_t old_v = 0; if (val & 0x1) { + qemu_mutex_lock_iothread(); loongarch_cpu_set_irq(cpu, IRQ_TIMER, 0); + qemu_mutex_unlock_iothread(); } return old_v; } diff --git a/target/loongarch/gdbstub.c b/target/loongarch/gdbstub.c index 0c48834201..24e126fb2d 100644 --- a/target/loongarch/gdbstub.c +++ b/target/loongarch/gdbstub.c @@ -21,7 +21,7 @@ int loongarch_cpu_gdb_read_register(CPUState *cs, GByteArray *mem_buf, int n) } else if (n == 32) { return gdb_get_regl(mem_buf, env->pc); } else if (n == 33) { - return gdb_get_regl(mem_buf, env->badaddr); + return gdb_get_regl(mem_buf, env->CSR_BADV); } return 0; } diff --git a/target/loongarch/helper.h b/target/loongarch/helper.h index 85c11a60d4..cbbe008f32 100644 --- a/target/loongarch/helper.h +++ b/target/loongarch/helper.h @@ -95,6 +95,7 @@ DEF_HELPER_FLAGS_2(set_rounding_mode, TCG_CALL_NO_RWG, void, env, i32) DEF_HELPER_1(rdtime_d, i64, env) +#ifndef CONFIG_USER_ONLY /* CSRs helper */ DEF_HELPER_1(csrrd_pgd, i64, env) DEF_HELPER_1(csrrd_tval, i64, env) @@ -128,3 +129,4 @@ DEF_HELPER_4(lddir, tl, env, tl, tl, i32) DEF_HELPER_4(ldpte, void, env, tl, tl, i32) DEF_HELPER_1(ertn, void, env) DEF_HELPER_1(idle, void, env) +#endif diff --git a/target/loongarch/insn_trans/trans_privileged.c.inc b/target/loongarch/insn_trans/trans_privileged.c.inc index 53596c4f77..9c4dcbfcfb 100644 --- a/target/loongarch/insn_trans/trans_privileged.c.inc +++ b/target/loongarch/insn_trans/trans_privileged.c.inc @@ -7,6 +7,41 @@ #include "cpu-csr.h" +#ifdef CONFIG_USER_ONLY + +#define GEN_FALSE_TRANS(name) \ +static bool trans_##name(DisasContext *ctx, arg_##name * a) \ +{ \ + return false; \ +} + +GEN_FALSE_TRANS(csrrd) +GEN_FALSE_TRANS(csrwr) +GEN_FALSE_TRANS(csrxchg) +GEN_FALSE_TRANS(iocsrrd_b) +GEN_FALSE_TRANS(iocsrrd_h) +GEN_FALSE_TRANS(iocsrrd_w) +GEN_FALSE_TRANS(iocsrrd_d) +GEN_FALSE_TRANS(iocsrwr_b) +GEN_FALSE_TRANS(iocsrwr_h) +GEN_FALSE_TRANS(iocsrwr_w) +GEN_FALSE_TRANS(iocsrwr_d) +GEN_FALSE_TRANS(tlbsrch) +GEN_FALSE_TRANS(tlbrd) +GEN_FALSE_TRANS(tlbwr) +GEN_FALSE_TRANS(tlbfill) +GEN_FALSE_TRANS(tlbclr) +GEN_FALSE_TRANS(tlbflush) +GEN_FALSE_TRANS(invtlb) +GEN_FALSE_TRANS(cacop) +GEN_FALSE_TRANS(ldpte) +GEN_FALSE_TRANS(lddir) +GEN_FALSE_TRANS(ertn) +GEN_FALSE_TRANS(dbcl) +GEN_FALSE_TRANS(idle) + +#else + typedef void (*GenCSRRead)(TCGv dest, TCGv_ptr env); typedef void (*GenCSRWrite)(TCGv dest, TCGv_ptr env, TCGv src); @@ -464,3 +499,4 @@ static bool trans_idle(DisasContext *ctx, arg_idle *a) ctx->base.is_jmp = DISAS_NORETURN; return true; } +#endif diff --git a/target/loongarch/internals.h b/target/loongarch/internals.h index 9d50fbdd81..ea227362b6 100644 --- a/target/loongarch/internals.h +++ b/target/loongarch/internals.h @@ -33,6 +33,7 @@ const char *loongarch_exception_name(int32_t exception); void restore_fp_status(CPULoongArchState *env); +#ifndef CONFIG_USER_ONLY extern const VMStateDescription vmstate_loongarch_cpu; void loongarch_cpu_set_irq(void *opaque, int irq, int level); @@ -48,6 +49,7 @@ bool loongarch_cpu_tlb_fill(CPUState *cs, vaddr address, int size, bool probe, uintptr_t retaddr); hwaddr loongarch_cpu_get_phys_page_debug(CPUState *cpu, vaddr addr); +#endif /* !CONFIG_USER_ONLY */ int loongarch_cpu_gdb_read_register(CPUState *cs, GByteArray *mem_buf, int n); int loongarch_cpu_gdb_write_register(CPUState *cs, uint8_t *mem_buf, int n); diff --git a/target/loongarch/op_helper.c b/target/loongarch/op_helper.c index d87049851f..4b429b6699 100644 --- a/target/loongarch/op_helper.c +++ b/target/loongarch/op_helper.c @@ -49,14 +49,14 @@ target_ulong helper_bitswap(target_ulong v) void helper_asrtle_d(CPULoongArchState *env, target_ulong rj, target_ulong rk) { if (rj > rk) { - do_raise_exception(env, EXCCODE_ADEM, GETPC()); + do_raise_exception(env, EXCCODE_BCE, 0); } } void helper_asrtgt_d(CPULoongArchState *env, target_ulong rj, target_ulong rk) { if (rj <= rk) { - do_raise_exception(env, EXCCODE_ADEM, GETPC()); + do_raise_exception(env, EXCCODE_BCE, 0); } } @@ -86,6 +86,9 @@ target_ulong helper_cpucfg(CPULoongArchState *env, target_ulong rj) uint64_t helper_rdtime_d(CPULoongArchState *env) { +#ifdef CONFIG_USER_ONLY + return cpu_get_host_ticks(); +#else uint64_t plv; LoongArchCPU *cpu = env_archcpu(env); @@ -95,8 +98,10 @@ uint64_t helper_rdtime_d(CPULoongArchState *env) } return cpu_loongarch_get_constant_timer_counter(cpu); +#endif } +#ifndef CONFIG_USER_ONLY void helper_ertn(CPULoongArchState *env) { uint64_t csr_pplv, csr_pie; @@ -131,3 +136,4 @@ void helper_idle(CPULoongArchState *env) cs->halted = 1; do_raise_exception(env, EXCP_HLT, 0); } +#endif |