uname.c 4.6 KB
Newer Older
1 2 3
/*
 *  cpu to uname machine name map
 *
4
 *  Copyright (c) 2009 Loïc Minier
5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
 *
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 2 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program; if not, see <http://www.gnu.org/licenses/>.
 */

P
Peter Maydell 已提交
20
#include "qemu/osdep.h"
21 22 23

#include "qemu.h"
//#include "qemu-common.h"
24
#include "uname.h"
25 26 27 28 29 30 31 32

/* return highest utsname machine name for emulated instruction set
 *
 * NB: the default emulated CPU ("any") might not match any existing CPU, e.g.
 * on ARM it has all features turned on, so there is no perfect arch string to
 * return here */
const char *cpu_to_uname_machine(void *cpu_env)
{
33 34
#if defined(TARGET_ARM) && !defined(TARGET_AARCH64)

35 36 37 38
    /* utsname machine name on linux arm is CPU arch name + endianness, e.g.
     * armv7l; to get a list of CPU arch names from the linux source, use:
     *     grep arch_name: -A1 linux/arch/arm/mm/proc-*.S
     * see arch/arm/kernel/setup.c: setup_processor()
39
     */
40 41 42 43 44 45 46 47 48 49 50 51 52 53 54

    /* in theory, endianness is configurable on some ARM CPUs, but this isn't
     * used in user mode emulation */
#ifdef TARGET_WORDS_BIGENDIAN
#define utsname_suffix "b"
#else
#define utsname_suffix "l"
#endif
    if (arm_feature(cpu_env, ARM_FEATURE_V7))
        return "armv7" utsname_suffix;
    if (arm_feature(cpu_env, ARM_FEATURE_V6))
        return "armv6" utsname_suffix;
    /* earliest emulated CPU is ARMv5TE; qemu can emulate the 1026, but not its
     * Jazelle support */
    return "armv5te" utsname_suffix;
55
#elif defined(TARGET_I386) && !defined(TARGET_X86_64)
56
    /* see arch/x86/kernel/cpu/bugs.c: check_bugs(), 386, 486, 586, 686 */
57 58 59
    CPUState *cpu = ENV_GET_CPU((CPUX86State *)cpu_env);
    int family = object_property_get_int(OBJECT(cpu), "family", NULL);
    if (family == 4) {
60
        return "i486";
61 62
    }
    if (family == 5) {
63
        return "i586";
64
    }
65 66 67 68 69 70
    return "i686";
#else
    /* default is #define-d in each arch/ subdir */
    return UNAME_MACHINE;
#endif
}
71 72 73 74


#define COPY_UTSNAME_FIELD(dest, src) \
  do { \
75 76
      memcpy((dest), (src), MIN(sizeof(src), sizeof(dest))); \
      (dest)[sizeof(dest) - 1] = '\0'; \
77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168
  } while (0)

int sys_uname(struct new_utsname *buf)
{
  struct utsname uts_buf;

  if (uname(&uts_buf) < 0)
      return (-1);

  /*
   * Just in case these have some differences, we
   * translate utsname to new_utsname (which is the
   * struct linux kernel uses).
   */

  memset(buf, 0, sizeof(*buf));
  COPY_UTSNAME_FIELD(buf->sysname, uts_buf.sysname);
  COPY_UTSNAME_FIELD(buf->nodename, uts_buf.nodename);
  COPY_UTSNAME_FIELD(buf->release, uts_buf.release);
  COPY_UTSNAME_FIELD(buf->version, uts_buf.version);
  COPY_UTSNAME_FIELD(buf->machine, uts_buf.machine);
#ifdef _GNU_SOURCE
  COPY_UTSNAME_FIELD(buf->domainname, uts_buf.domainname);
#endif
  return (0);

#undef COPY_UTSNAME_FIELD
}

static int relstr_to_int(const char *s)
{
    /* Convert a uname release string like "2.6.18" to an integer
     * of the form 0x020612. (Beware that 0x020612 is *not* 2.6.12.)
     */
    int i, n, tmp;

    tmp = 0;
    for (i = 0; i < 3; i++) {
        n = 0;
        while (*s >= '0' && *s <= '9') {
            n *= 10;
            n += *s - '0';
            s++;
        }
        tmp = (tmp << 8) + n;
        if (*s == '.') {
            s++;
        }
    }
    return tmp;
}

int get_osversion(void)
{
    static int osversion;
    struct new_utsname buf;
    const char *s;

    if (osversion)
        return osversion;
    if (qemu_uname_release && *qemu_uname_release) {
        s = qemu_uname_release;
    } else {
        if (sys_uname(&buf))
            return 0;
        s = buf.release;
    }
    osversion = relstr_to_int(s);
    return osversion;
}

void init_qemu_uname_release(void)
{
    /* Initialize qemu_uname_release for later use.
     * If the host kernel is too old and the user hasn't asked for
     * a specific fake version number, we might want to fake a minimum
     * target kernel version.
     */
    struct new_utsname buf;

    if (qemu_uname_release && *qemu_uname_release) {
        return;
    }

    if (sys_uname(&buf)) {
        return;
    }

    if (relstr_to_int(buf.release) < relstr_to_int(UNAME_MINIMUM_RELEASE)) {
        qemu_uname_release = UNAME_MINIMUM_RELEASE;
    }
}