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----- 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>
This commit is contained in:
commit
1437479e5e
3
configs/targets/loongarch64-linux-user.mak
Normal file
3
configs/targets/loongarch64-linux-user.mak
Normal file
@ -0,0 +1,3 @@
|
||||
# Default configuration for loongarch64-linux-user
|
||||
TARGET_ARCH=loongarch64
|
||||
TARGET_BASE_ARCH=loongarch
|
@ -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)
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
uint64_t expire_time;
|
||||
|
||||
/*
|
||||
* need to recaculate rtc offset
|
||||
* and expire time when enable it.
|
||||
*/
|
||||
now = ls7a_rtc_ticks();
|
||||
s->offset_rtc = s->save_rtc - now;
|
||||
|
||||
/* 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";
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
};
|
||||
|
@ -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
|
||||
|
96
linux-user/loongarch64/cpu_loop.c
Normal file
96
linux-user/loongarch64/cpu_loop.c
Normal file
@ -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;
|
||||
|
||||
}
|
335
linux-user/loongarch64/signal.c
Normal file
335
linux-user/loongarch64/signal.c
Normal file
@ -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);
|
||||
}
|
11
linux-user/loongarch64/sockbits.h
Normal file
11
linux-user/loongarch64/sockbits.h
Normal file
@ -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
|
312
linux-user/loongarch64/syscall_nr.h
Normal file
312
linux-user/loongarch64/syscall_nr.h
Normal file
@ -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 */
|
34
linux-user/loongarch64/target_cpu.h
Normal file
34
linux-user/loongarch64/target_cpu.h
Normal file
@ -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
|
12
linux-user/loongarch64/target_elf.h
Normal file
12
linux-user/loongarch64/target_elf.h
Normal file
@ -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
|
12
linux-user/loongarch64/target_errno_defs.h
Normal file
12
linux-user/loongarch64/target_errno_defs.h
Normal file
@ -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
|
11
linux-user/loongarch64/target_fcntl.h
Normal file
11
linux-user/loongarch64/target_fcntl.h
Normal file
@ -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
|
1
linux-user/loongarch64/target_prctl.h
Normal file
1
linux-user/loongarch64/target_prctl.h
Normal file
@ -0,0 +1 @@
|
||||
/* No special prctl support required. */
|
11
linux-user/loongarch64/target_resource.h
Normal file
11
linux-user/loongarch64/target_resource.h
Normal file
@ -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
|
13
linux-user/loongarch64/target_signal.h
Normal file
13
linux-user/loongarch64/target_signal.h
Normal file
@ -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 */
|
11
linux-user/loongarch64/target_structs.h
Normal file
11
linux-user/loongarch64/target_structs.h
Normal file
@ -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
|
48
linux-user/loongarch64/target_syscall.h
Normal file
48
linux-user/loongarch64/target_syscall.h
Normal file
@ -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
|
11
linux-user/loongarch64/termbits.h
Normal file
11
linux-user/loongarch64/termbits.h
Normal file
@ -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
|
@ -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
|
||||
|
@ -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"
|
||||
|
@ -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
|
||||
|
@ -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/
|
||||
|
@ -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;
|
||||
|
@ -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,
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user