aboutsummaryrefslogtreecommitdiff
path: root/linux-user
diff options
context:
space:
mode:
Diffstat (limited to 'linux-user')
-rw-r--r--linux-user/aarch64/signal.c143
-rw-r--r--linux-user/arm/cpu_loop.c1
-rw-r--r--linux-user/elfload.c83
-rw-r--r--linux-user/fd-trans.h10
-rw-r--r--linux-user/gen-vdso.c43
-rw-r--r--linux-user/hppa/cpu_loop.c12
-rw-r--r--linux-user/main.c5
-rw-r--r--linux-user/meson.build5
-rw-r--r--linux-user/mips/target_signal.h1
-rw-r--r--linux-user/mmap.c2
-rw-r--r--linux-user/plugin-api.c1
-rw-r--r--linux-user/strace.list3
-rw-r--r--linux-user/syscall.c29
-rw-r--r--linux-user/syscall_defs.h4
14 files changed, 306 insertions, 36 deletions
diff --git a/linux-user/aarch64/signal.c b/linux-user/aarch64/signal.c
index bc7a138..668353b 100644
--- a/linux-user/aarch64/signal.c
+++ b/linux-user/aarch64/signal.c
@@ -121,6 +121,30 @@ struct target_za_context {
#define TARGET_ZA_SIG_CONTEXT_SIZE(VQ) \
TARGET_ZA_SIG_ZAV_OFFSET(VQ, VQ * TARGET_SVE_VQ_BYTES)
+#define TARGET_TPIDR2_MAGIC 0x54504902
+
+struct target_tpidr2_context {
+ struct target_aarch64_ctx head;
+ uint64_t tpidr2;
+};
+
+#define TARGET_ZT_MAGIC 0x5a544e01
+
+struct target_zt_context {
+ struct target_aarch64_ctx head;
+ uint16_t nregs;
+ uint16_t reserved[3];
+ /* ZTn register data immediately follows */
+};
+
+#define TARGET_ZT_SIG_REG_BYTES (512 / 8)
+#define TARGET_ZT_SIG_REGS_SIZE(n) (TARGET_ZT_SIG_REG_BYTES * (n))
+#define TARGET_ZT_SIG_CONTEXT_SIZE(n) (sizeof(struct target_zt_context) + \
+ TARGET_ZT_SIG_REGS_SIZE(n))
+#define TARGET_ZT_SIG_REGS_OFFSET sizeof(struct target_zt_context)
+QEMU_BUILD_BUG_ON(TARGET_ZT_SIG_REG_BYTES != \
+ sizeof_field(CPUARMState, za_state.zt0));
+
struct target_rt_sigframe {
struct target_siginfo info;
struct target_ucontext uc;
@@ -248,11 +272,41 @@ static void target_setup_za_record(struct target_za_context *za,
for (i = 0; i < vl; ++i) {
uint64_t *z = (void *)za + TARGET_ZA_SIG_ZAV_OFFSET(vq, i);
for (j = 0; j < vq * 2; ++j) {
- __put_user_e(env->zarray[i].d[j], z + j, le);
+ __put_user_e(env->za_state.za[i].d[j], z + j, le);
}
}
}
+static void target_setup_tpidr2_record(struct target_tpidr2_context *tpidr2,
+ CPUARMState *env)
+{
+ __put_user(TARGET_TPIDR2_MAGIC, &tpidr2->head.magic);
+ __put_user(sizeof(struct target_tpidr2_context), &tpidr2->head.size);
+ __put_user(env->cp15.tpidr2_el0, &tpidr2->tpidr2);
+}
+
+static void target_setup_zt_record(struct target_zt_context *zt,
+ CPUARMState *env, int size)
+{
+ uint64_t *z;
+
+ memset(zt, 0, sizeof(*zt));
+ __put_user(TARGET_ZT_MAGIC, &zt->head.magic);
+ __put_user(size, &zt->head.size);
+ /*
+ * The record format allows for multiple ZT regs, but
+ * currently there is only one, ZT0.
+ */
+ __put_user(1, &zt->nregs);
+ assert(size == TARGET_ZT_SIG_CONTEXT_SIZE(1));
+
+ /* ZT0 is the same byte-stream format as SVE regs and ZA */
+ z = (void *)zt + TARGET_ZT_SIG_REGS_OFFSET;
+ for (int i = 0; i < ARRAY_SIZE(env->za_state.zt0); i++) {
+ __put_user_e(env->za_state.zt0[i], z + i, le);
+ }
+}
+
static void target_restore_general_frame(CPUARMState *env,
struct target_rt_sigframe *sf)
{
@@ -397,12 +451,42 @@ static bool target_restore_za_record(CPUARMState *env,
for (i = 0; i < vl; ++i) {
uint64_t *z = (void *)za + TARGET_ZA_SIG_ZAV_OFFSET(vq, i);
for (j = 0; j < vq * 2; ++j) {
- __get_user_e(env->zarray[i].d[j], z + j, le);
+ __get_user_e(env->za_state.za[i].d[j], z + j, le);
}
}
return true;
}
+static void target_restore_tpidr2_record(CPUARMState *env,
+ struct target_tpidr2_context *tpidr2)
+{
+ __get_user(env->cp15.tpidr2_el0, &tpidr2->tpidr2);
+}
+
+static bool target_restore_zt_record(CPUARMState *env,
+ struct target_zt_context *zt, int size,
+ int svcr)
+{
+ uint16_t nregs;
+ uint64_t *z;
+
+ if (!(FIELD_EX64(svcr, SVCR, ZA))) {
+ return false;
+ }
+
+ __get_user(nregs, &zt->nregs);
+
+ if (nregs != 1) {
+ return false;
+ }
+
+ z = (void *)zt + TARGET_ZT_SIG_REGS_OFFSET;
+ for (int i = 0; i < ARRAY_SIZE(env->za_state.zt0); i++) {
+ __get_user_e(env->za_state.zt0[i], z + i, le);
+ }
+ return true;
+}
+
static int target_restore_sigframe(CPUARMState *env,
struct target_rt_sigframe *sf)
{
@@ -410,10 +494,13 @@ static int target_restore_sigframe(CPUARMState *env,
struct target_fpsimd_context *fpsimd = NULL;
struct target_sve_context *sve = NULL;
struct target_za_context *za = NULL;
+ struct target_tpidr2_context *tpidr2 = NULL;
+ struct target_zt_context *zt = NULL;
uint64_t extra_datap = 0;
bool used_extra = false;
int sve_size = 0;
int za_size = 0;
+ int zt_size = 0;
int svcr = 0;
target_restore_general_frame(env, sf);
@@ -460,6 +547,23 @@ static int target_restore_sigframe(CPUARMState *env,
za_size = size;
break;
+ case TARGET_TPIDR2_MAGIC:
+ if (tpidr2 || size != sizeof(struct target_tpidr2_context) ||
+ !cpu_isar_feature(aa64_sme, env_archcpu(env))) {
+ goto err;
+ }
+ tpidr2 = (struct target_tpidr2_context *)ctx;
+ break;
+
+ case TARGET_ZT_MAGIC:
+ if (zt || size != TARGET_ZT_SIG_CONTEXT_SIZE(1) ||
+ !cpu_isar_feature(aa64_sme2, env_archcpu(env))) {
+ goto err;
+ }
+ zt = (struct target_zt_context *)ctx;
+ zt_size = size;
+ break;
+
case TARGET_EXTRA_MAGIC:
if (extra || size != sizeof(struct target_extra_context)) {
goto err;
@@ -497,6 +601,16 @@ static int target_restore_sigframe(CPUARMState *env,
if (za && !target_restore_za_record(env, za, za_size, &svcr)) {
goto err;
}
+ if (tpidr2) {
+ target_restore_tpidr2_record(env, tpidr2);
+ }
+ /*
+ * NB that we must restore ZT after ZA so the check that there's
+ * no ZT record if SVCR.ZA is 0 gets the right value of SVCR.
+ */
+ if (zt && !target_restore_zt_record(env, zt, zt_size, svcr)) {
+ goto err;
+ }
if (env->svcr != svcr) {
env->svcr = svcr;
arm_rebuild_hflags(env);
@@ -568,8 +682,9 @@ static void target_setup_frame(int usig, struct target_sigaction *ka,
.total_size = offsetof(struct target_rt_sigframe,
uc.tuc_mcontext.__reserved),
};
- int fpsimd_ofs, fr_ofs, sve_ofs = 0, za_ofs = 0;
- int sve_size = 0, za_size = 0;
+ int fpsimd_ofs, fr_ofs, sve_ofs = 0, za_ofs = 0, tpidr2_ofs = 0;
+ int zt_ofs = 0;
+ int sve_size = 0, za_size = 0, tpidr2_size = 0, zt_size = 0;
struct target_rt_sigframe *frame;
struct target_rt_frame_record *fr;
abi_ulong frame_addr, return_addr;
@@ -585,6 +700,8 @@ static void target_setup_frame(int usig, struct target_sigaction *ka,
sve_ofs = alloc_sigframe_space(sve_size, &layout);
}
if (cpu_isar_feature(aa64_sme, env_archcpu(env))) {
+ tpidr2_size = sizeof(struct target_tpidr2_context);
+ tpidr2_ofs = alloc_sigframe_space(tpidr2_size, &layout);
/* ZA state needs saving only if it is enabled. */
if (FIELD_EX64(env->svcr, SVCR, ZA)) {
za_size = TARGET_ZA_SIG_CONTEXT_SIZE(sme_vq(env));
@@ -593,6 +710,12 @@ static void target_setup_frame(int usig, struct target_sigaction *ka,
}
za_ofs = alloc_sigframe_space(za_size, &layout);
}
+ if (cpu_isar_feature(aa64_sme2, env_archcpu(env)) &&
+ FIELD_EX64(env->svcr, SVCR, ZA)) {
+ /* If SME ZA storage is enabled, we must also save SME2 ZT0 */
+ zt_size = TARGET_ZT_SIG_CONTEXT_SIZE(1);
+ zt_ofs = alloc_sigframe_space(zt_size, &layout);
+ }
if (layout.extra_ofs) {
/* Reserve space for the extra end marker. The standard end marker
@@ -644,6 +767,12 @@ static void target_setup_frame(int usig, struct target_sigaction *ka,
if (za_ofs) {
target_setup_za_record((void *)frame + za_ofs, env, za_size);
}
+ if (tpidr2_ofs) {
+ target_setup_tpidr2_record((void *)frame + tpidr2_ofs, env);
+ }
+ if (zt_ofs) {
+ target_setup_zt_record((void *)frame + zt_ofs, env, zt_size);
+ }
/* Set up the stack frame for unwinding. */
fr = (void *)frame + fr_ofs;
@@ -666,8 +795,12 @@ static void target_setup_frame(int usig, struct target_sigaction *ka,
env->btype = 2;
}
- /* Invoke the signal handler with both SM and ZA disabled. */
+ /*
+ * Invoke the signal handler with a clean SME state: both SM and ZA
+ * disabled and TPIDR2_EL0 cleared.
+ */
aarch64_set_svcr(env, 0, R_SVCR_SM_MASK | R_SVCR_ZA_MASK);
+ env->cp15.tpidr2_el0 = 0;
if (info) {
frame->info = *info;
diff --git a/linux-user/arm/cpu_loop.c b/linux-user/arm/cpu_loop.c
index e8417d0..33f6395 100644
--- a/linux-user/arm/cpu_loop.c
+++ b/linux-user/arm/cpu_loop.c
@@ -363,6 +363,7 @@ void cpu_loop(CPUARMState *env)
switch (n) {
case ARM_NR_cacheflush:
/* nop */
+ env->regs[0] = 0;
break;
case ARM_NR_set_tls:
cpu_set_tls(env, env->regs[0]);
diff --git a/linux-user/elfload.c b/linux-user/elfload.c
index 82ebf6a..ea21410 100644
--- a/linux-user/elfload.c
+++ b/linux-user/elfload.c
@@ -751,7 +751,23 @@ enum {
ARM_HWCAP_A64_SSBS = 1 << 28,
ARM_HWCAP_A64_SB = 1 << 29,
ARM_HWCAP_A64_PACA = 1 << 30,
- ARM_HWCAP_A64_PACG = 1UL << 31,
+ ARM_HWCAP_A64_PACG = 1ULL << 31,
+ ARM_HWCAP_A64_GCS = 1ULL << 32,
+ ARM_HWCAP_A64_CMPBR = 1ULL << 33,
+ ARM_HWCAP_A64_FPRCVT = 1ULL << 34,
+ ARM_HWCAP_A64_F8MM8 = 1ULL << 35,
+ ARM_HWCAP_A64_F8MM4 = 1ULL << 36,
+ ARM_HWCAP_A64_SVE_F16MM = 1ULL << 37,
+ ARM_HWCAP_A64_SVE_ELTPERM = 1ULL << 38,
+ ARM_HWCAP_A64_SVE_AES2 = 1ULL << 39,
+ ARM_HWCAP_A64_SVE_BFSCALE = 1ULL << 40,
+ ARM_HWCAP_A64_SVE2P2 = 1ULL << 41,
+ ARM_HWCAP_A64_SME2P2 = 1ULL << 42,
+ ARM_HWCAP_A64_SME_SBITPERM = 1ULL << 43,
+ ARM_HWCAP_A64_SME_AES = 1ULL << 44,
+ ARM_HWCAP_A64_SME_SFEXPA = 1ULL << 45,
+ ARM_HWCAP_A64_SME_STMOP = 1ULL << 46,
+ ARM_HWCAP_A64_SME_SMOP4 = 1ULL << 47,
ARM_HWCAP2_A64_DCPODP = 1 << 0,
ARM_HWCAP2_A64_SVE2 = 1 << 1,
@@ -798,6 +814,25 @@ enum {
ARM_HWCAP2_A64_SME_F16F16 = 1ULL << 42,
ARM_HWCAP2_A64_MOPS = 1ULL << 43,
ARM_HWCAP2_A64_HBC = 1ULL << 44,
+ ARM_HWCAP2_A64_SVE_B16B16 = 1ULL << 45,
+ ARM_HWCAP2_A64_LRCPC3 = 1ULL << 46,
+ ARM_HWCAP2_A64_LSE128 = 1ULL << 47,
+ ARM_HWCAP2_A64_FPMR = 1ULL << 48,
+ ARM_HWCAP2_A64_LUT = 1ULL << 49,
+ ARM_HWCAP2_A64_FAMINMAX = 1ULL << 50,
+ ARM_HWCAP2_A64_F8CVT = 1ULL << 51,
+ ARM_HWCAP2_A64_F8FMA = 1ULL << 52,
+ ARM_HWCAP2_A64_F8DP4 = 1ULL << 53,
+ ARM_HWCAP2_A64_F8DP2 = 1ULL << 54,
+ ARM_HWCAP2_A64_F8E4M3 = 1ULL << 55,
+ ARM_HWCAP2_A64_F8E5M2 = 1ULL << 56,
+ ARM_HWCAP2_A64_SME_LUTV2 = 1ULL << 57,
+ ARM_HWCAP2_A64_SME_F8F16 = 1ULL << 58,
+ ARM_HWCAP2_A64_SME_F8F32 = 1ULL << 59,
+ ARM_HWCAP2_A64_SME_SF8FMA = 1ULL << 60,
+ ARM_HWCAP2_A64_SME_SF8DP4 = 1ULL << 61,
+ ARM_HWCAP2_A64_SME_SF8DP2 = 1ULL << 62,
+ ARM_HWCAP2_A64_POE = 1ULL << 63,
};
#define ELF_HWCAP get_elf_hwcap()
@@ -880,13 +915,21 @@ uint64_t get_elf_hwcap2(void)
GET_FEATURE_ID(aa64_sme_fa64, ARM_HWCAP2_A64_SME_FA64);
GET_FEATURE_ID(aa64_hbc, ARM_HWCAP2_A64_HBC);
GET_FEATURE_ID(aa64_mops, ARM_HWCAP2_A64_MOPS);
+ GET_FEATURE_ID(aa64_sve2p1, ARM_HWCAP2_A64_SVE2P1);
+ GET_FEATURE_ID(aa64_sme2, (ARM_HWCAP2_A64_SME2 |
+ ARM_HWCAP2_A64_SME_I16I32 |
+ ARM_HWCAP2_A64_SME_BI32I32));
+ GET_FEATURE_ID(aa64_sme2p1, ARM_HWCAP2_A64_SME2P1);
+ GET_FEATURE_ID(aa64_sme_b16b16, ARM_HWCAP2_A64_SME_B16B16);
+ GET_FEATURE_ID(aa64_sme_f16f16, ARM_HWCAP2_A64_SME_F16F16);
+ GET_FEATURE_ID(aa64_sve_b16b16, ARM_HWCAP2_A64_SVE_B16B16);
return hwcaps;
}
const char *elf_hwcap_str(uint32_t bit)
{
- static const char *hwcap_str[] = {
+ static const char * const hwcap_str[] = {
[__builtin_ctz(ARM_HWCAP_A64_FP )] = "fp",
[__builtin_ctz(ARM_HWCAP_A64_ASIMD )] = "asimd",
[__builtin_ctz(ARM_HWCAP_A64_EVTSTRM )] = "evtstrm",
@@ -919,6 +962,22 @@ const char *elf_hwcap_str(uint32_t bit)
[__builtin_ctz(ARM_HWCAP_A64_SB )] = "sb",
[__builtin_ctz(ARM_HWCAP_A64_PACA )] = "paca",
[__builtin_ctz(ARM_HWCAP_A64_PACG )] = "pacg",
+ [__builtin_ctzll(ARM_HWCAP_A64_GCS )] = "gcs",
+ [__builtin_ctzll(ARM_HWCAP_A64_CMPBR )] = "cmpbr",
+ [__builtin_ctzll(ARM_HWCAP_A64_FPRCVT)] = "fprcvt",
+ [__builtin_ctzll(ARM_HWCAP_A64_F8MM8 )] = "f8mm8",
+ [__builtin_ctzll(ARM_HWCAP_A64_F8MM4 )] = "f8mm4",
+ [__builtin_ctzll(ARM_HWCAP_A64_SVE_F16MM)] = "svef16mm",
+ [__builtin_ctzll(ARM_HWCAP_A64_SVE_ELTPERM)] = "sveeltperm",
+ [__builtin_ctzll(ARM_HWCAP_A64_SVE_AES2)] = "sveaes2",
+ [__builtin_ctzll(ARM_HWCAP_A64_SVE_BFSCALE)] = "svebfscale",
+ [__builtin_ctzll(ARM_HWCAP_A64_SVE2P2)] = "sve2p2",
+ [__builtin_ctzll(ARM_HWCAP_A64_SME2P2)] = "sme2p2",
+ [__builtin_ctzll(ARM_HWCAP_A64_SME_SBITPERM)] = "smesbitperm",
+ [__builtin_ctzll(ARM_HWCAP_A64_SME_AES)] = "smeaes",
+ [__builtin_ctzll(ARM_HWCAP_A64_SME_SFEXPA)] = "smesfexpa",
+ [__builtin_ctzll(ARM_HWCAP_A64_SME_STMOP)] = "smestmop",
+ [__builtin_ctzll(ARM_HWCAP_A64_SME_SMOP4)] = "smesmop4",
};
return bit < ARRAY_SIZE(hwcap_str) ? hwcap_str[bit] : NULL;
@@ -926,7 +985,7 @@ const char *elf_hwcap_str(uint32_t bit)
const char *elf_hwcap2_str(uint32_t bit)
{
- static const char *hwcap_str[] = {
+ static const char * const hwcap_str[] = {
[__builtin_ctz(ARM_HWCAP2_A64_DCPODP )] = "dcpodp",
[__builtin_ctz(ARM_HWCAP2_A64_SVE2 )] = "sve2",
[__builtin_ctz(ARM_HWCAP2_A64_SVEAES )] = "sveaes",
@@ -972,6 +1031,24 @@ const char *elf_hwcap2_str(uint32_t bit)
[__builtin_ctzll(ARM_HWCAP2_A64_SME_F16F16 )] = "smef16f16",
[__builtin_ctzll(ARM_HWCAP2_A64_MOPS )] = "mops",
[__builtin_ctzll(ARM_HWCAP2_A64_HBC )] = "hbc",
+ [__builtin_ctzll(ARM_HWCAP2_A64_SVE_B16B16 )] = "sveb16b16",
+ [__builtin_ctzll(ARM_HWCAP2_A64_LRCPC3 )] = "lrcpc3",
+ [__builtin_ctzll(ARM_HWCAP2_A64_LSE128 )] = "lse128",
+ [__builtin_ctzll(ARM_HWCAP2_A64_FPMR )] = "fpmr",
+ [__builtin_ctzll(ARM_HWCAP2_A64_LUT )] = "lut",
+ [__builtin_ctzll(ARM_HWCAP2_A64_FAMINMAX )] = "faminmax",
+ [__builtin_ctzll(ARM_HWCAP2_A64_F8CVT )] = "f8cvt",
+ [__builtin_ctzll(ARM_HWCAP2_A64_F8FMA )] = "f8fma",
+ [__builtin_ctzll(ARM_HWCAP2_A64_F8DP4 )] = "f8dp4",
+ [__builtin_ctzll(ARM_HWCAP2_A64_F8DP2 )] = "f8dp2",
+ [__builtin_ctzll(ARM_HWCAP2_A64_F8E4M3 )] = "f8e4m3",
+ [__builtin_ctzll(ARM_HWCAP2_A64_F8E5M2 )] = "f8e5m2",
+ [__builtin_ctzll(ARM_HWCAP2_A64_SME_LUTV2 )] = "smelutv2",
+ [__builtin_ctzll(ARM_HWCAP2_A64_SME_F8F16 )] = "smef8f16",
+ [__builtin_ctzll(ARM_HWCAP2_A64_SME_F8F32 )] = "smef8f32",
+ [__builtin_ctzll(ARM_HWCAP2_A64_SME_SF8DP4 )] = "smesf8dp4",
+ [__builtin_ctzll(ARM_HWCAP2_A64_SME_SF8DP2 )] = "smesf8dp2",
+ [__builtin_ctzll(ARM_HWCAP2_A64_POE )] = "poe",
};
return bit < ARRAY_SIZE(hwcap_str) ? hwcap_str[bit] : NULL;
diff --git a/linux-user/fd-trans.h b/linux-user/fd-trans.h
index 910faaf..e14f960 100644
--- a/linux-user/fd-trans.h
+++ b/linux-user/fd-trans.h
@@ -36,6 +36,16 @@ static inline void fd_trans_init(void)
qemu_mutex_init(&target_fd_trans_lock);
}
+static inline void fd_trans_prefork(void)
+{
+ qemu_mutex_lock(&target_fd_trans_lock);
+}
+
+static inline void fd_trans_postfork(void)
+{
+ qemu_mutex_unlock(&target_fd_trans_lock);
+}
+
static inline TargetFdDataFunc fd_trans_target_to_host_data(int fd)
{
if (fd < 0) {
diff --git a/linux-user/gen-vdso.c b/linux-user/gen-vdso.c
index 721f38d..aeaa927 100644
--- a/linux-user/gen-vdso.c
+++ b/linux-user/gen-vdso.c
@@ -56,13 +56,14 @@ static unsigned rt_sigreturn_addr;
int main(int argc, char **argv)
{
- FILE *inf, *outf;
+ FILE *inf = NULL, *outf = NULL;
long total_len;
const char *prefix = "vdso";
const char *inf_name;
const char *outf_name = NULL;
- unsigned char *buf;
+ unsigned char *buf = NULL;
bool need_bswap;
+ int ret = EXIT_FAILURE;
while (1) {
int opt = getopt(argc, argv, "o:p:r:s:");
@@ -112,9 +113,21 @@ int main(int argc, char **argv)
* We expect the vdso to be small, on the order of one page,
* therefore we do not expect a partial read.
*/
- fseek(inf, 0, SEEK_END);
+ if (fseek(inf, 0, SEEK_END) < 0) {
+ goto perror_inf;
+ }
total_len = ftell(inf);
- fseek(inf, 0, SEEK_SET);
+ if (total_len < 0) {
+ goto perror_inf;
+ }
+ if (fseek(inf, 0, SEEK_SET) < 0) {
+ goto perror_inf;
+ }
+
+ if (total_len < EI_NIDENT) {
+ fprintf(stderr, "%s: file too small (truncated?)\n", inf_name);
+ return EXIT_FAILURE;
+ }
buf = malloc(total_len);
if (buf == NULL) {
@@ -129,7 +142,6 @@ int main(int argc, char **argv)
fprintf(stderr, "%s: incomplete read\n", inf_name);
return EXIT_FAILURE;
}
- fclose(inf);
/*
* Identify which elf flavor we're processing.
@@ -205,19 +217,24 @@ int main(int argc, char **argv)
fprintf(outf, " .rt_sigreturn_ofs = 0x%x,\n", rt_sigreturn_addr);
fprintf(outf, "};\n");
- /*
- * Everything should have gone well.
- */
- if (fclose(outf)) {
- goto perror_outf;
+ ret = EXIT_SUCCESS;
+
+ cleanup:
+ free(buf);
+
+ if (outf && fclose(outf) != 0) {
+ ret = EXIT_FAILURE;
+ }
+ if (inf && fclose(inf) != 0) {
+ ret = EXIT_FAILURE;
}
- return EXIT_SUCCESS;
+ return ret;
perror_inf:
perror(inf_name);
- return EXIT_FAILURE;
+ goto cleanup;
perror_outf:
perror(outf_name);
- return EXIT_FAILURE;
+ goto cleanup;
}
diff --git a/linux-user/hppa/cpu_loop.c b/linux-user/hppa/cpu_loop.c
index 890e758..9abaad5 100644
--- a/linux-user/hppa/cpu_loop.c
+++ b/linux-user/hppa/cpu_loop.c
@@ -112,7 +112,7 @@ static abi_ulong hppa_lws(CPUHPPAState *env)
void cpu_loop(CPUHPPAState *env)
{
CPUState *cs = env_cpu(env);
- abi_ulong ret;
+ abi_ulong ret, si_code = 0;
int trapnr;
while (1) {
@@ -169,7 +169,15 @@ void cpu_loop(CPUHPPAState *env)
force_sig_fault(TARGET_SIGFPE, TARGET_FPE_CONDTRAP, env->iaoq_f);
break;
case EXCP_ASSIST:
- force_sig_fault(TARGET_SIGFPE, 0, env->iaoq_f);
+ #define set_si_code(mask, val) \
+ if (env->fr[0] & mask) { si_code = val; }
+ set_si_code(R_FPSR_FLG_I_MASK, TARGET_FPE_FLTRES);
+ set_si_code(R_FPSR_FLG_U_MASK, TARGET_FPE_FLTUND);
+ set_si_code(R_FPSR_FLG_O_MASK, TARGET_FPE_FLTOVF);
+ set_si_code(R_FPSR_FLG_Z_MASK, TARGET_FPE_FLTDIV);
+ set_si_code(R_FPSR_FLG_V_MASK, TARGET_FPE_FLTINV);
+ #undef set_si_code
+ force_sig_fault(TARGET_SIGFPE, si_code, env->iaoq_f);
break;
case EXCP_BREAK:
force_sig_fault(TARGET_SIGTRAP, TARGET_TRAP_BRKPT, env->iaoq_f);
diff --git a/linux-user/main.c b/linux-user/main.c
index 5ac5b55..68972f0 100644
--- a/linux-user/main.c
+++ b/linux-user/main.c
@@ -42,6 +42,7 @@
#include "user/page-protection.h"
#include "exec/gdbstub.h"
#include "gdbstub/user.h"
+#include "accel/accel-ops.h"
#include "tcg/startup.h"
#include "qemu/timer.h"
#include "qemu/envlist.h"
@@ -149,12 +150,14 @@ void fork_start(void)
cpu_list_lock();
qemu_plugin_user_prefork_lock();
gdbserver_fork_start();
+ fd_trans_prefork();
}
void fork_end(pid_t pid)
{
bool child = pid == 0;
+ fd_trans_postfork();
qemu_plugin_user_postfork(child);
mmap_fork_end(child);
if (child) {
@@ -820,7 +823,7 @@ int main(int argc, char **argv, char **envp)
opt_one_insn_per_tb, &error_abort);
object_property_set_int(OBJECT(accel), "tb-size",
opt_tb_size, &error_abort);
- ac->init_machine(NULL);
+ ac->init_machine(accel, NULL);
}
/*
diff --git a/linux-user/meson.build b/linux-user/meson.build
index f47a213..efca843 100644
--- a/linux-user/meson.build
+++ b/linux-user/meson.build
@@ -27,7 +27,10 @@ linux_user_ss.add(libdw)
linux_user_ss.add(when: 'TARGET_HAS_BFLT', if_true: files('flatload.c'))
linux_user_ss.add(when: 'TARGET_I386', if_true: files('vm86.c'))
linux_user_ss.add(when: 'CONFIG_ARM_COMPATIBLE_SEMIHOSTING', if_true: files('semihost.c'))
-linux_user_ss.add(when: 'CONFIG_TCG_PLUGINS', if_true: files('plugin-api.c'))
+
+if get_option('plugins')
+ linux_user_ss.add(files('plugin-api.c'))
+endif
syscall_nr_generators = {}
diff --git a/linux-user/mips/target_signal.h b/linux-user/mips/target_signal.h
index fa542c1..4481426 100644
--- a/linux-user/mips/target_signal.h
+++ b/linux-user/mips/target_signal.h
@@ -64,7 +64,6 @@ typedef struct target_sigaltstack {
#define TARGET_SA_NODEFER 0x40000000
#define TARGET_SA_RESTART 0x10000000
#define TARGET_SA_RESETHAND 0x80000000
-#define TARGET_SA_RESTORER 0x04000000 /* Only for O32 */
#define TARGET_MINSIGSTKSZ 2048
diff --git a/linux-user/mmap.c b/linux-user/mmap.c
index f88a80c..002e1e6 100644
--- a/linux-user/mmap.c
+++ b/linux-user/mmap.c
@@ -645,7 +645,7 @@ static abi_long mmap_h_eq_g(abi_ulong start, abi_ulong len,
*
* However, this case is rather common with executable images,
* so the workaround is important for even trivial tests, whereas
- * the mmap of of a file being extended is less common.
+ * the mmap of a file being extended is less common.
*/
static abi_long mmap_h_lt_g(abi_ulong start, abi_ulong len, int host_prot,
int mmap_flags, int page_flags, int fd,
diff --git a/linux-user/plugin-api.c b/linux-user/plugin-api.c
index 66755df..8d6fbb6 100644
--- a/linux-user/plugin-api.c
+++ b/linux-user/plugin-api.c
@@ -12,4 +12,5 @@
#include "qemu/osdep.h"
#include "qemu.h"
+#include "loader.h"
#include "common-user/plugin-api.c.inc"
diff --git a/linux-user/strace.list b/linux-user/strace.list
index fdf94ef..ab81835 100644
--- a/linux-user/strace.list
+++ b/linux-user/strace.list
@@ -1716,3 +1716,6 @@
{ TARGET_NR_clock_gettime64, "clock_gettime64" , NULL, print_clock_gettime64,
print_syscall_ret_clock_gettime64 },
#endif
+#ifdef TARGET_NR_riscv_hwprobe
+{ TARGET_NR_riscv_hwprobe, "riscv_hwprobe" , "%s(%p,%d,%d,%d,%d,%d)", NULL, NULL },
+#endif
diff --git a/linux-user/syscall.c b/linux-user/syscall.c
index 23b901b..91360a0 100644
--- a/linux-user/syscall.c
+++ b/linux-user/syscall.c
@@ -790,6 +790,10 @@ safe_syscall6(ssize_t, copy_file_range, int, infd, loff_t *, pinoff,
int, outfd, loff_t *, poutoff, size_t, length,
unsigned int, flags)
#endif
+#if defined(TARGET_NR_fchmodat2) && defined(__NR_fchmodat2)
+safe_syscall4(int, fchmodat2, int, dfd, const char *, filename,
+ unsigned short, mode, unsigned int, flags)
+#endif
/* We do ioctl like this rather than via safe_syscall3 to preserve the
* "third argument might be integer or pointer or not present" behaviour of
@@ -6743,10 +6747,9 @@ static int do_fork(CPUArchState *env, unsigned int flags, abi_ulong newsp,
int pid_child = ret;
pid_fd = pidfd_open(pid_child, 0);
if (pid_fd >= 0) {
- fcntl(pid_fd, F_SETFD, fcntl(pid_fd, F_GETFL)
- | FD_CLOEXEC);
+ qemu_set_cloexec(pid_fd);
} else {
- pid_fd = 0;
+ pid_fd = 0;
}
#endif
put_user_u32(pid_fd, parent_tidptr);
@@ -8235,6 +8238,9 @@ static int open_self_stat(CPUArchState *cpu_env, int fd)
} else if (i == 3) {
/* ppid */
g_string_printf(buf, FMT_pid " ", getppid());
+ } else if (i == 4) {
+ /* pgid */
+ g_string_printf(buf, FMT_pid " ", getpgrp());
} else if (i == 19) {
/* num_threads */
int cpus = 0;
@@ -10711,6 +10717,15 @@ static abi_long do_syscall1(CPUArchState *cpu_env, int num, abi_long arg1,
unlock_user(p, arg2, 0);
return ret;
#endif
+#if defined(TARGET_NR_fchmodat2) && defined(__NR_fchmodat2)
+ case TARGET_NR_fchmodat2:
+ if (!(p = lock_user_string(arg2))) {
+ return -TARGET_EFAULT;
+ }
+ ret = get_errno(safe_fchmodat2(arg1, p, arg3, arg4));
+ unlock_user(p, arg2, 0);
+ return ret;
+#endif
case TARGET_NR_getpriority:
/* Note that negative values are valid for getpriority, so we must
differentiate based on errno settings. */
@@ -11627,10 +11642,14 @@ static abi_long do_syscall1(CPUArchState *cpu_env, int num, abi_long arg1,
case TARGET_NR_nanosleep:
{
struct timespec req, rem;
- target_to_host_timespec(&req, arg1);
+ if (target_to_host_timespec(&req, arg1)) {
+ return -TARGET_EFAULT;
+ }
ret = get_errno(safe_nanosleep(&req, &rem));
if (is_error(ret) && arg2) {
- host_to_target_timespec(arg2, &rem);
+ if (host_to_target_timespec(arg2, &rem)) {
+ return -TARGET_EFAULT;
+ }
}
}
return ret;
diff --git a/linux-user/syscall_defs.h b/linux-user/syscall_defs.h
index 5d22759..df26a2d 100644
--- a/linux-user/syscall_defs.h
+++ b/linux-user/syscall_defs.h
@@ -515,10 +515,6 @@ struct target_sigaction {
abi_ulong _sa_handler;
#endif
target_sigset_t sa_mask;
-#ifdef TARGET_ARCH_HAS_SA_RESTORER
- /* ??? This is always present, but ignored unless O32. */
- abi_ulong sa_restorer;
-#endif
};
#else
struct target_old_sigaction {