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:
commit
ae9108f8f0
@ -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
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
|
201
util/path.c
201
util/path.c
@ -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;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user