You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
libshit/tools/qemu-6.0.0.patch

464 lines
17 KiB
Diff

Note: incorporates execve patch from here, probably gpl garbage:
https://patchwork.ozlabs.org/project/qemu-devel/patch/20200730160106.16613-1-rj.bcjesus@gmail.com/
diff --git a/linux-user/main.c b/linux-user/main.c
index f956afccab..f85effddaf 100644
--- a/linux-user/main.c
+++ b/linux-user/main.c
@@ -114,6 +114,7 @@ static void usage(int exitcode);
static const char *interp_prefix = CONFIG_QEMU_INTERP_PREFIX;
const char *qemu_uname_release;
+const char *qemu_execve_path;
/* XXX: on x86 MAP_GROWSDOWN only works if ESP <= address + 32, so
we allocate a bigger stack. Need a better solution, for example
@@ -345,6 +346,11 @@ static void handle_arg_guest_base(const char *arg)
have_guest_base = true;
}
+static void handle_arg_execve(const char *arg)
+{
+ qemu_execve_path = strdup(arg);
+}
+
static void handle_arg_reserved_va(const char *arg)
{
char *p;
@@ -447,6 +453,8 @@ static const struct qemu_argument arg_table[] = {
"uname", "set qemu uname release string to 'uname'"},
{"B", "QEMU_GUEST_BASE", true, handle_arg_guest_base,
"address", "set guest_base address to 'address'"},
+ {"execve", "QEMU_EXECVE", true, handle_arg_execve,
+ "", "use this interpreter when a process calls execve()"},
{"R", "QEMU_RESERVED_VA", true, handle_arg_reserved_va,
"size", "reserve 'size' bytes for guest virtual address space"},
{"d", "QEMU_LOG", true, handle_arg_log,
diff --git a/linux-user/mmap.c b/linux-user/mmap.c
index 7e3b245036..0b3f7288ac 100644
--- a/linux-user/mmap.c
+++ b/linux-user/mmap.c
@@ -311,7 +311,7 @@ static abi_ulong mmap_find_vma_reserved(abi_ulong start, abi_ulong size,
* It must be called with mmap_lock() held.
* Return -1 if error.
*/
-abi_ulong mmap_find_vma(abi_ulong start, abi_ulong size, abi_ulong align)
+abi_ulong mmap_find_vma(abi_ulong start, abi_ulong size, abi_ulong align, bool map_32bit)
{
void *ptr, *prev;
abi_ulong addr;
@@ -346,7 +346,7 @@ abi_ulong mmap_find_vma(abi_ulong start, abi_ulong size, abi_ulong align)
* - shmat() with SHM_REMAP flag
*/
ptr = mmap(g2h_untagged(addr), size, PROT_NONE,
- MAP_ANONYMOUS|MAP_PRIVATE|MAP_NORESERVE, -1, 0);
+ MAP_ANONYMOUS|MAP_PRIVATE|MAP_NORESERVE|(map_32bit?MAP_32BIT:0), -1, 0);
/* ENOMEM, if host address space has no memory */
if (ptr == MAP_FAILED) {
@@ -357,7 +357,7 @@ abi_ulong mmap_find_vma(abi_ulong start, abi_ulong size, abi_ulong align)
This is used to modify the search algorithm below. */
repeat = (ptr == prev ? repeat + 1 : 0);
- if (h2g_valid(ptr + size - 1)) {
+ if (map_32bit ? h2g(ptr+size-1) == (uint32_t) (ptrdiff_t) (ptr+size-1): h2g_valid(ptr + size - 1)) {
addr = h2g(ptr);
if ((addr & (align - 1)) == 0) {
@@ -459,7 +459,7 @@ abi_long target_mmap(abi_ulong start, abi_ulong len, int target_prot,
if (!(flags & MAP_FIXED)) {
host_len = len + offset - host_offset;
host_len = HOST_PAGE_ALIGN(host_len);
- start = mmap_find_vma(real_start, host_len, TARGET_PAGE_SIZE);
+ start = mmap_find_vma(real_start, host_len, TARGET_PAGE_SIZE, flags & MAP_32BIT);
if (start == (abi_ulong)-1) {
errno = ENOMEM;
goto fail;
@@ -756,7 +756,7 @@ abi_long target_mremap(abi_ulong old_addr, abi_ulong old_size,
} else if (flags & MREMAP_MAYMOVE) {
abi_ulong mmap_start;
- mmap_start = mmap_find_vma(0, new_size, TARGET_PAGE_SIZE);
+ mmap_start = mmap_find_vma(0, new_size, TARGET_PAGE_SIZE, flags & MAP_32BIT);
if (mmap_start == -1) {
errno = ENOMEM;
diff --git a/linux-user/qemu.h b/linux-user/qemu.h
index 74e06e7121..612c90b2bc 100644
--- a/linux-user/qemu.h
+++ b/linux-user/qemu.h
@@ -164,6 +164,7 @@ void init_task_state(TaskState *ts);
void task_settid(TaskState *);
void stop_all_tasks(void);
extern const char *qemu_uname_release;
+extern const char *qemu_execve_path;
extern unsigned long mmap_min_addr;
/* ??? See if we can avoid exposing so much of the loader internals. */
@@ -477,7 +478,7 @@ abi_long target_mremap(abi_ulong old_addr, abi_ulong old_size,
abi_ulong new_addr);
extern unsigned long last_brk;
extern abi_ulong mmap_next_start;
-abi_ulong mmap_find_vma(abi_ulong, abi_ulong, abi_ulong);
+abi_ulong mmap_find_vma(abi_ulong, abi_ulong, abi_ulong, bool);
void mmap_fork_start(void);
void mmap_fork_end(int child);
diff --git a/linux-user/strace.c b/linux-user/strace.c
index e969121b6c..278c749bbc 100644
--- a/linux-user/strace.c
+++ b/linux-user/strace.c
@@ -1071,6 +1071,9 @@ UNUSED static struct flags mmap_flags[] = {
#ifdef MAP_POPULATE
FLAG_TARGET(MAP_POPULATE),
#endif
+#ifdef TARGET_MAP_32BIT
+ FLAG_TARGET(MAP_32BIT),
+#endif
#ifdef TARGET_MAP_UNINITIALIZED
FLAG_TARGET(MAP_UNINITIALIZED),
#endif
diff --git a/linux-user/syscall.c b/linux-user/syscall.c
index 95d79ddc43..f8808ad72f 100644
--- a/linux-user/syscall.c
+++ b/linux-user/syscall.c
@@ -123,6 +123,7 @@
#include <libdrm/drm.h>
#include <libdrm/i915_drm.h>
#endif
+#include <linux/binfmts.h>
#include "linux_loop.h"
#include "uname.h"
@@ -4639,7 +4640,7 @@ static inline abi_ulong do_shmat(CPUArchState *cpu_env,
abi_ulong mmap_start;
/* In order to use the host shmat, we need to honor host SHMLBA. */
- mmap_start = mmap_find_vma(0, shm_info.shm_segsz, MAX(SHMLBA, shmlba));
+ mmap_start = mmap_find_vma(0, shm_info.shm_segsz, MAX(SHMLBA, shmlba), false);
if (mmap_start == -1) {
errno = ENOMEM;
@@ -6063,6 +6064,9 @@ static const StructEntry struct_termios_def = {
};
static bitmask_transtbl mmap_flags_tbl[] = {
+#ifdef TARGET_MAP_32BIT
+ { TARGET_MAP_32BIT, TARGET_MAP_32BIT, MAP_32BIT, MAP_32BIT },
+#endif
{ TARGET_MAP_SHARED, TARGET_MAP_SHARED, MAP_SHARED, MAP_SHARED },
{ TARGET_MAP_PRIVATE, TARGET_MAP_PRIVATE, MAP_PRIVATE, MAP_PRIVATE },
{ TARGET_MAP_FIXED, TARGET_MAP_FIXED, MAP_FIXED, MAP_FIXED },
@@ -8178,6 +8182,131 @@ static target_timer_t get_timer_id(abi_long arg)
return timerid;
}
+/* qemu_execve() Must return target values and target errnos.
+ *
+ * Although execve() is not an interruptible syscall it is
+ * a special case where we must use the safe_syscall wrapper:
+ * if we allow a signal to happen before we make the host
+ * syscall then we will 'lose' it, because at the point of
+ * execve the process leaves QEMU's control. So we use the
+ * safe syscall wrapper to ensure that we either take the
+ * signal as a guest signal, or else it does not happen
+ * before the execve completes and makes it the other
+ * program's problem.
+ */
+static abi_long qemu_execve(char *filename, char *argv[],
+ char *envp[])
+{
+ char *i_arg = NULL, *i_name = NULL;
+ char **new_argp;
+ int argc, fd, ret, i, offset = 5;
+ char *cp;
+ char buf[BINPRM_BUF_SIZE];
+
+ /* normal execve case */
+ if (qemu_execve_path == NULL || *qemu_execve_path == 0) {
+ return get_errno(safe_execve(filename, argv, envp));
+ }
+
+ for (argc = 0; argv[argc] != NULL; argc++) {
+ /* nothing */ ;
+ }
+
+ fd = open(filename, O_RDONLY);
+ if (fd == -1) {
+ return get_errno(fd);
+ }
+
+ ret = read(fd, buf, BINPRM_BUF_SIZE);
+ if (ret == -1) {
+ close(fd);
+ return get_errno(ret);
+ }
+
+ /* if we have less than 2 bytes, we can guess it is not executable */
+ if (ret < 2) {
+ close(fd);
+ return -host_to_target_errno(ENOEXEC);
+ }
+
+ close(fd);
+
+ /* adapted from the kernel
+ * https://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/tree/fs/binfmt_script.c
+ */
+ if ((buf[0] == '#') && (buf[1] == '!')) {
+ /*
+ * This section does the #! interpretation.
+ * Sorta complicated, but hopefully it will work. -TYT
+ */
+
+ buf[BINPRM_BUF_SIZE - 1] = '\0';
+ cp = strchr(buf, '\n');
+ if (cp == NULL) {
+ cp = buf + BINPRM_BUF_SIZE - 1;
+ }
+ *cp = '\0';
+ while (cp > buf) {
+ cp--;
+ if ((*cp == ' ') || (*cp == '\t')) {
+ *cp = '\0';
+ } else {
+ break;
+ }
+ }
+ for (cp = buf + 2; (*cp == ' ') || (*cp == '\t'); cp++) {
+ /* nothing */ ;
+ }
+ if (*cp == '\0') {
+ return -ENOEXEC; /* No interpreter name found */
+ }
+ i_name = cp;
+ i_arg = NULL;
+ for ( ; *cp && (*cp != ' ') && (*cp != '\t'); cp++) {
+ /* nothing */ ;
+ }
+ while ((*cp == ' ') || (*cp == '\t')) {
+ *cp++ = '\0';
+ }
+ if (*cp) {
+ i_arg = cp;
+ }
+
+ if (i_arg) {
+ offset += 2;
+ } else {
+ offset += 1;
+ }
+ }
+
+ new_argp = alloca((argc + offset + 1) * sizeof(void *));
+
+ /* Copy the original arguments with offset */
+ for (i = 0; i < argc; i++) {
+ new_argp[i + offset] = argv[i];
+ }
+
+ new_argp[0] = strdup(qemu_execve_path);
+ new_argp[1] = strdup("--execve");
+ new_argp[2] = strdup(qemu_execve_path);
+ new_argp[3] = strdup("-0");
+ new_argp[offset] = filename;
+ new_argp[argc + offset] = NULL;
+
+ if (i_name) {
+ new_argp[4] = i_name;
+ new_argp[5] = i_name;
+
+ if (i_arg) {
+ new_argp[6] = i_arg;
+ }
+ } else {
+ new_argp[4] = argv[0];
+ }
+
+ return get_errno(safe_execve(qemu_execve_path, new_argp, envp));
+}
+
static int target_to_host_cpu_mask(unsigned long *host_mask,
size_t host_size,
abi_ulong target_addr,
@@ -8527,17 +8656,7 @@ static abi_long do_syscall1(void *cpu_env, int num, abi_long arg1,
if (!(p = lock_user_string(arg1)))
goto execve_efault;
- /* Although execve() is not an interruptible syscall it is
- * a special case where we must use the safe_syscall wrapper:
- * if we allow a signal to happen before we make the host
- * syscall then we will 'lose' it, because at the point of
- * execve the process leaves QEMU's control. So we use the
- * safe syscall wrapper to ensure that we either take the
- * signal as a guest signal, or else it does not happen
- * before the execve completes and makes it the other
- * program's problem.
- */
- ret = get_errno(safe_execve(p, argp, envp));
+ ret = qemu_execve(p, argp, envp);
unlock_user(p, arg1, 0);
goto execve_end;
diff --git a/linux-user/syscall_defs.h b/linux-user/syscall_defs.h
index 25be414727..c0772c1ae7 100644
--- a/linux-user/syscall_defs.h
+++ b/linux-user/syscall_defs.h
@@ -1390,6 +1390,7 @@ struct target_winsize {
#else
#define TARGET_MAP_FIXED 0x10 /* Interpret addr exactly */
#define TARGET_MAP_ANONYMOUS 0x20 /* don't use a file */
+#define TARGET_MAP_32BIT 0x40
#define TARGET_MAP_GROWSDOWN 0x0100 /* stack-like segment */
#define TARGET_MAP_DENYWRITE 0x0800 /* ETXTBSY */
#define TARGET_MAP_EXECUTABLE 0x1000 /* mark it as an executable */
diff --git a/target/i386/cpu.c b/target/i386/cpu.c
index ad99cad0e7..8258b92e5b 100644
--- a/target/i386/cpu.c
+++ b/target/i386/cpu.c
@@ -1653,6 +1653,7 @@ typedef struct X86CPUDefinition {
int family;
int model;
int stepping;
+ int brand_id;
FeatureWordArray features;
const char *model_id;
CPUCaches *cache_info;
@@ -2137,6 +2138,54 @@ static X86CPUDefinition builtin_x86_defs[] = {
.xlevel = 0,
.model_id = "",
},
+ {
+ /* http://users.atw.hu/instlatx64/AuthenticAMD/AuthenticAMD0000F4A_K8_Clawhammer_CPUID.txt */
+ .name = "athlon-64",
+ .level = 1,
+ .vendor = CPUID_VENDOR_AMD,
+ .family = 15,
+ .model = 4,
+ .stepping = 10,
+ .features[FEAT_1_EDX] =
+ CPUID_FP87 | CPUID_VME | CPUID_DE | CPUID_PSE |
+ CPUID_TSC | CPUID_MSR | CPUID_PAE | CPUID_MCE |
+ CPUID_CX8 | CPUID_APIC | CPUID_SEP |
+ CPUID_MTRR | CPUID_PGE | CPUID_MCA | CPUID_CMOV |
+ CPUID_PAT | CPUID_PSE36 | /*no: CPUID_PN |*/ CPUID_CLFLUSH |
+ /*no: CPUID_DTS | CPUID_ACPI |*/ CPUID_MMX |
+ CPUID_FXSR | CPUID_SSE | CPUID_SSE2,
+ .features[FEAT_8000_0001_EDX] =
+ (CPUID_EXT2_FPU | CPUID_EXT2_VME | CPUID_EXT2_DE | CPUID_EXT2_PSE |
+ CPUID_EXT2_TSC | CPUID_EXT2_MSR | CPUID_EXT2_PAE | CPUID_EXT2_MCE |
+ CPUID_EXT2_CX8 | CPUID_EXT2_APIC | CPUID_EXT2_SYSCALL |
+ CPUID_EXT2_MTRR | CPUID_EXT2_PGE | CPUID_EXT2_MCA | CPUID_EXT2_CMOV |
+ CPUID_EXT2_PAT | CPUID_EXT2_PSE36 | /*no: CPUID_EXT2_MP */
+ CPUID_EXT2_NX | CPUID_EXT2_MMXEXT | CPUID_EXT2_MMX |
+ CPUID_EXT2_FXSR | /*no: CPUID_EXT2_FFXSR | CPUID_EXT2_PDPE1G | CPUID_EXT2_RTDSCP*/
+ CPUID_EXT2_LM | CPUID_EXT2_3DNOWEXT | CPUID_EXT2_3DNOW) &
+ ~CPUID_EXT2_AMD_ALIASES,
+ /* todo cache info 0x80000005-6 */
+ .features[FEAT_8000_0007_EDX] = 0x0f, /*??*/
+ /*.phys_bits = 0x00003028,*/
+ .xlevel = 0x80000018,
+ .brand_id = 0x106,
+ .model_id = "AMD Athlon(tm) 64 Processor 2800+",
+ },
+ {
+ .name = "u3-64bit-minimal",
+ .level = 1,
+ .vendor = CPUID_VENDOR_AMD,
+ .family = 15,
+ .model = 4,
+ .stepping = 10,
+ .features[FEAT_1_EDX] =
+ PENTIUM2_FEATURES | PPRO_FEATURES | CPUID_CLFLUSH /*sse2?*/,
+ .features[FEAT_8000_0001_EDX] =
+ /* NX: amd: since amd64, intel: P4 Prescott+ */
+ CPUID_EXT2_SYSCALL | CPUID_EXT2_NX | CPUID_EXT2_LM,
+ .xlevel = 0x80000018,
+ .model_id = "Fuck off",
+ },
{
.name = "athlon",
.level = 2,
@@ -4657,6 +4706,41 @@ static void x86_cpuid_version_set_stepping(Object *obj, Visitor *v,
env->cpuid_version |= value & 0xf;
}
+static void x86_cpuid_version_get_brand_id(Object *obj, Visitor *v,
+ const char *name, void *opaque,
+ Error **errp)
+{
+ X86CPU *cpu = X86_CPU(obj);
+ CPUX86State *env = &cpu->env;
+ int64_t value;
+
+ value = env->cpuid_brand_id;
+ visit_type_int(v, name, &value, errp);
+}
+
+static void x86_cpuid_version_set_brand_id(Object *obj, Visitor *v,
+ const char *name, void *opaque,
+ Error **errp)
+{
+ X86CPU *cpu = X86_CPU(obj);
+ CPUX86State *env = &cpu->env;
+ const int64_t min = 0;
+ const int64_t max = 0xffff;
+ int64_t value;
+
+ if (!visit_type_int(v, name, &value, errp)) {
+ return;
+ }
+ if (value < min || value > max) {
+ error_setg(errp, QERR_PROPERTY_VALUE_OUT_OF_RANGE, "",
+ name ? name : "null", value, min, max);
+ return;
+ }
+
+ env->cpuid_brand_id = value;
+}
+
+
static char *x86_cpuid_get_vendor(Object *obj, Error **errp)
{
X86CPU *cpu = X86_CPU(obj);
@@ -5269,6 +5353,8 @@ static void x86_cpu_load_model(X86CPU *cpu, X86CPUModel *model)
&error_abort);
object_property_set_str(OBJECT(cpu), "model-id", def->model_id,
&error_abort);
+ object_property_set_int(OBJECT(cpu), "brand-id", def->brand_id,
+ &error_abort);
for (w = 0; w < FEATURE_WORDS; w++) {
env->features[w] = def->features[w];
}
@@ -5936,7 +6022,7 @@ void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count,
break;
case 0x80000001:
*eax = env->cpuid_version;
- *ebx = 0;
+ *ebx = env->cpuid_brand_id;
*ecx = env->features[FEAT_8000_0001_ECX];
*edx = env->features[FEAT_8000_0001_EDX];
@@ -7455,6 +7541,9 @@ static void x86_cpu_common_class_init(ObjectClass *oc, void *data)
object_class_property_add(oc, "stepping", "int",
x86_cpuid_version_get_stepping,
x86_cpuid_version_set_stepping, NULL, NULL);
+ object_class_property_add(oc, "brand-id", "int",
+ x86_cpuid_version_get_brand_id,
+ x86_cpuid_version_set_brand_id, NULL, NULL);
object_class_property_add_str(oc, "vendor",
x86_cpuid_get_vendor,
x86_cpuid_set_vendor);
diff --git a/target/i386/cpu.h b/target/i386/cpu.h
index 570f916878..2e7b3c838c 100644
--- a/target/i386/cpu.h
+++ b/target/i386/cpu.h
@@ -1591,6 +1591,7 @@ typedef struct CPUX86State {
uint32_t cpuid_vendor2;
uint32_t cpuid_vendor3;
uint32_t cpuid_version;
+ uint32_t cpuid_brand_id;
FeatureWordArray features;
/* Features that were explicitly enabled/disabled */
FeatureWordArray user_features;