qemu-6.0.0.patch (17332B)
1 Note: incorporates execve patch from here, probably gpl garbage: 2 https://patchwork.ozlabs.org/project/qemu-devel/patch/20200730160106.16613-1-rj.bcjesus@gmail.com/ 3 4 diff --git a/linux-user/main.c b/linux-user/main.c 5 index f956afccab..f85effddaf 100644 6 --- a/linux-user/main.c 7 +++ b/linux-user/main.c 8 @@ -114,6 +114,7 @@ static void usage(int exitcode); 9 10 static const char *interp_prefix = CONFIG_QEMU_INTERP_PREFIX; 11 const char *qemu_uname_release; 12 +const char *qemu_execve_path; 13 14 /* XXX: on x86 MAP_GROWSDOWN only works if ESP <= address + 32, so 15 we allocate a bigger stack. Need a better solution, for example 16 @@ -345,6 +346,11 @@ static void handle_arg_guest_base(const char *arg) 17 have_guest_base = true; 18 } 19 20 +static void handle_arg_execve(const char *arg) 21 +{ 22 + qemu_execve_path = strdup(arg); 23 +} 24 + 25 static void handle_arg_reserved_va(const char *arg) 26 { 27 char *p; 28 @@ -447,6 +453,8 @@ static const struct qemu_argument arg_table[] = { 29 "uname", "set qemu uname release string to 'uname'"}, 30 {"B", "QEMU_GUEST_BASE", true, handle_arg_guest_base, 31 "address", "set guest_base address to 'address'"}, 32 + {"execve", "QEMU_EXECVE", true, handle_arg_execve, 33 + "", "use this interpreter when a process calls execve()"}, 34 {"R", "QEMU_RESERVED_VA", true, handle_arg_reserved_va, 35 "size", "reserve 'size' bytes for guest virtual address space"}, 36 {"d", "QEMU_LOG", true, handle_arg_log, 37 diff --git a/linux-user/mmap.c b/linux-user/mmap.c 38 index 7e3b245036..0b3f7288ac 100644 39 --- a/linux-user/mmap.c 40 +++ b/linux-user/mmap.c 41 @@ -311,7 +311,7 @@ static abi_ulong mmap_find_vma_reserved(abi_ulong start, abi_ulong size, 42 * It must be called with mmap_lock() held. 43 * Return -1 if error. 44 */ 45 -abi_ulong mmap_find_vma(abi_ulong start, abi_ulong size, abi_ulong align) 46 +abi_ulong mmap_find_vma(abi_ulong start, abi_ulong size, abi_ulong align, bool map_32bit) 47 { 48 void *ptr, *prev; 49 abi_ulong addr; 50 @@ -346,7 +346,7 @@ abi_ulong mmap_find_vma(abi_ulong start, abi_ulong size, abi_ulong align) 51 * - shmat() with SHM_REMAP flag 52 */ 53 ptr = mmap(g2h_untagged(addr), size, PROT_NONE, 54 - MAP_ANONYMOUS|MAP_PRIVATE|MAP_NORESERVE, -1, 0); 55 + MAP_ANONYMOUS|MAP_PRIVATE|MAP_NORESERVE|(map_32bit?MAP_32BIT:0), -1, 0); 56 57 /* ENOMEM, if host address space has no memory */ 58 if (ptr == MAP_FAILED) { 59 @@ -357,7 +357,7 @@ abi_ulong mmap_find_vma(abi_ulong start, abi_ulong size, abi_ulong align) 60 This is used to modify the search algorithm below. */ 61 repeat = (ptr == prev ? repeat + 1 : 0); 62 63 - if (h2g_valid(ptr + size - 1)) { 64 + if (map_32bit ? h2g(ptr+size-1) == (uint32_t) (ptrdiff_t) (ptr+size-1): h2g_valid(ptr + size - 1)) { 65 addr = h2g(ptr); 66 67 if ((addr & (align - 1)) == 0) { 68 @@ -459,7 +459,7 @@ abi_long target_mmap(abi_ulong start, abi_ulong len, int target_prot, 69 if (!(flags & MAP_FIXED)) { 70 host_len = len + offset - host_offset; 71 host_len = HOST_PAGE_ALIGN(host_len); 72 - start = mmap_find_vma(real_start, host_len, TARGET_PAGE_SIZE); 73 + start = mmap_find_vma(real_start, host_len, TARGET_PAGE_SIZE, flags & MAP_32BIT); 74 if (start == (abi_ulong)-1) { 75 errno = ENOMEM; 76 goto fail; 77 @@ -756,7 +756,7 @@ abi_long target_mremap(abi_ulong old_addr, abi_ulong old_size, 78 } else if (flags & MREMAP_MAYMOVE) { 79 abi_ulong mmap_start; 80 81 - mmap_start = mmap_find_vma(0, new_size, TARGET_PAGE_SIZE); 82 + mmap_start = mmap_find_vma(0, new_size, TARGET_PAGE_SIZE, flags & MAP_32BIT); 83 84 if (mmap_start == -1) { 85 errno = ENOMEM; 86 diff --git a/linux-user/qemu.h b/linux-user/qemu.h 87 index 74e06e7121..612c90b2bc 100644 88 --- a/linux-user/qemu.h 89 +++ b/linux-user/qemu.h 90 @@ -164,6 +164,7 @@ void init_task_state(TaskState *ts); 91 void task_settid(TaskState *); 92 void stop_all_tasks(void); 93 extern const char *qemu_uname_release; 94 +extern const char *qemu_execve_path; 95 extern unsigned long mmap_min_addr; 96 97 /* ??? See if we can avoid exposing so much of the loader internals. */ 98 @@ -477,7 +478,7 @@ abi_long target_mremap(abi_ulong old_addr, abi_ulong old_size, 99 abi_ulong new_addr); 100 extern unsigned long last_brk; 101 extern abi_ulong mmap_next_start; 102 -abi_ulong mmap_find_vma(abi_ulong, abi_ulong, abi_ulong); 103 +abi_ulong mmap_find_vma(abi_ulong, abi_ulong, abi_ulong, bool); 104 void mmap_fork_start(void); 105 void mmap_fork_end(int child); 106 107 diff --git a/linux-user/strace.c b/linux-user/strace.c 108 index e969121b6c..278c749bbc 100644 109 --- a/linux-user/strace.c 110 +++ b/linux-user/strace.c 111 @@ -1071,6 +1071,9 @@ UNUSED static struct flags mmap_flags[] = { 112 #ifdef MAP_POPULATE 113 FLAG_TARGET(MAP_POPULATE), 114 #endif 115 +#ifdef TARGET_MAP_32BIT 116 + FLAG_TARGET(MAP_32BIT), 117 +#endif 118 #ifdef TARGET_MAP_UNINITIALIZED 119 FLAG_TARGET(MAP_UNINITIALIZED), 120 #endif 121 diff --git a/linux-user/syscall.c b/linux-user/syscall.c 122 index 95d79ddc43..f8808ad72f 100644 123 --- a/linux-user/syscall.c 124 +++ b/linux-user/syscall.c 125 @@ -123,6 +123,7 @@ 126 #include <libdrm/drm.h> 127 #include <libdrm/i915_drm.h> 128 #endif 129 +#include <linux/binfmts.h> 130 #include "linux_loop.h" 131 #include "uname.h" 132 133 @@ -4639,7 +4640,7 @@ static inline abi_ulong do_shmat(CPUArchState *cpu_env, 134 abi_ulong mmap_start; 135 136 /* In order to use the host shmat, we need to honor host SHMLBA. */ 137 - mmap_start = mmap_find_vma(0, shm_info.shm_segsz, MAX(SHMLBA, shmlba)); 138 + mmap_start = mmap_find_vma(0, shm_info.shm_segsz, MAX(SHMLBA, shmlba), false); 139 140 if (mmap_start == -1) { 141 errno = ENOMEM; 142 @@ -6063,6 +6064,9 @@ static const StructEntry struct_termios_def = { 143 }; 144 145 static bitmask_transtbl mmap_flags_tbl[] = { 146 +#ifdef TARGET_MAP_32BIT 147 + { TARGET_MAP_32BIT, TARGET_MAP_32BIT, MAP_32BIT, MAP_32BIT }, 148 +#endif 149 { TARGET_MAP_SHARED, TARGET_MAP_SHARED, MAP_SHARED, MAP_SHARED }, 150 { TARGET_MAP_PRIVATE, TARGET_MAP_PRIVATE, MAP_PRIVATE, MAP_PRIVATE }, 151 { TARGET_MAP_FIXED, TARGET_MAP_FIXED, MAP_FIXED, MAP_FIXED }, 152 @@ -8178,6 +8182,131 @@ static target_timer_t get_timer_id(abi_long arg) 153 return timerid; 154 } 155 156 +/* qemu_execve() Must return target values and target errnos. 157 + * 158 + * Although execve() is not an interruptible syscall it is 159 + * a special case where we must use the safe_syscall wrapper: 160 + * if we allow a signal to happen before we make the host 161 + * syscall then we will 'lose' it, because at the point of 162 + * execve the process leaves QEMU's control. So we use the 163 + * safe syscall wrapper to ensure that we either take the 164 + * signal as a guest signal, or else it does not happen 165 + * before the execve completes and makes it the other 166 + * program's problem. 167 + */ 168 +static abi_long qemu_execve(char *filename, char *argv[], 169 + char *envp[]) 170 +{ 171 + char *i_arg = NULL, *i_name = NULL; 172 + char **new_argp; 173 + int argc, fd, ret, i, offset = 5; 174 + char *cp; 175 + char buf[BINPRM_BUF_SIZE]; 176 + 177 + /* normal execve case */ 178 + if (qemu_execve_path == NULL || *qemu_execve_path == 0) { 179 + return get_errno(safe_execve(filename, argv, envp)); 180 + } 181 + 182 + for (argc = 0; argv[argc] != NULL; argc++) { 183 + /* nothing */ ; 184 + } 185 + 186 + fd = open(filename, O_RDONLY); 187 + if (fd == -1) { 188 + return get_errno(fd); 189 + } 190 + 191 + ret = read(fd, buf, BINPRM_BUF_SIZE); 192 + if (ret == -1) { 193 + close(fd); 194 + return get_errno(ret); 195 + } 196 + 197 + /* if we have less than 2 bytes, we can guess it is not executable */ 198 + if (ret < 2) { 199 + close(fd); 200 + return -host_to_target_errno(ENOEXEC); 201 + } 202 + 203 + close(fd); 204 + 205 + /* adapted from the kernel 206 + * https://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/tree/fs/binfmt_script.c 207 + */ 208 + if ((buf[0] == '#') && (buf[1] == '!')) { 209 + /* 210 + * This section does the #! interpretation. 211 + * Sorta complicated, but hopefully it will work. -TYT 212 + */ 213 + 214 + buf[BINPRM_BUF_SIZE - 1] = '\0'; 215 + cp = strchr(buf, '\n'); 216 + if (cp == NULL) { 217 + cp = buf + BINPRM_BUF_SIZE - 1; 218 + } 219 + *cp = '\0'; 220 + while (cp > buf) { 221 + cp--; 222 + if ((*cp == ' ') || (*cp == '\t')) { 223 + *cp = '\0'; 224 + } else { 225 + break; 226 + } 227 + } 228 + for (cp = buf + 2; (*cp == ' ') || (*cp == '\t'); cp++) { 229 + /* nothing */ ; 230 + } 231 + if (*cp == '\0') { 232 + return -ENOEXEC; /* No interpreter name found */ 233 + } 234 + i_name = cp; 235 + i_arg = NULL; 236 + for ( ; *cp && (*cp != ' ') && (*cp != '\t'); cp++) { 237 + /* nothing */ ; 238 + } 239 + while ((*cp == ' ') || (*cp == '\t')) { 240 + *cp++ = '\0'; 241 + } 242 + if (*cp) { 243 + i_arg = cp; 244 + } 245 + 246 + if (i_arg) { 247 + offset += 2; 248 + } else { 249 + offset += 1; 250 + } 251 + } 252 + 253 + new_argp = alloca((argc + offset + 1) * sizeof(void *)); 254 + 255 + /* Copy the original arguments with offset */ 256 + for (i = 0; i < argc; i++) { 257 + new_argp[i + offset] = argv[i]; 258 + } 259 + 260 + new_argp[0] = strdup(qemu_execve_path); 261 + new_argp[1] = strdup("--execve"); 262 + new_argp[2] = strdup(qemu_execve_path); 263 + new_argp[3] = strdup("-0"); 264 + new_argp[offset] = filename; 265 + new_argp[argc + offset] = NULL; 266 + 267 + if (i_name) { 268 + new_argp[4] = i_name; 269 + new_argp[5] = i_name; 270 + 271 + if (i_arg) { 272 + new_argp[6] = i_arg; 273 + } 274 + } else { 275 + new_argp[4] = argv[0]; 276 + } 277 + 278 + return get_errno(safe_execve(qemu_execve_path, new_argp, envp)); 279 +} 280 + 281 static int target_to_host_cpu_mask(unsigned long *host_mask, 282 size_t host_size, 283 abi_ulong target_addr, 284 @@ -8527,17 +8656,7 @@ static abi_long do_syscall1(void *cpu_env, int num, abi_long arg1, 285 286 if (!(p = lock_user_string(arg1))) 287 goto execve_efault; 288 - /* Although execve() is not an interruptible syscall it is 289 - * a special case where we must use the safe_syscall wrapper: 290 - * if we allow a signal to happen before we make the host 291 - * syscall then we will 'lose' it, because at the point of 292 - * execve the process leaves QEMU's control. So we use the 293 - * safe syscall wrapper to ensure that we either take the 294 - * signal as a guest signal, or else it does not happen 295 - * before the execve completes and makes it the other 296 - * program's problem. 297 - */ 298 - ret = get_errno(safe_execve(p, argp, envp)); 299 + ret = qemu_execve(p, argp, envp); 300 unlock_user(p, arg1, 0); 301 302 goto execve_end; 303 diff --git a/linux-user/syscall_defs.h b/linux-user/syscall_defs.h 304 index 25be414727..c0772c1ae7 100644 305 --- a/linux-user/syscall_defs.h 306 +++ b/linux-user/syscall_defs.h 307 @@ -1390,6 +1390,7 @@ struct target_winsize { 308 #else 309 #define TARGET_MAP_FIXED 0x10 /* Interpret addr exactly */ 310 #define TARGET_MAP_ANONYMOUS 0x20 /* don't use a file */ 311 +#define TARGET_MAP_32BIT 0x40 312 #define TARGET_MAP_GROWSDOWN 0x0100 /* stack-like segment */ 313 #define TARGET_MAP_DENYWRITE 0x0800 /* ETXTBSY */ 314 #define TARGET_MAP_EXECUTABLE 0x1000 /* mark it as an executable */ 315 diff --git a/target/i386/cpu.c b/target/i386/cpu.c 316 index ad99cad0e7..8258b92e5b 100644 317 --- a/target/i386/cpu.c 318 +++ b/target/i386/cpu.c 319 @@ -1653,6 +1653,7 @@ typedef struct X86CPUDefinition { 320 int family; 321 int model; 322 int stepping; 323 + int brand_id; 324 FeatureWordArray features; 325 const char *model_id; 326 CPUCaches *cache_info; 327 @@ -2137,6 +2138,54 @@ static X86CPUDefinition builtin_x86_defs[] = { 328 .xlevel = 0, 329 .model_id = "", 330 }, 331 + { 332 + /* http://users.atw.hu/instlatx64/AuthenticAMD/AuthenticAMD0000F4A_K8_Clawhammer_CPUID.txt */ 333 + .name = "athlon-64", 334 + .level = 1, 335 + .vendor = CPUID_VENDOR_AMD, 336 + .family = 15, 337 + .model = 4, 338 + .stepping = 10, 339 + .features[FEAT_1_EDX] = 340 + CPUID_FP87 | CPUID_VME | CPUID_DE | CPUID_PSE | 341 + CPUID_TSC | CPUID_MSR | CPUID_PAE | CPUID_MCE | 342 + CPUID_CX8 | CPUID_APIC | CPUID_SEP | 343 + CPUID_MTRR | CPUID_PGE | CPUID_MCA | CPUID_CMOV | 344 + CPUID_PAT | CPUID_PSE36 | /*no: CPUID_PN |*/ CPUID_CLFLUSH | 345 + /*no: CPUID_DTS | CPUID_ACPI |*/ CPUID_MMX | 346 + CPUID_FXSR | CPUID_SSE | CPUID_SSE2, 347 + .features[FEAT_8000_0001_EDX] = 348 + (CPUID_EXT2_FPU | CPUID_EXT2_VME | CPUID_EXT2_DE | CPUID_EXT2_PSE | 349 + CPUID_EXT2_TSC | CPUID_EXT2_MSR | CPUID_EXT2_PAE | CPUID_EXT2_MCE | 350 + CPUID_EXT2_CX8 | CPUID_EXT2_APIC | CPUID_EXT2_SYSCALL | 351 + CPUID_EXT2_MTRR | CPUID_EXT2_PGE | CPUID_EXT2_MCA | CPUID_EXT2_CMOV | 352 + CPUID_EXT2_PAT | CPUID_EXT2_PSE36 | /*no: CPUID_EXT2_MP */ 353 + CPUID_EXT2_NX | CPUID_EXT2_MMXEXT | CPUID_EXT2_MMX | 354 + CPUID_EXT2_FXSR | /*no: CPUID_EXT2_FFXSR | CPUID_EXT2_PDPE1G | CPUID_EXT2_RTDSCP*/ 355 + CPUID_EXT2_LM | CPUID_EXT2_3DNOWEXT | CPUID_EXT2_3DNOW) & 356 + ~CPUID_EXT2_AMD_ALIASES, 357 + /* todo cache info 0x80000005-6 */ 358 + .features[FEAT_8000_0007_EDX] = 0x0f, /*??*/ 359 + /*.phys_bits = 0x00003028,*/ 360 + .xlevel = 0x80000018, 361 + .brand_id = 0x106, 362 + .model_id = "AMD Athlon(tm) 64 Processor 2800+", 363 + }, 364 + { 365 + .name = "u3-64bit-minimal", 366 + .level = 1, 367 + .vendor = CPUID_VENDOR_AMD, 368 + .family = 15, 369 + .model = 4, 370 + .stepping = 10, 371 + .features[FEAT_1_EDX] = 372 + PENTIUM2_FEATURES | PPRO_FEATURES | CPUID_CLFLUSH /*sse2?*/, 373 + .features[FEAT_8000_0001_EDX] = 374 + /* NX: amd: since amd64, intel: P4 Prescott+ */ 375 + CPUID_EXT2_SYSCALL | CPUID_EXT2_NX | CPUID_EXT2_LM, 376 + .xlevel = 0x80000018, 377 + .model_id = "Fuck off", 378 + }, 379 { 380 .name = "athlon", 381 .level = 2, 382 @@ -4657,6 +4706,41 @@ static void x86_cpuid_version_set_stepping(Object *obj, Visitor *v, 383 env->cpuid_version |= value & 0xf; 384 } 385 386 +static void x86_cpuid_version_get_brand_id(Object *obj, Visitor *v, 387 + const char *name, void *opaque, 388 + Error **errp) 389 +{ 390 + X86CPU *cpu = X86_CPU(obj); 391 + CPUX86State *env = &cpu->env; 392 + int64_t value; 393 + 394 + value = env->cpuid_brand_id; 395 + visit_type_int(v, name, &value, errp); 396 +} 397 + 398 +static void x86_cpuid_version_set_brand_id(Object *obj, Visitor *v, 399 + const char *name, void *opaque, 400 + Error **errp) 401 +{ 402 + X86CPU *cpu = X86_CPU(obj); 403 + CPUX86State *env = &cpu->env; 404 + const int64_t min = 0; 405 + const int64_t max = 0xffff; 406 + int64_t value; 407 + 408 + if (!visit_type_int(v, name, &value, errp)) { 409 + return; 410 + } 411 + if (value < min || value > max) { 412 + error_setg(errp, QERR_PROPERTY_VALUE_OUT_OF_RANGE, "", 413 + name ? name : "null", value, min, max); 414 + return; 415 + } 416 + 417 + env->cpuid_brand_id = value; 418 +} 419 + 420 + 421 static char *x86_cpuid_get_vendor(Object *obj, Error **errp) 422 { 423 X86CPU *cpu = X86_CPU(obj); 424 @@ -5269,6 +5353,8 @@ static void x86_cpu_load_model(X86CPU *cpu, X86CPUModel *model) 425 &error_abort); 426 object_property_set_str(OBJECT(cpu), "model-id", def->model_id, 427 &error_abort); 428 + object_property_set_int(OBJECT(cpu), "brand-id", def->brand_id, 429 + &error_abort); 430 for (w = 0; w < FEATURE_WORDS; w++) { 431 env->features[w] = def->features[w]; 432 } 433 @@ -5936,7 +6022,7 @@ void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count, 434 break; 435 case 0x80000001: 436 *eax = env->cpuid_version; 437 - *ebx = 0; 438 + *ebx = env->cpuid_brand_id; 439 *ecx = env->features[FEAT_8000_0001_ECX]; 440 *edx = env->features[FEAT_8000_0001_EDX]; 441 442 @@ -7455,6 +7541,9 @@ static void x86_cpu_common_class_init(ObjectClass *oc, void *data) 443 object_class_property_add(oc, "stepping", "int", 444 x86_cpuid_version_get_stepping, 445 x86_cpuid_version_set_stepping, NULL, NULL); 446 + object_class_property_add(oc, "brand-id", "int", 447 + x86_cpuid_version_get_brand_id, 448 + x86_cpuid_version_set_brand_id, NULL, NULL); 449 object_class_property_add_str(oc, "vendor", 450 x86_cpuid_get_vendor, 451 x86_cpuid_set_vendor); 452 diff --git a/target/i386/cpu.h b/target/i386/cpu.h 453 index 570f916878..2e7b3c838c 100644 454 --- a/target/i386/cpu.h 455 +++ b/target/i386/cpu.h 456 @@ -1591,6 +1591,7 @@ typedef struct CPUX86State { 457 uint32_t cpuid_vendor2; 458 uint32_t cpuid_vendor3; 459 uint32_t cpuid_version; 460 + uint32_t cpuid_brand_id; 461 FeatureWordArray features; 462 /* Features that were explicitly enabled/disabled */ 463 FeatureWordArray user_features;