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-8.1.3.patch

375 lines
13 KiB
Diff

diff --git a/linux-user/main.c b/linux-user/main.c
index 96be354897..bc4c8864c7 100644
--- a/linux-user/main.c
+++ b/linux-user/main.c
@@ -124,6 +124,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;
#if !defined(TARGET_DEFAULT_STACK_SIZE)
/* XXX: on x86 MAP_GROWSDOWN only works if ESP <= address + 32, so
@@ -370,6 +371,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;
@@ -486,6 +492,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/syscall.c b/linux-user/syscall.c
index 9353268cc1..790744adfb 100644
--- a/linux-user/syscall.c
+++ b/linux-user/syscall.c
@@ -125,6 +125,7 @@
#include <libdrm/drm.h>
#include <libdrm/i915_drm.h>
#endif
+#include <linux/binfmts.h>
#include "linux_loop.h"
#include "uname.h"
@@ -8680,6 +8681,137 @@ ssize_t do_guest_readlink(const char *pathname, char *buf, size_t bufsiz)
return ret;
}
+/* 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(int dirfd, char *filename, char *argv[],
+ char *envp[], int flags, bool is_execveat)
+{
+ 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(is_execveat ?
+ safe_execveat(dirfd, filename, argv, envp, flags) :
+ safe_execve(filename, argv, envp));
+ }
+
+ if (is_execveat) {
+ return -TARGET_ENOSYS;
+ }
+
+ 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 do_execv(CPUArchState *cpu_env, int dirfd,
abi_long pathname, abi_long guest_argp,
abi_long guest_envp, int flags, bool is_execveat)
@@ -8745,17 +8877,6 @@ static int do_execv(CPUArchState *cpu_env, int dirfd,
}
*q = NULL;
- /*
- * 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.
- */
p = lock_user_string(pathname);
if (!p) {
goto execve_efault;
@@ -8765,10 +8886,7 @@ static int do_execv(CPUArchState *cpu_env, int dirfd,
if (is_proc_myself(p, "exe")) {
exe = exec_path;
}
- ret = is_execveat
- ? safe_execveat(dirfd, exe, argp, envp, flags)
- : safe_execve(exe, argp, envp);
- ret = get_errno(ret);
+ ret = qemu_execve(dirfd, exe, argp, envp, flags, is_execveat);
unlock_user(p, pathname, 0);
diff --git a/linux-user/user-internals.h b/linux-user/user-internals.h
index c63ef45fc7..125e499370 100644
--- a/linux-user/user-internals.h
+++ b/linux-user/user-internals.h
@@ -28,6 +28,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;
typedef struct IOCTLEntry IOCTLEntry;
diff --git a/target/i386/cpu.c b/target/i386/cpu.c
index 97ad229d8b..408db3365d 100644
--- a/target/i386/cpu.c
+++ b/target/i386/cpu.c
@@ -1759,6 +1759,7 @@ typedef struct X86CPUDefinition {
int family;
int model;
int stepping;
+ int brand_id;
FeatureWordArray features;
const char *model_id;
const CPUCaches *const cache_info;
@@ -2444,6 +2445,54 @@ static const 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,
@@ -5165,6 +5214,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);
@@ -5877,6 +5961,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];
}
@@ -6488,7 +6574,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];
@@ -7982,6 +8068,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 e0771a1043..2b9a1aef24 100644
--- a/target/i386/cpu.h
+++ b/target/i386/cpu.h
@@ -1803,6 +1803,7 @@ typedef struct CPUArchState {
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;