Merge remote-tracking branch 'rth/auxv-2' into staging

# By Richard Henderson
# Via Richard Henderson
* rth/auxv-2:
  linux-user: Use qemu_getauxval for AT_EXECFD
  util: Use qemu_getauxval in linux qemu_cache_utils_init
  tcg-s390: Use qemu_getauxval in query_facilities
  tcg-arm: Use qemu_getauxval
  tcg-ppc64: Use qemu_getauxval
  osdep: Create qemu_getauxval and qemu_init_auxval

Message-id: 1385757754-10702-1-git-send-email-rth@twiddle.net
Signed-off-by: Anthony Liguori <aliguori@amazon.com>
This commit is contained in:
Anthony Liguori 2013-12-06 12:57:21 -08:00
commit cdac7a7184
11 changed files with 223 additions and 161 deletions

View file

@ -411,6 +411,65 @@ typedef struct {
#define R_SPARC_5 44
#define R_SPARC_6 45
/* Bits present in AT_HWCAP for ARM. */
#define HWCAP_ARM_SWP (1 << 0)
#define HWCAP_ARM_HALF (1 << 1)
#define HWCAP_ARM_THUMB (1 << 2)
#define HWCAP_ARM_26BIT (1 << 3)
#define HWCAP_ARM_FAST_MULT (1 << 4)
#define HWCAP_ARM_FPA (1 << 5)
#define HWCAP_ARM_VFP (1 << 6)
#define HWCAP_ARM_EDSP (1 << 7)
#define HWCAP_ARM_JAVA (1 << 8)
#define HWCAP_ARM_IWMMXT (1 << 9)
#define HWCAP_ARM_CRUNCH (1 << 10)
#define HWCAP_ARM_THUMBEE (1 << 11)
#define HWCAP_ARM_NEON (1 << 12)
#define HWCAP_ARM_VFPv3 (1 << 13)
#define HWCAP_ARM_VFPv3D16 (1 << 14) /* also set for VFPv4-D16 */
#define HWCAP_ARM_TLS (1 << 15)
#define HWCAP_ARM_VFPv4 (1 << 16)
#define HWCAP_ARM_IDIVA (1 << 17)
#define HWCAP_ARM_IDIVT (1 << 18)
#define HWCAP_IDIV (HWCAP_IDIVA | HWCAP_IDIVT)
#define HWCAP_VFPD32 (1 << 19) /* set if VFP has 32 regs */
#define HWCAP_LPAE (1 << 20)
/* Bits present in AT_HWCAP for PowerPC. */
#define PPC_FEATURE_32 0x80000000
#define PPC_FEATURE_64 0x40000000
#define PPC_FEATURE_601_INSTR 0x20000000
#define PPC_FEATURE_HAS_ALTIVEC 0x10000000
#define PPC_FEATURE_HAS_FPU 0x08000000
#define PPC_FEATURE_HAS_MMU 0x04000000
#define PPC_FEATURE_HAS_4xxMAC 0x02000000
#define PPC_FEATURE_UNIFIED_CACHE 0x01000000
#define PPC_FEATURE_HAS_SPE 0x00800000
#define PPC_FEATURE_HAS_EFP_SINGLE 0x00400000
#define PPC_FEATURE_HAS_EFP_DOUBLE 0x00200000
#define PPC_FEATURE_NO_TB 0x00100000
#define PPC_FEATURE_POWER4 0x00080000
#define PPC_FEATURE_POWER5 0x00040000
#define PPC_FEATURE_POWER5_PLUS 0x00020000
#define PPC_FEATURE_CELL 0x00010000
#define PPC_FEATURE_BOOKE 0x00008000
#define PPC_FEATURE_SMT 0x00004000
#define PPC_FEATURE_ICACHE_SNOOP 0x00002000
#define PPC_FEATURE_ARCH_2_05 0x00001000
#define PPC_FEATURE_PA6T 0x00000800
#define PPC_FEATURE_HAS_DFP 0x00000400
#define PPC_FEATURE_POWER6_EXT 0x00000200
#define PPC_FEATURE_ARCH_2_06 0x00000100
#define PPC_FEATURE_HAS_VSX 0x00000080
#define PPC_FEATURE_PSERIES_PERFMON_COMPAT \
0x00000040
#define PPC_FEATURE_TRUE_LE 0x00000002
#define PPC_FEATURE_PPC_LE 0x00000001
/* Bits present in AT_HWCAP, primarily for Sparc32. */
#define HWCAP_SPARC_FLUSH 1 /* CPU supports flush instruction. */
@ -420,6 +479,20 @@ typedef struct {
#define HWCAP_SPARC_V9 16
#define HWCAP_SPARC_ULTRA3 32
/* Bits present in AT_HWCAP for s390. */
#define HWCAP_S390_ESAN3 1
#define HWCAP_S390_ZARCH 2
#define HWCAP_S390_STFLE 4
#define HWCAP_S390_MSA 8
#define HWCAP_S390_LDISP 16
#define HWCAP_S390_EIMM 32
#define HWCAP_S390_DFP 64
#define HWCAP_S390_HPAGE 128
#define HWCAP_S390_ETF3EH 256
#define HWCAP_S390_HIGH_GPRS 512
#define HWCAP_S390_TE 1024
/*
* 68k ELF relocation types
*/

View file

@ -12,7 +12,7 @@ struct qemu_cache_conf {
extern struct qemu_cache_conf qemu_cache_conf;
void qemu_cache_utils_init(char **envp);
void qemu_cache_utils_init(void);
/* mildly adjusted code from tcg-dyngen.c */
static inline void flush_icache_range(uintptr_t start, uintptr_t stop)
@ -38,7 +38,7 @@ static inline void flush_icache_range(uintptr_t start, uintptr_t stop)
}
#else
#define qemu_cache_utils_init(envp) do { (void) (envp); } while (0)
#define qemu_cache_utils_init() do { } while (0)
#endif
#endif /* QEMU_CACHE_UTILS_H */

View file

@ -215,4 +215,29 @@ bool fips_get_state(void);
*/
char *qemu_get_local_state_pathname(const char *relative_pathname);
/**
* qemu_getauxval:
* @type: the auxiliary vector key to lookup
*
* Search the auxiliary vector for @type, returning the value
* or 0 if @type is not present.
*/
#if defined(CONFIG_GETAUXVAL) || defined(__linux__)
unsigned long qemu_getauxval(unsigned long type);
#else
static inline unsigned long qemu_getauxval(unsigned long type) { return 0; }
#endif
/**
* qemu_init_auxval:
* @envp: the third argument to main
*
* If supported and required, locate the auxiliary vector at program startup.
*/
#if defined(CONFIG_GETAUXVAL) || !defined(__linux__)
static inline void qemu_init_auxval(char **envp) { }
#else
void qemu_init_auxval(char **envp);
#endif
#endif

View file

@ -3663,26 +3663,6 @@ static int parse_args(int argc, char **argv)
return optind;
}
static int get_execfd(char **envp)
{
typedef struct {
long a_type;
long a_val;
} auxv_t;
auxv_t *auxv;
while (*envp++ != NULL) {
;
}
for (auxv = (auxv_t *)envp; auxv->a_type != AT_NULL; auxv++) {
if (auxv->a_type == AT_EXECFD) {
return auxv->a_val;
}
}
return -1;
}
int main(int argc, char **argv, char **envp)
{
struct target_pt_regs regs1, *regs = &regs1;
@ -3701,7 +3681,8 @@ int main(int argc, char **argv, char **envp)
module_call_init(MODULE_INIT_QOM);
qemu_cache_utils_init(envp);
qemu_init_auxval(envp);
qemu_cache_utils_init();
if ((envlist = envlist_create()) == NULL) {
(void) fprintf(stderr, "Unable to allocate envlist\n");
@ -3875,13 +3856,13 @@ int main(int argc, char **argv, char **envp)
env->opaque = ts;
task_settid(ts);
execfd = get_execfd(envp);
if (execfd < 0) {
execfd = qemu_getauxval(AT_EXECFD);
if (execfd == 0) {
execfd = open(filename, O_RDONLY);
}
if (execfd < 0) {
printf("Error while loading %s: %s\n", filename, strerror(-execfd));
_exit(1);
if (execfd < 0) {
printf("Error while loading %s: %s\n", filename, strerror(errno));
_exit(1);
}
}
ret = loader_exec(execfd, filename, target_argv, target_environ, regs,

View file

@ -22,6 +22,7 @@
* THE SOFTWARE.
*/
#include "elf.h"
#include "tcg-be-ldst.h"
/* The __ARM_ARCH define is provided by gcc 4.8. Construct it otherwise. */
@ -58,9 +59,6 @@ static int arm_arch = __ARM_ARCH;
#ifndef use_idiv_instructions
bool use_idiv_instructions;
#endif
#ifdef CONFIG_GETAUXVAL
# include <sys/auxv.h>
#endif
#ifndef NDEBUG
static const char * const tcg_target_reg_names[TCG_TARGET_NB_REGS] = {
@ -2036,22 +2034,20 @@ static const TCGTargetOpDef arm_op_defs[] = {
static void tcg_target_init(TCGContext *s)
{
#if defined(CONFIG_GETAUXVAL)
/* Only probe for the platform and capabilities if we havn't already
determined maximum values at compile time. */
# if !defined(use_idiv_instructions)
#ifndef use_idiv_instructions
{
unsigned long hwcap = getauxval(AT_HWCAP);
unsigned long hwcap = qemu_getauxval(AT_HWCAP);
use_idiv_instructions = (hwcap & HWCAP_ARM_IDIVA) != 0;
}
# endif
#endif
if (__ARM_ARCH < 7) {
const char *pl = (const char *)getauxval(AT_PLATFORM);
const char *pl = (const char *)qemu_getauxval(AT_PLATFORM);
if (pl != NULL && pl[0] == 'v' && pl[1] >= '4' && pl[1] <= '9') {
arm_arch = pl[1] - '0';
}
}
#endif /* GETAUXVAL */
tcg_regset_set32(tcg_target_available_regs[TCG_TYPE_I32], 0, 0xffff);
tcg_regset_set32(tcg_target_call_clobber_regs, 0,

View file

@ -45,15 +45,10 @@ static uint8_t *tb_ret_addr;
#define GUEST_BASE 0
#endif
#ifdef CONFIG_GETAUXVAL
#include <sys/auxv.h>
#include "elf.h"
static bool have_isa_2_06;
#define HAVE_ISA_2_06 have_isa_2_06
#define HAVE_ISEL have_isa_2_06
#else
#define HAVE_ISA_2_06 0
#define HAVE_ISEL 0
#endif
#ifdef CONFIG_USE_GUEST_BASE
#define TCG_GUEST_BASE_REG 30
@ -2132,12 +2127,10 @@ static const TCGTargetOpDef ppc_op_defs[] = {
static void tcg_target_init(TCGContext *s)
{
#ifdef CONFIG_GETAUXVAL
unsigned long hwcap = getauxval(AT_HWCAP);
unsigned long hwcap = qemu_getauxval(AT_HWCAP);
if (hwcap & PPC_FEATURE_ARCH_2_06) {
have_isa_2_06 = true;
}
#endif
tcg_regset_set32(tcg_target_available_regs[TCG_TYPE_I32], 0, 0xffffffff);
tcg_regset_set32(tcg_target_available_regs[TCG_TYPE_I64], 0, 0xffffffff);

View file

@ -31,6 +31,8 @@
#error "unsupported code generation mode"
#endif
#include "elf.h"
/* ??? The translation blocks produced by TCG are generally small enough to
be entirely reachable with a 16-bit displacement. Leaving the option for
a 32-bit displacement here Just In Case. */
@ -2233,91 +2235,18 @@ static void sigill_handler(int sig)
static void query_facilities(void)
{
struct sigaction sa_old, sa_new;
register int r0 __asm__("0");
register void *r1 __asm__("1");
int fail;
unsigned long hwcap = qemu_getauxval(AT_HWCAP);
memset(&sa_new, 0, sizeof(sa_new));
sa_new.sa_handler = sigill_handler;
sigaction(SIGILL, &sa_new, &sa_old);
/* Is STORE FACILITY LIST EXTENDED available? Honestly, I believe this
is present on all 64-bit systems, but let's check for it anyway. */
if (hwcap & HWCAP_S390_STFLE) {
register int r0 __asm__("0");
register void *r1 __asm__("1");
/* First, try STORE FACILITY LIST EXTENDED. If this is present, then
we need not do any more probing. Unfortunately, this itself is an
extension and the original STORE FACILITY LIST instruction is
kernel-only, storing its results at absolute address 200. */
/* stfle 0(%r1) */
r1 = &facilities;
asm volatile(".word 0xb2b0,0x1000"
: "=r"(r0) : "0"(0), "r"(r1) : "memory", "cc");
if (got_sigill) {
/* STORE FACILITY EXTENDED is not available. Probe for one of each
kind of instruction that we're interested in. */
/* ??? Possibly some of these are in practice never present unless
the store-facility-extended facility is also present. But since
that isn't documented it's just better to probe for each. */
/* Test for z/Architecture. Required even in 31-bit mode. */
got_sigill = 0;
/* agr %r0,%r0 */
asm volatile(".word 0xb908,0x0000" : "=r"(r0) : : "cc");
if (!got_sigill) {
facilities |= FACILITY_ZARCH_ACTIVE;
}
/* Test for long displacement. */
got_sigill = 0;
/* ly %r0,0(%r1) */
/* stfle 0(%r1) */
r1 = &facilities;
asm volatile(".word 0xe300,0x1000,0x0058"
: "=r"(r0) : "r"(r1) : "cc");
if (!got_sigill) {
facilities |= FACILITY_LONG_DISP;
}
/* Test for extended immediates. */
got_sigill = 0;
/* afi %r0,0 */
asm volatile(".word 0xc209,0x0000,0x0000" : : : "cc");
if (!got_sigill) {
facilities |= FACILITY_EXT_IMM;
}
/* Test for general-instructions-extension. */
got_sigill = 0;
/* msfi %r0,1 */
asm volatile(".word 0xc201,0x0000,0x0001");
if (!got_sigill) {
facilities |= FACILITY_GEN_INST_EXT;
}
}
sigaction(SIGILL, &sa_old, NULL);
/* The translator currently uses these extensions unconditionally.
Pruning this back to the base ESA/390 architecture doesn't seem
worthwhile, since even the KVM target requires z/Arch. */
fail = 0;
if ((facilities & FACILITY_ZARCH_ACTIVE) == 0) {
fprintf(stderr, "TCG: z/Arch facility is required.\n");
fprintf(stderr, "TCG: Boot with a 64-bit enabled kernel.\n");
fail = 1;
}
if ((facilities & FACILITY_LONG_DISP) == 0) {
fprintf(stderr, "TCG: long-displacement facility is required.\n");
fail = 1;
}
/* So far there's just enough support for 31-bit mode to let the
compile succeed. This is good enough to run QEMU with KVM. */
if (sizeof(void *) != 8) {
fprintf(stderr, "TCG: 31-bit mode is not supported.\n");
fail = 1;
}
if (fail) {
exit(-1);
asm volatile(".word 0xb2b0,0x1000"
: "=r"(r0) : "0"(0), "r"(r1) : "memory", "cc");
}
}

View file

@ -12,3 +12,4 @@ util-obj-y += qemu-option.o qemu-progress.o
util-obj-y += hexdump.o
util-obj-y += crc32c.o
util-obj-y += throttle.o
util-obj-y += getauxval.o

View file

@ -1,3 +1,4 @@
#include "qemu-common.h"
#include "qemu/cache-utils.h"
#if defined(_ARCH_PPC)
@ -9,31 +10,33 @@ struct qemu_cache_conf qemu_cache_conf = {
#if defined _AIX
#include <sys/systemcfg.h>
static void ppc_init_cacheline_sizes(void)
void qemu_cache_utils_init(void)
{
qemu_cache_conf.icache_bsize = _system_configuration.icache_line;
qemu_cache_conf.dcache_bsize = _system_configuration.dcache_line;
}
#elif defined __linux__
#include "qemu/osdep.h"
#include "elf.h"
#define QEMU_AT_NULL 0
#define QEMU_AT_DCACHEBSIZE 19
#define QEMU_AT_ICACHEBSIZE 20
static void ppc_init_cacheline_sizes(char **envp)
void qemu_cache_utils_init(void)
{
unsigned long *auxv;
unsigned long dsize = qemu_getauxval(AT_DCACHEBSIZE);
unsigned long isize = qemu_getauxval(AT_ICACHEBSIZE);
while (*envp++);
for (auxv = (unsigned long *) envp; *auxv != QEMU_AT_NULL; auxv += 2) {
switch (*auxv) {
case QEMU_AT_DCACHEBSIZE: qemu_cache_conf.dcache_bsize = auxv[1]; break;
case QEMU_AT_ICACHEBSIZE: qemu_cache_conf.icache_bsize = auxv[1]; break;
default: break;
if (dsize == 0 || isize == 0) {
if (dsize == 0) {
fprintf(stderr, "getauxval AT_DCACHEBSIZE failed\n");
}
if (isize == 0) {
fprintf(stderr, "getauxval AT_ICACHEBSIZE failed\n");
}
exit(1);
}
qemu_cache_conf.dcache_bsize = dsize;
qemu_cache_conf.icache_bsize = isize;
}
#elif defined __APPLE__
@ -41,7 +44,7 @@ static void ppc_init_cacheline_sizes(char **envp)
#include <sys/types.h>
#include <sys/sysctl.h>
static void ppc_init_cacheline_sizes(void)
void qemu_cache_utils_init(void)
{
size_t len;
unsigned cacheline;
@ -55,9 +58,8 @@ static void ppc_init_cacheline_sizes(void)
qemu_cache_conf.icache_bsize = cacheline;
}
}
#endif
#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
#elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
@ -65,7 +67,7 @@ static void ppc_init_cacheline_sizes(void)
#include <sys/types.h>
#include <sys/sysctl.h>
static void ppc_init_cacheline_sizes(void)
void qemu_cache_utils_init(void)
{
size_t len = 4;
unsigned cacheline;
@ -81,17 +83,4 @@ static void ppc_init_cacheline_sizes(void)
}
#endif
#ifdef __linux__
void qemu_cache_utils_init(char **envp)
{
ppc_init_cacheline_sizes(envp);
}
#else
void qemu_cache_utils_init(char **envp)
{
(void) envp;
ppc_init_cacheline_sizes();
}
#endif
#endif /* _ARCH_PPC */

74
util/getauxval.c Normal file
View file

@ -0,0 +1,74 @@
/*
* QEMU access to the auxiliary vector
*
* Copyright (C) 2013 Red Hat, Inc
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include "qemu-common.h"
#include "qemu/osdep.h"
#ifdef CONFIG_GETAUXVAL
/* Don't inline this in qemu/osdep.h, because pulling in <sys/auxv.h> for
the system declaration of getauxval pulls in the system <elf.h>, which
conflicts with qemu's version. */
#include <sys/auxv.h>
unsigned long qemu_getauxval(unsigned long key)
{
return getauxval(key);
}
#elif defined(__linux__)
#include "elf.h"
/* Our elf.h doesn't contain Elf32_auxv_t and Elf64_auxv_t, which is ok because
that just makes it easier to define it properly for the host here. */
typedef struct {
unsigned long a_type;
unsigned long a_val;
} ElfW_auxv_t;
static const ElfW_auxv_t *auxv;
void qemu_init_auxval(char **envp)
{
/* The auxiliary vector is located just beyond the initial environment. */
while (*envp++ != NULL) {
continue;
}
auxv = (const ElfW_auxv_t *)envp;
}
unsigned long qemu_getauxval(unsigned long type)
{
/* If we were able to find the auxiliary vector, use it. */
if (auxv) {
const ElfW_auxv_t *a;
for (a = auxv; a->a_type != 0; a++) {
if (a->a_type == type) {
return a->a_val;
}
}
}
return 0;
}
#endif

3
vl.c
View file

@ -2894,7 +2894,8 @@ int main(int argc, char **argv, char **envp)
init_clocks();
rtc_clock = QEMU_CLOCK_HOST;
qemu_cache_utils_init(envp);
qemu_init_auxval(envp);
qemu_cache_utils_init();
QLIST_INIT (&vm_change_state_head);
os_setup_early_signal_handling();