qemu-7.2.0.patch (21246B)
1 diff --git a/linux-user/main.c b/linux-user/main.c 2 index a17fed045b..999b65bfc1 100644 3 --- a/linux-user/main.c 4 +++ b/linux-user/main.c 5 @@ -123,6 +123,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 #if !defined(TARGET_DEFAULT_STACK_SIZE) 12 /* XXX: on x86 MAP_GROWSDOWN only works if ESP <= address + 32, so 13 @@ -362,6 +363,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 @@ -464,6 +470,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 10f5079331..d2c6919f60 100644 36 --- a/linux-user/mmap.c 37 +++ b/linux-user/mmap.c 38 @@ -321,7 +321,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 @@ -356,7 +356,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 @@ -367,7 +367,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 @@ -484,7 +484,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 @@ -799,7 +799,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 9ae5a812cd..8ab56ff3b6 100644 85 --- a/linux-user/strace.c 86 +++ b/linux-user/strace.c 87 @@ -1086,6 +1086,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 24b25759be..9ce518bb7a 100644 99 --- a/linux-user/syscall.c 100 +++ b/linux-user/syscall.c 101 @@ -166,6 +166,7 @@ struct file_clone_range { 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 @@ -1058,7 +1059,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 @@ -1066,7 +1067,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 @@ -1076,13 +1077,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 @@ -1809,9 +1810,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 @@ -1897,7 +1898,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 @@ -4591,7 +4592,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 @@ -6015,6 +6016,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 @@ -6209,7 +6213,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 @@ -6287,7 +6291,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 @@ -6303,8 +6307,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 @@ -8378,6 +8382,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 @@ -8922,20 +9051,10 @@ static abi_long do_syscall1(CPUArchState *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 if (is_proc_myself(p, "exe")) { 359 - ret = get_errno(safe_execve(exec_path, argp, envp)); 360 + ret = qemu_execve(exec_path, argp, envp); 361 } else { 362 - ret = get_errno(safe_execve(p, argp, envp)); 363 + ret = qemu_execve(p, argp, envp); 364 } 365 unlock_user(p, arg1, 0); 366 367 @@ -11473,7 +11592,7 @@ static abi_long do_syscall1(CPUArchState *cpu_env, int num, abi_long arg1, 368 return get_errno(fchown(arg1, low2highuid(arg2), low2highgid(arg3))); 369 #if defined(TARGET_NR_fchownat) 370 case TARGET_NR_fchownat: 371 - if (!(p = lock_user_string(arg2))) 372 + if (!(p = lock_user_string(arg2))) 373 return -TARGET_EFAULT; 374 ret = get_errno(fchownat(arg1, p, low2highuid(arg3), 375 low2highgid(arg4), arg5)); 376 diff --git a/linux-user/syscall_defs.h b/linux-user/syscall_defs.h 377 index 77864de57f..c0bcfacd42 100644 378 --- a/linux-user/syscall_defs.h 379 +++ b/linux-user/syscall_defs.h 380 @@ -1330,6 +1330,7 @@ struct target_winsize { 381 #else 382 #define TARGET_MAP_FIXED 0x10 /* Interpret addr exactly */ 383 #define TARGET_MAP_ANONYMOUS 0x20 /* don't use a file */ 384 +#define TARGET_MAP_32BIT 0x40 385 #define TARGET_MAP_GROWSDOWN 0x0100 /* stack-like segment */ 386 #define TARGET_MAP_DENYWRITE 0x0800 /* ETXTBSY */ 387 #define TARGET_MAP_EXECUTABLE 0x1000 /* mark it as an executable */ 388 diff --git a/linux-user/user-internals.h b/linux-user/user-internals.h 389 index 0280e76add..7586971298 100644 390 --- a/linux-user/user-internals.h 391 +++ b/linux-user/user-internals.h 392 @@ -27,6 +27,7 @@ void init_task_state(TaskState *ts); 393 void task_settid(TaskState *); 394 void stop_all_tasks(void); 395 extern const char *qemu_uname_release; 396 +extern const char *qemu_execve_path; 397 extern unsigned long mmap_min_addr; 398 399 typedef struct IOCTLEntry IOCTLEntry; 400 diff --git a/linux-user/user-mmap.h b/linux-user/user-mmap.h 401 index 480ce1c114..042bd299dd 100644 402 --- a/linux-user/user-mmap.h 403 +++ b/linux-user/user-mmap.h 404 @@ -28,7 +28,7 @@ abi_long target_mremap(abi_ulong old_addr, abi_ulong old_size, 405 abi_long target_madvise(abi_ulong start, abi_ulong len_in, int advice); 406 extern unsigned long last_brk; 407 extern abi_ulong mmap_next_start; 408 -abi_ulong mmap_find_vma(abi_ulong, abi_ulong, abi_ulong); 409 +abi_ulong mmap_find_vma(abi_ulong, abi_ulong, abi_ulong, bool); 410 void mmap_fork_start(void); 411 void mmap_fork_end(int child); 412 413 diff --git a/target/i386/cpu.c b/target/i386/cpu.c 414 index 22b681ca37..8986804373 100644 415 --- a/target/i386/cpu.c 416 +++ b/target/i386/cpu.c 417 @@ -1608,6 +1608,7 @@ typedef struct X86CPUDefinition { 418 int family; 419 int model; 420 int stepping; 421 + int brand_id; 422 FeatureWordArray features; 423 const char *model_id; 424 const CPUCaches *const cache_info; 425 @@ -2093,6 +2094,54 @@ static const X86CPUDefinition builtin_x86_defs[] = { 426 .xlevel = 0, 427 .model_id = "", 428 }, 429 + { 430 + /* http://users.atw.hu/instlatx64/AuthenticAMD/AuthenticAMD0000F4A_K8_Clawhammer_CPUID.txt */ 431 + .name = "athlon-64", 432 + .level = 1, 433 + .vendor = CPUID_VENDOR_AMD, 434 + .family = 15, 435 + .model = 4, 436 + .stepping = 10, 437 + .features[FEAT_1_EDX] = 438 + CPUID_FP87 | CPUID_VME | CPUID_DE | CPUID_PSE | 439 + CPUID_TSC | CPUID_MSR | CPUID_PAE | CPUID_MCE | 440 + CPUID_CX8 | CPUID_APIC | CPUID_SEP | 441 + CPUID_MTRR | CPUID_PGE | CPUID_MCA | CPUID_CMOV | 442 + CPUID_PAT | CPUID_PSE36 | /*no: CPUID_PN |*/ CPUID_CLFLUSH | 443 + /*no: CPUID_DTS | CPUID_ACPI |*/ CPUID_MMX | 444 + CPUID_FXSR | CPUID_SSE | CPUID_SSE2, 445 + .features[FEAT_8000_0001_EDX] = 446 + (CPUID_EXT2_FPU | CPUID_EXT2_VME | CPUID_EXT2_DE | CPUID_EXT2_PSE | 447 + CPUID_EXT2_TSC | CPUID_EXT2_MSR | CPUID_EXT2_PAE | CPUID_EXT2_MCE | 448 + CPUID_EXT2_CX8 | CPUID_EXT2_APIC | CPUID_EXT2_SYSCALL | 449 + CPUID_EXT2_MTRR | CPUID_EXT2_PGE | CPUID_EXT2_MCA | CPUID_EXT2_CMOV | 450 + CPUID_EXT2_PAT | CPUID_EXT2_PSE36 | /*no: CPUID_EXT2_MP */ 451 + CPUID_EXT2_NX | CPUID_EXT2_MMXEXT | CPUID_EXT2_MMX | 452 + CPUID_EXT2_FXSR | /*no: CPUID_EXT2_FFXSR | CPUID_EXT2_PDPE1G | CPUID_EXT2_RTDSCP*/ 453 + CPUID_EXT2_LM | CPUID_EXT2_3DNOWEXT | CPUID_EXT2_3DNOW) & 454 + ~CPUID_EXT2_AMD_ALIASES, 455 + /* todo cache info 0x80000005-6 */ 456 + .features[FEAT_8000_0007_EDX] = 0x0f, /*??*/ 457 + /*.phys_bits = 0x00003028,*/ 458 + .xlevel = 0x80000018, 459 + .brand_id = 0x106, 460 + .model_id = "AMD Athlon(tm) 64 Processor 2800+", 461 + }, 462 + { 463 + .name = "u3-64bit-minimal", 464 + .level = 1, 465 + .vendor = CPUID_VENDOR_AMD, 466 + .family = 15, 467 + .model = 4, 468 + .stepping = 10, 469 + .features[FEAT_1_EDX] = 470 + PENTIUM2_FEATURES | PPRO_FEATURES | CPUID_CLFLUSH /*sse2?*/, 471 + .features[FEAT_8000_0001_EDX] = 472 + /* NX: amd: since amd64, intel: P4 Prescott+ */ 473 + CPUID_EXT2_SYSCALL | CPUID_EXT2_NX | CPUID_EXT2_LM, 474 + .xlevel = 0x80000018, 475 + .model_id = "Fuck off", 476 + }, 477 { 478 .name = "athlon", 479 .level = 2, 480 @@ -4409,6 +4458,41 @@ static void x86_cpuid_version_set_stepping(Object *obj, Visitor *v, 481 env->cpuid_version |= value & 0xf; 482 } 483 484 +static void x86_cpuid_version_get_brand_id(Object *obj, Visitor *v, 485 + const char *name, void *opaque, 486 + Error **errp) 487 +{ 488 + X86CPU *cpu = X86_CPU(obj); 489 + CPUX86State *env = &cpu->env; 490 + int64_t value; 491 + 492 + value = env->cpuid_brand_id; 493 + visit_type_int(v, name, &value, errp); 494 +} 495 + 496 +static void x86_cpuid_version_set_brand_id(Object *obj, Visitor *v, 497 + const char *name, void *opaque, 498 + Error **errp) 499 +{ 500 + X86CPU *cpu = X86_CPU(obj); 501 + CPUX86State *env = &cpu->env; 502 + const int64_t min = 0; 503 + const int64_t max = 0xffff; 504 + int64_t value; 505 + 506 + if (!visit_type_int(v, name, &value, errp)) { 507 + return; 508 + } 509 + if (value < min || value > max) { 510 + error_setg(errp, QERR_PROPERTY_VALUE_OUT_OF_RANGE, "", 511 + name ? name : "null", value, min, max); 512 + return; 513 + } 514 + 515 + env->cpuid_brand_id = value; 516 +} 517 + 518 + 519 static char *x86_cpuid_get_vendor(Object *obj, Error **errp) 520 { 521 X86CPU *cpu = X86_CPU(obj); 522 @@ -5085,6 +5169,8 @@ static void x86_cpu_load_model(X86CPU *cpu, X86CPUModel *model) 523 &error_abort); 524 object_property_set_str(OBJECT(cpu), "model-id", def->model_id, 525 &error_abort); 526 + object_property_set_int(OBJECT(cpu), "brand-id", def->brand_id, 527 + &error_abort); 528 for (w = 0; w < FEATURE_WORDS; w++) { 529 env->features[w] = def->features[w]; 530 } 531 @@ -5691,7 +5777,7 @@ void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count, 532 break; 533 case 0x80000001: 534 *eax = env->cpuid_version; 535 - *ebx = 0; 536 + *ebx = env->cpuid_brand_id; 537 *ecx = env->features[FEAT_8000_0001_ECX]; 538 *edx = env->features[FEAT_8000_0001_EDX]; 539 540 @@ -7158,6 +7244,9 @@ static void x86_cpu_common_class_init(ObjectClass *oc, void *data) 541 object_class_property_add(oc, "stepping", "int", 542 x86_cpuid_version_get_stepping, 543 x86_cpuid_version_set_stepping, NULL, NULL); 544 + object_class_property_add(oc, "brand-id", "int", 545 + x86_cpuid_version_get_brand_id, 546 + x86_cpuid_version_set_brand_id, NULL, NULL); 547 object_class_property_add_str(oc, "vendor", 548 x86_cpuid_get_vendor, 549 x86_cpuid_set_vendor); 550 diff --git a/target/i386/cpu.h b/target/i386/cpu.h 551 index d4bc19577a..a8eff25d92 100644 552 --- a/target/i386/cpu.h 553 +++ b/target/i386/cpu.h 554 @@ -1749,6 +1749,7 @@ typedef struct CPUArchState { 555 uint32_t cpuid_vendor2; 556 uint32_t cpuid_vendor3; 557 uint32_t cpuid_version; 558 + uint32_t cpuid_brand_id; 559 FeatureWordArray features; 560 /* Features that were explicitly enabled/disabled */ 561 FeatureWordArray user_features;