Update ppc64 feature and default CPU

next setsockops() options
 Improve "-L" option
 Another fix for 5.2-rc1 headers
 -----BEGIN PGP SIGNATURE-----
 
 iQJGBAABCAAwFiEEzS913cjjpNwuT1Fz8ww4vT8vvjwFAl0TYNgSHGxhdXJlbnRA
 dml2aWVyLmV1AAoJEPMMOL0/L748KaMP/3kj/OfTuTuDCp6WOvPXrqY7houUWYFs
 pp1fX72lm+zmRki0rQwzUqoZGaWl6MXkNc/dSTWclNXaeHgdvB8vIgju3f3HOfdq
 IP+T1U9XA0ERayAGwIzB38ivkaaXGdS96bbWOJ5SvmI8PWWSUJHmqDg/GMryUVOh
 xvIFtVMxMl8J30d8OC3T8T1CJs4WdGwtMUhKpixAXVI/CbaTcdgjgK1SlOow5odE
 o5yv7In1l+6FvzrPpPW2Nd/+YRAMffIiQgGQpZ6PhRtQqSc+/F5rwOAu6TGYovr8
 WV+fop09fSnwOPb9JgZkfamEKpQ9fVGr5Egn7ghWM7U8pAMa1j4Mcg+YMxEi97Vj
 jSFI5jZ0DETz1ec1ylkSxBV4Zoe/ERKr1f4I71PCRHg1+nQ9ZUb1iAiuDuHzFQVb
 TffncotU09UR51aSzVHILMR7o7airYjDx3M4W1IFoWVxkqCgGuWeWQc0bsNo0/pX
 yWf0okjGQ7svekgnk/sWEy5F7+0P/cMZu+dfrEppCIKVMkcrimYtPxEhrJwI7Rv7
 EGYAKH/lju06517KP4VFM5wuVOyxxDY5110x3Ny+PKwyeUdXsKGeee9aI9tu+uHw
 RsxQI5KBC/bXn1bnL6fJaevid6sBNlwFX4p56gKdiC4cCmCxvfAe6QhuMgbc6NZF
 bM42J/pWAw+3
 =mVPy
 -----END PGP SIGNATURE-----

Merge remote-tracking branch 'remotes/vivier2/tags/linux-user-for-4.1-pull-request' into staging

Update ppc64 feature and default CPU
next setsockops() options
Improve "-L" option
Another fix for 5.2-rc1 headers

# gpg: Signature made Wed 26 Jun 2019 13:11:04 BST
# gpg:                using RSA key CD2F75DDC8E3A4DC2E4F5173F30C38BD3F2FBE3C
# gpg:                issuer "laurent@vivier.eu"
# gpg: Good signature from "Laurent Vivier <lvivier@redhat.com>" [full]
# gpg:                 aka "Laurent Vivier <laurent@vivier.eu>" [full]
# gpg:                 aka "Laurent Vivier (Red Hat) <lvivier@redhat.com>" [full]
# Primary key fingerprint: CD2F 75DD C8E3 A4DC 2E4F  5173 F30C 38BD 3F2F BE3C

* remotes/vivier2/tags/linux-user-for-4.1-pull-request:
  linux-user: set default PPC64 CPU
  linux-user: update PPC64 HWCAP2 feature list
  linux-user: Add support for setsockopt() options IPV6_<ADD|DROP>_MEMBERSHIP
  linux-user: Add support for setsockopt() option SOL_ALG
  linux-user: emulate msgsnd(), msgrcv() and semtimedop()
  util/path: Do not cache all filenames at startup

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
Peter Maydell 2019-07-01 15:55:40 +01:00
commit ae9108f8f0
5 changed files with 139 additions and 188 deletions

View File

@ -768,7 +768,13 @@ enum {
QEMU_PPC_FEATURE2_HAS_EBB = 0x10000000, /* Event Base Branching */
QEMU_PPC_FEATURE2_HAS_ISEL = 0x08000000, /* Integer Select */
QEMU_PPC_FEATURE2_HAS_TAR = 0x04000000, /* Target Address Register */
QEMU_PPC_FEATURE2_VEC_CRYPTO = 0x02000000,
QEMU_PPC_FEATURE2_HTM_NOSC = 0x01000000,
QEMU_PPC_FEATURE2_ARCH_3_00 = 0x00800000, /* ISA 3.00 */
QEMU_PPC_FEATURE2_HAS_IEEE128 = 0x00400000, /* VSX IEEE Bin Float 128-bit */
QEMU_PPC_FEATURE2_DARN = 0x00200000, /* darn random number insn */
QEMU_PPC_FEATURE2_SCV = 0x00100000, /* scv syscall */
QEMU_PPC_FEATURE2_HTM_NO_SUSPEND = 0x00080000, /* TM w/o suspended state */
};
#define ELF_HWCAP get_elf_hwcap()
@ -822,8 +828,10 @@ static uint32_t get_elf_hwcap2(void)
GET_FEATURE(PPC_ISEL, QEMU_PPC_FEATURE2_HAS_ISEL);
GET_FEATURE2(PPC2_BCTAR_ISA207, QEMU_PPC_FEATURE2_HAS_TAR);
GET_FEATURE2((PPC2_BCTAR_ISA207 | PPC2_LSQ_ISA207 | PPC2_ALTIVEC_207 |
PPC2_ISA207S), QEMU_PPC_FEATURE2_ARCH_2_07);
GET_FEATURE2(PPC2_ISA300, QEMU_PPC_FEATURE2_ARCH_3_00);
PPC2_ISA207S), QEMU_PPC_FEATURE2_ARCH_2_07 |
QEMU_PPC_FEATURE2_VEC_CRYPTO);
GET_FEATURE2(PPC2_ISA300, QEMU_PPC_FEATURE2_ARCH_3_00 |
QEMU_PPC_FEATURE2_DARN);
#undef GET_FEATURE
#undef GET_FEATURE2

View File

@ -10,7 +10,7 @@
static inline const char *cpu_get_model(uint32_t eflags)
{
#ifdef TARGET_PPC64
return "POWER8";
return "POWER9";
#else
return "750";
#endif

View File

@ -102,6 +102,7 @@
#include <linux/blkpg.h>
#include <netpacket/packet.h>
#include <linux/netlink.h>
#include <linux/if_alg.h>
#include "linux_loop.h"
#include "uname.h"
@ -762,50 +763,21 @@ safe_syscall2(int, nanosleep, const struct timespec *, req,
safe_syscall4(int, clock_nanosleep, const clockid_t, clock, int, flags,
const struct timespec *, req, struct timespec *, rem)
#endif
#if !defined(__NR_msgsnd) || !defined(__NR_msgrcv) || !defined(__NR_semtimedop)
/* This host kernel architecture uses a single ipc syscall; fake up
* wrappers for the sub-operations to hide this implementation detail.
* Annoyingly we can't include linux/ipc.h to get the constant definitions
* for the call parameter because some structs in there conflict with the
* sys/ipc.h ones. So we just define them here, and rely on them being
* the same for all host architectures.
*/
#define Q_SEMTIMEDOP 4
#define Q_MSGSND 11
#define Q_MSGRCV 12
#define Q_IPCCALL(VERSION, OP) ((VERSION) << 16 | (OP))
#ifdef __NR_ipc
safe_syscall6(int, ipc, int, call, long, first, long, second, long, third,
void *, ptr, long, fifth)
#endif
#ifdef __NR_msgsnd
safe_syscall4(int, msgsnd, int, msgid, const void *, msgp, size_t, sz,
int, flags)
#else
static int safe_msgsnd(int msgid, const void *msgp, size_t sz, int flags)
{
return safe_ipc(Q_IPCCALL(0, Q_MSGSND), msgid, sz, flags, (void *)msgp, 0);
}
#endif
#ifdef __NR_msgrcv
safe_syscall5(int, msgrcv, int, msgid, void *, msgp, size_t, sz,
long, msgtype, int, flags)
#else
static int safe_msgrcv(int msgid, void *msgp, size_t sz, long type, int flags)
{
return safe_ipc(Q_IPCCALL(1, Q_MSGRCV), msgid, sz, flags, msgp, type);
}
#endif
#ifdef __NR_semtimedop
safe_syscall4(int, semtimedop, int, semid, struct sembuf *, tsops,
unsigned, nsops, const struct timespec *, timeout)
#else
static int safe_semtimedop(int semid, struct sembuf *tsops, unsigned nsops,
const struct timespec *timeout)
{
return safe_ipc(Q_IPCCALL(0, Q_SEMTIMEDOP), semid, nsops, 0, tsops,
(long)timeout);
}
#endif
#if defined(TARGET_NR_mq_open) && defined(__NR_mq_open)
safe_syscall5(int, mq_timedsend, int, mqdes, const char *, msg_ptr,
@ -1920,6 +1892,25 @@ static abi_long do_setsockopt(int sockfd, int level, int optname,
&pki, sizeof(pki)));
break;
}
case IPV6_ADD_MEMBERSHIP:
case IPV6_DROP_MEMBERSHIP:
{
struct ipv6_mreq ipv6mreq;
if (optlen < sizeof(ipv6mreq)) {
return -TARGET_EINVAL;
}
if (copy_from_user(&ipv6mreq, optval_addr, sizeof(ipv6mreq))) {
return -TARGET_EFAULT;
}
ipv6mreq.ipv6mr_interface = tswap32(ipv6mreq.ipv6mr_interface);
ret = get_errno(setsockopt(sockfd, level, optname,
&ipv6mreq, sizeof(ipv6mreq)));
break;
}
default:
goto unimplemented;
}
@ -1970,6 +1961,36 @@ static abi_long do_setsockopt(int sockfd, int level, int optname,
goto unimplemented;
}
break;
#if defined(SOL_ALG) && defined(ALG_SET_KEY) && defined(ALG_SET_AEAD_AUTHSIZE)
case SOL_ALG:
switch (optname) {
case ALG_SET_KEY:
{
char *alg_key = g_malloc(optlen);
if (!alg_key) {
return -TARGET_ENOMEM;
}
if (copy_from_user(alg_key, optval_addr, optlen)) {
g_free(alg_key);
return -TARGET_EFAULT;
}
ret = get_errno(setsockopt(sockfd, level, optname,
alg_key, optlen));
g_free(alg_key);
break;
}
case ALG_SET_AEAD_AUTHSIZE:
{
ret = get_errno(setsockopt(sockfd, level, optname,
NULL, optlen));
break;
}
default:
goto unimplemented;
}
break;
#endif
case TARGET_SOL_SOCKET:
switch (optname) {
case TARGET_SO_RCVTIMEO:
@ -3529,11 +3550,21 @@ static inline abi_long target_to_host_sembuf(struct sembuf *host_sembuf,
static inline abi_long do_semop(int semid, abi_long ptr, unsigned nsops)
{
struct sembuf sops[nsops];
abi_long ret;
if (target_to_host_sembuf(sops, ptr, nsops))
return -TARGET_EFAULT;
return get_errno(safe_semtimedop(semid, sops, nsops, NULL));
ret = -TARGET_ENOSYS;
#ifdef __NR_semtimedop
ret = get_errno(safe_semtimedop(semid, sops, nsops, NULL));
#endif
#ifdef __NR_ipc
if (ret == -TARGET_ENOSYS) {
ret = get_errno(safe_ipc(IPCOP_semtimedop, semid, nsops, 0, sops, 0));
}
#endif
return ret;
}
struct target_msqid_ds
@ -3688,7 +3719,16 @@ static inline abi_long do_msgsnd(int msqid, abi_long msgp,
}
host_mb->mtype = (abi_long) tswapal(target_mb->mtype);
memcpy(host_mb->mtext, target_mb->mtext, msgsz);
ret = -TARGET_ENOSYS;
#ifdef __NR_msgsnd
ret = get_errno(safe_msgsnd(msqid, host_mb, msgsz, msgflg));
#endif
#ifdef __NR_ipc
if (ret == -TARGET_ENOSYS) {
ret = get_errno(safe_ipc(IPCOP_msgsnd, msqid, msgsz, msgflg,
host_mb, 0));
}
#endif
g_free(host_mb);
unlock_user_struct(target_mb, msgp, 0);
@ -3716,7 +3756,16 @@ static inline abi_long do_msgrcv(int msqid, abi_long msgp,
ret = -TARGET_ENOMEM;
goto end;
}
ret = -TARGET_ENOSYS;
#ifdef __NR_msgrcv
ret = get_errno(safe_msgrcv(msqid, host_mb, msgsz, msgtyp, msgflg));
#endif
#ifdef __NR_ipc
if (ret == -TARGET_ENOSYS) {
ret = get_errno(safe_ipc(IPCOP_CALL(1, IPCOP_msgrcv), msqid, msgsz,
msgflg, host_mb, msgtyp));
}
#endif
if (ret > 0) {
abi_ulong target_mtext_addr = msgp + sizeof(abi_ulong);

View File

@ -32,6 +32,7 @@
#define TARGET_SYS_RECVMMSG 19 /* recvmmsg() */
#define TARGET_SYS_SENDMMSG 20 /* sendmmsg() */
#define IPCOP_CALL(VERSION, OP) ((VERSION) << 16 | (OP))
#define IPCOP_semop 1
#define IPCOP_semget 2
#define IPCOP_semctl 3

View File

@ -8,170 +8,63 @@
#include <dirent.h>
#include "qemu/cutils.h"
#include "qemu/path.h"
#include "qemu/thread.h"
struct pathelem
{
/* Name of this, eg. lib */
char *name;
/* Full path name, eg. /usr/gnemul/x86-linux/lib. */
char *pathname;
struct pathelem *parent;
/* Children */
unsigned int num_entries;
struct pathelem *entries[0];
};
static struct pathelem *base;
/* First N chars of S1 match S2, and S2 is N chars long. */
static int strneq(const char *s1, unsigned int n, const char *s2)
{
unsigned int i;
for (i = 0; i < n; i++)
if (s1[i] != s2[i])
return 0;
return s2[i] == 0;
}
static struct pathelem *add_entry(struct pathelem *root, const char *name,
unsigned type);
static struct pathelem *new_entry(const char *root,
struct pathelem *parent,
const char *name)
{
struct pathelem *new = g_malloc(sizeof(*new));
new->name = g_strdup(name);
new->pathname = g_strdup_printf("%s/%s", root, name);
new->num_entries = 0;
return new;
}
#define streq(a,b) (strcmp((a), (b)) == 0)
/* Not all systems provide this feature */
#if defined(DT_DIR) && defined(DT_UNKNOWN) && defined(DT_LNK)
# define dirent_type(dirent) ((dirent)->d_type)
# define is_dir_maybe(type) \
((type) == DT_DIR || (type) == DT_UNKNOWN || (type) == DT_LNK)
#else
# define dirent_type(dirent) (1)
# define is_dir_maybe(type) (type)
#endif
static struct pathelem *add_dir_maybe(struct pathelem *path)
{
DIR *dir;
if ((dir = opendir(path->pathname)) != NULL) {
struct dirent *dirent;
while ((dirent = readdir(dir)) != NULL) {
if (!streq(dirent->d_name,".") && !streq(dirent->d_name,"..")){
path = add_entry(path, dirent->d_name, dirent_type(dirent));
}
}
closedir(dir);
}
return path;
}
static struct pathelem *add_entry(struct pathelem *root, const char *name,
unsigned type)
{
struct pathelem **e;
root->num_entries++;
root = g_realloc(root, sizeof(*root)
+ sizeof(root->entries[0])*root->num_entries);
e = &root->entries[root->num_entries-1];
*e = new_entry(root->pathname, root, name);
if (is_dir_maybe(type)) {
*e = add_dir_maybe(*e);
}
return root;
}
/* This needs to be done after tree is stabilized (ie. no more reallocs!). */
static void set_parents(struct pathelem *child, struct pathelem *parent)
{
unsigned int i;
child->parent = parent;
for (i = 0; i < child->num_entries; i++)
set_parents(child->entries[i], child);
}
/* FIXME: Doesn't handle DIR/.. where DIR is not in emulated dir. */
static const char *
follow_path(const struct pathelem *cursor, const char *name)
{
unsigned int i, namelen;
name += strspn(name, "/");
namelen = strcspn(name, "/");
if (namelen == 0)
return cursor->pathname;
if (strneq(name, namelen, ".."))
return follow_path(cursor->parent, name + namelen);
if (strneq(name, namelen, "."))
return follow_path(cursor, name + namelen);
for (i = 0; i < cursor->num_entries; i++)
if (strneq(name, namelen, cursor->entries[i]->name))
return follow_path(cursor->entries[i], name + namelen);
/* Not found */
return NULL;
}
static const char *base;
static GHashTable *hash;
static QemuMutex lock;
void init_paths(const char *prefix)
{
char pref_buf[PATH_MAX];
if (prefix[0] == '\0' ||
!strcmp(prefix, "/"))
if (prefix[0] == '\0' || !strcmp(prefix, "/")) {
return;
if (prefix[0] != '/') {
char *cwd = getcwd(NULL, 0);
size_t pref_buf_len = sizeof(pref_buf);
if (!cwd)
abort();
pstrcpy(pref_buf, sizeof(pref_buf), cwd);
pstrcat(pref_buf, pref_buf_len, "/");
pstrcat(pref_buf, pref_buf_len, prefix);
free(cwd);
} else
pstrcpy(pref_buf, sizeof(pref_buf), prefix + 1);
base = new_entry("", NULL, pref_buf);
base = add_dir_maybe(base);
if (base->num_entries == 0) {
g_free(base->pathname);
g_free(base->name);
g_free(base);
base = NULL;
} else {
set_parents(base, base);
}
if (prefix[0] == '/') {
base = g_strdup(prefix);
} else {
char *cwd = g_get_current_dir();
base = g_build_filename(cwd, prefix, NULL);
g_free(cwd);
}
hash = g_hash_table_new(g_str_hash, g_str_equal);
qemu_mutex_init(&lock);
}
/* Look for path in emulation dir, otherwise return name. */
const char *path(const char *name)
{
/* Only do absolute paths: quick and dirty, but should mostly be OK.
Could do relative by tracking cwd. */
if (!base || !name || name[0] != '/')
return name;
gpointer key, value;
const char *ret;
return follow_path(base, name) ?: name;
/* Only do absolute paths: quick and dirty, but should mostly be OK. */
if (!base || !name || name[0] != '/') {
return name;
}
qemu_mutex_lock(&lock);
/* Have we looked up this file before? */
if (g_hash_table_lookup_extended(hash, name, &key, &value)) {
ret = value ? value : name;
} else {
char *save = g_strdup(name);
char *full = g_build_filename(base, name, NULL);
/* Look for the path; record the result, pass or fail. */
if (access(full, F_OK) == 0) {
/* Exists. */
g_hash_table_insert(hash, save, full);
ret = full;
} else {
/* Does not exist. */
g_free(full);
g_hash_table_insert(hash, save, NULL);
ret = name;
}
}
qemu_mutex_unlock(&lock);
return ret;
}