Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
Merge tag 'linux-user-for-8.1-pull-request' of https://github.com/viv…
…ier/qemu into staging

linux-user pull request 20230512-v2

add open_tree(), move_mount()
add /proc/cpuinfo for riscv
fixes and cleanup

# -----BEGIN PGP SIGNATURE-----
#
# iQJGBAABCAAwFiEEzS913cjjpNwuT1Fz8ww4vT8vvjwFAmRh7bsSHGxhdXJlbnRA
# dml2aWVyLmV1AAoJEPMMOL0/L748EBMP/jX55NLMxEjnWMDVmK0dRBAjpN51ZBl3
# vWwsNp1XVW2GmSqBwAxAyOf4YxbqYjZzep1+SDVMoFm6JiTDBzgvyeeiVJ2wJ7HS
# HIyWSSIJ+IQbvjINl6W4kk1CwehnMoDJ1Uaj1SPkLYgeqtR+RxqQkCmk+sOuEKK3
# R5gVynj6bajWTCYrJMyxsG/P/2z5yfiZ3mhQXqprqHvcEU5LaTvoYZV6pF9iDgCa
# JE21Y6Vr/do5BnoK5Pr39taE5INM8dAsBCwuFg8tNhtTuxw4gj3bnzyZex3NCDDA
# dep6wS9QeOchhpY7YgL22WtQPE5HkwIqIHc8qcNJa41Zmv0o9CPX047ee3juF3+j
# G7Mmmih85QEpA7U8pncP+HcAweRYojS5IeBpqaPr8RRwmJRyQFu8EHyjsYaZ+msQ
# aSY/6j5B+F8nXyrxEOT1T3p4b4eCInsxrC1JA+d5ThDZN4mKl5LBLQEic1cJarJW
# 71m2cSSTN48besI9AJMJp4YOcpyZv5l20q+Hmp304BuIAM4Zn2HmxO2vxubpEjXT
# jRitrK+1nfbmdNXYPGSnHw9k9SEonQgR+Q0gU5/W/Lbwte8n/oxiwE/9Bqy8D+ys
# HmZD1m9fUCbBTQOp8SXdXYPky0QKlL6BdkExaCxGdfgq7GwxyvBlU9CgFgEXceZq
# Pnocsi3jw6AW
# =ctJG
# -----END PGP SIGNATURE-----
# gpg: Signature made Mon 15 May 2023 01:30:51 AM PDT
# gpg:                using RSA key CD2F75DDC8E3A4DC2E4F5173F30C38BD3F2FBE3C
# gpg:                issuer "laurent@vivier.eu"
# gpg: Good signature from "Laurent Vivier <lvivier@redhat.com>" [undefined]
# gpg:                 aka "Laurent Vivier <laurent@vivier.eu>" [undefined]
# gpg:                 aka "Laurent Vivier (Red Hat) <lvivier@redhat.com>" [undefined]
# gpg: WARNING: This key is not certified with a trusted signature!
# gpg:          There is no indication that the signature belongs to the owner.
# Primary key fingerprint: CD2F 75DD C8E3 A4DC 2E4F  5173 F30C 38BD 3F2F BE3C

* tag 'linux-user-for-8.1-pull-request' of https://github.com/vivier/qemu:
  linux-user: fix getgroups/setgroups allocations
  linux-user: Fix mips fp64 executables loading
  linux-user: Don't require PROT_READ for mincore
  linux-user: Add new flag VERIFY_NONE
  linux-user/main: Use list_cpus() instead of cpu_list()
  linux-user: Add open_tree() syscall
  linux-user: Add move_mount() syscall
  linux-user: report ENOTTY for unknown ioctls
  linux-user: Emulate /proc/cpuinfo output for riscv

Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
  • Loading branch information
rth7680 committed May 15, 2023
2 parents 8844bb8 + 015ebc4 commit 67de9eb
Show file tree
Hide file tree
Showing 6 changed files with 207 additions and 42 deletions.
5 changes: 1 addition & 4 deletions linux-user/main.c
Expand Up @@ -359,10 +359,7 @@ static void handle_arg_cpu(const char *arg)
{
cpu_model = strdup(arg);
if (cpu_model == NULL || is_help_option(cpu_model)) {
/* XXX: implement xxx_cpu_list for targets that still miss it */
#if defined(cpu_list)
cpu_list();
#endif
list_cpus();
exit(EXIT_FAILURE);
}
}
Expand Down
5 changes: 4 additions & 1 deletion linux-user/mips/cpu_loop.c
Expand Up @@ -290,7 +290,10 @@ void target_cpu_copy_regs(CPUArchState *env, struct target_pt_regs *regs)
env->CP0_Status |= (1 << CP0St_FR);
env->hflags |= MIPS_HFLAG_F64;
}
} else if (!prog_req.fre && !prog_req.frdefault &&
} else if (prog_req.fr1) {
env->CP0_Status |= (1 << CP0St_FR);
env->hflags |= MIPS_HFLAG_F64;
} else if (!prog_req.fre && !prog_req.frdefault &&
!prog_req.fr1 && !prog_req.single && !prog_req.soft) {
fprintf(stderr, "qemu: Can't find a matching FPU mode\n");
exit(1);
Expand Down
1 change: 1 addition & 0 deletions linux-user/qemu.h
Expand Up @@ -168,6 +168,7 @@ abi_long do_brk(abi_ulong new_brk);

/* user access */

#define VERIFY_NONE 0
#define VERIFY_READ PAGE_READ
#define VERIFY_WRITE (PAGE_READ | PAGE_WRITE)

Expand Down
207 changes: 170 additions & 37 deletions linux-user/syscall.c
Expand Up @@ -5747,7 +5747,7 @@ static abi_long do_ioctl(int fd, int cmd, abi_long arg)
if (ie->target_cmd == 0) {
qemu_log_mask(
LOG_UNIMP, "Unsupported ioctl: cmd=0x%04lx\n", (long)cmd);
return -TARGET_ENOSYS;
return -TARGET_ENOTTY;
}
if (ie->target_cmd == cmd)
break;
Expand All @@ -5759,7 +5759,7 @@ static abi_long do_ioctl(int fd, int cmd, abi_long arg)
} else if (!ie->host_cmd) {
/* Some architectures define BSD ioctls in their headers
that are not implemented in Linux. */
return -TARGET_ENOSYS;
return -TARGET_ENOTTY;
}

switch(arg_type[0]) {
Expand Down Expand Up @@ -5817,7 +5817,7 @@ static abi_long do_ioctl(int fd, int cmd, abi_long arg)
qemu_log_mask(LOG_UNIMP,
"Unsupported ioctl type: cmd=0x%04lx type=%d\n",
(long)cmd, arg_type[0]);
ret = -TARGET_ENOSYS;
ret = -TARGET_ENOTTY;
break;
}
return ret;
Expand Down Expand Up @@ -8231,7 +8231,8 @@ void target_exception_dump(CPUArchState *env, const char *fmt, int code)
}

#if HOST_BIG_ENDIAN != TARGET_BIG_ENDIAN || \
defined(TARGET_SPARC) || defined(TARGET_M68K) || defined(TARGET_HPPA)
defined(TARGET_SPARC) || defined(TARGET_M68K) || defined(TARGET_HPPA) || \
defined(TARGET_RISCV)
static int is_proc(const char *filename, const char *entry)
{
return strcmp(filename, entry) == 0;
Expand Down Expand Up @@ -8309,6 +8310,35 @@ static int open_cpuinfo(CPUArchState *cpu_env, int fd)
}
#endif

#if defined(TARGET_RISCV)
static int open_cpuinfo(CPUArchState *cpu_env, int fd)
{
int i;
int num_cpus = sysconf(_SC_NPROCESSORS_ONLN);
RISCVCPU *cpu = env_archcpu(cpu_env);
const RISCVCPUConfig *cfg = riscv_cpu_cfg((CPURISCVState *) cpu_env);
char *isa_string = riscv_isa_string(cpu);
const char *mmu;

if (cfg->mmu) {
mmu = (cpu_env->xl == MXL_RV32) ? "sv32" : "sv48";
} else {
mmu = "none";
}

for (i = 0; i < num_cpus; i++) {
dprintf(fd, "processor\t: %d\n", i);
dprintf(fd, "hart\t\t: %d\n", i);
dprintf(fd, "isa\t\t: %s\n", isa_string);
dprintf(fd, "mmu\t\t: %s\n", mmu);
dprintf(fd, "uarch\t\t: qemu\n\n");
}

g_free(isa_string);
return 0;
}
#endif

#if defined(TARGET_M68K)
static int open_hardware(CPUArchState *cpu_env, int fd)
{
Expand All @@ -8333,7 +8363,7 @@ static int do_openat(CPUArchState *cpu_env, int dirfd, const char *pathname, int
#if HOST_BIG_ENDIAN != TARGET_BIG_ENDIAN
{ "/proc/net/route", open_net_route, is_proc },
#endif
#if defined(TARGET_SPARC) || defined(TARGET_HPPA)
#if defined(TARGET_SPARC) || defined(TARGET_HPPA) || defined(TARGET_RISCV)
{ "/proc/cpuinfo", open_cpuinfo, is_proc },
#endif
#if defined(TARGET_M68K)
Expand Down Expand Up @@ -8746,6 +8776,18 @@ static int do_getdents64(abi_long dirfd, abi_long arg2, abi_long count)
_syscall2(int, pivot_root, const char *, new_root, const char *, put_old)
#endif

#if defined(TARGET_NR_open_tree) && defined(__NR_open_tree)
#define __NR_sys_open_tree __NR_open_tree
_syscall3(int, sys_open_tree, int, __dfd, const char *, __filename,
unsigned int, __flags)
#endif

#if defined(TARGET_NR_move_mount) && defined(__NR_move_mount)
#define __NR_sys_move_mount __NR_move_mount
_syscall5(int, sys_move_mount, int, __from_dfd, const char *, __from_pathname,
int, __to_dfd, const char *, __to_pathname, unsigned int, flag)
#endif

/* This is an internal helper for do_syscall so that it is easier
* to have a single return point, so that actions, such as logging
* of syscall results, can be performed.
Expand Down Expand Up @@ -9139,6 +9181,60 @@ static abi_long do_syscall1(CPUArchState *cpu_env, int num, abi_long arg1,
unlock_user(p, arg1, 0);
return ret;
#endif
#if defined(TARGET_NR_move_mount) && defined(__NR_move_mount)
case TARGET_NR_move_mount:
{
void *p2, *p4;

if (!arg2 || !arg4) {
return -TARGET_EFAULT;
}

p2 = lock_user_string(arg2);
if (!p2) {
return -TARGET_EFAULT;
}

p4 = lock_user_string(arg4);
if (!p4) {
unlock_user(p2, arg2, 0);
return -TARGET_EFAULT;
}
ret = get_errno(sys_move_mount(arg1, p2, arg3, p4, arg5));

unlock_user(p2, arg2, 0);
unlock_user(p4, arg4, 0);

return ret;
}
#endif
#if defined(TARGET_NR_open_tree) && defined(__NR_open_tree)
case TARGET_NR_open_tree:
{
void *p2;
int host_flags;

if (!arg2) {
return -TARGET_EFAULT;
}

p2 = lock_user_string(arg2);
if (!p2) {
return -TARGET_EFAULT;
}

host_flags = arg3 & ~TARGET_O_CLOEXEC;
if (arg3 & TARGET_O_CLOEXEC) {
host_flags |= O_CLOEXEC;
}

ret = get_errno(sys_open_tree(arg1, p2, host_flags));

unlock_user(p2, arg2, 0);

return ret;
}
#endif
#ifdef TARGET_NR_stime /* not on alpha */
case TARGET_NR_stime:
{
Expand Down Expand Up @@ -11475,39 +11571,58 @@ static abi_long do_syscall1(CPUArchState *cpu_env, int num, abi_long arg1,
{
int gidsetsize = arg1;
target_id *target_grouplist;
gid_t *grouplist;
g_autofree gid_t *grouplist = NULL;
int i;

grouplist = alloca(gidsetsize * sizeof(gid_t));
if (gidsetsize > NGROUPS_MAX) {
return -TARGET_EINVAL;
}
if (gidsetsize > 0) {
grouplist = g_try_new(gid_t, gidsetsize);
if (!grouplist) {
return -TARGET_ENOMEM;
}
}
ret = get_errno(getgroups(gidsetsize, grouplist));
if (gidsetsize == 0)
return ret;
if (!is_error(ret)) {
target_grouplist = lock_user(VERIFY_WRITE, arg2, gidsetsize * sizeof(target_id), 0);
if (!target_grouplist)
if (!is_error(ret) && gidsetsize > 0) {
target_grouplist = lock_user(VERIFY_WRITE, arg2,
gidsetsize * sizeof(target_id), 0);
if (!target_grouplist) {
return -TARGET_EFAULT;
for(i = 0;i < ret; i++)
}
for (i = 0; i < ret; i++) {
target_grouplist[i] = tswapid(high2lowgid(grouplist[i]));
unlock_user(target_grouplist, arg2, gidsetsize * sizeof(target_id));
}
unlock_user(target_grouplist, arg2,
gidsetsize * sizeof(target_id));
}
return ret;
}
return ret;
case TARGET_NR_setgroups:
{
int gidsetsize = arg1;
target_id *target_grouplist;
gid_t *grouplist = NULL;
g_autofree gid_t *grouplist = NULL;
int i;
if (gidsetsize) {
grouplist = alloca(gidsetsize * sizeof(gid_t));
target_grouplist = lock_user(VERIFY_READ, arg2, gidsetsize * sizeof(target_id), 1);

if (gidsetsize > NGROUPS_MAX || gidsetsize < 0) {
return -TARGET_EINVAL;
}
if (gidsetsize > 0) {
grouplist = g_try_new(gid_t, gidsetsize);
if (!grouplist) {
return -TARGET_ENOMEM;
}
target_grouplist = lock_user(VERIFY_READ, arg2,
gidsetsize * sizeof(target_id), 1);
if (!target_grouplist) {
return -TARGET_EFAULT;
}
for (i = 0; i < gidsetsize; i++) {
grouplist[i] = low2highgid(tswapid(target_grouplist[i]));
}
unlock_user(target_grouplist, arg2, 0);
unlock_user(target_grouplist, arg2,
gidsetsize * sizeof(target_id));
}
return get_errno(setgroups(gidsetsize, grouplist));
}
Expand Down Expand Up @@ -11792,41 +11907,59 @@ static abi_long do_syscall1(CPUArchState *cpu_env, int num, abi_long arg1,
{
int gidsetsize = arg1;
uint32_t *target_grouplist;
gid_t *grouplist;
g_autofree gid_t *grouplist = NULL;
int i;

grouplist = alloca(gidsetsize * sizeof(gid_t));
if (gidsetsize > NGROUPS_MAX) {
return -TARGET_EINVAL;
}
if (gidsetsize > 0) {
grouplist = g_try_new(gid_t, gidsetsize);
if (!grouplist) {
return -TARGET_ENOMEM;
}
}
ret = get_errno(getgroups(gidsetsize, grouplist));
if (gidsetsize == 0)
return ret;
if (!is_error(ret)) {
target_grouplist = lock_user(VERIFY_WRITE, arg2, gidsetsize * 4, 0);
if (!is_error(ret) && gidsetsize > 0) {
target_grouplist = lock_user(VERIFY_WRITE, arg2,
gidsetsize * 4, 0);
if (!target_grouplist) {
return -TARGET_EFAULT;
}
for(i = 0;i < ret; i++)
for (i = 0; i < ret; i++) {
target_grouplist[i] = tswap32(grouplist[i]);
}
unlock_user(target_grouplist, arg2, gidsetsize * 4);
}
return ret;
}
return ret;
#endif
#ifdef TARGET_NR_setgroups32
case TARGET_NR_setgroups32:
{
int gidsetsize = arg1;
uint32_t *target_grouplist;
gid_t *grouplist;
g_autofree gid_t *grouplist = NULL;
int i;

grouplist = alloca(gidsetsize * sizeof(gid_t));
target_grouplist = lock_user(VERIFY_READ, arg2, gidsetsize * 4, 1);
if (!target_grouplist) {
return -TARGET_EFAULT;
if (gidsetsize > NGROUPS_MAX || gidsetsize < 0) {
return -TARGET_EINVAL;
}
if (gidsetsize > 0) {
grouplist = g_try_new(gid_t, gidsetsize);
if (!grouplist) {
return -TARGET_ENOMEM;
}
target_grouplist = lock_user(VERIFY_READ, arg2,
gidsetsize * 4, 1);
if (!target_grouplist) {
return -TARGET_EFAULT;
}
for (i = 0; i < gidsetsize; i++) {
grouplist[i] = tswap32(target_grouplist[i]);
}
unlock_user(target_grouplist, arg2, 0);
}
for(i = 0;i < gidsetsize; i++)
grouplist[i] = tswap32(target_grouplist[i]);
unlock_user(target_grouplist, arg2, 0);
return get_errno(setgroups(gidsetsize, grouplist));
}
#endif
Expand Down Expand Up @@ -11897,7 +12030,7 @@ static abi_long do_syscall1(CPUArchState *cpu_env, int num, abi_long arg1,
#ifdef TARGET_NR_mincore
case TARGET_NR_mincore:
{
void *a = lock_user(VERIFY_READ, arg1, arg2, 0);
void *a = lock_user(VERIFY_NONE, arg1, arg2, 0);
if (!a) {
return -TARGET_ENOMEM;
}
Expand Down
1 change: 1 addition & 0 deletions tests/tcg/riscv64/Makefile.target
Expand Up @@ -4,6 +4,7 @@
VPATH += $(SRC_PATH)/tests/tcg/riscv64
TESTS += test-div
TESTS += noexec
TESTS += cpuinfo

# Disable compressed instructions for test-noc
TESTS += test-noc
Expand Down
30 changes: 30 additions & 0 deletions tests/tcg/riscv64/cpuinfo.c
@@ -0,0 +1,30 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>

#define BUFFER_SIZE 1024

int main(void)
{
char buffer[BUFFER_SIZE];
FILE *fp = fopen("/proc/cpuinfo", "r");
assert(fp != NULL);

while (fgets(buffer, BUFFER_SIZE, fp) != NULL) {
if (strstr(buffer, "processor") != NULL) {
assert(strstr(buffer, "processor\t: ") == buffer);
} else if (strstr(buffer, "hart") != NULL) {
assert(strstr(buffer, "hart\t\t: ") == buffer);
} else if (strstr(buffer, "isa") != NULL) {
assert(strcmp(buffer, "isa\t\t: rv64imafdc_zicsr_zifencei\n") == 0);
} else if (strstr(buffer, "mmu") != NULL) {
assert(strcmp(buffer, "mmu\t\t: sv48\n") == 0);
} else if (strstr(buffer, "uarch") != NULL) {
assert(strcmp(buffer, "uarch\t\t: qemu\n") == 0);
}
}

fclose(fp);
return 0;
}

0 comments on commit 67de9eb

Please sign in to comment.