diff options
57 files changed, 1344 insertions, 549 deletions
diff --git a/Makefile.target b/Makefile.target index 8f35dae1e2..3456672830 100644 --- a/Makefile.target +++ b/Makefile.target @@ -149,13 +149,16 @@ obj-$(CONFIG_XEN_I386) += xen-hvm.o xen-mapcache.o obj-$(call lnot,$(CONFIG_XEN)) += xen-common-stub.o obj-$(call lnot,$(CONFIG_XEN_I386)) += xen-hvm-stub.o -# HAX support -ifdef CONFIG_WIN32 -obj-$(CONFIG_HAX) += target-i386/hax-all.o target-i386/hax-windows.o -endif -ifdef CONFIG_DARWIN -obj-$(CONFIG_HAX) += target-i386/hax-all.o target-i386/hax-darwin.o +# HAX support, only when targetting i386 or x86_64 +ifeq (y,$(CONFIG_HAX)) +ifneq (,$(filter i386 x86_64,$(TARGET_NAME))) +obj-y += target-i386/hax-all.o target-i386/hax-slot.o +obj-$(CONFIG_WIN32) += target-i386/hax-windows.o +obj-$(CONFIG_DARWIN) += target-i386/hax-darwin.o +else +obj-y += hax-stub.o endif +endif # CONFIG_HAX obj-$(call lnot,$(CONFIG_HAX)) += hax-stub.o # Hardware support @@ -712,6 +712,11 @@ void cpu_synchronize_all_states(void) CPU_FOREACH(cpu) { cpu_synchronize_state(cpu); +#ifdef CONFIG_HAX + if (hax_enabled() && hax_ug_platform()) { + hax_cpu_synchronize_state(cpu); + } +#endif } } diff --git a/hw/vigs/vigs_gl_backend.c b/hw/vigs/vigs_gl_backend.c index 7fcd2c092f..94b95ff5c0 100644 --- a/hw/vigs/vigs_gl_backend.c +++ b/hw/vigs/vigs_gl_backend.c @@ -2938,6 +2938,9 @@ void vigs_gl_backend_cleanup(struct vigs_gl_backend *gl_backend) if (gl_backend->dpy_tex) { gl_backend->DeleteTextures(1, &gl_backend->dpy_tex); } + if (gl_backend->dpy_fb) { + gl_backend->DeleteFramebuffers(1, &gl_backend->dpy_fb); + } gl_backend->DeleteBuffers(1, &gl_backend->dpy_vbo); gl_backend->DetachShader(gl_backend->dpy_scale_prog_id, gl_backend->dpy_scale_prog_vs_id); diff --git a/hw/yagl/yagl_process.c b/hw/yagl/yagl_process.c index eb740315c2..1e6844f831 100644 --- a/hw/yagl/yagl_process.c +++ b/hw/yagl/yagl_process.c @@ -34,6 +34,7 @@ #include "yagl_stats.h" #include "yagl_object_map.h" #include "sysemu/kvm.h" +#include "sysemu/hax.h" struct yagl_process_state *yagl_process_state_create(struct yagl_server_state *ss, @@ -47,13 +48,20 @@ struct yagl_process_state ps->object_map = yagl_object_map_create(); QLIST_INIT(&ps->threads); -#ifdef CONFIG_KVM - if (kvm_enabled()) { - cpu_synchronize_state(current_cpu); +#if defined (CONFIG_KVM) || defined (CONFIG_HAX) + if (kvm_enabled() || hax_enabled()) { + if (kvm_enabled()) { + cpu_synchronize_state(current_cpu); + } else { +#ifdef CONFIG_HAX + hax_cpu_synchronize_state(current_cpu); +#endif + } + CPUX86State *env = current_cpu->env_ptr; memcpy(&ps->cr[0], - &((CPUX86State *)current_cpu->env_ptr)->cr[0], - sizeof(ps->cr)); - ps->hflags = ((CPUX86State *)current_cpu->env_ptr)->hflags; + &((CPUX86State *)current_cpu->env_ptr)->cr[0], + sizeof(ps->cr)); + ps->hflags = env->hflags; } #endif diff --git a/hw/yagl/yagl_process.h b/hw/yagl/yagl_process.h index 4cbae5212c..bbf4568b58 100644 --- a/hw/yagl/yagl_process.h +++ b/hw/yagl/yagl_process.h @@ -55,7 +55,7 @@ struct yagl_process_state QLIST_HEAD(, yagl_thread_state) threads; -#ifdef CONFIG_KVM +#if defined (CONFIG_KVM) || defined (CONFIG_HAX) target_ulong cr[5]; uint32_t hflags; #endif diff --git a/hw/yagl/yagl_thread.c b/hw/yagl/yagl_thread.c index 82a8d808dd..b965e32371 100644 --- a/hw/yagl/yagl_thread.c +++ b/hw/yagl/yagl_thread.c @@ -53,14 +53,15 @@ struct yagl_thread_work_item uint32_t out_arrays_size; }; -#ifdef CONFIG_KVM +#if defined (CONFIG_KVM) || defined (CONFIG_HAX) static __inline void yagl_cpu_synchronize_state(struct yagl_process_state *ps) { - if (kvm_enabled()) { + if (kvm_enabled() || hax_enabled()) { + CPUX86State *env = current_cpu->env_ptr; memcpy(&((CPUX86State *)current_cpu->env_ptr)->cr[0], - &ps->cr[0], - sizeof(ps->cr)); - ((CPUX86State *)current_cpu->env_ptr)->hflags = ps->hflags; + &ps->cr[0], + sizeof(ps->cr)); + env->hflags = ps->hflags; } } #else diff --git a/include/sysemu/hax.h b/include/sysemu/hax.h index 58fb039e75..ac4cf7d3ad 100644 --- a/include/sysemu/hax.h +++ b/include/sysemu/hax.h @@ -44,8 +44,9 @@ int hax_vcpu_exec(CPUState *cpu); int hax_smp_cpu_exec(CPUState *cpu); void hax_cpu_synchronize_post_reset(CPUState *cpu); void hax_cpu_synchronize_post_init(CPUState *cpu); +void hax_cpu_synchronize_state(CPUState *cpu); int hax_populate_ram(uint64_t va, uint32_t size); -int hax_set_phys_mem(MemoryRegionSection *section); +int hax_set_ram(uint64_t start_pa, uint32_t size, uint64_t host_va, int flags); int hax_vcpu_emulation_mode(CPUState *cpu); int hax_stop_emulation(CPUState *cpu); int hax_stop_translate(CPUState *cpu); diff --git a/package/changelog b/package/changelog index 62caaf7bc5..21583477be 100644 --- a/package/changelog +++ b/package/changelog @@ -1,3 +1,33 @@ +* 2.6.10 +- modify VM lock +== Munkyu Im <munkyu.im@samsung.com> 2016-11-08 +* 2.6.9 +- fix checking tap device +== Munkyu Im <munkyu.im@samsung.com> 2016-10-25 +* 2.6.8 +- change QMatrix to QTransform +- fix abnormal exit issue +- remove Qt::AA_X11InitThreads attribute +- modify backtrace feature for Windows +== Sooyoung Ha <yoosah.ha@samsung.com> 2016-10-13 +* 2.6.7 +- display: Revert "display: move display functionality to Qt5 GUI" for AMD gpu issue +- display: fix display rotation failure +== Jinhyung Jo <jinhyung.jo@samsung.com> 2016-10-05 +* 2.6.6 +- adjust vm lock module +- change version of about dialog +- add surface option for AMD gpu driver +==jihye kim<jihye424.kim@samsung.com> 2016-09-28 +* 2.6.5 +- temporarily remove shortcut info in mac +- add missing "break" statement in skin +== jihye kim <jihye424.kim@samsung.com> 2016-09-22 +* 2.6.4 +- fix transparency bug +- separate cli vm searching +- launch ecp using .app file in mac os +== jihye kim <jihye424.kim@samsung.com> 2016-09-21 * 2.6.2 - tizen-kvm is moved to emulator-supplements package == SeokYeon Hwang <syeon.hwang@samsung.com> 2016-03-22 diff --git a/package/pkginfo.manifest b/package/pkginfo.manifest index b7b6b20495..c900929a76 100644 --- a/package/pkginfo.manifest +++ b/package/pkginfo.manifest @@ -1,4 +1,4 @@ -Version: 2.6.3 +Version: 2.6.10 Maintainer: SeokYeon Hwang <syeon.hwang@samsung.com> Source: emulator diff --git a/target-i386/hax-all.c b/target-i386/hax-all.c index 916fcd47c1..10fec180a3 100644 --- a/target-i386/hax-all.c +++ b/target-i386/hax-all.c @@ -26,6 +26,7 @@ #include "strings.h" #include "hax-i386.h" +#include "hax-slot.h" #include "hw/boards.h" #include "sysemu/accel.h" #include "exec/address-spaces.h" @@ -371,7 +372,8 @@ struct hax_vm *hax_vm_create(struct hax_state *hax) } hax->vm = vm; - dprint("End of VM create, id %d\n", vm->id); + hax_slot_init_registry(); + return vm; error: @@ -384,6 +386,7 @@ int hax_vm_destroy(struct hax_vm *vm) { int i; + hax_slot_free_registry(); for (i = 0; i < HAX_MAX_VCPU; i++) if (vm->vcpus[i]) { @@ -396,6 +399,41 @@ int hax_vm_destroy(struct hax_vm *vm) return 0; } +static void hax_set_phys_mem(MemoryRegionSection *section) +{ + MemoryRegion *mr = section->mr; + hwaddr start_pa = section->offset_within_address_space; + ram_addr_t size = int128_get64(section->size); + unsigned int delta; + void *host_ptr; + int flags; + + /* We only care about RAM and ROM */ + if (!memory_region_is_ram(mr)) { + return; + } + + /* Adjust start_pa and size so that they are page-aligned. (Cf + * kvm_set_phys_mem() in kvm-all.c). + */ + delta = TARGET_PAGE_SIZE - (start_pa & ~TARGET_PAGE_MASK); + delta &= ~TARGET_PAGE_MASK; + if (delta > size) { + return; + } + start_pa += delta; + size -= delta; + size &= TARGET_PAGE_MASK; + if (!size || start_pa & ~TARGET_PAGE_MASK) { + return; + } + + host_ptr = memory_region_get_ram_ptr(mr) + section->offset_within_region + + delta; + flags = memory_region_is_rom(mr) ? 1 : 0; + hax_slot_register(start_pa, size, (uintptr_t) host_ptr, flags); +} + static void hax_region_add(MemoryListener *listener, MemoryRegionSection *section) { @@ -405,7 +443,7 @@ hax_region_add(MemoryListener *listener, MemoryRegionSection *section) static void hax_region_del(MemoryListener *listener, MemoryRegionSection *section) { - hax_set_phys_mem(section); + // Memory mappings will be removed at VM close. } @@ -417,11 +455,17 @@ hax_region_del(MemoryListener *listener, MemoryRegionSection *section) static void hax_log_sync(MemoryListener *listener, MemoryRegionSection *section) { MemoryRegion *mr = section->mr; + + if (!memory_region_is_ram(mr)) { + /* Skip MMIO regions */ + return; + } + unsigned long c; unsigned int len = ((int128_get64(section->size) / TARGET_PAGE_SIZE) + HOST_LONG_BITS - 1) / HOST_LONG_BITS; unsigned long bitmap[len]; - int i, j; + unsigned int i, j; for (i = 0; i < len; i++) { bitmap[i] = 1; @@ -767,13 +811,6 @@ static int hax_vcpu_hax_exec(CPUArchState *env, int ug_platform) break; } -#if 0 - if (cpu->hax_vcpu_dirty) { - hax_vcpu_sync_state(env, 1); - cpu->hax_vcpu_dirty = 0; - } -#endif - hax_vcpu_interrupt(env); if (!ug_platform) { @@ -863,37 +900,52 @@ static int hax_vcpu_hax_exec(CPUArchState *env, int ug_platform) return ret; } -#if 0 -static void do_hax_cpu_synchronize_state(void *_env) +static void do_hax_cpu_synchronize_state(void *arg) { - CPUArchState *env = _env; - CPUState *cpu = ENV_GET_CPU(env); - if (!cpu->hax_vcpu_dirty) { - hax_vcpu_sync_state(env, 0); - cpu->hax_vcpu_dirty = 1; - } + CPUState *cpu = arg; + CPUArchState *env = cpu->env_ptr; + + hax_arch_get_registers(env); + cpu->hax_vcpu_dirty = true; } -static void hax_cpu_synchronize_state(CPUState *cpu) +void hax_cpu_synchronize_state(CPUState *cpu) { - if (!cpu->hax_vcpu_dirty) { - run_on_cpu(cpu, do_hax_cpu_synchronize_state, cpu); - } + /* TODO: Do not sync if cpu->hax_vcpu_dirty is true. (Cf + * kvm_cpu_synchronize_state() in kvm-all.c) + * This would require that this flag be updated properly and consistently + * wherever a vCPU state sync between QEMU and HAX takes place. For now, + * just perform the sync regardless of hax_vcpu_dirty. + */ + run_on_cpu(cpu, do_hax_cpu_synchronize_state, cpu); } -#endif -void hax_cpu_synchronize_post_reset(CPUState *cpu) +static void do_hax_cpu_synchronize_post_reset(void *arg) { - CPUArchState *env = (CPUArchState *)(cpu->env_ptr); + CPUState *cpu = arg; + CPUArchState *env = cpu->env_ptr; + hax_vcpu_sync_state(env, 1); - cpu->hax_vcpu_dirty = 0; + cpu->hax_vcpu_dirty = false; } -void hax_cpu_synchronize_post_init(CPUState *cpu) +void hax_cpu_synchronize_post_reset(CPUState * cpu) { - CPUArchState *env = (CPUArchState *)(cpu->env_ptr); + run_on_cpu(cpu, do_hax_cpu_synchronize_post_reset, cpu); +} + +static void do_hax_cpu_synchronize_post_init(void *arg) +{ + CPUState *cpu = arg; + CPUArchState *env = cpu->env_ptr; + hax_vcpu_sync_state(env, 1); - cpu->hax_vcpu_dirty = 0; + cpu->hax_vcpu_dirty = false; +} + +void hax_cpu_synchronize_post_init(CPUState * cpu) +{ + run_on_cpu(cpu, do_hax_cpu_synchronize_post_init, cpu); } /* @@ -1145,7 +1197,16 @@ static int hax_sync_vcpu_register(CPUArchState *env, int set) hax_getput_reg(®s._rdi, &env->regs[R_EDI], set); hax_getput_reg(®s._rsp, &env->regs[R_ESP], set); hax_getput_reg(®s._rbp, &env->regs[R_EBP], set); - +#ifdef TARGET_X86_64 + hax_getput_reg(®s._r8, &env->regs[8], set); + hax_getput_reg(®s._r9, &env->regs[9], set); + hax_getput_reg(®s._r10, &env->regs[10], set); + hax_getput_reg(®s._r11, &env->regs[11], set); + hax_getput_reg(®s._r12, &env->regs[12], set); + hax_getput_reg(®s._r13, &env->regs[13], set); + hax_getput_reg(®s._r14, &env->regs[14], set); + hax_getput_reg(®s._r15, &env->regs[15], set); +#endif hax_getput_reg(®s._rflags, &env->eflags, set); hax_getput_reg(®s._rip, &env->eip, set); @@ -1173,8 +1234,14 @@ static int hax_sync_vcpu_register(CPUArchState *env, int set) if (ret < 0) return -1; } + + // it should be done after get_msrs, since it needs + // EFER synchonization +#if 0 if (!set) hax_setup_qemu_emulator(env); +#endif + return 0; } @@ -1196,6 +1263,14 @@ static int hax_get_msrs(CPUArchState *env) msrs[n++].entry = MSR_IA32_SYSENTER_ESP; msrs[n++].entry = MSR_IA32_SYSENTER_EIP; msrs[n++].entry = MSR_IA32_TSC; +#ifdef TARGET_X86_64 + msrs[n++].entry = MSR_EFER; + msrs[n++].entry = MSR_STAR; + msrs[n++].entry = MSR_LSTAR; + msrs[n++].entry = MSR_CSTAR; + msrs[n++].entry = MSR_FMASK; + msrs[n++].entry = MSR_KERNELGSBASE; +#endif md.nr_msr = n; ret = hax_sync_msr(env, &md, 0); if (ret < 0) @@ -1215,6 +1290,26 @@ static int hax_get_msrs(CPUArchState *env) case MSR_IA32_TSC: env->tsc = msrs[i].value; break; +#ifdef TARGET_X86_64 + case MSR_EFER: + env->efer = msrs[i].value; + break; + case MSR_STAR: + env->star = msrs[i].value; + break; + case MSR_LSTAR: + env->lstar = msrs[i].value; + break; + case MSR_CSTAR: + env->cstar = msrs[i].value; + break; + case MSR_FMASK: + env->fmask = msrs[i].value; + break; + case MSR_KERNELGSBASE: + env->kernelgsbase = msrs[i].value; + break; +#endif } } @@ -1233,6 +1328,14 @@ static int hax_set_msrs(CPUArchState *env) hax_msr_entry_set(&msrs[n++], MSR_IA32_SYSENTER_ESP, env->sysenter_esp); hax_msr_entry_set(&msrs[n++], MSR_IA32_SYSENTER_EIP, env->sysenter_eip); hax_msr_entry_set(&msrs[n++], MSR_IA32_TSC, env->tsc); +#ifdef TARGET_X86_64 + hax_msr_entry_set(&msrs[n++], MSR_EFER, env->efer); + hax_msr_entry_set(&msrs[n++], MSR_STAR, env->star); + hax_msr_entry_set(&msrs[n++], MSR_LSTAR, env->lstar); + hax_msr_entry_set(&msrs[n++], MSR_CSTAR, env->cstar); + hax_msr_entry_set(&msrs[n++], MSR_FMASK, env->fmask); + hax_msr_entry_set(&msrs[n++], MSR_KERNELGSBASE, env->kernelgsbase); +#endif md.nr_msr = n; md.done = 0; @@ -1255,9 +1358,13 @@ static int hax_get_fpu(CPUArchState *env) for (i = 0; i < 8; ++i) env->fptags[i] = !((fpu.ftw >> i) & 1); memcpy(env->fpregs, fpu.st_mm, sizeof(env->fpregs)); + for (i = 0; i < 8; ++i) { + memcpy(&env->xmm_regs[i], fpu.mmx_1[i], sizeof(fpu.mmx_1[i])); + } + for (i = 0; i < 8; ++i) { + memcpy(&env->xmm_regs[8 + i], fpu.mmx_2[i], sizeof(fpu.mmx_2[i])); + } - memcpy(env->xmm_regs, fpu.mmx_1, sizeof(fpu.mmx_1)); - memcpy((ZMMReg *)(env->xmm_regs) + 8, fpu.mmx_2, sizeof(fpu.mmx_2)); env->mxcsr = fpu.mxcsr; return 0; @@ -1277,8 +1384,12 @@ static int hax_set_fpu(CPUArchState *env) fpu.ftw |= (!env->fptags[i]) << i; memcpy(fpu.st_mm, env->fpregs, sizeof (env->fpregs)); - memcpy(fpu.mmx_1, env->xmm_regs, sizeof (fpu.mmx_1)); - memcpy(fpu.mmx_2, (ZMMReg *)(env->xmm_regs) + 8, sizeof (fpu.mmx_2)); + for (i = 0; i < 8; i++) { + memcpy(fpu.mmx_1[i], &env->xmm_regs[i], sizeof(fpu.mmx_1[i])); + } + for (i = 0; i < 8; i++) { + memcpy(fpu.mmx_2[i], &env->xmm_regs[i + 8], sizeof(fpu.mmx_2[i])); + } fpu.mxcsr = env->mxcsr; @@ -1301,6 +1412,8 @@ static int hax_arch_get_registers(CPUArchState *env) if (ret < 0) return ret; + hax_setup_qemu_emulator(env); + return 0; } diff --git a/target-i386/hax-darwin.c b/target-i386/hax-darwin.c index b8dcbd40ab..be30d74af6 100644 --- a/target-i386/hax-darwin.c +++ b/target-i386/hax-darwin.c @@ -63,43 +63,23 @@ int hax_populate_ram(uint64_t va, uint32_t size) return 0; } -int hax_set_phys_mem(MemoryRegionSection *section) +int hax_set_ram(uint64_t start_pa, uint32_t size, uint64_t host_va, int flags) { - struct hax_set_ram_info info, *pinfo = &info; - MemoryRegion *mr = section->mr; - hwaddr start_addr = section->offset_within_address_space; - ram_addr_t size = int128_get64(section->size); + struct hax_set_ram_info info; int ret; - /*We only care for the RAM and ROM*/ - if(!memory_region_is_ram(mr)) - return 0; - - if ( (start_addr & ~TARGET_PAGE_MASK) || (size & ~TARGET_PAGE_MASK)) - { - dprint("set_phys_mem %llx %lx requires page aligned addr and size\n", start_addr, size); - exit(1); - return -1; - } - - info.pa_start = start_addr; + info.pa_start = start_pa; info.size = size; - info.va = (uint64_t)(intptr_t)(memory_region_get_ram_ptr(mr) + section->offset_within_region); - info.flags = memory_region_is_rom(mr) ? 1 : 0; + info.va = host_va; + info.flags = (uint8_t) flags; - ret = ioctl(hax_global.vm->fd, HAX_VM_IOCTL_SET_RAM, pinfo); - if (ret < 0) - { - dprint("has set phys mem failed\n"); - exit(1); + ret = ioctl(hax_global.vm->fd, HAX_VM_IOCTL_SET_RAM, &info); + if (ret < 0) { + return -errno; } - - return ret; - + return 0; } - - int hax_capability(struct hax_state *hax, struct hax_capabilityinfo *cap) { int ret; diff --git a/target-i386/hax-slot.c b/target-i386/hax-slot.c new file mode 100644 index 0000000000..b0b3ed9dab --- /dev/null +++ b/target-i386/hax-slot.c @@ -0,0 +1,328 @@ +/* +** HAX memory slot operations +** +** Copyright (c) 2015-16 Intel Corporation +** +** This software is licensed under the terms of the GNU General Public +** License version 2, as published by the Free Software Foundation, and +** may be copied, distributed, and modified under those terms. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU General Public License for more details. +*/ + +#include "target-i386/hax-slot.h" +#include "target-i386/hax-i386.h" +#include "qemu/queue.h" + +//#define DEBUG_HAX_SLOT + +#ifdef DEBUG_HAX_SLOT +#define DPRINTF(fmt, ...) \ + do { fprintf(stdout, fmt, ## __VA_ARGS__); } while (0) +#else +#define DPRINTF(fmt, ...) \ + do { } while (0) +#endif + +/** + * HAXSlot: describes a guest physical memory region and its mapping + * + * @start_pa: a guest physical address marking the start of the region; must be + * page-aligned + * @end_pa: a guest physical address marking the end of the region; must be + * page-aligned + * @hva_pa_delta: the host virtual address to which guest physical address 0 is + * mapped; in other words, for any guest physical address within + * the region (start_pa <= pa < end_pa), the corresponding host + * virtual address is calculated by host_va = pa + hva_pa_delta + * @flags: parameters for the mapping; must be non-negative + * @entry: additional fields for linking #HAXSlot instances together + */ +typedef struct HAXSlot { + uint64_t start_pa; + uint64_t end_pa; + uint64_t hva_pa_delta; + int flags; + QTAILQ_ENTRY(HAXSlot) entry; +} HAXSlot; + +/* A doubly-linked list (actually a tail queue) of all registered slots */ +static QTAILQ_HEAD(HAXSlotListHead, HAXSlot) slot_list = + QTAILQ_HEAD_INITIALIZER(slot_list); + +void hax_slot_init_registry(void) +{ + HAXSlot *initial_slot; + + g_assert(QTAILQ_EMPTY(&slot_list)); + + initial_slot = (HAXSlot *) g_malloc0(sizeof(*initial_slot)); + /* Implied: initial_slot->start_pa = 0; */ + /* Ideally we want to set end_pa to 2^64, but that is too large for + * uint64_t. We don't need to support such a large guest physical address + * space anyway; (2^64 - TARGET_PAGE_SIZE) should be (more than) enough. + */ + initial_slot->end_pa = TARGET_PAGE_MASK; + /* hva_pa_delta and flags are initialized with invalid values */ + initial_slot->hva_pa_delta = ~TARGET_PAGE_MASK; + initial_slot->flags = -1; + QTAILQ_INSERT_TAIL(&slot_list, initial_slot, entry); +} + +void hax_slot_free_registry(void) +{ + DPRINTF("%s: Deleting all registered slots\n", __func__); + while (!QTAILQ_EMPTY(&slot_list)) { + HAXSlot *slot = QTAILQ_FIRST(&slot_list); + QTAILQ_REMOVE(&slot_list, slot, entry); + g_free(slot); + } +} + +/** + * hax_slot_dump: dumps a slot to stdout (for debugging) + * + * @slot: the slot to dump + */ +static void hax_slot_dump(HAXSlot *slot) +{ + DPRINTF("[ start_pa=0x%016" PRIx64 ", end_pa=0x%016" PRIx64 + ", hva_pa_delta=0x%016" PRIx64 ", flags=%d ]\n", slot->start_pa, + slot->end_pa, slot->hva_pa_delta, slot->flags); +} + +/** + * hax_slot_dump_list: dumps @slot_list to stdout (for debugging) + */ +static void hax_slot_dump_list(void) +{ +#ifdef DEBUG_HAX_SLOT + HAXSlot *slot; + int i = 0; + + DPRINTF("**** BEGIN HAX SLOT LIST DUMP ****\n"); + QTAILQ_FOREACH(slot, &slot_list, entry) { + DPRINTF("Slot %d:\n\t", i++); + hax_slot_dump(slot); + } + DPRINTF("**** END HAX SLOT LIST DUMP ****\n"); +#endif +} + +/** + * hax_slot_find: locates the slot containing a guest physical address + * + * Traverses @slot_list, starting from @start_slot, and returns the slot which + * contains @pa. There should be one and only one such slot, because: + * + * 1) @slot_list is initialized with a slot which covers all valid @pa values. + * This coverage stays unchanged as new slots are inserted into @slot_list. + * 2) @slot_list does not contain overlapping slots. + * + * @start_slot: the first slot from which @slot_list is traversed and searched; + * must not be %NULL + * @pa: the guest physical address to locate; must not be less than the lower + * bound of @start_slot + */ +static HAXSlot * hax_slot_find(HAXSlot *start_slot, uint64_t pa) +{ + HAXSlot *slot; + + g_assert(start_slot); + g_assert(start_slot->start_pa <= pa); + + slot = start_slot; + do { + if (slot->end_pa > pa) { + return slot; + } + slot = QTAILQ_NEXT(slot, entry); + } while (slot); + + /* Should never reach here */ + g_assert_not_reached(); + return NULL; +} + +/** + * hax_slot_split: splits a slot into two + * + * Shrinks @slot and creates a new slot from the vacated region. Returns the + * new slot. + * + * @slot: the slot to be split/shrinked + * @pa: the splitting point; must be page-aligned and within @slot + */ +static HAXSlot * hax_slot_split(HAXSlot *slot, uint64_t pa) +{ + HAXSlot *new_slot; + + g_assert(slot); + g_assert(pa > slot->start_pa && pa < slot->end_pa); + g_assert(!(pa & ~TARGET_PAGE_MASK)); + + new_slot = (HAXSlot *) g_malloc0(sizeof(*new_slot)); + new_slot->start_pa = pa; + new_slot->end_pa = slot->end_pa; + new_slot->hva_pa_delta = slot->hva_pa_delta; + new_slot->flags = slot->flags; + + slot->end_pa = pa; + QTAILQ_INSERT_AFTER(&slot_list, slot, new_slot, entry); + return new_slot; +} + +/** + * hax_slot_can_merge: tests if two slots are compatible + * + * Two slots are considered compatible if they share the same memory mapping + * attributes. Compatible slots can be merged if they overlap or are adjacent. + * + * Returns %true if @slot1 and @slot2 are compatible. + * + * @slot1: one of the slots to be tested; must not be %NULL + * @slot2: the other slot to be tested; must not be %NULL + */ +static bool hax_slot_can_merge(HAXSlot *slot1, HAXSlot *slot2) +{ + g_assert(slot1 && slot2); + + return slot1->hva_pa_delta == slot2->hva_pa_delta + && slot1->flags == slot2->flags; +} + +/** + * hax_slot_insert: inserts a slot into @slot_list, with the potential side + * effect of creating/updating memory mappings + * + * Causes memory mapping attributes of @slot to override those of overlapping + * slots (including partial slots) in @slot_list. For any slot whose mapping + * attributes have changed, performs an ioctl to enforce the new mapping. + * + * Aborts QEMU on error. + * + * @slot: the slot to be inserted + */ +static void hax_slot_insert(HAXSlot *slot) +{ + HAXSlot *low_slot, *high_slot; + HAXSlot *low_slot_prev, *high_slot_next; + HAXSlot *old_slot, *old_slot_next; + + g_assert(!QTAILQ_EMPTY(&slot_list)); + + low_slot = hax_slot_find(QTAILQ_FIRST(&slot_list), slot->start_pa); + g_assert(low_slot); + low_slot_prev = QTAILQ_PREV(low_slot, HAXSlotListHead, entry); + + /* Adjust slot and/or low_slot such that their lower bounds (start_pa) + * align. + */ + if (hax_slot_can_merge(low_slot, slot)) { + slot->start_pa = low_slot->start_pa; + } else if (slot->start_pa == low_slot->start_pa && low_slot_prev + && hax_slot_can_merge(low_slot_prev, slot)) { + low_slot = low_slot_prev; + slot->start_pa = low_slot->start_pa; + } else if (slot->start_pa != low_slot->start_pa) { + /* low_slot->start_pa < slot->start_pa < low_slot->end_pa */ + low_slot = hax_slot_split(low_slot, slot->start_pa); + g_assert(low_slot); + } + /* Now we have slot->start_pa == low_slot->start_pa */ + + high_slot = hax_slot_find(low_slot, slot->end_pa - 1); + g_assert(high_slot); + high_slot_next = QTAILQ_NEXT(high_slot, entry); + + /* Adjust slot and/or high_slot such that their upper bounds (end_pa) + * align. + */ + if (hax_slot_can_merge(slot, high_slot)) { + slot->end_pa = high_slot->end_pa; + } else if (slot->end_pa == high_slot->end_pa && high_slot_next + && hax_slot_can_merge(slot, high_slot_next)) { + high_slot = high_slot_next; + slot->end_pa = high_slot->end_pa; + } else if (slot->end_pa != high_slot->end_pa) { + /* high_slot->start_pa < slot->end_pa < high_slot->end_pa */ + high_slot_next = hax_slot_split(high_slot, slot->end_pa); + g_assert(high_slot_next); + } + /* Now we have slot->end_pa == high_slot->end_pa */ + + /* We are ready for substitution: replace all slots between low_slot and + * high_slot (inclusive) with slot. */ + + /* Step 1: insert slot into the list, before low_slot */ + QTAILQ_INSERT_BEFORE(low_slot, slot, entry); + + /* Step 2: remove low_slot..high_slot, one by one */ + for (old_slot = low_slot; + /* This condition always evaluates to 1. See: + * https://en.wikipedia.org/wiki/Comma_operator + */ + old_slot_next = QTAILQ_NEXT(old_slot, entry), 1; + old_slot = old_slot_next) { + g_assert(old_slot); + + QTAILQ_REMOVE(&slot_list, old_slot, entry); + if (!hax_slot_can_merge(slot, old_slot)) { + /* Mapping for guest memory region [old_slot->start_pa, + * old_slot->end_pa) has changed - must do ioctl. */ + /* TODO: Further reduce the number of ioctl calls by preprocessing + * the low_slot..high_slot sublist and combining any two adjacent + * slots that are both incompatible with slot. + */ + uint32_t size = old_slot->end_pa - old_slot->start_pa; + uint64_t host_va = old_slot->start_pa + slot->hva_pa_delta; + int err; + + DPRINTF("%s: Doing ioctl (size=0x%08" PRIx32 ")\n", __func__, size); + /* Use the new host_va and flags */ + err = hax_set_ram(old_slot->start_pa, size, host_va, slot->flags); + if (err) { + fprintf(stderr, "%s: Failed to set memory mapping (err=%d)\n", + __func__, err); + abort(); + } + } + g_free(old_slot); + + /* Exit the infinite loop following the removal of high_slot */ + if (old_slot == high_slot) { + break; + } + } +} + +void hax_slot_register(uint64_t start_pa, uint32_t size, uint64_t host_va, + int flags) +{ + uint64_t end_pa = start_pa + size; + HAXSlot *slot; + + g_assert(!(start_pa & ~TARGET_PAGE_MASK)); + g_assert(!(end_pa & ~TARGET_PAGE_MASK)); + g_assert(start_pa < end_pa); + g_assert(host_va); + g_assert(flags >= 0); + + slot = g_malloc0(sizeof(*slot)); + slot->start_pa = start_pa; + slot->end_pa = end_pa; + slot->hva_pa_delta = host_va - start_pa; + slot->flags = flags; + + DPRINTF("%s: Inserting slot:\n\t", __func__); + hax_slot_dump(slot); + hax_slot_dump_list(); + + hax_slot_insert(slot); + + DPRINTF("%s: Done\n", __func__); + hax_slot_dump_list(); +} diff --git a/target-i386/hax-slot.h b/target-i386/hax-slot.h new file mode 100644 index 0000000000..d991c53d38 --- /dev/null +++ b/target-i386/hax-slot.h @@ -0,0 +1,58 @@ +/* +** HAX memory slot operations +** +** Copyright (c) 2015-16 Intel Corporation +** +** This software is licensed under the terms of the GNU General Public +** License version 2, as published by the Free Software Foundation, and +** may be copied, distributed, and modified under those terms. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU General Public License for more details. +*/ + +#ifndef _HAX_SLOT_H +#define _HAX_SLOT_H + +#include <inttypes.h> + +/** + * hax_slot_init_registry: initializes the registry of memory slots. + * + * Should be called during HAX initialization, before any call to + * hax_slot_register(). + */ +void hax_slot_init_registry(void); + +/** + * hax_slot_free_registry: destroys the registry of memory slots. + * + * Should be called during HAX cleanup to free up resources used by the + * registry of memory slots. + */ +void hax_slot_free_registry(void); + +/** + * hax_slot_register: registers a memory slot, updating HAX memory mappings if + * necessary. + * + * Must be called after hax_slot_init_registry(). Can be called multiple times + * to create new memory mappings or update existing ones. This function is smart + * enough to avoid asking the HAXM driver to do the same mapping twice for any + * guest physical page. + * + * Aborts QEMU on error. + * + * @start_pa: a guest physical address marking the start of the slot to + * register; must be page-aligned + * @size: size of the slot to register; must be page-aligned and positive + * @host_va: a host virtual address to which @start_pa should be mapped + * @flags: parameters for the mapping, passed verbatim to the HAXM driver if + * necessary; must be non-negative + */ +void hax_slot_register(uint64_t start_pa, uint32_t size, uint64_t host_va, + int flags); + +#endif diff --git a/target-i386/hax-windows.c b/target-i386/hax-windows.c index 5ff5916db5..f24a9e195e 100644 --- a/target-i386/hax-windows.c +++ b/target-i386/hax-windows.c @@ -90,48 +90,21 @@ int hax_populate_ram(uint64_t va, uint32_t size) return 0; } - -/* - * much simpler than kvm, at least in first stage because: - * We don't need consider the device pass-through, we don't need - * consider the framebuffer, and we may even remove the bios at all - */ - -int hax_set_phys_mem(MemoryRegionSection *section) +int hax_set_ram(uint64_t start_pa, uint32_t size, uint64_t host_va, int flags) { - struct hax_set_ram_info info, *pinfo = &info; - MemoryRegion *mr = section->mr; - hwaddr start_addr = section->offset_within_address_space; - ram_addr_t size = int128_get64(section->size); - HANDLE hDeviceVM; + struct hax_set_ram_info info; + HANDLE hDeviceVM = hax_global.vm->fd; DWORD dSize = 0; - int ret = 0; - - /* We only care for the RAM and ROM */ - if (!memory_region_is_ram(mr)) { - return 0; - } - - if ( (start_addr & ~TARGET_PAGE_MASK) || (size & ~TARGET_PAGE_MASK)) { - dprint( - "set_phys_mem %" PRIx64 " %" PRIxPTR " requires page aligned addr and size\n", - start_addr, size); - return -1; - } + int ret; - info.pa_start = start_addr; + info.pa_start = start_pa; info.size = size; - info.va = (uint64_t)(intptr_t)(memory_region_get_ram_ptr(mr) + section->offset_within_region); - info.flags = memory_region_is_rom(mr) ? 1 : 0; - - hDeviceVM = hax_global.vm->fd; + info.va = host_va; + info.flags = (uint8_t) flags; - ret = DeviceIoControl(hDeviceVM, - HAX_VM_IOCTL_SET_RAM, - pinfo, sizeof(*pinfo), - NULL, 0, - &dSize, - (LPOVERLAPPED) NULL); + ret = DeviceIoControl(hDeviceVM, HAX_VM_IOCTL_SET_RAM, + &info, sizeof(info), NULL, 0, &dSize, + (LPOVERLAPPED) NULL); if (!ret) return -EFAULT; diff --git a/target-i386/monitor.c b/target-i386/monitor.c index fccfe40ab7..1f0e46cb7e 100644 --- a/target-i386/monitor.c +++ b/target-i386/monitor.c @@ -36,7 +36,7 @@ static void print_pte(Monitor *mon, hwaddr addr, { #ifdef TARGET_X86_64 if (addr & (1ULL << 47)) { - addr |= -1LL << 48; + addr |= ~0ULL << 48; } #endif monitor_printf(mon, TARGET_FMT_plx ": " TARGET_FMT_plx diff --git a/tizen/src/ecs/ecs.c b/tizen/src/ecs/ecs.c index c77b6c0a55..758579281c 100644 --- a/tizen/src/ecs/ecs.c +++ b/tizen/src/ecs/ecs.c @@ -51,6 +51,9 @@ #include "ecs.h" #include "emul_state.h" +#include "hw/virtio/maru_virtio_sensor.h" +#include "hw/virtio/maru_virtio_nfc.h" + #include "debug_ch.h" MULTI_DEBUG_CHANNEL(qemu, ecs); @@ -77,6 +80,40 @@ static QemuThread ecs_thread_id; static int suspend_state = 1; +static char device_capabilities [16]; + +enum ecs_check_cap_list { + CHECK_CAP_BATTERY = 0, + CHECK_CAP_LOCATION, + CHECK_CAP_NFC, + CHECK_CAP_TELEPHONY, + CHECK_CAP_ACCEL, + CHECK_CAP_GYRO, + CHECK_CAP_GEO, + CHECK_CAP_PROXI, + CHECK_CAP_LIGHT, + CHECK_CAP_PRESSURE, + CHECK_CAP_HEARTRATE, + CHECK_CAP_UV, + CHECK_CAP_PEDO +}; + +static int cap_device_list[] = { + 0x0001, // Battery + 0x0002, // Location + 0x0004, // NFC + 0x0008, // Telephony + 0x0010, // Accelerometer + 0x0020, // Gyroscope + 0x0040, // Magnetometer + 0x0080, // Proximity + 0x0100, // Light + 0x0200, // Pressure + 0x0400, // HeartRate + 0x0800, // Ultraviolet + 0x1000, // Pedometer +}; + void ecs_set_suspend_state(int state) { suspend_state = state; @@ -87,6 +124,78 @@ int ecs_get_suspend_state(void) return suspend_state; } +static void check_sensor_capability(int* capacity) +{ + int sensor_cap = get_sensor_capability(); + if ((sensor_cap & sensor_cap_accel) == 0) { + *capacity &= ~cap_device_list[CHECK_CAP_ACCEL]; + } + if ((sensor_cap & sensor_cap_geo) == 0) { + *capacity &= ~cap_device_list[CHECK_CAP_GEO]; + } + + if ((sensor_cap & sensor_cap_gyro) == 0) { + *capacity &= ~cap_device_list[CHECK_CAP_GYRO]; + } + + if ((sensor_cap & sensor_cap_proxi) == 0) { + *capacity &= ~cap_device_list[CHECK_CAP_PROXI]; + } + + if ((sensor_cap & sensor_cap_light) == 0) { + *capacity &= ~cap_device_list[CHECK_CAP_LIGHT]; + } + + if ((sensor_cap & sensor_cap_pressure) == 0) { + *capacity &= ~cap_device_list[CHECK_CAP_PRESSURE]; + } + + if ((sensor_cap & sensor_cap_uv) == 0) { + *capacity &= ~cap_device_list[CHECK_CAP_UV]; + } + + if ((sensor_cap & sensor_cap_hrm) == 0) { + *capacity &= ~cap_device_list[CHECK_CAP_HEARTRATE]; + } + + if ((sensor_cap & sensor_cap_pedo) == 0) { + *capacity &= ~cap_device_list[CHECK_CAP_PEDO]; + } +} + +extern VirtIONFC *vio_nfc; +static void check_nfc_capability(int* capacity) +{ + if (!vio_nfc) { + *capacity &= ~cap_device_list[CHECK_CAP_NFC]; + } +} + +void ecs_set_device_capabilities(const char* cap) +{ + int capability = 0; + + memset(device_capabilities, 0, sizeof(device_capabilities)); + + if (cap != NULL) { + capability = atoi(cap); + // check sensor capability + check_sensor_capability(&capability); + // check nfc capability + check_nfc_capability(&capability); + + LOG_INFO("check_sensor_capability: %04x\n", capability); + snprintf(device_capabilities, sizeof(device_capabilities), "%d", capability); + } + + make_send_device_ntf((char*)MSG_TYPE_CAP, MSG_GROUP_STATUS, 0, device_capabilities); +} + +const char* ecs_get_device_capabilities(void) +{ + return device_capabilities; +} + int ecs_write(int fd, const uint8_t *buf, int len) { int ret, remain; diff --git a/tizen/src/ecs/ecs.h b/tizen/src/ecs/ecs.h index 028c2f0675..3458dfaaa5 100644 --- a/tizen/src/ecs/ecs.h +++ b/tizen/src/ecs/ecs.h @@ -55,6 +55,7 @@ #define MSG_TYPE_HDS "hds" #define MSG_TYPE_PACKAGE "package" #define MSG_TYPE_SYSTEM "system" +#define MSG_TYPE_CAP "cap" #define MSG_GROUP_STATUS 15 @@ -95,4 +96,8 @@ int ecs_get_suspend_state(void); void ecs_set_suspend_state(int state); void ecs_suspend_lock_state(int state); +/* Device capabilities check */ +const char* ecs_get_device_capabilities(void); +void ecs_set_device_capabilities(const char* cap); + #endif /* __ECS_H__ */ diff --git a/tizen/src/ecs/ecs_msg.c b/tizen/src/ecs/ecs_msg.c index 3eb314823a..305eb77051 100644 --- a/tizen/src/ecs/ecs_msg.c +++ b/tizen/src/ecs/ecs_msg.c @@ -197,6 +197,8 @@ void send_shutdown_request(int action) if (!ret) { LOG_SEVERE("fail to send evdi shutdown system call to emuld.\n"); } + + ecs_set_device_capabilities(NULL); } bool ntf_to_injector(const char *data, const int len) diff --git a/tizen/src/ecs/ecs_msg_device.c b/tizen/src/ecs/ecs_msg_device.c index 3000478bde..4e7f5c1e84 100644 --- a/tizen/src/ecs/ecs_msg_device.c +++ b/tizen/src/ecs/ecs_msg_device.c @@ -431,14 +431,14 @@ bool msgproc_device_req(ECS_Client *ccli, ECS__DeviceReq *msg) #endif } else if (!strcmp(cmd, "input")) { msgproc_device_req_input(ccli, msg, cmd); - } else if (!strcmp(cmd, "vmname")) { - const char *vmname = get_vm_name(); - msgproc_device_ans(ccli, cmd, true, vmname); } else if (!strcmp(cmd, "vminfo")) { gchar vminfo[128]; g_snprintf(vminfo, sizeof(vminfo) - 1, "%s %s %s", get_vm_name(), get_profile_name(), get_platform_version()); msgproc_device_ans(ccli, cmd, true, vminfo); + } else if (!strcmp(cmd, MSG_TYPE_CAP)) { + const char* cap = ecs_get_device_capabilities(); + make_send_device_ntf(cmd, MSG_GROUP_STATUS, 0, (char*)cap); } else if (!strcmp(cmd, "nfc")) { msgproc_device_req_nfc(ccli, msg); } else if (!strcmp(cmd, "sdcard")) { diff --git a/tizen/src/ecs/ecs_msg_injector.c b/tizen/src/ecs/ecs_msg_injector.c index a65f70c044..c577ea3b9e 100644 --- a/tizen/src/ecs/ecs_msg_injector.c +++ b/tizen/src/ecs/ecs_msg_injector.c @@ -463,6 +463,10 @@ static bool injector_req_handle(char *cat, type_action action, const char *data) LOG_WARNING("VirtFS is not enabled.\n"); return false; #endif + } else if (!strcmp(cat, MSG_TYPE_CAP)) { + LOG_INFO("set capabilities: %s\n", data); + ecs_set_device_capabilities(data); + return true; } else if (!strcmp(cat, MSG_TYPE_PACKAGE)) { do_package(cat, action, data); return true; diff --git a/tizen/src/emul_state.c b/tizen/src/emul_state.c index 8e6b7ea7c0..5ecf70dca7 100644 --- a/tizen/src/emul_state.c +++ b/tizen/src/emul_state.c @@ -311,38 +311,38 @@ const char *get_kernel_file(void) return qemu_opt_get(qemu_get_machine_opts(), "kernel"); } -// http proxy -static const char *http_proxy_addr = NULL; +// https proxy +static const char *https_proxy_addr = NULL; -const char *get_http_proxy_addr(void) +const char *get_https_proxy_addr(void) { - if (http_proxy_addr) { - return http_proxy_addr; + if (https_proxy_addr) { + return https_proxy_addr; } const char *kernel_cmdline = qemu_opt_get(qemu_get_machine_opts(), "append"); // kernel cmdline always contains proxy information - char *buf = g_strstr_len(kernel_cmdline, -1, "http_proxy="); + char *buf = g_strstr_len(kernel_cmdline, -1, "https_proxy="); if (buf) { char **token = g_strsplit_set(buf, "= ", 3); if (token[0] && token[1] && g_strcmp0(token[1], "")) { - http_proxy_addr = g_strdup(token[1]); + https_proxy_addr = g_strdup(token[1]); g_strfreev(token); - LOG_INFO("HTTP proxy address: %s\n", http_proxy_addr); + LOG_INFO("HTTPS proxy address: %s\n", https_proxy_addr); - return http_proxy_addr; + return https_proxy_addr; } g_strfreev(token); } - http_proxy_addr = g_strdup(""); + https_proxy_addr = g_strdup(""); - LOG_INFO("HTTP proxy address is not set.\n"); + LOG_INFO("HTTPS proxy address is not set.\n"); - return http_proxy_addr; + return https_proxy_addr; } // vm_name @@ -549,10 +549,7 @@ bool is_netclient_tap_attached(void) NET_CLIENT_DRIVER_NIC, MAX_QUEUE_NUM); for (i = 0; i < queues; ++i) { - if (ncs[i]->info->type == NET_CLIENT_DRIVER_TAP && - (ncs[i]->peer->info->type == NET_CLIENT_DRIVER_NIC || - // for legacy -net option. - ncs[i]->peer->info->type == NET_CLIENT_DRIVER_HUBPORT)) { + if (ncs[i]->info->type == NET_CLIENT_DRIVER_TAP) { return true; } } @@ -742,8 +739,8 @@ static void emul_state_notify_exit(Notifier *notifier, void *data) g_free((void *)swap_image_file); swap_image_file = NULL; - g_free((void *)http_proxy_addr); - http_proxy_addr = NULL; + g_free((void *)https_proxy_addr); + https_proxy_addr = NULL; g_free((void *)vm_name); vm_name = NULL; diff --git a/tizen/src/emul_state.h b/tizen/src/emul_state.h index b360e88332..91a427a952 100644 --- a/tizen/src/emul_state.h +++ b/tizen/src/emul_state.h @@ -128,7 +128,7 @@ const char *get_drive_image_file(void); const char *get_drive_image_ver(void); const char *get_swap_image_file(void); const char *get_kernel_file(void); -const char *get_http_proxy_addr(void); +const char *get_https_proxy_addr(void); const char *get_vm_name(void); const char *get_profile_name(void); const char *get_platform_version(void); diff --git a/tizen/src/emulator.c b/tizen/src/emulator.c index b1d6bab6c8..b63d020518 100644 --- a/tizen/src/emulator.c +++ b/tizen/src/emulator.c @@ -47,7 +47,10 @@ #include "ecs/ecs.h" #include "util/device_hotplug.h" #include "util/exported_strings.h" - +#ifdef CONFIG_WIN32 +#include <windows.h> +#include <sddl.h> +#endif #ifdef CONFIG_QT #include <qt5_supplement.h> #endif @@ -240,7 +243,6 @@ const char *prepare_maru(const char * const kernel_cmdline) void prepare_maru_after_device_init(void) { - make_vm_lock_os(); init_device_hotplug(); start_ecs(); @@ -283,7 +285,10 @@ static int emulator_main(int argc, char *argv[], char **envp) set_variable(argv[optind - 1], argv[optind], true); break; case 'c': - launch_conf_file = g_strdup(optarg); + if (optind == 3) { + // "--conf" should be a first argument + launch_conf_file = g_strdup(optarg); + } break; case 'q': c = -1; @@ -295,8 +300,12 @@ static int emulator_main(int argc, char *argv[], char **envp) } if (!launch_conf_file && qemu_arg_index == 0) { - fprintf(stderr, "Usage: %s {-c|--conf} conf_file ...\n", - basename(argv[0])); + char *executable = basename(argv[0]); + fprintf(stderr, "Usage: %s {-c|--conf} conf_file [--<key> <value>]...\n" + " %*s [{-q|--qemu} <QEMU_ARGS>...]\n", + executable, (int)strlen(executable), ""); + fprintf(stderr, " %s {-q|--qemu} <QEMU_ARGS>...\n", + executable); return -1; } @@ -308,6 +317,12 @@ static int emulator_main(int argc, char *argv[], char **envp) set_bin_path_os(_qemu_argv[0]); if (launch_conf_file) { + if (!g_file_test(launch_conf_file, G_FILE_TEST_EXISTS)) { + fprintf(stderr, "conf_file(%s) does not exist.\n", launch_conf_file); + return -1; + } + + make_vm_lock_os(g_path_get_dirname(launch_conf_file)); if (!load_conf(launch_conf_file)) { return -1; } @@ -346,6 +361,15 @@ int main(int argc, char *argv[], char **envp) init_error_handler(); return emulator_main(argc, argv, envp); } +#elif defined (CONFIG_WIN32) +int main(int argc, char *argv[]) +{ + if (!check_integrity_level_and_respawn()) { + init_error_handler(); + return emulator_main(argc, argv, NULL); + } + return 0; +} #else int main(int argc, char *argv[]) { diff --git a/tizen/src/emulator_options.c b/tizen/src/emulator_options.c index 209bbabd94..03ea020bb5 100644 --- a/tizen/src/emulator_options.c +++ b/tizen/src/emulator_options.c @@ -220,7 +220,12 @@ bool load_conf(const char * const conf) assert(!!conf); filename = g_strdup(conf); - file = fopen(filename, "r"); + if(!g_file_test(filename, G_FILE_TEST_IS_REGULAR)) { + fprintf(stderr, + "Profile configuration file [%s] is invalid.\n", filename); + return false; + } + file = g_fopen(filename, "r"); if (!file) { fprintf(stderr, "Profile configuration file [%s] is not found.\n", filename); diff --git a/tizen/src/hw/virtio/maru_virtio_sensor.c b/tizen/src/hw/virtio/maru_virtio_sensor.c index b6522ac4b8..94d892d619 100644 --- a/tizen/src/hw/virtio/maru_virtio_sensor.c +++ b/tizen/src/hw/virtio/maru_virtio_sensor.c @@ -726,6 +726,11 @@ static void parse_sensor_capability(char *lists) LOG_INFO("sensor device capabilty enabled with %02x\n", sensor_capability); } +int get_sensor_capability(void) +{ + return sensor_capability; +} + static void virtio_sensor_realize(DeviceState *dev, Error **errp) { LOG_INFO("initialize virtio-sensor device\n"); diff --git a/tizen/src/hw/virtio/maru_virtio_sensor.h b/tizen/src/hw/virtio/maru_virtio_sensor.h index 1c0a743934..1cb5b19de9 100644 --- a/tizen/src/hw/virtio/maru_virtio_sensor.h +++ b/tizen/src/hw/virtio/maru_virtio_sensor.h @@ -143,6 +143,8 @@ typedef struct VirtIOSENSOR { char *sensors; } VirtIOSENSOR; +int get_sensor_capability(void); + void req_sensor_data(enum sensor_types type, enum request_cmd req, char *data, int len); #define get_sensor_accel() \ diff --git a/tizen/src/hw/virtio/maru_virtio_tablet.c b/tizen/src/hw/virtio/maru_virtio_tablet.c index 9a564ba502..5bab39cc95 100644 --- a/tizen/src/hw/virtio/maru_virtio_tablet.c +++ b/tizen/src/hw/virtio/maru_virtio_tablet.c @@ -148,9 +148,7 @@ static void maru_tablet_bh(void *opaque) qemu_mutex_unlock(&vt->mutex); /* Get a queue buffer which is written by guest side. */ - do { - elem = virtqueue_pop(vt->vq, sizeof(VirtQueueElement)); - } while (elem); + elem = virtqueue_pop(vt->vq, sizeof(VirtQueueElement)); qemu_mutex_lock(&vt->mutex); while (!QTAILQ_EMPTY(&events_queue)) { @@ -160,10 +158,10 @@ static void maru_tablet_bh(void *opaque) /* copy event into virtio buffer */ len = iov_from_buf(elem->in_sg, elem->in_num, push_len, &(event_entry->tablet), sizeof(EmulTabletEvent)); - if(len != sizeof(EmulTabletEvent)) { + if (len != sizeof(EmulTabletEvent)) { LOG_WARNING("len != sizeof(EmulTabletEvent).\n"); LOG_WARNING("len: %zu, sizeof(EmulTabletEvent): %zu\n", - len, sizeof(EmulTabletEvent)); + len, sizeof(EmulTabletEvent)); } push_len += sizeof(EmulTabletEvent); diff --git a/tizen/src/ui/displaybase.cpp b/tizen/src/ui/displaybase.cpp index 80b8b9b9e1..1daff0677c 100644 --- a/tizen/src/ui/displaybase.cpp +++ b/tizen/src/ui/displaybase.cpp @@ -110,21 +110,22 @@ void DisplayBase::showOffGuideImg() { offGuideShown = true; - offGuide = new QLabel(win); - offGuide->setAttribute(Qt::WA_DeleteOnClose); - offGuide->setStyleSheet( - "background-color: black; border-style: none;"); - offGuide->setAlignment(Qt::AlignCenter); - - offGuide->setGeometry(getGeometry()); - offGuide->setPixmap(offGuideImg.scaled( - getGeometry().width(), getGeometry().height(), - Qt::KeepAspectRatio, Qt::SmoothTransformation)); - - if (maskImage.size() != QSize(0, 0)) { - offGuide->setMask(maskImage.scaled( - maskImage.width() * scaleFactor, - maskImage.height() * scaleFactor).mask()); + if (!offGuide) { + offGuide = new QLabel(win); + offGuide->setStyleSheet( + "background-color: black; border-style: none;"); + offGuide->setAlignment(Qt::AlignCenter); + + offGuide->setGeometry(getGeometry()); + offGuide->setPixmap(offGuideImg.scaled( + getGeometry().width(), getGeometry().height(), + Qt::KeepAspectRatio, Qt::SmoothTransformation)); + + if (maskImage.size() != QSize(0, 0)) { + offGuide->setMask(maskImage.scaled( + maskImage.width() * scaleFactor, + maskImage.height() * scaleFactor).mask()); + } } offGuide->show(); @@ -134,7 +135,6 @@ void DisplayBase::hideOffGuideImg() { if (offGuide != NULL) { offGuide->close(); - offGuide = NULL; } offGuideShown = false; diff --git a/tizen/src/ui/displayswwidget.cpp b/tizen/src/ui/displayswwidget.cpp index 3880f7deb1..ec149a5c9f 100644 --- a/tizen/src/ui/displayswwidget.cpp +++ b/tizen/src/ui/displayswwidget.cpp @@ -40,11 +40,11 @@ DisplaySWWidget::DisplaySWWidget(QWidget *parent, DisplayType *displayForm, QSize resolution, qreal scaleFactor) : QLabel(parent), DisplayBase(displayForm, resolution, scaleFactor, this) { - /* fill the screen with black surface */ + /* fill the screen with black(with full alpha) surface */ QPixmap initImage( displayForm->getRect().width() * scaleFactor, displayForm->getRect().height() * scaleFactor); - initImage.fill(Qt::black); + initImage.fill(QColor(0, 0, 0, 255)); setPixmap(initImage); /* to be enable to drop events */ setAcceptDrops(true); diff --git a/tizen/src/ui/input/keyboardshortcut.cpp b/tizen/src/ui/input/keyboardshortcut.cpp index c14f2cfdb6..a5f598c8a3 100644 --- a/tizen/src/ui/input/keyboardshortcut.cpp +++ b/tizen/src/ui/input/keyboardshortcut.cpp @@ -87,11 +87,10 @@ void KeyboardShortcut::registerHwKeyShortcuts(QList<HardwareKey *> &list) void KeyboardShortcut::cancelHwKeyShortcuts(QList<HardwareKey *> &list) { for (int index = 0; index < list.count(); index++) { - delete hwKeyShortcutMap.value(list.at(index)); - hwKeyShortcutMap.remove(list.at(index)); + delete hwKeyShortcutMap.take(list.at(index)); } - qDebug() << hwKeyShortcutMap.count() << "shortcuts have been registered"; + qDebug() << hwKeyShortcutMap.count() << "shortcuts have been unregistered"; } void KeyboardShortcut::slotHwKeyShortcut(int keycode) diff --git a/tizen/src/ui/mainwindow.cpp b/tizen/src/ui/mainwindow.cpp index 8667059807..54f441d46b 100644 --- a/tizen/src/ui/mainwindow.cpp +++ b/tizen/src/ui/mainwindow.cpp @@ -67,6 +67,8 @@ MainWindow::MainWindow(UiInformation *uiInfo, QWidget *parent) : this->captureRequestData = NULL; this->movingWidget = NULL; + this->isMovingMode = false; + /* windowing */ setWindowTitle(EMULATOR_TITLE); setWindowIcon(QIcon(":/icons/emulator_icon.ico")); @@ -97,7 +99,7 @@ MainWindow::MainWindow(UiInformation *uiInfo, QWidget *parent) : } /* display */ - updateDisplayMatrix(); + updateDisplayTransform(); display = createDisplay(uiInfo->getMainFormDpyType()); /* set HW Key shortcut */ @@ -211,9 +213,9 @@ UIState *MainWindow::getUiState() return uiInfo->getUiState(); } -const QMatrix &MainWindow::getDisplayMatrix() +const QTransform &MainWindow::getDisplayTransform() { - return dpyMatrix; + return dpyTransform; } MainView *MainWindow::getMainView() @@ -412,12 +414,12 @@ void MainWindow::setMask(const QRegion ®ion) } } -void MainWindow::updateDisplayMatrix() +void MainWindow::updateDisplayTransform() { - dpyMatrix.reset(); - dpyMatrix.scale( + dpyTransform.reset(); + dpyTransform.scale( getUiState()->getScaleFactor(), getUiState()->getScaleFactor()); - dpyMatrix.rotate(uiInfo->getMainFormDpyType()->getAngle()); + dpyTransform.rotate(uiInfo->getMainFormDpyType()->getAngle()); } void MainWindow::switchForm(int index) @@ -436,7 +438,7 @@ void MainWindow::switchForm(int index) /* register new HW key shortcuts */ keyboardShortcut->registerHwKeyShortcuts(uiInfo->getMainForm()->getKeyList()); - updateDisplayMatrix(); + updateDisplayTransform(); if (getDockingCon() != NULL) { getDockingCon()->updateGeometry(); @@ -467,7 +469,7 @@ void MainWindow::scaleForm(int scale) /* scale changing */ getUiState()->setScalePct(scale); - updateDisplayMatrix(); + updateDisplayTransform(); if (getDockingCon() != NULL) { getDockingCon()->updateGeometry(); @@ -518,9 +520,12 @@ void MainWindow::processCaptured(bool captured, void *pixels, if (captured) { qDebug("save captured image: %p", pixels); - - QImage image = QImage((uchar *)pixels, width, height, QImage::Format_RGB32); - QPixmap pixmap = QPixmap::fromImage(image); /* deep copy the data */ + // pixels's format is ARGB32 + QImage image = + QImage((uchar *)pixels, width, height, QImage::Format_ARGB32); + // deep copy from image & set all alpha channel value to 0xFF + QPixmap pixmap = + QPixmap::fromImage(image.convertToFormat(QImage::Format_RGB32)); QMetaObject::invokeMethod(popupMenu, "slotShowScreenshot", Qt::QueuedConnection, Q_ARG(QPixmap, pixmap)); @@ -528,6 +533,8 @@ void MainWindow::processCaptured(bool captured, void *pixels, qDebug("save blank image"); QPixmap pixmap(uiInfo->getResolution().width(), uiInfo->getResolution().height()); + // fill the uninitialized buffer of the pixmap with 0xFF000000 + pixmap.fill(QColor(0, 0, 0, 255)); QMetaObject::invokeMethod(popupMenu, "slotShowScreenshot", Qt::QueuedConnection, Q_ARG(QPixmap, pixmap)); } @@ -556,12 +563,17 @@ void MainWindow::turnOnMovingMode() { qDebug("enter the moving mode"); + if (isMovingMode) { + return; + } + getDisplay()->turnOnMovingMode(); - if (isMovingMode() == false) { + if (movingWidget == NULL) { movingWidget = new MovingWidget(this); } + isMovingMode = true; movingWidget->show(); } @@ -569,17 +581,14 @@ void MainWindow::turnOffMovingMode() { qDebug("leave the moving mode"); - getDisplay()->turnOffMovingMode(); - - if (isMovingMode() == true) { - movingWidget->close(); - movingWidget = NULL; + if (!isMovingMode) { + return; } -} -bool MainWindow::isMovingMode() -{ - return (movingWidget != NULL); + getDisplay()->turnOffMovingMode(); + + movingWidget->close(); + isMovingMode = false; } /* override */ @@ -599,17 +608,29 @@ void MainWindow::closeEvent(QCloseEvent *event) } } -MainWindow::~MainWindow() +QMessageBox *MainWindow::showMsgBox( + QMessageBox::Icon iconType, const QString &text, + QMessageBox::StandardButtons buttons, + QMessageBox::StandardButton defaultButton) { - qDebug("destroy main window"); + qWarning() << text; - if (popupMenu) { - delete popupMenu; - popupMenu = NULL; + QMessageBox *msgBox = new QMessageBox(iconType, + EMULATOR_TITLE, text, buttons, this); + if (defaultButton != QMessageBox::NoButton) { + msgBox->setDefaultButton(defaultButton); } + msgBox->setAttribute(Qt::WA_DeleteOnClose); + msgBox->show(); /* non-blocking */ - if (rotary != NULL) { - delete rotary; - rotary = NULL; - } +#ifdef CONFIG_LINUX + popupMenu->slotOnTop(getUiState()->isOnTop()); +#endif + + return msgBox; +} + +MainWindow::~MainWindow() +{ + qDebug("destroy main window"); } diff --git a/tizen/src/ui/mainwindow.h b/tizen/src/ui/mainwindow.h index 183aeb337c..cd90e7395f 100644 --- a/tizen/src/ui/mainwindow.h +++ b/tizen/src/ui/mainwindow.h @@ -53,19 +53,24 @@ class MainWindow : public QWidget Q_OBJECT public: + bool isMovingMode; + explicit MainWindow(UiInformation *uiInfo, QWidget *parent = 0); ~MainWindow(); UiInformation *getUiInfo(void); UIState *getUiState(void); - const QMatrix &getDisplayMatrix(); + const QTransform &getDisplayTransform(); MainView *getMainView(); ContextMenu *getPopupMenu(); DisplayBase *getDisplay(); KeyboardShortcut *getKeyboardShortcut(); QLabel *getScreenWidget(); + QMessageBox *showMsgBox(QMessageBox::Icon iconType, const QString &text, + QMessageBox::StandardButtons buttons = QMessageBox::NoButton, + QMessageBox::StandardButton defaultButton = QMessageBox::NoButton); - void updateDisplayMatrix(); + void updateDisplayTransform(); void switchForm(int angle); void scaleForm(int scale); void capture(void); @@ -84,7 +89,6 @@ public: void turnOnMovingMode(); void turnOffMovingMode(); - bool isMovingMode(); public slots: void slotContextMenu(const QPoint &pos); @@ -105,7 +109,7 @@ private: UiInformation *uiInfo; /* windowing */ - QMatrix dpyMatrix; + QTransform dpyTransform; QGraphicsScene *mainScene; MainView *mainView; DisplayBase *display; diff --git a/tizen/src/ui/menu/aboutdialog.cpp b/tizen/src/ui/menu/aboutdialog.cpp index 491eef6ed2..b956dd83ad 100644 --- a/tizen/src/ui/menu/aboutdialog.cpp +++ b/tizen/src/ui/menu/aboutdialog.cpp @@ -30,12 +30,17 @@ #include "aboutdialog.h" #include "resource/ui_strings.h" #include "build_info.h" +#include "mainwindow.h" +#include "emul_state.h" AboutDialog::AboutDialog(QWidget *parent) : QDialog(parent, Qt::Dialog | Qt::WindowStaysOnTopHint) { setWindowTitle(ABOUT_TITLE); + // remove ? button + setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint); + QVBoxLayout *baseLayout = new QVBoxLayout(this); baseLayout->setMargin(0); baseLayout->setSpacing(5); @@ -56,6 +61,9 @@ AboutDialog::AboutDialog(QWidget *parent) : } upsideLayout->addWidget(imageLabel); + /* Emulator platform version*/ + QString platformVersion = QString(get_platform_version()).section('-', 1).trimmed(); + /* SDK version */ QString versionFilePath = QDir(QCoreApplication::applicationDirPath() + QDir::separator() + SDK_ROOT_PATH + SDK_VERSION_FILE).absolutePath(); @@ -90,7 +98,7 @@ AboutDialog::AboutDialog(QWidget *parent) : */ QString aboutText = - "<b>" + QString(EMULATOR_TITLE) + " for " + EMULATOR_BUILD_VER + "</b><p>" + + "<b>" + QString(EMULATOR_TITLE) + " for " + platformVersion + "</b><p>" + ABOUT_SDK_VERSION_TEXT + " : " + sdkVer + "<br>" + ABOUT_PKG_VERSION_TEXT + " : " + pkgVer + "<br>" + /* "Snapshot : " + SnapshotName + "<br>" + */ diff --git a/tizen/src/ui/menu/contextmenu.cpp b/tizen/src/ui/menu/contextmenu.cpp index cf60abdc21..0c0c348f9d 100644 --- a/tizen/src/ui/menu/contextmenu.cpp +++ b/tizen/src/ui/menu/contextmenu.cpp @@ -925,12 +925,12 @@ void ContextMenu::slotShell() QFileInfo sdbFileInfo(sdbPath); if (sdbFileInfo.exists() == false) { - showMsgBox(QMessageBox::Warning, MSG_SDB_NOT_EXIST + sdbPath); + parent->showMsgBox(QMessageBox::Warning, MSG_SDB_NOT_EXIST + sdbPath); return; } if (!is_sdb_daemon_initialized()) { - showMsgBox(QMessageBox::Warning, MSG_SDB_NOT_READY); + parent->showMsgBox(QMessageBox::Warning, MSG_SDB_NOT_READY); return; } @@ -941,21 +941,19 @@ void ContextMenu::slotShell() void ContextMenu::launchControlPanel(QString& command, QStringList& arguments) { - QString httpProxyAddr; - QString httpProxyPort; - const char *http_proxy_addr = get_http_proxy_addr(); - if (http_proxy_addr) { - char **proxy = g_strsplit(http_proxy_addr, ":", 2); + const char *https_proxy_addr = get_https_proxy_addr(); + if (https_proxy_addr) { + char **proxy = g_strsplit(https_proxy_addr, ":", 2); if (proxy[0] && proxy[1]) { - httpProxyAddr = "-Dhttp.proxyHost=" + QString(proxy[0]); - httpProxyPort = "-Dhttp.proxyPort=" + QString(proxy[1]); + QString httpsProxyAddr = "-Dhttps.proxyHost=" + QString(proxy[0]); + QString httpsProxyPort = "-Dhttps.proxyPort=" + QString(proxy[1]); + if (httpsProxyAddr != NULL && httpsProxyPort != NULL) { + arguments << httpsProxyAddr << httpsProxyPort; + } } g_strfreev(proxy); } - if (httpProxyAddr != NULL && httpProxyPort != NULL) { - arguments << httpProxyAddr << httpProxyPort; - } QString loggingCommand = QString("launching ecp: \"" + command + "\""); @@ -973,7 +971,7 @@ void ContextMenu::launchControlPanel(QString& command, try { QProcess::startDetached(command, arguments, workingDir); } catch (QString &error) { - showMsgBox(QMessageBox::Warning, MSG_INVALID_ECP_OPEN + error); + parent->showMsgBox(QMessageBox::Warning, MSG_INVALID_ECP_OPEN + error); return; } #else @@ -999,7 +997,7 @@ void ContextMenu::launchControlPanel(QString& command, QString error = QString::number(GetLastError()); qWarning() << qPrintable(QString("error occured during launching \ ECP: ") + error); - showMsgBox(QMessageBox::Warning, MSG_INVALID_ECP_OPEN + error); + parent->showMsgBox(QMessageBox::Warning, MSG_INVALID_ECP_OPEN + error); } CloseHandle(pinfo.hThread); @@ -1015,18 +1013,28 @@ void ContextMenu::slotControlPanel() QStringList arguments; // check for new ECP -#ifndef CONFIG_WIN32 - QString newCommand = QDir(QCoreApplication::applicationDirPath() + +#if defined(CONFIG_WIN32) + QString ecpCommand = QDir(QCoreApplication::applicationDirPath() + + QDir::separator() + SDK_EMULATOR_TOOLS_BIN_PATH + + SDK_ECP_FILE + ".cmd").absolutePath(); +#elif defined(CONFIG_LINUX) + QString ecpCommand = QDir(QCoreApplication::applicationDirPath() + QDir::separator() + SDK_EMULATOR_TOOLS_BIN_PATH + SDK_ECP_FILE).absolutePath(); #else - QString newCommand = QDir(QCoreApplication::applicationDirPath() + + QString ecpCommand = QDir(QCoreApplication::applicationDirPath() + QDir::separator() + SDK_EMULATOR_TOOLS_BIN_PATH + - SDK_ECP_FILE + ".cmd").absolutePath(); + SDK_ECP_FILE + ".app").absolutePath(); +#endif + if (QFileInfo(ecpCommand).exists()) { +#if defined(CONFIG_DARWIN) + // In mac os x, launch .app using "open" command + // ex : open emulator-control-panel.app --args vm_name=... platform_version=... + command = "open"; + arguments << ecpCommand << "--args"; +#else + command = ecpCommand; #endif - if (QFileInfo(newCommand).exists()) { - command = newCommand; - QString vmNameOpt = "vm_name=" + parent->getUiInfo()->getVmName(); QString platformVersionOpt = "platform_version=" + QString::fromLocal8Bit(get_platform_version()); @@ -1061,7 +1069,7 @@ void ContextMenu::slotControlPanel() command = QString::fromLocal8Bit(path); } else { // can not enter here... - showMsgBox(QMessageBox::Warning, MSG_INVALID_JAVA_PATH); + parent->showMsgBox(QMessageBox::Warning, MSG_INVALID_JAVA_PATH); return; } @@ -1088,7 +1096,7 @@ void ContextMenu::slotControlPanel() } // we can not launch ControlPanel - showMsgBox(QMessageBox::Warning, MSG_ECP_NOT_EXIST); + parent->showMsgBox(QMessageBox::Warning, MSG_ECP_NOT_EXIST); return; } @@ -1204,37 +1212,10 @@ QSignalMapper *ContextMenu::getControllerMapper() return controllerMapper; } -QMessageBox *ContextMenu::showMsgBox( - QMessageBox::Icon iconType, const QString &text, - QMessageBox::StandardButtons buttons, - QMessageBox::StandardButton defaultButton) -{ - qWarning() << text; - - QMessageBox *msgBox = new QMessageBox(iconType, - EMULATOR_TITLE, text, buttons, parent); - if (defaultButton != QMessageBox::NoButton) { - msgBox->setDefaultButton(defaultButton); - } - msgBox->setAttribute(Qt::WA_DeleteOnClose); - msgBox->show(); /* non-blocking */ - -#ifdef CONFIG_LINUX - slotOnTop(parent->getUiState()->isOnTop()); -#endif - - return msgBox; -} - ContextMenu::~ContextMenu() { qDebug("destroy menu"); - if (infoDialog) { - delete infoDialog; - infoDialog = NULL; - } - delete sdbHelper; longPressTimer->stop(); diff --git a/tizen/src/ui/menu/contextmenu.h b/tizen/src/ui/menu/contextmenu.h index 88370a483d..f8518de322 100644 --- a/tizen/src/ui/menu/contextmenu.h +++ b/tizen/src/ui/menu/contextmenu.h @@ -128,10 +128,6 @@ private: const QString &text, QShortcut *shortcut, const char *slot); void attachShortcut(QAction *action, QShortcut *shortcut, const char *slot); - QMessageBox *showMsgBox(QMessageBox::Icon iconType, const QString &text, - QMessageBox::StandardButtons buttons = QMessageBox::NoButton, - QMessageBox::StandardButton defaultButton = QMessageBox::NoButton); - MainWindow *parent; QString vmName; DetailedInfoDialog *infoDialog; diff --git a/tizen/src/ui/menu/detailedinfodialog.cpp b/tizen/src/ui/menu/detailedinfodialog.cpp index 7f404902fa..cbf6640552 100644 --- a/tizen/src/ui/menu/detailedinfodialog.cpp +++ b/tizen/src/ui/menu/detailedinfodialog.cpp @@ -34,6 +34,7 @@ #include "resource/ui_strings.h" #include "mainwindow.h" #include "menu/advancedmenuitem.h" +#include "emul_state.h" extern "C" { int get_display_pixel_density(void); @@ -54,6 +55,9 @@ DetailedInfoDialog::DetailedInfoDialog(QWidget *parent) : win = ((MainWindow *)parent); keyboardShortcut = win->getKeyboardShortcut(); + // remove ? button + setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint); + setWindowTitle(DETAILED_INFO_TITLE); setMinimumWidth(DIALOG_MIN_WIDTH); setMinimumHeight(DIALOG_MIN_HEIGHT); @@ -73,8 +77,10 @@ DetailedInfoDialog::DetailedInfoDialog(QWidget *parent) : /* VM information table */ vmInfoTable = createVmInfoTable(); tabWidget->addTab(vmInfoTable, tr(DETAILED_INFO_VMTAB_TITLE)); - +// FIXME: temporarily remove shortcut dialog in DARWIN +#ifndef CONFIG_DARWIN /* shortcut information table */ + QTabWidget *shortcutTab = new QTabWidget(tabWidget); menuShortcutTable = createShortcutInfoTable(); @@ -83,6 +89,8 @@ DetailedInfoDialog::DetailedInfoDialog(QWidget *parent) : shortcutTab->addTab(keyShortcutTable, "HW Key"); tabWidget->addTab(shortcutTab, DETAILED_INFO_SHORTCUTTAB_TITLE); +#endif + } upsideLayout->addWidget(tabWidget); @@ -195,7 +203,7 @@ QTableWidget *DetailedInfoDialog::createVmInfoTable() } QString pkgVer = QString(pkginfo_version).section(':', 1).trimmed(); - insertTableRow(vmInfo, QString(DETAILED_INFO_EMUL_VER), QString(EMULATOR_BUILD_VER) + + insertTableRow(vmInfo, QString(DETAILED_INFO_EMUL_VER), QString(get_platform_version()).section('-', 1).trimmed() + " Release on " + sdkVer + " SDK (" + pkgVer + ")"); /* add double click event listener */ @@ -319,7 +327,10 @@ void DetailedInfoDialog::insertHwKeyShortcutInfo( /* override */ void DetailedInfoDialog::showEvent(QShowEvent *event) { +// FIXME: temporarily remove shortcut dialog in DARWIN +#ifndef CONFIG_DARWIN updateShortcutTableItems(); +#endif if ((windowState() & Qt::WindowMaximized) == 0) { tabWidget->setCurrentIndex(0); diff --git a/tizen/src/ui/menu/screenshotdialog.cpp b/tizen/src/ui/menu/screenshotdialog.cpp index b41798c905..42505d07ae 100644 --- a/tizen/src/ui/menu/screenshotdialog.cpp +++ b/tizen/src/ui/menu/screenshotdialog.cpp @@ -231,14 +231,12 @@ void ScreenShotDialog::updateRatio(int level) void ScreenShotDialog::updateScreenShot(QPixmap &shotData) { - /* scaling */ - QPixmap shotImage = shotData.scaled(shotData.size() * ratio, - Qt::KeepAspectRatio, Qt::FastTransformation); - - /* rotate */ - QMatrix matrix; - matrix.rotate(getDisplayAngle()); - shotImage = shotImage.transformed(matrix); + /* scaling & rotate */ + QTransform transform; + QPixmap shotImage = + shotData.transformed( + transform.scale(ratio, ratio).rotate(getDisplayAngle()), + Qt::SmoothTransformation); /* update */ scene->setSceneRect(0, 0, shotImage.width(), shotImage.height()); @@ -277,6 +275,4 @@ void ScreenShotDialog::showEvent(QShowEvent *event) ScreenShotDialog::~ScreenShotDialog() { qDebug("destroy screenshot dialog"); - - win->getPopupMenu()->screenshotDialog = NULL; } diff --git a/tizen/src/ui/menu/sdbhelper.cpp b/tizen/src/ui/menu/sdbhelper.cpp index 742966ffb2..c1da058892 100644 --- a/tizen/src/ui/menu/sdbhelper.cpp +++ b/tizen/src/ui/menu/sdbhelper.cpp @@ -30,6 +30,7 @@ #include "config-host.h" #include "mainwindow.h" +#include "displaybase.h" #include "sdbhelper.h" #include "sdbhelperthread.h" #include "resource/ui_strings.h" diff --git a/tizen/src/ui/menu/sdbhelperthread.cpp b/tizen/src/ui/menu/sdbhelperthread.cpp index 2c0389ec6f..dec4171205 100644 --- a/tizen/src/ui/menu/sdbhelperthread.cpp +++ b/tizen/src/ui/menu/sdbhelperthread.cpp @@ -28,6 +28,7 @@ */ #include "sdbhelperthread.h" +#include "mainwindow.h" #include "sdbhelper.h" #include "displaybase.h" #include "resource/ui_strings.h" @@ -82,24 +83,5 @@ void SdbHelperThread::handleErrorOccured(QString errString, int exitCode) { qDebug() << "exitcode: " << exitCode; //FIXME: (sdb) cannot returns exit code like "no space left" - showMsgBox(QMessageBox::Warning, MSG_SDB_FAILED_PROCESSING + errString); -} - -QMessageBox *SdbHelperThread::showMsgBox( - QMessageBox::Icon iconType, const QString &text, - QMessageBox::StandardButtons buttons, - QMessageBox::StandardButton defaultButton) -{ - qWarning() << text; - - QMessageBox *msgBox = new QMessageBox(iconType, - EMULATOR_TITLE, text, buttons, (QWidget *)parent->getMainWindow()); - if (defaultButton != QMessageBox::NoButton) { - msgBox->setDefaultButton(defaultButton); - } - msgBox->setAttribute(Qt::WA_DeleteOnClose); - msgBox->setModal(false); - msgBox->show(); /* non-blocking */ - - return msgBox; + ((MainWindow *)parent->getMainWindow())->showMsgBox(QMessageBox::Warning, MSG_SDB_FAILED_PROCESSING + errString); } diff --git a/tizen/src/ui/menu/sdbhelperthread.h b/tizen/src/ui/menu/sdbhelperthread.h index 5cdfcfc389..162ce1813a 100644 --- a/tizen/src/ui/menu/sdbhelperthread.h +++ b/tizen/src/ui/menu/sdbhelperthread.h @@ -53,9 +53,6 @@ private: int command; QString errorMsg; QString outMsg; - QMessageBox *showMsgBox(QMessageBox::Icon iconType, const QString &text, - QMessageBox::StandardButtons buttons = QMessageBox::NoButton, - QMessageBox::StandardButton defaultButton = QMessageBox::NoButton); signals: void errorOccured(QString errString, int exitCode); diff --git a/tizen/src/ui/movingwidget.cpp b/tizen/src/ui/movingwidget.cpp index e3daff486a..669da8fe36 100644 --- a/tizen/src/ui/movingwidget.cpp +++ b/tizen/src/ui/movingwidget.cpp @@ -43,7 +43,6 @@ MovingWidget::MovingWidget(QWidget *parent) : QWidget(parent) setAttribute(Qt::WA_NoSystemBackground); setAttribute(Qt::WA_TranslucentBackground); - setAttribute(Qt::WA_DeleteOnClose); resize(win->size()); qDebug() << "moving widget size:" << win->size(); diff --git a/tizen/src/ui/qt5.c b/tizen/src/ui/qt5.c index cb934524d5..0b19be65bd 100644 --- a/tizen/src/ui/qt5.c +++ b/tizen/src/ui/qt5.c @@ -156,7 +156,8 @@ void maru_early_qt5_display_init(bool isOnscreen) } } -static void maru_qt5_display_fini(void) +// should be called before exit main() +void maru_qt5_display_fini(void) { if (qt5_console) { g_free(qt5_console); @@ -177,6 +178,11 @@ int get_display_pixel_density(void) return pixel_density_dpi; } +void maru_qt5_set_force_legacy(bool isLegacy) +{ + qt5_set_force_legacy(isLegacy); +} + void maru_qt5_display_init(DisplayState *ds, int full_screen) { int i; @@ -207,7 +213,6 @@ void maru_qt5_display_init(DisplayState *ds, int full_screen) if (full_screen) { /* TODO */ } - atexit(maru_qt5_display_fini); /* TODO mouse_mode_notifier.notify = qt2_mouse_mode_change; diff --git a/tizen/src/ui/qt5.h b/tizen/src/ui/qt5.h index 64f2d4042a..226ea3759d 100644 --- a/tizen/src/ui/qt5.h +++ b/tizen/src/ui/qt5.h @@ -36,8 +36,11 @@ void maru_early_qt5_display_init(bool isOnscreen); void maru_qt5_display_init(DisplayState *ds, int full_screen); +void maru_qt5_display_fini(void); void set_display_pixel_density(int dpi); int get_display_pixel_density(void); +void maru_qt5_set_force_legacy(bool isLegacy); + #endif // __QT5_H__ diff --git a/tizen/src/ui/qt5_supplement.cpp b/tizen/src/ui/qt5_supplement.cpp index 639b9dac74..81202fe124 100644 --- a/tizen/src/ui/qt5_supplement.cpp +++ b/tizen/src/ui/qt5_supplement.cpp @@ -54,6 +54,7 @@ bool is_display_off(void); //using namespace std; bool qt5IsOnscreen; QApplication *qt5App = NULL; +bool isForceLegacy; static int argc = 0; static char *argv[0]; @@ -181,6 +182,7 @@ static void qMessageOutput(QtMsgType type, const QMessageLogContext &context, case QtCriticalMsg: case QtFatalMsg: typeChar = 'S'; + break; default: qFatal("invalid message type"); break; @@ -442,23 +444,17 @@ void qt5_destroy() uiInfo = NULL; } +void qt5_set_force_legacy(bool isLegacy) +{ + isForceLegacy = isLegacy; +} + void qt5_early_prepare(bool isOnscreen) { qt5IsOnscreen = isOnscreen; Q_INIT_RESOURCE(resource); -#ifdef CONFIG_LINUX - /* QGLWidget threading: Note that under X11 it is necessary to set the - * Qt::AA_X11InitThreads application attribute to make the X11 library - * and GLX calls thread safe, otherwise the above scenarios will fail. */ - - /* Calls XInitThreads() as part of the QApplication construction in order - * to make Xlib calls thread-safe. This attribute must be set before - * QApplication is constructed. */ - QCoreApplication::setAttribute(Qt::AA_X11InitThreads); -#endif - qt5App = new QApplication(argc, argv); /* add the path in the application's main() function, right after the @@ -482,11 +478,11 @@ void qt5_prepare(void) void qt5_update_internal(void *data, int width, int height) { - QImage image((uchar *)data, width, height, QImage::Format_RGB32); + QImage image((uchar *)data, width, height, QImage::Format_ARGB32); - mainwindow->getScreenWidget()->setPixmap( - QPixmap::fromImage(image.transformed( - mainwindow->getDisplayMatrix(), Qt::SmoothTransformation))); + mainwindow->getScreenWidget()->setPixmap(QPixmap::fromImage( + image.convertToFormat(QImage::Format_RGB32).transformed( + mainwindow->getDisplayTransform(), Qt::SmoothTransformation))); } void qt5_switch_internal(void) diff --git a/tizen/src/ui/qt5_supplement.h b/tizen/src/ui/qt5_supplement.h index 836af47ce9..dbdcd06be2 100644 --- a/tizen/src/ui/qt5_supplement.h +++ b/tizen/src/ui/qt5_supplement.h @@ -46,6 +46,8 @@ void qt5_switch_internal(void); void qt5_refresh_internal(void); const char* qt5_get_version(void); + +void qt5_set_force_legacy(bool isLegacy); #ifdef __cplusplus } #endif diff --git a/tizen/src/ui/resource/ui_strings.h b/tizen/src/ui/resource/ui_strings.h index 65566ffcf8..3a5c3afa5c 100644 --- a/tizen/src/ui/resource/ui_strings.h +++ b/tizen/src/ui/resource/ui_strings.h @@ -33,7 +33,6 @@ #define UI_STRINGS_H #define EMULATOR_TITLE "Tizen Emulator" -#define EMULATOR_BUILD_VER "3.0" #define SDK_OFFICIAL_NAME "Tizen SDK" #define SDK_OFFICIAL_URL "https://developer.tizen.org" diff --git a/tizen/src/ui/rotaryview.cpp b/tizen/src/ui/rotaryview.cpp index 3297f3fc34..fdb6816d7f 100644 --- a/tizen/src/ui/rotaryview.cpp +++ b/tizen/src/ui/rotaryview.cpp @@ -193,6 +193,4 @@ RotaryView::~RotaryView() qDebug("destroy rotary view"); timer->stop(); - - scene()->clear(); } diff --git a/tizen/src/ui/skinpainter.cpp b/tizen/src/ui/skinpainter.cpp index 0dac529d34..2c2bb3d3dc 100644 --- a/tizen/src/ui/skinpainter.cpp +++ b/tizen/src/ui/skinpainter.cpp @@ -88,12 +88,11 @@ void SkinPainter::drawSkin(QString patchPath, QSize center, int degree, painter.drawEllipse(tagLeftTop, COLOR_TAG_SIZE, COLOR_TAG_SIZE); /* rotate */ - QMatrix matrix; - matrix.rotate(degree); - skin = new QPixmap(image.transformed(matrix)); + QTransform transform; + skin = new QPixmap(image.transformed(transform.rotate(degree))); centeralRect = QRect( - centeralRect0.topLeft(), matrix.mapRect(centeralRect0).size()); + centeralRect0.topLeft(), transform.mapRect(centeralRect0).size()); } QImage SkinPainter::getSkinImage() const diff --git a/tizen/src/util/Makefile.objs b/tizen/src/util/Makefile.objs index a4a2969fcc..a322caf7d7 100644 --- a/tizen/src/util/Makefile.objs +++ b/tizen/src/util/Makefile.objs @@ -30,6 +30,9 @@ obj-y += qt5_error_report.o # error handler obj-y += error_handler.o +ifdef CONFIG_WIN32 +LIBS += -ldbghelp +endif # debug channel obj-y += new_debug_ch.o diff --git a/tizen/src/util/error_handler.c b/tizen/src/util/error_handler.c index 1f91e8df85..959594e83c 100644 --- a/tizen/src/util/error_handler.c +++ b/tizen/src/util/error_handler.c @@ -4,6 +4,7 @@ * Copyright (C) 2015 Samsung Electronics Co., Ltd. All rights reserved. * * Contact: + * Jinhyung Jo <jinhyung.jo@samsung.com> * SeokYeon Hwang <syeon.hwang@samsung.com> * GiWoong Kim <giwoong.kim@samsung.com> * @@ -37,6 +38,7 @@ #ifdef CONFIG_WIN32 #include <windows.h> +#include <dbghelp.h> #else #include <execinfo.h> #endif @@ -47,244 +49,229 @@ #include "emulator_common.h" #include "emulator.h" -#include "debug_ch.h" - -MULTI_DEBUG_CHANNEL(qemu, backtrace); - #ifdef CONFIG_QT #include "qt5_error_report.h" #endif -#if defined(CONFIG_WIN32) -static LPTOP_LEVEL_EXCEPTION_FILTER prevExceptionFilter; -#elif defined(CONFIG_LINUX) -static pthread_spinlock_t siglock; -#endif +#include "new_debug_ch.h" -bool print_backtrace_at_normal_exit_enabled = false; +DECLARE_DEBUG_CHANNEL(backtrace); -/* Print 'backtrace' */ -#ifdef _WIN32 -struct frame_layout { - void *pNext; - void *pReturnAddr; -}; +bool print_backtrace_at_normal_exit_enabled; -static char *get_filename_from_path(char *path_buf) +void enable_print_backtrace_at_normal_exit(void) { - char *ret_slash; - char *ret_rslash; - - ret_slash = strrchr(path_buf, '/'); - ret_rslash = strrchr(path_buf, '\\'); - - if (ret_slash || ret_rslash) { - if (ret_slash > ret_rslash) { - return ret_slash + 1; - } else{ - return ret_rslash + 1; - } - } - - return path_buf; + print_backtrace_at_normal_exit_enabled = true; } +#ifdef CONFIG_WIN32 +static LPTOP_LEVEL_EXCEPTION_FILTER prevExceptionFilter; -static HMODULE get_module_handle(void *dwAddress) -{ - MEMORY_BASIC_INFORMATION Buffer; - return VirtualQuery((LPCVOID) dwAddress, &Buffer, sizeof(Buffer)) - ? (HMODULE) Buffer.AllocationBase : (HMODULE) 0; -} -#endif - -static void dump_backtrace(void *ptr, int depth) +/* The MSDN says as followed in "Updated Platform Support" page, + (https://msdn.microsoft.com/en-us/library/windows/desktop/ + ms681408(v=vs.85).aspx) + "Where necessary, the DbgHelp library has been widened to support both 32- + and 64-bit Windows. The original function and structure definitions are + still in DbgHelp.h, but there are also updated versions of these + definitions that are compatible with 64-bit Windows. If you use the updated + functions in your code, it can be compiled for both 32- and 64-bit Windows. + Your code will also be more efficient, since the original functions simply + call the updated functions to perform the work." + However, using the updated functinos does not work on the Windows 32-bit. + IMHO, in the MinGW cross compile environment rather than the Visual Studio + it does not compile correctly. + Thus, use explicitly. +*/ +static void dump_backtrace(void *ptr) { -#ifdef _WIN32 - int nCount; - void *pTopFrame; - struct frame_layout currentFrame; - struct frame_layout *pCurrentFrame; - - char module_buf[1024]; - HMODULE hModule; - - PCONTEXT pContext = ptr; - if (!pContext) { - __asm__ __volatile__ ("movl %%ebp, %0" : "=m" (pTopFrame)); - } else { #ifdef _WIN64 - pTopFrame = (void *)((PCONTEXT)pContext)->Rbp; + STACKFRAME64 frame; #else - pTopFrame = (void *)((PCONTEXT)pContext)->Ebp; + STACKFRAME frame; #endif + int i; + DWORD image; + CONTEXT context; + HANDLE hProcess = GetCurrentProcess(); + HANDLE hThread = GetCurrentThread(); + + if (!ptr) { + ZeroMemory(&context, sizeof(CONTEXT)); + context.ContextFlags = CONTEXT_FULL; + RtlCaptureContext(&context); + } else { + CopyMemory(&context, ptr, sizeof(CONTEXT)); } - if (pTopFrame == NULL) { - INFO("ebp is null, skip this for now\n"); - return ; - } - - nCount = 0; - currentFrame.pNext = ((struct frame_layout *)pTopFrame)->pNext; - currentFrame.pReturnAddr = ((struct frame_layout *)pTopFrame)->pReturnAddr; - pCurrentFrame = (struct frame_layout *)pTopFrame; + SymInitialize(hProcess, NULL, TRUE); - ERR("\nBacktrace Dump Start :\n"); - if (pContext) { - memset(module_buf, 0, sizeof(module_buf)); #ifdef _WIN64 - hModule = get_module_handle((void *)((PCONTEXT)pContext)->Rip); + ZeroMemory(&frame, sizeof(STACKFRAME64)); + image = IMAGE_FILE_MACHINE_AMD64; + frame.AddrPC.Offset = context.Rip; + frame.AddrPC.Mode = AddrModeFlat; + frame.AddrFrame.Offset = context.Rbp; + frame.AddrFrame.Mode = AddrModeFlat; + frame.AddrStack.Offset = context.Rsp; + frame.AddrStack.Mode = AddrModeFlat; #else - hModule = get_module_handle((void *)((PCONTEXT)pContext)->Eip); + ZeroMemory(&frame, sizeof(STACKFRAME)); + image = IMAGE_FILE_MACHINE_I386; + frame.AddrPC.Offset = context.Eip; + frame.AddrPC.Mode = AddrModeFlat; + frame.AddrFrame.Offset = context.Ebp; + frame.AddrFrame.Mode = AddrModeFlat; + frame.AddrStack.Offset = context.Esp; + frame.AddrStack.Mode = AddrModeFlat; #endif - if (hModule) { - if (!GetModuleFileNameA(hModule, module_buf, sizeof(module_buf))) { - memset(module_buf, 0, sizeof(module_buf)); - } - } + + i = 0; + while (1) { #ifdef _WIN64 - ERR("[%02d]Addr = 0x%p : %s\n", nCount, ((PCONTEXT)pContext)->Rip, get_filename_from_path(module_buf)); + BOOL result = StackWalk64(image, hProcess, hThread, + &frame, &context, NULL, + SymFunctionTableAccess64, + SymGetModuleBase64, NULL); #else - ERR("[%02d]Addr = 0x%p : %s\n", nCount, ((PCONTEXT)pContext)->Eip, get_filename_from_path(module_buf)); + BOOL result = StackWalk(image, hProcess, hThread, + &frame, &context, NULL, + SymFunctionTableAccess, + SymGetModuleBase, NULL); #endif - nCount++; - } - - while (1) { - if (((void *)pCurrentFrame < pTopFrame) - || ((void *)pCurrentFrame >= (void *)0xC0000000)) { + if (!result) { break; } - - memset(module_buf, 0, sizeof(module_buf)); - hModule = get_module_handle(currentFrame.pReturnAddr); - if (hModule) { - if (!GetModuleFileNameA(hModule, module_buf, sizeof(module_buf))) { - memset(module_buf, 0, sizeof(module_buf)); - } - } - ERR("[%02d]Addr = 0x%p : %s\n", nCount, currentFrame.pReturnAddr, get_filename_from_path(module_buf)); - - if (!ReadProcessMemory(GetCurrentProcess(), currentFrame.pNext, - (void *)¤tFrame, sizeof(struct frame_layout), NULL)) { - break; - } - pCurrentFrame = (struct frame_layout *)pCurrentFrame->pNext; - - if (depth) { - if (!--depth) { - break; + TCHAR buffer[sizeof(SYMBOL_INFO) + (MAX_SYM_NAME - 1) * sizeof(TCHAR)]; + PSYMBOL_INFO pSymbol = (PSYMBOL_INFO)buffer; + pSymbol->SizeOfStruct = sizeof(SYMBOL_INFO); + pSymbol->MaxNameLen = MAX_SYM_NAME; + DWORD64 displacement = 0; + TCHAR pFileName[MAX_PATH] = {0, }; +#ifdef _WIN64 + DWORD64 dwBase = SymGetModuleBase64(hProcess, frame.AddrPC.Offset); +#else + DWORD dwBase = SymGetModuleBase(hProcess, frame.AddrPC.Offset); +#endif + if (dwBase) { + HMODULE hModule = (HMODULE)((DWORD_PTR)dwBase); + if (!GetModuleFileNameA(hModule, pFileName, MAX_PATH)) { + snprintf(pFileName, MAX_PATH, "Unknown Module"); } } - nCount++; - } + /* TODO: take the symbols for the static functions + without import .pdb */ + if (SymFromAddr(hProcess, + frame.AddrPC.Offset, + &displacement, pSymbol)) { +#ifdef _WIN64 + LOG_INFO("#%04d 0x%016I64x in %s from %s\n", #else - void *trace[1024]; - int ndepth = backtrace(trace, 1024); - ERR("Backtrace depth is %d.\n", ndepth); - - backtrace_symbols_fd(trace, ndepth, fileno(stderr)); + LOG_INFO("#%04d 0x%08x in %s from %s\n", +#endif + i, frame.AddrPC.Offset, pSymbol->Name, pFileName); + } else { +#ifdef _WIN64 + LOG_INFO("#%04d 0x%016I64x in ???????? from %s\n", +#else + LOG_INFO("#%04d 0x%08x in ???????? from %s\n", #endif + i, frame.AddrPC.Offset, pFileName); + } + i++; + } + SymCleanup(hProcess); } -static void handle_error_at_exit(void) +static WINAPI LONG +maru_unhandled_exception_filter(LPEXCEPTION_POINTERS pException) { - if (print_backtrace_at_normal_exit_enabled) { - INFO("Stack backtrace for tracing...\n"); - INFO("This is not an error.\n"); - dump_backtrace(NULL, 0); - } -} +#ifdef _WIN64 + LOG_SEVERE("Exception occurred: Code[0x%x], Address[0x%016I64x]\n", +#else + LOG_SEVERE("Exception occurred: Code[0x%x], Address[0x%08x]\n", +#endif + pException->ExceptionRecord->ExceptionCode, + pException->ExceptionRecord->ExceptionAddress); -void enable_print_backtrace_at_normal_exit(void) { - print_backtrace_at_normal_exit_enabled = true; -} + dump_backtrace(pException->ContextRecord); -#ifdef CONFIG_WIN32 -static WINAPI LONG maru_unhandled_exception_filter(LPEXCEPTION_POINTERS pExceptionInfo){ - char module_buf[1024]; + return EXCEPTION_CONTINUE_SEARCH; +} - // print system information again - print_system_info(); +static void register_exception_handler(void) +{ + prevExceptionFilter = + SetUnhandledExceptionFilter(maru_unhandled_exception_filter); +} - DWORD dwException = pExceptionInfo->ExceptionRecord->ExceptionCode; - ERR("%d\n ", (int)dwException); +#else /* END FOR WINDOWS, START FOR LINUX & DARWIN */ - PEXCEPTION_RECORD pExceptionRecord; - HMODULE hModule; - PCONTEXT pContext; +/* prevent an interrupt by another signal */ +QemuMutex siglock; +/* uses in case SIGSEGV */ +struct sigaction old_sa; - pExceptionRecord = pExceptionInfo->ExceptionRecord; +/* Print 'backtrace' */ +static void dump_backtrace(void *ptr) +{ + int i; + void *trace[1024]; + int ndepth = backtrace(trace, 1024); + char **syms = backtrace_symbols(trace, ndepth); - memset(module_buf, 0, sizeof(module_buf)); - hModule = get_module_handle(pExceptionRecord->ExceptionAddress); - if(hModule){ - if(!GetModuleFileNameA(hModule, module_buf, sizeof(module_buf))){ - memset(module_buf, 0, sizeof(module_buf)); - } + LOG_INFO("Backtrace depth is %d\n", ndepth); + for (i = 0; i < ndepth; i++) { + LOG_INFO("#%04d %s\n", i, syms[i]); } - - ERR("Exception [%X] occured at %s:0x%08x\n", - pExceptionRecord->ExceptionCode, - get_filename_from_path(module_buf), - pExceptionRecord->ExceptionAddress - ); - - pContext = pExceptionInfo->ContextRecord; - dump_backtrace(pContext, 0); - _exit(0); - //return EXCEPTION_CONTINUE_SEARCH; + free(syms); } -#endif -#ifdef CONFIG_LINUX static void maru_sighandler(int sig) { - ERR("Got signal %d\n", sig); - // print system information again - print_system_info(); - - pthread_spin_lock(&siglock); - dump_backtrace(NULL, 0); - pthread_spin_unlock(&siglock); - _exit(0); + LOG_SEVERE("Got signal: %d(%s)\n", sig, strsignal(sig)); + + qemu_mutex_lock(&siglock); + dump_backtrace(NULL); + qemu_mutex_unlock(&siglock); + qemu_mutex_destroy(&siglock); + if (sig == SIGSEGV) { + sigaction(SIGSEGV, &old_sa, NULL); + raise(SIGSEGV); + } } -#endif - -#ifndef CONFIG_DARWIN static void register_exception_handler(void) { - #ifdef CONFIG_WIN32 - prevExceptionFilter = SetUnhandledExceptionFilter(maru_unhandled_exception_filter); - #else // LINUX void *trace[1]; struct sigaction sa; - // make dummy call to explicitly load glibc library + /* make dummy call to explicitly load glibc library */ backtrace(trace, 1); - pthread_spin_init(&siglock,0); - sa.sa_handler = (void*) maru_sighandler; + qemu_mutex_init(&siglock); + sa.sa_handler = maru_sighandler; sigemptyset(&sa.sa_mask); sa.sa_flags = SA_RESTART; - sigaction(SIGSEGV, &sa, NULL); + /* store previous signal action */ + sigaction(SIGSEGV, &sa, &old_sa); sigaction(SIGBUS, &sa, NULL); sigaction(SIGILL, &sa, NULL); sigaction(SIGFPE, &sa, NULL); sigaction(SIGABRT, &sa, NULL); - // main thread only + /* main thread only */ sigaction(SIGTERM, &sa, NULL); sigaction(SIGINT, &sa, NULL); - #endif } -#else // CONFIG_DARWIN -static void register_exception_handler(void) +#endif /* END FOR LINUX & DARWIN */ + +static void handle_error_at_exit(void) { - // TODO: Exception handling on darwin + if (print_backtrace_at_normal_exit_enabled) { + LOG_INFO("Stack backtrace for tracing...\n"); + LOG_INFO("This is not an error\n"); + dump_backtrace(NULL); + } } -#endif #define MAX_MESSAGE_LEN 2048 static size_t message_len; @@ -296,9 +283,9 @@ static void report(const char *fmt, va_list ap) message_len = g_strlcat(message, new_message, MAX_MESSAGE_LEN); g_free(new_message); - // We are wating for '\n' + /* We are waiting for '\n' */ if (message[message_len - 1] == '\n') { -#if defined(CONFIG_QT) +#ifdef CONFIG_QT start_qt5_msgbox(CRITICAL_ICON, message); #endif @@ -307,10 +294,12 @@ static void report(const char *fmt, va_list ap) } } -static ErrorReporter error_reporter = - { .report = report }; +static ErrorReporter error_reporter = { + .report = report +}; -void init_error_handler(void) { +void init_error_handler(void) +{ register_exception_handler(); add_error_reporter(&error_reporter); diff --git a/tizen/src/util/osutil-darwin.c b/tizen/src/util/osutil-darwin.c index b27ed7ca24..c797ca8df0 100644 --- a/tizen/src/util/osutil-darwin.c +++ b/tizen/src/util/osutil-darwin.c @@ -47,8 +47,8 @@ #include "new_debug_ch.h" DECLARE_DEBUG_CHANNEL(osutil); -void make_vm_lock_os(void) { - make_vm_lock_posix(); +void make_vm_lock_os(gchar *vms_path) { + make_vm_lock_posix(vms_path); } void set_bin_path_os(char const *const exec_argv) diff --git a/tizen/src/util/osutil-linux.c b/tizen/src/util/osutil-linux.c index 8e432f990b..c46e46123f 100644 --- a/tizen/src/util/osutil-linux.c +++ b/tizen/src/util/osutil-linux.c @@ -50,8 +50,8 @@ #include "new_debug_ch.h" DECLARE_DEBUG_CHANNEL(osutil); -void make_vm_lock_os(void) { - make_vm_lock_posix(); +void make_vm_lock_os(gchar *vms_path) { + make_vm_lock_posix(vms_path); } void set_bin_path_os(char const *const exec_argv) diff --git a/tizen/src/util/osutil-win32.c b/tizen/src/util/osutil-win32.c index a76edfc2e6..48220da10c 100644 --- a/tizen/src/util/osutil-win32.c +++ b/tizen/src/util/osutil-win32.c @@ -83,29 +83,36 @@ image file and kernel log file are aleady opened with exclusive write lock by pre-executed emulator. But it is still useful for emulator-manager. */ -void make_vm_lock_os(void) +void make_vm_lock_os(gchar *vms_path) { + g_assert(lock_file == INVALID_HANDLE_VALUE); g_assert(lock_filename == NULL); - lock_filename = g_strdup_printf("%s.lock", get_drive_image_file()); + lock_filename = g_strdup_printf("%s\\%s", vms_path, VMLOCK_FILE); if (g_mkdir_with_parents(g_path_get_dirname(lock_filename), 0777)) { LOG_WARNING("Can not create directory for lock file: %ld\n", GetLastError()); + // do not create the lock file. + g_free(lock_filename); + lock_filename = NULL; + return; } lock_file = CreateFile(lock_filename, - GENERIC_READ | GENERIC_WRITE, - 0, // No share - NULL, - CREATE_ALWAYS, - FILE_ATTRIBUTE_NORMAL | FILE_FLAG_DELETE_ON_CLOSE, - NULL); + GENERIC_READ | GENERIC_WRITE, + 0, // No share + NULL, + CREATE_ALWAYS, + FILE_ATTRIBUTE_NORMAL | FILE_FLAG_DELETE_ON_CLOSE, + NULL); if (lock_file == INVALID_HANDLE_VALUE) { DWORD error = GetLastError(); // On Windows, the file opened by CreateFile has exclusive lock // naturally unless FILE_SHARE_* attribute is set. if (error == ERROR_SHARING_VIOLATION) { + g_free(lock_filename); + lock_filename = NULL; error_report("Can not execute this VM. " "The same VM may be running now."); exit(1); @@ -201,12 +208,12 @@ bool make_sdcard_lock_os(char *sdcard) fname = g_strdup_printf("%s.lck", sdcard); h = CreateFile(fname, - GENERIC_READ, - 0, // No share - NULL, - CREATE_ALWAYS, - FILE_ATTRIBUTE_NORMAL | FILE_FLAG_DELETE_ON_CLOSE, - NULL); + GENERIC_READ, + 0, // No share + NULL, + CREATE_ALWAYS, + FILE_ATTRIBUTE_NORMAL | FILE_FLAG_DELETE_ON_CLOSE, + NULL); if (h == INVALID_HANDLE_VALUE) { LOG_WARNING("Failed to CreateFile a sdcard lock file: %d\n", @@ -277,11 +284,11 @@ void get_java_path_win32(const char **java_path) /* Opens above key to query the current version */ res = RegOpenKeyEx(HKEY_LOCAL_MACHINE, - strKey, - 0, - KEY_QUERY_VALUE | - MY_KEY_WOW64_64KEY, - &hKey); + strKey, + 0, + KEY_QUERY_VALUE | + MY_KEY_WOW64_64KEY, + &hKey); if (res != ERROR_SUCCESS) { LOG_WARNING("Java Runtime Environment key not found\n"); goto javahome_not_found; @@ -289,11 +296,11 @@ void get_java_path_win32(const char **java_path) /* Queries for the current version */ res = RegQueryValueEx(hKey, - "CurrentVersion", - NULL, - NULL, - (LPBYTE)strVersion, - &dwBufLen); + "CurrentVersion", + NULL, + NULL, + (LPBYTE)strVersion, + &dwBufLen); RegCloseKey(hKey); if (res != ERROR_SUCCESS) { LOG_WARNING("JRE CurrentVersion not found\n"); @@ -306,11 +313,11 @@ void get_java_path_win32(const char **java_path) /* Opens above key to query the JavaHome */ res = RegOpenKeyEx(HKEY_LOCAL_MACHINE, - strKey, - 0, - KEY_QUERY_VALUE | - MY_KEY_WOW64_64KEY, - &hKey); + strKey, + 0, + KEY_QUERY_VALUE | + MY_KEY_WOW64_64KEY, + &hKey); if (res == ERROR_SUCCESS) { /* Queries for the JavaHome */ dwBufLen = PATH_MAX; @@ -336,3 +343,117 @@ javahome_not_found: *java_path = current_java_path; } + +bool check_integrity_level_and_respawn(void) +{ + BOOL bResult = false; + HANDLE hToken = NULL; + HANDLE hNewToken = NULL; + PSID pIntegritySid = NULL; + TOKEN_MANDATORY_LABEL TIL = { { 0, }, }; + PTOKEN_MANDATORY_LABEL pTIL = NULL; + PROCESS_INFORMATION ProcInfo = { 0, }; + STARTUPINFO StartupInfo = { 0, }; + SID_IDENTIFIER_AUTHORITY + MLAuthority = { SECURITY_MANDATORY_LABEL_AUTHORITY }; + DWORD dwIntegrityLevel, dwSize = 0; + + if(!OpenProcessToken(GetCurrentProcess(), + TOKEN_DUPLICATE | TOKEN_ADJUST_DEFAULT | TOKEN_QUERY | + TOKEN_ASSIGN_PRIMARY, &hToken)) { + LOG_WARNING("OpenProcessToken Error %lu\n", GetLastError()); + goto CleanExit; + } + + if (!GetTokenInformation(hToken, TokenGroups, NULL, 0, &dwSize)) { + DWORD dwResult = GetLastError(); + if (dwResult != ERROR_INSUFFICIENT_BUFFER) { + LOG_WARNING("GetTokenInformation Error %lu\n", dwResult); + goto CleanExit; + } + } + + pTIL = (PTOKEN_MANDATORY_LABEL)LocalAlloc(0, dwSize); + if (!pTIL) { + LOG_WARNING("LocalAlloc Error %lu\n", GetLastError()); + goto CleanExit; + } + + if (!GetTokenInformation(hToken, TokenIntegrityLevel, pTIL, + dwSize, &dwSize)) { + LOG_WARNING("GetTokenInformation Error %lu\n", GetLastError()); + goto CleanExit; + } + + dwIntegrityLevel = *GetSidSubAuthority(pTIL->Label.Sid, + (DWORD)(UCHAR)(*GetSidSubAuthorityCount(pTIL->Label.Sid) - 1)); + + if (dwIntegrityLevel >= SECURITY_MANDATORY_MEDIUM_RID && + dwIntegrityLevel < SECURITY_MANDATORY_HIGH_RID) { + // We have medium integrity level. So keep going on. + goto CleanExit; + } + + LOG_INFO("Running with elevated integrity level. Try to respawn.\n"); + + if (!DuplicateTokenEx(hToken, 0, NULL, SecurityImpersonation, + TokenPrimary, &hNewToken)) { + LOG_WARNING("DuplicateTokenEx Error %lu\n", GetLastError()); + goto CleanExit; + } + + if (!AllocateAndInitializeSid(&MLAuthority, 1, SECURITY_MANDATORY_MEDIUM_RID, + 0, 0, 0, 0, 0, 0, 0, &pIntegritySid)) { + LOG_WARNING("AllocateAndInitializeSid Error %lu\n", GetLastError()); + goto CleanExit; + } + + TIL.Label.Attributes = SE_GROUP_INTEGRITY; + TIL.Label.Sid = pIntegritySid; + + if (!SetTokenInformation(hNewToken, + TokenIntegrityLevel, + &TIL, + sizeof(TOKEN_MANDATORY_LABEL) + GetLengthSid(pIntegritySid))) { + LOG_WARNING("SetTokenInformation Error %lu\n", GetLastError()); + goto CleanExit; + } + + if (!CreateProcessAsUser(hNewToken, 0, GetCommandLine(), + NULL, NULL, FALSE, 0, NULL, NULL, &StartupInfo, &ProcInfo)) { + LOG_WARNING( "CreateProcessAsUser Error %lu\n", GetLastError()); + goto CleanExit; + } + + LOG_INFO("Respawning success. Waiting for child process.\n"); + bResult = true; + WaitForSingleObject(ProcInfo.hProcess, INFINITE); + +CleanExit: + if (ProcInfo.hProcess != NULL) { + CloseHandle(ProcInfo.hProcess); + } + + if (ProcInfo.hThread != NULL) { + CloseHandle(ProcInfo.hThread); + } + + if (pIntegritySid != NULL) { + LocalFree(pIntegritySid); + } + + if (hNewToken != NULL) { + CloseHandle(hNewToken); + } + + if (hToken != NULL) { + CloseHandle(hToken); + } + + if (pTIL != NULL) { + LocalFree(pTIL); + } + + return bResult; +} + diff --git a/tizen/src/util/osutil.c b/tizen/src/util/osutil.c index 099e1780b7..540579381b 100644 --- a/tizen/src/util/osutil.c +++ b/tizen/src/util/osutil.c @@ -46,6 +46,7 @@ DECLARE_DEBUG_CHANNEL(osutil) static int lock_file = -1; +static gchar *lock_filename = NULL; static struct flock _lock = { .l_type = F_WRLCK, .l_start = 0, @@ -101,6 +102,7 @@ static bool fd_checklock(int fd) static void remove_vm_lock_posix(void) { + int error = 0; if (lock_file == -1) { return; } @@ -110,6 +112,16 @@ static void remove_vm_lock_posix(void) } close(lock_file); + if (lock_filename != NULL) { + if (unlink(lock_filename) == -1) { + error = errno; + LOG_WARNING("Failed to unlink lock file(%d): %s\n", + error, strerror(error)); + } + g_free(lock_filename); + lock_filename = NULL; + } + lock_file = -1; } @@ -120,20 +132,22 @@ static void notify_remove_lock(Notifier *notifier, void *data) static Notifier remove_lock = { .notify = notify_remove_lock }; -void make_vm_lock_posix(void) +void make_vm_lock_posix(gchar *vms_path) { - const char *image_file = get_drive_image_file(); int error = 0; + lock_filename = g_strdup_printf("%s/%s", vms_path, VMLOCK_FILE); - g_assert(lock_file == -1); - g_assert(image_file != NULL); + g_assert(lock_filename != NULL); retry: - lock_file = open(image_file, O_RDWR); + lock_file = open(lock_filename, O_RDWR|O_CREAT, 0666); if (lock_file == -1) { error = errno; - LOG_WARNING("Failed to open image file for lock: %s\n", - strerror(error)); + LOG_WARNING("Failed to open file for lock(%d): %s\n", + error, strerror(error)); + // do not create the lock file. + g_free(lock_filename); + lock_filename = NULL; return; } @@ -152,10 +166,7 @@ retry: exit(1); } - LOG_WARNING("Failed to lock image file: %s\n", strerror(error)); - close(lock_file); - lock_file = -1; - return; + LOG_WARNING("Failed to lock file: %s\n", strerror(error)); } emulator_add_exit_notifier(&remove_lock); diff --git a/tizen/src/util/osutil.h b/tizen/src/util/osutil.h index 8e9d2ac519..d478155f28 100644 --- a/tizen/src/util/osutil.h +++ b/tizen/src/util/osutil.h @@ -42,20 +42,22 @@ #define ERR_NODEV 4 /* ACT_SDCARD_DETACH_FAIL. No sdcard attached. */ #define ERR_BUSY 5 /* ACT_SDCARD_ATTACH_FAIL. Already sdcard attached. */ #define ERR_NOENT 6 /* ACT_SDCARD_NO_ATTACH_FOUND. Other sdcard attached. */ +#define VMLOCK_FILE "vm.lock" extern const char *pac_tempfile; -void make_vm_lock_os(void); +void make_vm_lock_os(gchar *vms_path); bool make_sdcard_lock_os(char *sdcard); int remove_sdcard_lock_os(char *sdcard); #ifndef CONFIG_WIN32 -void make_vm_lock_posix(void); +void make_vm_lock_posix(gchar *dirname); bool make_sdcard_lock_posix(char *sdcard); int remove_sdcard_lock_posix(char *sdcard); #else void get_java_path_win32(const char **java_path); +bool check_integrity_level_and_respawn(void); #endif void set_bin_path_os(char const *const); diff --git a/version.rc b/version.rc index c7922d5200..86455bb873 100644 --- a/version.rc +++ b/version.rc @@ -14,7 +14,11 @@ FILESUBTYPE VFT2_UNKNOWN BLOCK "040904E4" { VALUE "CompanyName", "http://www.qemu-project.org" +#ifdef CONFIG_MARU + VALUE "FileDescription", "Tizen Emulator" +#else VALUE "FileDescription", "QEMU machine emulators and tools" +#endif VALUE "FileVersion", QEMU_VERSION VALUE "LegalCopyright", "Copyright various authors. Released under the GNU General Public License." VALUE "LegalTrademarks", "QEMU is a trademark of Fabrice Bellard." @@ -2261,6 +2261,9 @@ static DisplayType select_display(const char *p) } set_display_pixel_density(dpi); nextopt = endptr; + } else if (strstart(opts, ",forcelegacy", &nextopt)) { + opts = nextopt; + //maru_qt5_set_force_legacy(true); } else { invalid_maru_qt_args: error_report(FAILED_TO_DISPLAY_PARSING); @@ -4847,5 +4850,16 @@ int main(int argc, char **argv, char **envp) monitor_cleanup(); qemu_chr_cleanup(); +#if defined(CONFIG_MARU) && defined(CONFIG_QT) + switch (display_type) { + case DT_MARU_QT_ONSCREEN: + case DT_MARU_QT_OFFSCREEN: + maru_qt5_display_fini(); + break; + default: + break; + } +#endif + return 0; } |