libshit

Just some random shit
git clone https://git.neptards.moe/neptards/libshit.git
Log | Files | Refs | Submodules | README | LICENSE

qemu-7.0.0.patch (21011B)


      1 diff --git a/linux-user/main.c b/linux-user/main.c
      2 index fbc9bcfd5f..8d5d8e8546 100644
      3 --- a/linux-user/main.c
      4 +++ b/linux-user/main.c
      5 @@ -119,6 +119,7 @@ static void usage(int exitcode);
      6  
      7  static const char *interp_prefix = CONFIG_QEMU_INTERP_PREFIX;
      8  const char *qemu_uname_release;
      9 +const char *qemu_execve_path;
     10  
     11  /* XXX: on x86 MAP_GROWSDOWN only works if ESP <= address + 32, so
     12     we allocate a bigger stack. Need a better solution, for example
     13 @@ -352,6 +353,11 @@ static void handle_arg_guest_base(const char *arg)
     14      have_guest_base = true;
     15  }
     16  
     17 +static void handle_arg_execve(const char *arg)
     18 +{
     19 +    qemu_execve_path = strdup(arg);
     20 +}
     21 +
     22  static void handle_arg_reserved_va(const char *arg)
     23  {
     24      char *p;
     25 @@ -454,6 +460,8 @@ static const struct qemu_argument arg_table[] = {
     26       "uname",      "set qemu uname release string to 'uname'"},
     27      {"B",          "QEMU_GUEST_BASE",  true,  handle_arg_guest_base,
     28       "address",    "set guest_base address to 'address'"},
     29 +    {"execve",     "QEMU_EXECVE",      true,  handle_arg_execve,
     30 +     "",           "use this interpreter when a process calls execve()"},
     31      {"R",          "QEMU_RESERVED_VA", true,  handle_arg_reserved_va,
     32       "size",       "reserve 'size' bytes for guest virtual address space"},
     33      {"d",          "QEMU_LOG",         true,  handle_arg_log,
     34 diff --git a/linux-user/mmap.c b/linux-user/mmap.c
     35 index c125031b90..692781ff18 100644
     36 --- a/linux-user/mmap.c
     37 +++ b/linux-user/mmap.c
     38 @@ -313,7 +313,7 @@ static abi_ulong mmap_find_vma_reserved(abi_ulong start, abi_ulong size,
     39   * It must be called with mmap_lock() held.
     40   * Return -1 if error.
     41   */
     42 -abi_ulong mmap_find_vma(abi_ulong start, abi_ulong size, abi_ulong align)
     43 +abi_ulong mmap_find_vma(abi_ulong start, abi_ulong size, abi_ulong align, bool map_32bit)
     44  {
     45      void *ptr, *prev;
     46      abi_ulong addr;
     47 @@ -348,7 +348,7 @@ abi_ulong mmap_find_vma(abi_ulong start, abi_ulong size, abi_ulong align)
     48           *  - shmat() with SHM_REMAP flag
     49           */
     50          ptr = mmap(g2h_untagged(addr), size, PROT_NONE,
     51 -                   MAP_ANONYMOUS|MAP_PRIVATE|MAP_NORESERVE, -1, 0);
     52 +                   MAP_ANONYMOUS|MAP_PRIVATE|MAP_NORESERVE|(map_32bit?MAP_32BIT:0), -1, 0);
     53  
     54          /* ENOMEM, if host address space has no memory */
     55          if (ptr == MAP_FAILED) {
     56 @@ -359,7 +359,7 @@ abi_ulong mmap_find_vma(abi_ulong start, abi_ulong size, abi_ulong align)
     57             This is used to modify the search algorithm below.  */
     58          repeat = (ptr == prev ? repeat + 1 : 0);
     59  
     60 -        if (h2g_valid(ptr + size - 1)) {
     61 +        if (map_32bit ? h2g(ptr+size-1) == (uint32_t) (ptrdiff_t) (ptr+size-1): h2g_valid(ptr + size - 1)) {
     62              addr = h2g(ptr);
     63  
     64              if ((addr & (align - 1)) == 0) {
     65 @@ -475,7 +475,7 @@ abi_long target_mmap(abi_ulong start, abi_ulong len, int target_prot,
     66      if (!(flags & MAP_FIXED)) {
     67          host_len = len + offset - host_offset;
     68          host_len = HOST_PAGE_ALIGN(host_len);
     69 -        start = mmap_find_vma(real_start, host_len, TARGET_PAGE_SIZE);
     70 +        start = mmap_find_vma(real_start, host_len, TARGET_PAGE_SIZE, flags & MAP_32BIT);
     71          if (start == (abi_ulong)-1) {
     72              errno = ENOMEM;
     73              goto fail;
     74 @@ -772,7 +772,7 @@ abi_long target_mremap(abi_ulong old_addr, abi_ulong old_size,
     75      } else if (flags & MREMAP_MAYMOVE) {
     76          abi_ulong mmap_start;
     77  
     78 -        mmap_start = mmap_find_vma(0, new_size, TARGET_PAGE_SIZE);
     79 +        mmap_start = mmap_find_vma(0, new_size, TARGET_PAGE_SIZE, flags & MAP_32BIT);
     80  
     81          if (mmap_start == -1) {
     82              errno = ENOMEM;
     83 diff --git a/linux-user/strace.c b/linux-user/strace.c
     84 index 2cdbf030ba..75f0c9a1b7 100644
     85 --- a/linux-user/strace.c
     86 +++ b/linux-user/strace.c
     87 @@ -1074,6 +1074,9 @@ UNUSED static struct flags mmap_flags[] = {
     88  #ifdef MAP_POPULATE
     89      FLAG_TARGET(MAP_POPULATE),
     90  #endif
     91 +#ifdef TARGET_MAP_32BIT
     92 +    FLAG_TARGET(MAP_32BIT),
     93 +#endif
     94  #ifdef TARGET_MAP_UNINITIALIZED
     95      FLAG_TARGET(MAP_UNINITIALIZED),
     96  #endif
     97 diff --git a/linux-user/syscall.c b/linux-user/syscall.c
     98 index f65045efe6..9ec4f5b128 100644
     99 --- a/linux-user/syscall.c
    100 +++ b/linux-user/syscall.c
    101 @@ -123,6 +123,7 @@
    102  #include <libdrm/drm.h>
    103  #include <libdrm/i915_drm.h>
    104  #endif
    105 +#include <linux/binfmts.h>
    106  #include "linux_loop.h"
    107  #include "uname.h"
    108  
    109 @@ -995,7 +996,7 @@ static inline rlim_t target_to_host_rlim(abi_ulong target_rlim)
    110  {
    111      abi_ulong target_rlim_swap;
    112      rlim_t result;
    113 -    
    114 +
    115      target_rlim_swap = tswapal(target_rlim);
    116      if (target_rlim_swap == TARGET_RLIM_INFINITY)
    117          return RLIM_INFINITY;
    118 @@ -1003,7 +1004,7 @@ static inline rlim_t target_to_host_rlim(abi_ulong target_rlim)
    119      result = target_rlim_swap;
    120      if (target_rlim_swap != (rlim_t)result)
    121          return RLIM_INFINITY;
    122 -    
    123 +
    124      return result;
    125  }
    126  #endif
    127 @@ -1013,13 +1014,13 @@ static inline abi_ulong host_to_target_rlim(rlim_t rlim)
    128  {
    129      abi_ulong target_rlim_swap;
    130      abi_ulong result;
    131 -    
    132 +
    133      if (rlim == RLIM_INFINITY || rlim != (abi_long)rlim)
    134          target_rlim_swap = TARGET_RLIM_INFINITY;
    135      else
    136          target_rlim_swap = rlim;
    137      result = tswapal(target_rlim_swap);
    138 -    
    139 +
    140      return result;
    141  }
    142  #endif
    143 @@ -1753,9 +1754,9 @@ static inline abi_long target_to_host_cmsg(struct msghdr *msgh,
    144      abi_ulong target_cmsg_addr;
    145      struct target_cmsghdr *target_cmsg, *target_cmsg_start;
    146      socklen_t space = 0;
    147 -    
    148 +
    149      msg_controllen = tswapal(target_msgh->msg_controllen);
    150 -    if (msg_controllen < sizeof (struct target_cmsghdr)) 
    151 +    if (msg_controllen < sizeof (struct target_cmsghdr))
    152          goto the_end;
    153      target_cmsg_addr = tswapal(target_msgh->msg_control);
    154      target_cmsg = lock_user(VERIFY_READ, target_cmsg_addr, msg_controllen, 1);
    155 @@ -1841,7 +1842,7 @@ static inline abi_long host_to_target_cmsg(struct target_msghdr *target_msgh,
    156      socklen_t space = 0;
    157  
    158      msg_controllen = tswapal(target_msgh->msg_controllen);
    159 -    if (msg_controllen < sizeof (struct target_cmsghdr)) 
    160 +    if (msg_controllen < sizeof (struct target_cmsghdr))
    161          goto the_end;
    162      target_cmsg_addr = tswapal(target_msgh->msg_control);
    163      target_cmsg = lock_user(VERIFY_WRITE, target_cmsg_addr, msg_controllen, 0);
    164 @@ -4534,7 +4535,7 @@ static inline abi_ulong do_shmat(CPUArchState *cpu_env,
    165          abi_ulong mmap_start;
    166  
    167          /* In order to use the host shmat, we need to honor host SHMLBA.  */
    168 -        mmap_start = mmap_find_vma(0, shm_info.shm_segsz, MAX(SHMLBA, shmlba));
    169 +        mmap_start = mmap_find_vma(0, shm_info.shm_segsz, MAX(SHMLBA, shmlba), false);
    170  
    171          if (mmap_start == -1) {
    172              errno = ENOMEM;
    173 @@ -5958,6 +5959,9 @@ static const StructEntry struct_termios_def = {
    174  };
    175  
    176  static const bitmask_transtbl mmap_flags_tbl[] = {
    177 +#ifdef TARGET_MAP_32BIT
    178 +    { TARGET_MAP_32BIT, TARGET_MAP_32BIT, MAP_32BIT, MAP_32BIT },
    179 +#endif
    180      { TARGET_MAP_SHARED, TARGET_MAP_SHARED, MAP_SHARED, MAP_SHARED },
    181      { TARGET_MAP_PRIVATE, TARGET_MAP_PRIVATE, MAP_PRIVATE, MAP_PRIVATE },
    182      { TARGET_MAP_FIXED, TARGET_MAP_FIXED, MAP_FIXED, MAP_FIXED },
    183 @@ -6152,7 +6156,7 @@ abi_long do_set_thread_area(CPUX86State *env, abi_ulong ptr)
    184      }
    185      unlock_user_struct(target_ldt_info, ptr, 1);
    186  
    187 -    if (ldt_info.entry_number < TARGET_GDT_ENTRY_TLS_MIN || 
    188 +    if (ldt_info.entry_number < TARGET_GDT_ENTRY_TLS_MIN ||
    189          ldt_info.entry_number > TARGET_GDT_ENTRY_TLS_MAX)
    190             return -TARGET_EINVAL;
    191      seg_32bit = ldt_info.flags & 1;
    192 @@ -6230,7 +6234,7 @@ static abi_long do_get_thread_area(CPUX86State *env, abi_ulong ptr)
    193      lp = (uint32_t *)(gdt_table + idx);
    194      entry_1 = tswap32(lp[0]);
    195      entry_2 = tswap32(lp[1]);
    196 -    
    197 +
    198      read_exec_only = ((entry_2 >> 9) & 1) ^ 1;
    199      contents = (entry_2 >> 10) & 3;
    200      seg_not_present = ((entry_2 >> 15) & 1) ^ 1;
    201 @@ -6246,8 +6250,8 @@ static abi_long do_get_thread_area(CPUX86State *env, abi_ulong ptr)
    202          (read_exec_only << 3) | (limit_in_pages << 4) |
    203          (seg_not_present << 5) | (useable << 6) | (lm << 7);
    204      limit = (entry_1 & 0xffff) | (entry_2  & 0xf0000);
    205 -    base_addr = (entry_1 >> 16) | 
    206 -        (entry_2 & 0xff000000) | 
    207 +    base_addr = (entry_1 >> 16) |
    208 +        (entry_2 & 0xff000000) |
    209          ((entry_2 & 0xff) << 16);
    210      target_ldt_info->base_addr = tswapal(base_addr);
    211      target_ldt_info->limit = tswap32(limit);
    212 @@ -8300,6 +8304,131 @@ static target_timer_t get_timer_id(abi_long arg)
    213      return timerid;
    214  }
    215  
    216 +/* qemu_execve() Must return target values and target errnos.
    217 + *
    218 + * Although execve() is not an interruptible syscall it is
    219 + * a special case where we must use the safe_syscall wrapper:
    220 + * if we allow a signal to happen before we make the host
    221 + * syscall then we will 'lose' it, because at the point of
    222 + * execve the process leaves QEMU's control. So we use the
    223 + * safe syscall wrapper to ensure that we either take the
    224 + * signal as a guest signal, or else it does not happen
    225 + * before the execve completes and makes it the other
    226 + * program's problem.
    227 + */
    228 +static abi_long qemu_execve(char *filename, char *argv[],
    229 +                  char *envp[])
    230 +{
    231 +    char *i_arg = NULL, *i_name = NULL;
    232 +    char **new_argp;
    233 +    int argc, fd, ret, i, offset = 5;
    234 +    char *cp;
    235 +    char buf[BINPRM_BUF_SIZE];
    236 +
    237 +    /* normal execve case */
    238 +    if (qemu_execve_path == NULL || *qemu_execve_path == 0) {
    239 +        return get_errno(safe_execve(filename, argv, envp));
    240 +    }
    241 +
    242 +    for (argc = 0; argv[argc] != NULL; argc++) {
    243 +        /* nothing */ ;
    244 +    }
    245 +
    246 +    fd = open(filename, O_RDONLY);
    247 +    if (fd == -1) {
    248 +        return get_errno(fd);
    249 +    }
    250 +
    251 +    ret = read(fd, buf, BINPRM_BUF_SIZE);
    252 +    if (ret == -1) {
    253 +        close(fd);
    254 +        return get_errno(ret);
    255 +    }
    256 +
    257 +    /* if we have less than 2 bytes, we can guess it is not executable */
    258 +    if (ret < 2) {
    259 +        close(fd);
    260 +        return -host_to_target_errno(ENOEXEC);
    261 +    }
    262 +
    263 +    close(fd);
    264 +
    265 +    /* adapted from the kernel
    266 +     * https://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/tree/fs/binfmt_script.c
    267 +     */
    268 +    if ((buf[0] == '#') && (buf[1] == '!')) {
    269 +        /*
    270 +         * This section does the #! interpretation.
    271 +         * Sorta complicated, but hopefully it will work.  -TYT
    272 +         */
    273 +
    274 +        buf[BINPRM_BUF_SIZE - 1] = '\0';
    275 +        cp = strchr(buf, '\n');
    276 +        if (cp == NULL) {
    277 +            cp = buf + BINPRM_BUF_SIZE - 1;
    278 +        }
    279 +        *cp = '\0';
    280 +        while (cp > buf) {
    281 +            cp--;
    282 +            if ((*cp == ' ') || (*cp == '\t')) {
    283 +                *cp = '\0';
    284 +            } else {
    285 +                break;
    286 +            }
    287 +        }
    288 +        for (cp = buf + 2; (*cp == ' ') || (*cp == '\t'); cp++) {
    289 +            /* nothing */ ;
    290 +        }
    291 +        if (*cp == '\0') {
    292 +            return -ENOEXEC; /* No interpreter name found */
    293 +        }
    294 +        i_name = cp;
    295 +        i_arg = NULL;
    296 +        for ( ; *cp && (*cp != ' ') && (*cp != '\t'); cp++) {
    297 +            /* nothing */ ;
    298 +        }
    299 +        while ((*cp == ' ') || (*cp == '\t')) {
    300 +            *cp++ = '\0';
    301 +        }
    302 +        if (*cp) {
    303 +            i_arg = cp;
    304 +        }
    305 +
    306 +        if (i_arg) {
    307 +            offset += 2;
    308 +        } else {
    309 +            offset += 1;
    310 +        }
    311 +    }
    312 +
    313 +    new_argp = alloca((argc + offset + 1) * sizeof(void *));
    314 +
    315 +    /* Copy the original arguments with offset */
    316 +    for (i = 0; i < argc; i++) {
    317 +        new_argp[i + offset] = argv[i];
    318 +    }
    319 +
    320 +    new_argp[0] = strdup(qemu_execve_path);
    321 +    new_argp[1] = strdup("--execve");
    322 +    new_argp[2] = strdup(qemu_execve_path);
    323 +    new_argp[3] = strdup("-0");
    324 +    new_argp[offset] = filename;
    325 +    new_argp[argc + offset] = NULL;
    326 +
    327 +    if (i_name) {
    328 +        new_argp[4] = i_name;
    329 +        new_argp[5] = i_name;
    330 +
    331 +        if (i_arg) {
    332 +            new_argp[6] = i_arg;
    333 +        }
    334 +    } else {
    335 +        new_argp[4] = argv[0];
    336 +    }
    337 +
    338 +    return get_errno(safe_execve(qemu_execve_path, new_argp, envp));
    339 +}
    340 +
    341  static int target_to_host_cpu_mask(unsigned long *host_mask,
    342                                     size_t host_size,
    343                                     abi_ulong target_addr,
    344 @@ -8803,17 +8932,7 @@ static abi_long do_syscall1(void *cpu_env, int num, abi_long arg1,
    345  
    346              if (!(p = lock_user_string(arg1)))
    347                  goto execve_efault;
    348 -            /* Although execve() is not an interruptible syscall it is
    349 -             * a special case where we must use the safe_syscall wrapper:
    350 -             * if we allow a signal to happen before we make the host
    351 -             * syscall then we will 'lose' it, because at the point of
    352 -             * execve the process leaves QEMU's control. So we use the
    353 -             * safe syscall wrapper to ensure that we either take the
    354 -             * signal as a guest signal, or else it does not happen
    355 -             * before the execve completes and makes it the other
    356 -             * program's problem.
    357 -             */
    358 -            ret = get_errno(safe_execve(p, argp, envp));
    359 +            ret = qemu_execve(p, argp, envp);
    360              unlock_user(p, arg1, 0);
    361  
    362              goto execve_end;
    363 @@ -11330,7 +11449,7 @@ static abi_long do_syscall1(void *cpu_env, int num, abi_long arg1,
    364          return get_errno(fchown(arg1, low2highuid(arg2), low2highgid(arg3)));
    365  #if defined(TARGET_NR_fchownat)
    366      case TARGET_NR_fchownat:
    367 -        if (!(p = lock_user_string(arg2))) 
    368 +        if (!(p = lock_user_string(arg2)))
    369              return -TARGET_EFAULT;
    370          ret = get_errno(fchownat(arg1, p, low2highuid(arg3),
    371                                   low2highgid(arg4), arg5));
    372 diff --git a/linux-user/syscall_defs.h b/linux-user/syscall_defs.h
    373 index 4587b62ac9..4753bce1dc 100644
    374 --- a/linux-user/syscall_defs.h
    375 +++ b/linux-user/syscall_defs.h
    376 @@ -1330,6 +1330,7 @@ struct target_winsize {
    377  #else
    378  #define TARGET_MAP_FIXED	0x10		/* Interpret addr exactly */
    379  #define TARGET_MAP_ANONYMOUS	0x20		/* don't use a file */
    380 +#define TARGET_MAP_32BIT	0x40
    381  #define TARGET_MAP_GROWSDOWN	0x0100		/* stack-like segment */
    382  #define TARGET_MAP_DENYWRITE	0x0800		/* ETXTBSY */
    383  #define TARGET_MAP_EXECUTABLE	0x1000		/* mark it as an executable */
    384 diff --git a/linux-user/user-internals.h b/linux-user/user-internals.h
    385 index ee152ccfaa..e9e0fef472 100644
    386 --- a/linux-user/user-internals.h
    387 +++ b/linux-user/user-internals.h
    388 @@ -27,6 +27,7 @@ void init_task_state(TaskState *ts);
    389  void task_settid(TaskState *);
    390  void stop_all_tasks(void);
    391  extern const char *qemu_uname_release;
    392 +extern const char *qemu_execve_path;
    393  extern unsigned long mmap_min_addr;
    394  
    395  typedef struct IOCTLEntry IOCTLEntry;
    396 diff --git a/linux-user/user-mmap.h b/linux-user/user-mmap.h
    397 index d1dec99c02..b73c448b9a 100644
    398 --- a/linux-user/user-mmap.h
    399 +++ b/linux-user/user-mmap.h
    400 @@ -27,7 +27,7 @@ abi_long target_mremap(abi_ulong old_addr, abi_ulong old_size,
    401                         abi_ulong new_addr);
    402  extern unsigned long last_brk;
    403  extern abi_ulong mmap_next_start;
    404 -abi_ulong mmap_find_vma(abi_ulong, abi_ulong, abi_ulong);
    405 +abi_ulong mmap_find_vma(abi_ulong, abi_ulong, abi_ulong, bool);
    406  void mmap_fork_start(void);
    407  void mmap_fork_end(int child);
    408  
    409 diff --git a/target/i386/cpu.c b/target/i386/cpu.c
    410 index cb6b5467d0..08647e5cab 100644
    411 --- a/target/i386/cpu.c
    412 +++ b/target/i386/cpu.c
    413 @@ -1556,6 +1556,7 @@ typedef struct X86CPUDefinition {
    414      int family;
    415      int model;
    416      int stepping;
    417 +    int brand_id;
    418      FeatureWordArray features;
    419      const char *model_id;
    420      const CPUCaches *const cache_info;
    421 @@ -2041,6 +2042,54 @@ static const X86CPUDefinition builtin_x86_defs[] = {
    422          .xlevel = 0,
    423          .model_id = "",
    424      },
    425 +    {
    426 +        /* http://users.atw.hu/instlatx64/AuthenticAMD/AuthenticAMD0000F4A_K8_Clawhammer_CPUID.txt */
    427 +        .name = "athlon-64",
    428 +        .level = 1,
    429 +        .vendor = CPUID_VENDOR_AMD,
    430 +        .family = 15,
    431 +        .model = 4,
    432 +        .stepping = 10,
    433 +        .features[FEAT_1_EDX] =
    434 +            CPUID_FP87 | CPUID_VME | CPUID_DE | CPUID_PSE |
    435 +            CPUID_TSC | CPUID_MSR | CPUID_PAE | CPUID_MCE |
    436 +            CPUID_CX8 | CPUID_APIC | CPUID_SEP |
    437 +            CPUID_MTRR | CPUID_PGE | CPUID_MCA | CPUID_CMOV |
    438 +            CPUID_PAT | CPUID_PSE36 | /*no: CPUID_PN |*/ CPUID_CLFLUSH |
    439 +            /*no: CPUID_DTS | CPUID_ACPI |*/ CPUID_MMX |
    440 +            CPUID_FXSR | CPUID_SSE | CPUID_SSE2,
    441 +        .features[FEAT_8000_0001_EDX] =
    442 +            (CPUID_EXT2_FPU | CPUID_EXT2_VME | CPUID_EXT2_DE | CPUID_EXT2_PSE |
    443 +             CPUID_EXT2_TSC | CPUID_EXT2_MSR | CPUID_EXT2_PAE | CPUID_EXT2_MCE |
    444 +             CPUID_EXT2_CX8 | CPUID_EXT2_APIC | CPUID_EXT2_SYSCALL |
    445 +             CPUID_EXT2_MTRR | CPUID_EXT2_PGE | CPUID_EXT2_MCA | CPUID_EXT2_CMOV |
    446 +             CPUID_EXT2_PAT | CPUID_EXT2_PSE36 | /*no: CPUID_EXT2_MP */
    447 +             CPUID_EXT2_NX | CPUID_EXT2_MMXEXT | CPUID_EXT2_MMX |
    448 +             CPUID_EXT2_FXSR | /*no: CPUID_EXT2_FFXSR | CPUID_EXT2_PDPE1G | CPUID_EXT2_RTDSCP*/
    449 +             CPUID_EXT2_LM | CPUID_EXT2_3DNOWEXT | CPUID_EXT2_3DNOW) &
    450 +            ~CPUID_EXT2_AMD_ALIASES,
    451 +        /* todo cache info 0x80000005-6 */
    452 +        .features[FEAT_8000_0007_EDX] = 0x0f, /*??*/
    453 +        /*.phys_bits = 0x00003028,*/
    454 +        .xlevel = 0x80000018,
    455 +        .brand_id = 0x106,
    456 +        .model_id = "AMD Athlon(tm) 64 Processor 2800+",
    457 +    },
    458 +    {
    459 +        .name = "u3-64bit-minimal",
    460 +        .level = 1,
    461 +        .vendor = CPUID_VENDOR_AMD,
    462 +        .family = 15,
    463 +        .model = 4,
    464 +        .stepping = 10,
    465 +        .features[FEAT_1_EDX] =
    466 +        PENTIUM2_FEATURES | PPRO_FEATURES | CPUID_CLFLUSH /*sse2?*/,
    467 +        .features[FEAT_8000_0001_EDX] =
    468 +            /* NX: amd: since amd64, intel: P4 Prescott+ */
    469 +            CPUID_EXT2_SYSCALL | CPUID_EXT2_NX | CPUID_EXT2_LM,
    470 +        .xlevel = 0x80000018,
    471 +        .model_id = "Fuck off",
    472 +    },
    473      {
    474          .name = "athlon",
    475          .level = 2,
    476 @@ -4479,6 +4528,41 @@ static void x86_cpuid_version_set_stepping(Object *obj, Visitor *v,
    477      env->cpuid_version |= value & 0xf;
    478  }
    479  
    480 +static void x86_cpuid_version_get_brand_id(Object *obj, Visitor *v,
    481 +                                           const char *name, void *opaque,
    482 +                                           Error **errp)
    483 +{
    484 +    X86CPU *cpu = X86_CPU(obj);
    485 +    CPUX86State *env = &cpu->env;
    486 +    int64_t value;
    487 +
    488 +    value = env->cpuid_brand_id;
    489 +    visit_type_int(v, name, &value, errp);
    490 +}
    491 +
    492 +static void x86_cpuid_version_set_brand_id(Object *obj, Visitor *v,
    493 +                                           const char *name, void *opaque,
    494 +                                           Error **errp)
    495 +{
    496 +    X86CPU *cpu = X86_CPU(obj);
    497 +    CPUX86State *env = &cpu->env;
    498 +    const int64_t min = 0;
    499 +    const int64_t max = 0xffff;
    500 +    int64_t value;
    501 +
    502 +    if (!visit_type_int(v, name, &value, errp)) {
    503 +        return;
    504 +    }
    505 +    if (value < min || value > max) {
    506 +        error_setg(errp, QERR_PROPERTY_VALUE_OUT_OF_RANGE, "",
    507 +                   name ? name : "null", value, min, max);
    508 +        return;
    509 +    }
    510 +
    511 +    env->cpuid_brand_id = value;
    512 +}
    513 +
    514 +
    515  static char *x86_cpuid_get_vendor(Object *obj, Error **errp)
    516  {
    517      X86CPU *cpu = X86_CPU(obj);
    518 @@ -5097,6 +5181,8 @@ static void x86_cpu_load_model(X86CPU *cpu, X86CPUModel *model)
    519                              &error_abort);
    520      object_property_set_str(OBJECT(cpu), "model-id", def->model_id,
    521                              &error_abort);
    522 +    object_property_set_int(OBJECT(cpu), "brand-id", def->brand_id,
    523 +                            &error_abort);
    524      for (w = 0; w < FEATURE_WORDS; w++) {
    525          env->features[w] = def->features[w];
    526      }
    527 @@ -5675,7 +5761,7 @@ void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count,
    528          break;
    529      case 0x80000001:
    530          *eax = env->cpuid_version;
    531 -        *ebx = 0;
    532 +        *ebx = env->cpuid_brand_id;
    533          *ecx = env->features[FEAT_8000_0001_ECX];
    534          *edx = env->features[FEAT_8000_0001_EDX];
    535  
    536 @@ -7065,6 +7151,9 @@ static void x86_cpu_common_class_init(ObjectClass *oc, void *data)
    537      object_class_property_add(oc, "stepping", "int",
    538                                x86_cpuid_version_get_stepping,
    539                                x86_cpuid_version_set_stepping, NULL, NULL);
    540 +    object_class_property_add(oc, "brand-id", "int",
    541 +                              x86_cpuid_version_get_brand_id,
    542 +                              x86_cpuid_version_set_brand_id, NULL, NULL);
    543      object_class_property_add_str(oc, "vendor",
    544                                    x86_cpuid_get_vendor,
    545                                    x86_cpuid_set_vendor);
    546 diff --git a/target/i386/cpu.h b/target/i386/cpu.h
    547 index 982c532353..29d6f92a03 100644
    548 --- a/target/i386/cpu.h
    549 +++ b/target/i386/cpu.h
    550 @@ -1676,6 +1676,7 @@ typedef struct CPUArchState {
    551      uint32_t cpuid_vendor2;
    552      uint32_t cpuid_vendor3;
    553      uint32_t cpuid_version;
    554 +    uint32_t cpuid_brand_id;
    555      FeatureWordArray features;
    556      /* Features that were explicitly enabled/disabled */
    557      FeatureWordArray user_features;