mirror of https://gitee.com/openkylin/qemu.git
QOM CPUState refactorings / X86CPU
* Fix for X86CPU model field of qemu32/qemu64 CPU models * Bug fix for longjmp on FreeBSD * Removal of unused function * Confinement of clone syscall infrastructure to linux-user -----BEGIN PGP SIGNATURE----- Version: GnuPG v2.0.19 (GNU/Linux) iQIcBAABAgAGBQJSVTKzAAoJEPou0S0+fgE/7tYP/i5dgm6q7jSnhJcwzgHlCHDE c0BTwnvFjdBdkuAARYb/soo0m9QWfsW/dgC4bG3rO5j3o84PLstMjiZSQch0pqM1 YhA0hYSiFjHrMcRk9FOwIECPIe+QcHZ79iNML+9G4K13D7qg36aJWISbVOWy24Dp kj5D0wBBDNw032Oh/3z3EAK4U+vLc/+i4s8XjfwtbuBCCn7GMCE3mRnEqnf8ZX3o H3Il3h/o+I3XQSzIJKXXyJZ5ZVXTtlj0z/0ShQXe8o8u1hINXE2Nf9lB6WG/6sh0 Y43d0uU/e9fWDer25j9yis9KfDNErgYyxlBMUA2X1+Rny5P0twjnnBr5GTAeKgSq Kcux8Ov7W8cbVoM/px03rnynF9rbFbgmGlx82L+QsNMKWhjnEsfs6unpccpGhHR5 UuZX3ZPrmeHfjv0AZD/U2ya3jfrp0v+9gsTqy3QV1rCPbqPDcJ6jg8jzbPZYjEfa /Zy0e/0O3sytSyiaAfBg3MzVPBxdzPcn0JjExJQV9BHsUlkZIVCZVMfePw1oIaf+ coyV4cT3hCe8LrSCzPZlRYP+1hIg41W4NicLbDxtS8lqgfRbcglvqw6NFdAM+NcB z3heQ7IFstQ+pEINXQNy6bS8orv8F1VVvCtZaV+2pzB4TZzjPYuGsrqygre4QkLU mtpN9BTfmSIjzyo6iYBv =hQfy -----END PGP SIGNATURE----- Merge remote-tracking branch 'afaerber/tags/qom-cpu-for-anthony' into staging QOM CPUState refactorings / X86CPU * Fix for X86CPU model field of qemu32/qemu64 CPU models * Bug fix for longjmp on FreeBSD * Removal of unused function * Confinement of clone syscall infrastructure to linux-user # gpg: Signature made Wed 09 Oct 2013 03:40:51 AM PDT using RSA key ID 3E7E013F # gpg: Can't check signature: public key not found # By Andreas Färber (2) and others # Via Andreas Färber * afaerber/tags/qom-cpu-for-anthony: cpu: Drop cpu_model_str from CPU_COMMON cpu: Move cpu_copy() into linux-user cputlb: Remove dead function tlb_update_dirty() cpu-exec: Also reload CPUClass *cc after longjmp return in cpu_exec() target-i386: Set model=6 on qemu64 & qemu32 CPU models
This commit is contained in:
commit
39c153b80f
|
@ -681,6 +681,10 @@ int cpu_exec(CPUArchState *env)
|
||||||
* local variables as longjmp is marked 'noreturn'. */
|
* local variables as longjmp is marked 'noreturn'. */
|
||||||
cpu = current_cpu;
|
cpu = current_cpu;
|
||||||
env = cpu->env_ptr;
|
env = cpu->env_ptr;
|
||||||
|
#if !(defined(CONFIG_USER_ONLY) && \
|
||||||
|
(defined(TARGET_M68K) || defined(TARGET_PPC) || defined(TARGET_S390X)))
|
||||||
|
cc = CPU_GET_CLASS(cpu);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
} /* for(;;) */
|
} /* for(;;) */
|
||||||
|
|
||||||
|
|
15
cputlb.c
15
cputlb.c
|
@ -169,21 +169,6 @@ static inline ram_addr_t qemu_ram_addr_from_host_nofail(void *ptr)
|
||||||
return ram_addr;
|
return ram_addr;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void tlb_update_dirty(CPUTLBEntry *tlb_entry)
|
|
||||||
{
|
|
||||||
ram_addr_t ram_addr;
|
|
||||||
void *p;
|
|
||||||
|
|
||||||
if (tlb_is_dirty_ram(tlb_entry)) {
|
|
||||||
p = (void *)(uintptr_t)((tlb_entry->addr_write & TARGET_PAGE_MASK)
|
|
||||||
+ tlb_entry->addend);
|
|
||||||
ram_addr = qemu_ram_addr_from_host_nofail(p);
|
|
||||||
if (!cpu_physical_memory_is_dirty(ram_addr)) {
|
|
||||||
tlb_entry->addr_write |= TLB_NOTDIRTY;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void cpu_tlb_reset_dirty_all(ram_addr_t start1, ram_addr_t length)
|
void cpu_tlb_reset_dirty_all(ram_addr_t start1, ram_addr_t length)
|
||||||
{
|
{
|
||||||
CPUState *cpu;
|
CPUState *cpu;
|
||||||
|
|
32
exec.c
32
exec.c
|
@ -625,38 +625,6 @@ void cpu_abort(CPUArchState *env, const char *fmt, ...)
|
||||||
abort();
|
abort();
|
||||||
}
|
}
|
||||||
|
|
||||||
CPUArchState *cpu_copy(CPUArchState *env)
|
|
||||||
{
|
|
||||||
CPUArchState *new_env = cpu_init(env->cpu_model_str);
|
|
||||||
#if defined(TARGET_HAS_ICE)
|
|
||||||
CPUBreakpoint *bp;
|
|
||||||
CPUWatchpoint *wp;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* Reset non arch specific state */
|
|
||||||
cpu_reset(ENV_GET_CPU(new_env));
|
|
||||||
|
|
||||||
/* Copy arch specific state into the new CPU */
|
|
||||||
memcpy(new_env, env, sizeof(CPUArchState));
|
|
||||||
|
|
||||||
/* Clone all break/watchpoints.
|
|
||||||
Note: Once we support ptrace with hw-debug register access, make sure
|
|
||||||
BP_CPU break/watchpoints are handled correctly on clone. */
|
|
||||||
QTAILQ_INIT(&env->breakpoints);
|
|
||||||
QTAILQ_INIT(&env->watchpoints);
|
|
||||||
#if defined(TARGET_HAS_ICE)
|
|
||||||
QTAILQ_FOREACH(bp, &env->breakpoints, entry) {
|
|
||||||
cpu_breakpoint_insert(new_env, bp->pc, bp->flags, NULL);
|
|
||||||
}
|
|
||||||
QTAILQ_FOREACH(wp, &env->watchpoints, entry) {
|
|
||||||
cpu_watchpoint_insert(new_env, wp->vaddr, (~wp->len_mask) + 1,
|
|
||||||
wp->flags, NULL);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
return new_env;
|
|
||||||
}
|
|
||||||
|
|
||||||
#if !defined(CONFIG_USER_ONLY)
|
#if !defined(CONFIG_USER_ONLY)
|
||||||
static void tlb_reset_dirty_range_all(ram_addr_t start, ram_addr_t end,
|
static void tlb_reset_dirty_range_all(ram_addr_t start, ram_addr_t end,
|
||||||
uintptr_t length)
|
uintptr_t length)
|
||||||
|
|
|
@ -178,7 +178,5 @@ typedef struct CPUWatchpoint {
|
||||||
\
|
\
|
||||||
/* user data */ \
|
/* user data */ \
|
||||||
void *opaque; \
|
void *opaque; \
|
||||||
\
|
|
||||||
const char *cpu_model_str;
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -230,6 +230,14 @@ int e820_add_entry(uint64_t, uint64_t, uint32_t);
|
||||||
.driver = "e1000",\
|
.driver = "e1000",\
|
||||||
.property = "mitigation",\
|
.property = "mitigation",\
|
||||||
.value = "off",\
|
.value = "off",\
|
||||||
|
},{\
|
||||||
|
.driver = "qemu64-" TYPE_X86_CPU,\
|
||||||
|
.property = "model",\
|
||||||
|
.value = stringify(2),\
|
||||||
|
},{\
|
||||||
|
.driver = "qemu32-" TYPE_X86_CPU,\
|
||||||
|
.property = "model",\
|
||||||
|
.value = stringify(3),\
|
||||||
}
|
}
|
||||||
|
|
||||||
#define PC_COMPAT_1_5 \
|
#define PC_COMPAT_1_5 \
|
||||||
|
|
|
@ -42,7 +42,7 @@ const char *filename;
|
||||||
const char *argv0;
|
const char *argv0;
|
||||||
int gdbstub_port;
|
int gdbstub_port;
|
||||||
envlist_t *envlist;
|
envlist_t *envlist;
|
||||||
const char *cpu_model;
|
static const char *cpu_model;
|
||||||
unsigned long mmap_min_addr;
|
unsigned long mmap_min_addr;
|
||||||
#if defined(CONFIG_USE_GUEST_BASE)
|
#if defined(CONFIG_USE_GUEST_BASE)
|
||||||
unsigned long guest_base;
|
unsigned long guest_base;
|
||||||
|
@ -3285,6 +3285,37 @@ void init_task_state(TaskState *ts)
|
||||||
ts->sigqueue_table[i].next = NULL;
|
ts->sigqueue_table[i].next = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
CPUArchState *cpu_copy(CPUArchState *env)
|
||||||
|
{
|
||||||
|
CPUArchState *new_env = cpu_init(cpu_model);
|
||||||
|
#if defined(TARGET_HAS_ICE)
|
||||||
|
CPUBreakpoint *bp;
|
||||||
|
CPUWatchpoint *wp;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Reset non arch specific state */
|
||||||
|
cpu_reset(ENV_GET_CPU(new_env));
|
||||||
|
|
||||||
|
memcpy(new_env, env, sizeof(CPUArchState));
|
||||||
|
|
||||||
|
/* Clone all break/watchpoints.
|
||||||
|
Note: Once we support ptrace with hw-debug register access, make sure
|
||||||
|
BP_CPU break/watchpoints are handled correctly on clone. */
|
||||||
|
QTAILQ_INIT(&env->breakpoints);
|
||||||
|
QTAILQ_INIT(&env->watchpoints);
|
||||||
|
#if defined(TARGET_HAS_ICE)
|
||||||
|
QTAILQ_FOREACH(bp, &env->breakpoints, entry) {
|
||||||
|
cpu_breakpoint_insert(new_env, bp->pc, bp->flags, NULL);
|
||||||
|
}
|
||||||
|
QTAILQ_FOREACH(wp, &env->watchpoints, entry) {
|
||||||
|
cpu_watchpoint_insert(new_env, wp->vaddr, (~wp->len_mask) + 1,
|
||||||
|
wp->flags, NULL);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return new_env;
|
||||||
|
}
|
||||||
|
|
||||||
static void handle_arg_help(const char *arg)
|
static void handle_arg_help(const char *arg)
|
||||||
{
|
{
|
||||||
usage();
|
usage();
|
||||||
|
|
|
@ -131,7 +131,6 @@ static ObjectClass *alpha_cpu_class_by_name(const char *cpu_model)
|
||||||
AlphaCPU *cpu_alpha_init(const char *cpu_model)
|
AlphaCPU *cpu_alpha_init(const char *cpu_model)
|
||||||
{
|
{
|
||||||
AlphaCPU *cpu;
|
AlphaCPU *cpu;
|
||||||
CPUAlphaState *env;
|
|
||||||
ObjectClass *cpu_class;
|
ObjectClass *cpu_class;
|
||||||
|
|
||||||
cpu_class = alpha_cpu_class_by_name(cpu_model);
|
cpu_class = alpha_cpu_class_by_name(cpu_model);
|
||||||
|
@ -140,9 +139,6 @@ AlphaCPU *cpu_alpha_init(const char *cpu_model)
|
||||||
cpu_class = object_class_by_name(TYPE("ev67"));
|
cpu_class = object_class_by_name(TYPE("ev67"));
|
||||||
}
|
}
|
||||||
cpu = ALPHA_CPU(object_new(object_class_get_name(cpu_class)));
|
cpu = ALPHA_CPU(object_new(object_class_get_name(cpu_class)));
|
||||||
env = &cpu->env;
|
|
||||||
|
|
||||||
env->cpu_model_str = cpu_model;
|
|
||||||
|
|
||||||
object_property_set_bool(OBJECT(cpu), true, "realized", NULL);
|
object_property_set_bool(OBJECT(cpu), true, "realized", NULL);
|
||||||
|
|
||||||
|
|
|
@ -1749,7 +1749,6 @@ void register_cp_regs_for_features(ARMCPU *cpu)
|
||||||
ARMCPU *cpu_arm_init(const char *cpu_model)
|
ARMCPU *cpu_arm_init(const char *cpu_model)
|
||||||
{
|
{
|
||||||
ARMCPU *cpu;
|
ARMCPU *cpu;
|
||||||
CPUARMState *env;
|
|
||||||
ObjectClass *oc;
|
ObjectClass *oc;
|
||||||
|
|
||||||
oc = cpu_class_by_name(TYPE_ARM_CPU, cpu_model);
|
oc = cpu_class_by_name(TYPE_ARM_CPU, cpu_model);
|
||||||
|
@ -1757,8 +1756,6 @@ ARMCPU *cpu_arm_init(const char *cpu_model)
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
cpu = ARM_CPU(object_new(object_class_get_name(oc)));
|
cpu = ARM_CPU(object_new(object_class_get_name(oc)));
|
||||||
env = &cpu->env;
|
|
||||||
env->cpu_model_str = cpu_model;
|
|
||||||
|
|
||||||
/* TODO this should be set centrally, once possible */
|
/* TODO this should be set centrally, once possible */
|
||||||
object_property_set_bool(OBJECT(cpu), true, "realized", NULL);
|
object_property_set_bool(OBJECT(cpu), true, "realized", NULL);
|
||||||
|
|
|
@ -545,7 +545,7 @@ static x86_def_t builtin_x86_defs[] = {
|
||||||
.level = 4,
|
.level = 4,
|
||||||
.vendor = CPUID_VENDOR_AMD,
|
.vendor = CPUID_VENDOR_AMD,
|
||||||
.family = 6,
|
.family = 6,
|
||||||
.model = 2,
|
.model = 6,
|
||||||
.stepping = 3,
|
.stepping = 3,
|
||||||
.features[FEAT_1_EDX] =
|
.features[FEAT_1_EDX] =
|
||||||
PPRO_FEATURES |
|
PPRO_FEATURES |
|
||||||
|
@ -648,7 +648,7 @@ static x86_def_t builtin_x86_defs[] = {
|
||||||
.level = 4,
|
.level = 4,
|
||||||
.vendor = CPUID_VENDOR_INTEL,
|
.vendor = CPUID_VENDOR_INTEL,
|
||||||
.family = 6,
|
.family = 6,
|
||||||
.model = 3,
|
.model = 6,
|
||||||
.stepping = 3,
|
.stepping = 3,
|
||||||
.features[FEAT_1_EDX] =
|
.features[FEAT_1_EDX] =
|
||||||
PPRO_FEATURES,
|
PPRO_FEATURES,
|
||||||
|
@ -1899,7 +1899,6 @@ X86CPU *cpu_x86_create(const char *cpu_model, DeviceState *icc_bridge,
|
||||||
Error **errp)
|
Error **errp)
|
||||||
{
|
{
|
||||||
X86CPU *cpu = NULL;
|
X86CPU *cpu = NULL;
|
||||||
CPUX86State *env;
|
|
||||||
gchar **model_pieces;
|
gchar **model_pieces;
|
||||||
char *name, *features;
|
char *name, *features;
|
||||||
char *typename;
|
char *typename;
|
||||||
|
@ -1922,8 +1921,6 @@ X86CPU *cpu_x86_create(const char *cpu_model, DeviceState *icc_bridge,
|
||||||
qdev_set_parent_bus(DEVICE(cpu), qdev_get_child_bus(icc_bridge, "icc"));
|
qdev_set_parent_bus(DEVICE(cpu), qdev_get_child_bus(icc_bridge, "icc"));
|
||||||
object_unref(OBJECT(cpu));
|
object_unref(OBJECT(cpu));
|
||||||
#endif
|
#endif
|
||||||
env = &cpu->env;
|
|
||||||
env->cpu_model_str = cpu_model;
|
|
||||||
|
|
||||||
cpu_x86_register(cpu, name, &error);
|
cpu_x86_register(cpu, name, &error);
|
||||||
if (error) {
|
if (error) {
|
||||||
|
|
|
@ -110,7 +110,6 @@ M68kCPU *cpu_m68k_init(const char *cpu_model)
|
||||||
}
|
}
|
||||||
cpu = M68K_CPU(object_new(object_class_get_name(oc)));
|
cpu = M68K_CPU(object_new(object_class_get_name(oc)));
|
||||||
env = &cpu->env;
|
env = &cpu->env;
|
||||||
env->cpu_model_str = cpu_model;
|
|
||||||
|
|
||||||
register_m68k_insns(env);
|
register_m68k_insns(env);
|
||||||
|
|
||||||
|
|
|
@ -15907,7 +15907,6 @@ MIPSCPU *cpu_mips_init(const char *cpu_model)
|
||||||
cpu = MIPS_CPU(object_new(TYPE_MIPS_CPU));
|
cpu = MIPS_CPU(object_new(TYPE_MIPS_CPU));
|
||||||
env = &cpu->env;
|
env = &cpu->env;
|
||||||
env->cpu_model = def;
|
env->cpu_model = def;
|
||||||
env->cpu_model_str = cpu_model;
|
|
||||||
|
|
||||||
#ifndef CONFIG_USER_ONLY
|
#ifndef CONFIG_USER_ONLY
|
||||||
mmu_init(env, def);
|
mmu_init(env, def);
|
||||||
|
|
|
@ -138,7 +138,6 @@ MoxieCPU *cpu_moxie_init(const char *cpu_model)
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
cpu = MOXIE_CPU(object_new(object_class_get_name(oc)));
|
cpu = MOXIE_CPU(object_new(object_class_get_name(oc)));
|
||||||
cpu->env.cpu_model_str = cpu_model;
|
|
||||||
|
|
||||||
object_property_set_bool(OBJECT(cpu), true, "realized", NULL);
|
object_property_set_bool(OBJECT(cpu), true, "realized", NULL);
|
||||||
|
|
||||||
|
|
|
@ -209,7 +209,6 @@ OpenRISCCPU *cpu_openrisc_init(const char *cpu_model)
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
cpu = OPENRISC_CPU(object_new(object_class_get_name(oc)));
|
cpu = OPENRISC_CPU(object_new(object_class_get_name(oc)));
|
||||||
cpu->env.cpu_model_str = cpu_model;
|
|
||||||
|
|
||||||
object_property_set_bool(OBJECT(cpu), true, "realized", NULL);
|
object_property_set_bool(OBJECT(cpu), true, "realized", NULL);
|
||||||
|
|
||||||
|
|
|
@ -8267,7 +8267,6 @@ static ObjectClass *ppc_cpu_class_by_name(const char *name)
|
||||||
PowerPCCPU *cpu_ppc_init(const char *cpu_model)
|
PowerPCCPU *cpu_ppc_init(const char *cpu_model)
|
||||||
{
|
{
|
||||||
PowerPCCPU *cpu;
|
PowerPCCPU *cpu;
|
||||||
CPUPPCState *env;
|
|
||||||
ObjectClass *oc;
|
ObjectClass *oc;
|
||||||
Error *err = NULL;
|
Error *err = NULL;
|
||||||
|
|
||||||
|
@ -8277,8 +8276,6 @@ PowerPCCPU *cpu_ppc_init(const char *cpu_model)
|
||||||
}
|
}
|
||||||
|
|
||||||
cpu = POWERPC_CPU(object_new(object_class_get_name(oc)));
|
cpu = POWERPC_CPU(object_new(object_class_get_name(oc)));
|
||||||
env = &cpu->env;
|
|
||||||
env->cpu_model_str = cpu_model;
|
|
||||||
|
|
||||||
object_property_set_bool(OBJECT(cpu), true, "realized", &err);
|
object_property_set_bool(OBJECT(cpu), true, "realized", &err);
|
||||||
if (err != NULL) {
|
if (err != NULL) {
|
||||||
|
|
|
@ -73,11 +73,8 @@ void s390x_cpu_timer(void *opaque)
|
||||||
S390CPU *cpu_s390x_init(const char *cpu_model)
|
S390CPU *cpu_s390x_init(const char *cpu_model)
|
||||||
{
|
{
|
||||||
S390CPU *cpu;
|
S390CPU *cpu;
|
||||||
CPUS390XState *env;
|
|
||||||
|
|
||||||
cpu = S390_CPU(object_new(TYPE_S390_CPU));
|
cpu = S390_CPU(object_new(TYPE_S390_CPU));
|
||||||
env = &cpu->env;
|
|
||||||
env->cpu_model_str = cpu_model;
|
|
||||||
|
|
||||||
object_property_set_bool(OBJECT(cpu), true, "realized", NULL);
|
object_property_set_bool(OBJECT(cpu), true, "realized", NULL);
|
||||||
|
|
||||||
|
|
|
@ -144,7 +144,6 @@ static ObjectClass *superh_cpu_class_by_name(const char *cpu_model)
|
||||||
SuperHCPU *cpu_sh4_init(const char *cpu_model)
|
SuperHCPU *cpu_sh4_init(const char *cpu_model)
|
||||||
{
|
{
|
||||||
SuperHCPU *cpu;
|
SuperHCPU *cpu;
|
||||||
CPUSH4State *env;
|
|
||||||
ObjectClass *oc;
|
ObjectClass *oc;
|
||||||
|
|
||||||
oc = superh_cpu_class_by_name(cpu_model);
|
oc = superh_cpu_class_by_name(cpu_model);
|
||||||
|
@ -152,8 +151,6 @@ SuperHCPU *cpu_sh4_init(const char *cpu_model)
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
cpu = SUPERH_CPU(object_new(object_class_get_name(oc)));
|
cpu = SUPERH_CPU(object_new(object_class_get_name(oc)));
|
||||||
env = &cpu->env;
|
|
||||||
env->cpu_model_str = cpu_model;
|
|
||||||
|
|
||||||
object_property_set_bool(OBJECT(cpu), true, "realized", NULL);
|
object_property_set_bool(OBJECT(cpu), true, "realized", NULL);
|
||||||
|
|
||||||
|
|
|
@ -84,7 +84,6 @@ static int cpu_sparc_register(CPUSPARCState *env, const char *cpu_model)
|
||||||
env->def->features |= CPU_FEATURE_FLOAT128;
|
env->def->features |= CPU_FEATURE_FLOAT128;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
env->cpu_model_str = cpu_model;
|
|
||||||
env->version = def->iu_version;
|
env->version = def->iu_version;
|
||||||
env->fsr = def->fpu_version;
|
env->fsr = def->fpu_version;
|
||||||
env->nwindows = def->nwindows;
|
env->nwindows = def->nwindows;
|
||||||
|
|
|
@ -37,7 +37,6 @@ CPUUniCore32State *uc32_cpu_init(const char *cpu_model)
|
||||||
}
|
}
|
||||||
cpu = UNICORE32_CPU(object_new(object_class_get_name(oc)));
|
cpu = UNICORE32_CPU(object_new(object_class_get_name(oc)));
|
||||||
env = &cpu->env;
|
env = &cpu->env;
|
||||||
env->cpu_model_str = cpu_model;
|
|
||||||
|
|
||||||
object_property_set_bool(OBJECT(cpu), true, "realized", NULL);
|
object_property_set_bool(OBJECT(cpu), true, "realized", NULL);
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue