From: Evgeny Voevodin Date: Mon, 8 Oct 2012 08:59:35 +0000 (+0400) Subject: Merge tag 'v1.2.0' into tizen-arm X-Git-Tag: TizenStudio_2.0_p2.3~1273^2~17 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=3fc10bcdbefd17250a7d626567870d3bc83c6dbb;p=sdk%2Femulator%2Fqemu.git Merge tag 'v1.2.0' into tizen-arm Tag for 1.2.0 --- 3fc10bcdbefd17250a7d626567870d3bc83c6dbb diff --cc Makefile.target index 03d1bfe,7892a8d..b4b0acd mode 100755,100644..100755 --- a/Makefile.target +++ b/Makefile.target @@@ -202,356 -138,39 +138,177 @@@ QEMU_CFLAGS += $(VNC_JPEG_CFLAGS QEMU_CFLAGS += $(VNC_PNG_CFLAGS) # xen support - obj-$(CONFIG_XEN) += xen-all.o xen_machine_pv.o xen_domainbuild.o xen-mapcache.o + obj-$(CONFIG_XEN) += xen-all.o xen-mapcache.o obj-$(CONFIG_NO_XEN) += xen-stub.o - obj-i386-$(CONFIG_XEN) += xen_platform.o xen_apic.o - +# HAX support +obj-$(CONFIG_HAX) += hax-all.o hax-windows.o +obj-$(CONFIG_NO_HAX) += hax-stub.o +ifdef CONFIG_DARWIN +obj-$(CONFIG_HAX) += \ + hax-all.o \ + hax-darwin.o +endif + - # Inter-VM PCI shared memory - CONFIG_IVSHMEM = - ifeq ($(CONFIG_KVM), y) - ifeq ($(CONFIG_PCI), y) - CONFIG_IVSHMEM = y - endif - endif - obj-$(CONFIG_IVSHMEM) += ivshmem.o - - # Generic hotplugging - obj-y += device-hotplug.o - # Hardware support - obj-i386-y += mc146818rtc.o pc.o - obj-i386-y += apic_common.o apic.o kvmvapic.o - obj-i386-y += sga.o ioapic_common.o ioapic.o piix_pci.o - obj-i386-y += vmport.o - obj-i386-y += pci-hotplug.o smbios.o wdt_ib700.o - obj-i386-y += debugcon.o multiboot.o - obj-i386-y += pc_piix.o - obj-i386-y += pc_sysfw.o - obj-i386-$(CONFIG_KVM) += kvm/clock.o kvm/apic.o kvm/i8259.o kvm/ioapic.o kvm/i8254.o - obj-i386-$(CONFIG_SPICE) += qxl.o qxl-logger.o qxl-render.o - - # shared objects - obj-ppc-y = ppc.o ppc_booke.o - # PREP target - obj-ppc-y += mc146818rtc.o - obj-ppc-y += ppc_prep.o - # OldWorld PowerMac - obj-ppc-y += ppc_oldworld.o - # NewWorld PowerMac - obj-ppc-y += ppc_newworld.o - # IBM pSeries (sPAPR) - obj-ppc-$(CONFIG_PSERIES) += spapr.o spapr_hcall.o spapr_rtas.o spapr_vio.o - obj-ppc-$(CONFIG_PSERIES) += xics.o spapr_vty.o spapr_llan.o spapr_vscsi.o - obj-ppc-$(CONFIG_PSERIES) += spapr_pci.o device-hotplug.o pci-hotplug.o - # PowerPC 4xx boards - obj-ppc-y += ppc4xx_devs.o ppc4xx_pci.o ppc405_uc.o ppc405_boards.o - obj-ppc-y += ppc440_bamboo.o - # PowerPC E500 boards - obj-ppc-y += ppce500_mpc8544ds.o mpc8544_guts.o ppce500_spin.o - # PowerPC 440 Xilinx ML507 reference board. - obj-ppc-y += virtex_ml507.o - obj-ppc-$(CONFIG_KVM) += kvm_ppc.o - obj-ppc-$(CONFIG_FDT) += device_tree.o - # PowerPC OpenPIC - obj-ppc-y += openpic.o - - # Xilinx PPC peripherals - obj-ppc-y += xilinx_intc.o - obj-ppc-y += xilinx_timer.o - obj-ppc-y += xilinx_uartlite.o - obj-ppc-y += xilinx_ethlite.o - - # LM32 boards - obj-lm32-y += lm32_boards.o - obj-lm32-y += milkymist.o - - # LM32 peripherals - obj-lm32-y += lm32_pic.o - obj-lm32-y += lm32_juart.o - obj-lm32-y += lm32_timer.o - obj-lm32-y += lm32_uart.o - obj-lm32-y += lm32_sys.o - obj-lm32-y += milkymist-ac97.o - obj-lm32-y += milkymist-hpdmc.o - obj-lm32-y += milkymist-memcard.o - obj-lm32-y += milkymist-minimac2.o - obj-lm32-y += milkymist-pfpu.o - obj-lm32-y += milkymist-softusb.o - obj-lm32-y += milkymist-sysctl.o - obj-lm32-$(CONFIG_OPENGL) += milkymist-tmu2.o - obj-lm32-y += milkymist-uart.o - obj-lm32-y += milkymist-vgafb.o - obj-lm32-y += framebuffer.o - - obj-mips-y = mips_r4k.o mips_jazz.o mips_malta.o mips_mipssim.o - obj-mips-y += mips_addr.o mips_timer.o mips_int.o - obj-mips-y += gt64xxx.o mc146818rtc.o - obj-mips-$(CONFIG_FULONG) += bonito.o vt82c686.o mips_fulong2e.o - - obj-microblaze-y = petalogix_s3adsp1800_mmu.o - obj-microblaze-y += petalogix_ml605_mmu.o - obj-microblaze-y += microblaze_boot.o - - obj-microblaze-y += microblaze_pic_cpu.o - obj-microblaze-y += xilinx_intc.o - obj-microblaze-y += xilinx_timer.o - obj-microblaze-y += xilinx_uartlite.o - obj-microblaze-y += xilinx_ethlite.o - obj-microblaze-y += xilinx_axidma.o - obj-microblaze-y += xilinx_axienet.o - - obj-microblaze-$(CONFIG_FDT) += device_tree.o - - # Boards - obj-cris-y = cris_pic_cpu.o - obj-cris-y += cris-boot.o - obj-cris-y += axis_dev88.o - - # IO blocks - obj-cris-y += etraxfs_dma.o - obj-cris-y += etraxfs_pic.o - obj-cris-y += etraxfs_eth.o - obj-cris-y += etraxfs_timer.o - obj-cris-y += etraxfs_ser.o - ifeq ($(TARGET_ARCH), sparc64) - obj-sparc-y = sun4u.o apb_pci.o - obj-sparc-y += mc146818rtc.o + obj-y += hw/sparc64/ else - obj-sparc-y = sun4m.o lance.o tcx.o sun4m_iommu.o slavio_intctl.o - obj-sparc-y += slavio_timer.o slavio_misc.o sparc32_dma.o - obj-sparc-y += cs4231.o eccmemctl.o sbi.o sun4c_intctl.o leon3.o - - # GRLIB - obj-sparc-y += grlib_gptimer.o grlib_irqmp.o grlib_apbuart.o + obj-y += hw/$(TARGET_BASE_ARCH)/ endif - obj-arm-y = integratorcp.o versatilepb.o arm_pic.o arm_timer.o - obj-arm-y += arm_boot.o pl011.o pl031.o pl050.o pl080.o pl110.o pl181.o pl190.o - obj-arm-y += versatile_pci.o - obj-arm-y += versatile_i2c.o - obj-arm-y += cadence_uart.o - obj-arm-y += cadence_ttc.o - obj-arm-y += cadence_gem.o - obj-arm-y += xilinx_zynq.o zynq_slcr.o - obj-arm-y += arm_gic.o - obj-arm-y += realview_gic.o realview.o arm_sysctl.o arm11mpcore.o a9mpcore.o - obj-arm-y += exynos4210_gic.o exynos4210_combiner.o exynos4210.o - obj-arm-y += exynos4_boards.o exynos4210_uart.o exynos4210_pwm.o - obj-arm-y += exynos4210_pmu.o exynos4210_mct.o exynos4210_fimd.o - obj-arm-y += exynos4210_rtc.o exynos4210_cmu.o exynos4210_g3d.o - obj-arm-y += exynos4210_i2c.o exynos4210_i2s.o exynos4210_audio.o - obj-arm-y += ac97.o - obj-arm-y += arm_l2x0.o - obj-arm-y += arm_mptimer.o a15mpcore.o - obj-arm-y += armv7m.o armv7m_nvic.o stellaris.o pl022.o stellaris_enet.o - obj-arm-y += highbank.o - obj-arm-y += pl061.o - obj-arm-y += xgmac.o - obj-arm-y += arm-semi.o - obj-arm-y += pxa2xx.o pxa2xx_pic.o pxa2xx_gpio.o pxa2xx_timer.o pxa2xx_dma.o - obj-arm-y += pxa2xx_lcd.o pxa2xx_mmci.o pxa2xx_pcmcia.o pxa2xx_keypad.o - obj-arm-y += gumstix.o - obj-arm-y += zaurus.o ide/microdrive.o spitz.o tosa.o tc6393xb.o - obj-arm-y += omap1.o omap_lcdc.o omap_dma.o omap_clk.o omap_mmc.o omap_i2c.o \ - omap_gpio.o omap_intc.o omap_uart.o - obj-arm-y += omap2.o omap_dss.o soc_dma.o omap_gptimer.o omap_synctimer.o \ - omap_gpmc.o omap_sdrc.o omap_spi.o omap_tap.o omap_l4.o - obj-arm-y += omap_sx1.o palm.o tsc210x.o - obj-arm-y += nseries.o blizzard.o onenand.o cbus.o tusb6010.o usb/hcd-musb.o - obj-arm-y += mst_fpga.o mainstone.o - obj-arm-y += z2.o - obj-arm-y += musicpal.o bitbang_i2c.o marvell_88w8618_audio.o - obj-arm-y += framebuffer.o - obj-arm-y += vexpress.o - obj-arm-y += strongarm.o - obj-arm-y += collie.o - obj-arm-y += pl041.o lm4549.o - obj-arm-$(CONFIG_FDT) += device_tree.o - - obj-sh4-y = shix.o r2d.o sh7750.o sh7750_regnames.o tc58128.o - obj-sh4-y += sh_timer.o sh_serial.o sh_intc.o sh_pci.o sm501.o - obj-sh4-y += ide/mmio.o - - obj-m68k-y = an5206.o mcf5206.o mcf_uart.o mcf_intc.o mcf5208.o mcf_fec.o - obj-m68k-y += m68k-semi.o dummy_m68k.o - - obj-s390x-y = s390-virtio-bus.o s390-virtio.o - - obj-alpha-y = mc146818rtc.o - obj-alpha-y += alpha_pci.o alpha_dp264.o alpha_typhoon.o - - obj-xtensa-y += xtensa_pic.o - obj-xtensa-y += xtensa_sim.o - obj-xtensa-y += xtensa_lx60.o - obj-xtensa-y += xtensa-semi.o - obj-xtensa-y += core-dc232b.o - obj-xtensa-y += core-dc233c.o - obj-xtensa-y += core-fsf.o - main.o: QEMU_CFLAGS+=$(GPROF_CFLAGS) - monitor.o: hmp-commands.h qmp-commands-old.h + GENERATED_HEADERS += hmp-commands.h qmp-commands-old.h - $(obj-y) $(obj-$(TARGET_BASE_ARCH)-y): $(GENERATED_HEADERS) + endif # CONFIG_SOFTMMU - obj-y += $(addprefix ../, $(universal-obj-y)) - obj-y += $(addprefix ../, $(common-obj-y)) - obj-y += $(addprefix ../libdis/, $(libdis-y)) - obj-y += $(libobj-y) - obj-y += $(addprefix $(HWDIR)/, $(hw-obj-y)) - obj-y += $(addprefix ../, $(trace-obj-y)) + nested-vars += obj-y +# Makefile for TIZEN-maru +ifdef CONFIG_MARU +include $(SRC_PATH)/tizen/src/Makefile.tizen +endif +## + +ifdef CONFIG_BUILD_YAGL + +# YaGL +QEMU_CFLAGS += -I$(SRC_PATH)/hw/yagl_inc + +$(call set-vpath, $(SRC_PATH)/hw/yagl_apis/egl: \ + $(SRC_PATH)/hw/yagl_apis/gles: \ + $(SRC_PATH)/hw/yagl_apis/gles1: \ + $(SRC_PATH)/hw/yagl_apis/gles2: \ + $(SRC_PATH)/hw/yagl_drivers/egl_glx: \ + $(SRC_PATH)/hw/yagl_drivers/gles_ogl: \ + $(SRC_PATH)/hw/yagl_drivers/gles1_ogl: \ + $(SRC_PATH)/hw/yagl_drivers/gles2_ogl) + - obj-$(TARGET_BASE_ARCH)-y += yagl_device.o - obj-$(TARGET_BASE_ARCH)-y += yagl_log.o - obj-$(TARGET_BASE_ARCH)-y += yagl_process.o - obj-$(TARGET_BASE_ARCH)-y += yagl_thread.o - obj-$(TARGET_BASE_ARCH)-y += yagl_server.o - obj-$(TARGET_BASE_ARCH)-y += yagl_ref.o - obj-$(TARGET_BASE_ARCH)-y += yagl_mem.o - obj-$(TARGET_BASE_ARCH)-y += yagl_mem_egl.o - obj-$(TARGET_BASE_ARCH)-y += yagl_mem_gl.o - obj-$(TARGET_BASE_ARCH)-y += yagl_mem_transfer.o - obj-$(TARGET_BASE_ARCH)-y += yagl_event.o - obj-$(TARGET_BASE_ARCH)-y += yagl_handle_gen.o - obj-$(TARGET_BASE_ARCH)-y += yagl_dyn_lib.o - obj-$(TARGET_BASE_ARCH)-y += yagl_api.o - obj-$(TARGET_BASE_ARCH)-y += yagl_vector.o - obj-$(TARGET_BASE_ARCH)-y += yagl_avl.o - obj-$(TARGET_BASE_ARCH)-y += yagl_range_list.o - obj-$(TARGET_BASE_ARCH)-y += yagl_egl_driver.o - obj-$(TARGET_BASE_ARCH)-y += yagl_gles_driver.o - obj-$(TARGET_BASE_ARCH)-y += yagl_gles1_driver.o - obj-$(TARGET_BASE_ARCH)-y += yagl_gles2_driver.o - obj-$(TARGET_BASE_ARCH)-y += yagl_egl_interface.o - obj-$(TARGET_BASE_ARCH)-y += yagl_client_interface.o - obj-$(TARGET_BASE_ARCH)-y += yagl_client_context.o - obj-$(TARGET_BASE_ARCH)-y += yagl_resource.o - obj-$(TARGET_BASE_ARCH)-y += yagl_resource_list.o - obj-$(TARGET_BASE_ARCH)-y += yagl_object.o - obj-$(TARGET_BASE_ARCH)-y += yagl_namespace.o - obj-$(TARGET_BASE_ARCH)-y += yagl_sharegroup.o - obj-$(TARGET_BASE_ARCH)-y += yagl_stats.o - obj-$(TARGET_BASE_ARCH)-y += yagl_compiled_transfer.o - obj-$(TARGET_BASE_ARCH)-y += yagl_egl_native_config.o - obj-$(TARGET_BASE_ARCH)-y += yagl_egl_surface_attribs.o ++obj-y += yagl_device.o ++obj-y += yagl_log.o ++obj-y += yagl_process.o ++obj-y += yagl_thread.o ++obj-y += yagl_server.o ++obj-y += yagl_ref.o ++obj-y += yagl_mem.o ++obj-y += yagl_mem_egl.o ++obj-y += yagl_mem_gl.o ++obj-y += yagl_mem_transfer.o ++obj-y += yagl_event.o ++obj-y += yagl_handle_gen.o ++obj-y += yagl_dyn_lib.o ++obj-y += yagl_api.o ++obj-y += yagl_vector.o ++obj-y += yagl_avl.o ++obj-y += yagl_range_list.o ++obj-y += yagl_egl_driver.o ++obj-y += yagl_gles_driver.o ++obj-y += yagl_gles1_driver.o ++obj-y += yagl_gles2_driver.o ++obj-y += yagl_egl_interface.o ++obj-y += yagl_client_interface.o ++obj-y += yagl_client_context.o ++obj-y += yagl_resource.o ++obj-y += yagl_resource_list.o ++obj-y += yagl_object.o ++obj-y += yagl_namespace.o ++obj-y += yagl_sharegroup.o ++obj-y += yagl_stats.o ++obj-y += yagl_compiled_transfer.o ++obj-y += yagl_egl_native_config.o ++obj-y += yagl_egl_surface_attribs.o +# EGL api - obj-$(TARGET_BASE_ARCH)-y += yagl_egl_api.o - obj-$(TARGET_BASE_ARCH)-y += yagl_egl_api_ps.o - obj-$(TARGET_BASE_ARCH)-y += yagl_egl_api_ts.o - obj-$(TARGET_BASE_ARCH)-y += yagl_egl_calls.o - obj-$(TARGET_BASE_ARCH)-y += yagl_egl_display.o - obj-$(TARGET_BASE_ARCH)-y += yagl_egl_config.o - obj-$(TARGET_BASE_ARCH)-y += yagl_egl_surface.o - obj-$(TARGET_BASE_ARCH)-y += yagl_egl_context.o - obj-$(TARGET_BASE_ARCH)-y += yagl_egl_validate.o - obj-$(TARGET_BASE_ARCH)-y += yagl_host_egl_calls.o ++obj-y += yagl_egl_api.o ++obj-y += yagl_egl_api_ps.o ++obj-y += yagl_egl_api_ts.o ++obj-y += yagl_egl_calls.o ++obj-y += yagl_egl_display.o ++obj-y += yagl_egl_config.o ++obj-y += yagl_egl_surface.o ++obj-y += yagl_egl_context.o ++obj-y += yagl_egl_validate.o ++obj-y += yagl_host_egl_calls.o +# GLES common api - obj-$(TARGET_BASE_ARCH)-y += yagl_gles_context.o - obj-$(TARGET_BASE_ARCH)-y += yagl_gles_array.o - obj-$(TARGET_BASE_ARCH)-y += yagl_gles_buffer.o - obj-$(TARGET_BASE_ARCH)-y += yagl_gles_texture.o - obj-$(TARGET_BASE_ARCH)-y += yagl_gles_framebuffer.o - obj-$(TARGET_BASE_ARCH)-y += yagl_gles_renderbuffer.o - obj-$(TARGET_BASE_ARCH)-y += yagl_gles_texture_unit.o - obj-$(TARGET_BASE_ARCH)-y += yagl_gles_validate.o - obj-$(TARGET_BASE_ARCH)-y += yagl_host_gles_calls.o ++obj-y += yagl_gles_context.o ++obj-y += yagl_gles_array.o ++obj-y += yagl_gles_buffer.o ++obj-y += yagl_gles_texture.o ++obj-y += yagl_gles_framebuffer.o ++obj-y += yagl_gles_renderbuffer.o ++obj-y += yagl_gles_texture_unit.o ++obj-y += yagl_gles_validate.o ++obj-y += yagl_host_gles_calls.o +# GLESv1_CM api - obj-$(TARGET_BASE_ARCH)-y += yagl_gles1_calls.o - obj-$(TARGET_BASE_ARCH)-y += yagl_host_gles1_calls.o ++obj-y += yagl_gles1_calls.o ++obj-y += yagl_host_gles1_calls.o +# GLESv2 api - obj-$(TARGET_BASE_ARCH)-y += yagl_gles2_api.o - obj-$(TARGET_BASE_ARCH)-y += yagl_gles2_api_ps.o - obj-$(TARGET_BASE_ARCH)-y += yagl_gles2_api_ts.o - obj-$(TARGET_BASE_ARCH)-y += yagl_gles2_calls.o - obj-$(TARGET_BASE_ARCH)-y += yagl_gles2_context.o - obj-$(TARGET_BASE_ARCH)-y += yagl_gles2_shader.o - obj-$(TARGET_BASE_ARCH)-y += yagl_gles2_program.o - obj-$(TARGET_BASE_ARCH)-y += yagl_gles2_validate.o - obj-$(TARGET_BASE_ARCH)-y += yagl_host_gles2_calls.o ++obj-y += yagl_gles2_api.o ++obj-y += yagl_gles2_api_ps.o ++obj-y += yagl_gles2_api_ts.o ++obj-y += yagl_gles2_calls.o ++obj-y += yagl_gles2_context.o ++obj-y += yagl_gles2_shader.o ++obj-y += yagl_gles2_program.o ++obj-y += yagl_gles2_validate.o ++obj-y += yagl_host_gles2_calls.o +# EGL GLX driver - obj-$(TARGET_BASE_ARCH)-y += yagl_egl_glx.o ++obj-y += yagl_egl_glx.o +# GLES OpenGL common driver - obj-$(TARGET_BASE_ARCH)-y += yagl_gles_ogl.o ++obj-y += yagl_gles_ogl.o +# GLESv1_CM OpenGL driver - obj-$(TARGET_BASE_ARCH)-y += yagl_gles1_ogl.o ++obj-y += yagl_gles1_ogl.o +# GLESv2 OpenGL driver - obj-$(TARGET_BASE_ARCH)-y += yagl_gles2_ogl.o ++obj-y += yagl_gles2_ogl.o + +endif + +ifdef CONFIG_BUILD_GLES + +gles2.o: gles2.c gles2.h +gles2_egl.o: gles2_egl.c gles2.h +gles2_es11.o: gles2_es11.c gles2.h +gles2_es20.o: gles2_es20.c gles2.h +gles2_kernel_calls.o: gles2_kernel_calls.c gles2.h gles2_calls.h +gles2_egl_calls.o: gles2_egl_calls.c gles2.h gles2_calls.h +gles2_es11_calls.o: gles2_es11_calls.c gles2.h gles2_calls.h +gles2_es20_calls.o: gles2_es20_calls.c gles2.h gles2_calls.h +obj-y += gles2.o gles2_egl.o gles2_es11.o gles2_es20.o +obj-y += gles2_kernel_calls.o gles2_egl_calls.o gles2_es11_calls.o +obj-y += gles2_es20_calls.o + +ifdef QEMU_PROGW +GLESLIBS_LINK_LIST:=$(wildcard $(CONFIG_GLES_LIBDIR)/*.dll) +else +GLESLIBS_LINK_LIST:=$(wildcard $(CONFIG_GLES_LIBDIR)/lib*) +endif + +$(GLESLIBS_LINK_LIST): + +GLESLIBS_RUNTIME_LIST:=$(addprefix ./,$(notdir $(GLESLIBS_LINK_LIST))) + +$(GLESLIBS_RUNTIME_LIST): $(GLESLIBS_LINK_LIST) + @cp -dpu -t ./ $(GLESLIBS_LINK_LIST) + +$(QEMU_PROG): $(GLESLIBS_RUNTIME_LIST) + +endif # CONFIG_BUILD_GLES + - endif # CONFIG_SOFTMMU + # This resolves all nested paths, so it must come last + include $(SRC_PATH)/Makefile.objs - ifndef CONFIG_LINUX_USER - ifndef CONFIG_BSD_USER - # libcacard needs qemu-thread support, and besides is only needed by devices - # so not requires with linux-user / bsd-user targets - obj-$(CONFIG_SMARTCARD_NSS) += $(addprefix ../libcacard/, $(libcacard-y)) - endif # CONFIG_BSD_USER - endif # CONFIG_LINUX_USER + all-obj-y = $(obj-y) + all-obj-y += $(addprefix ../, $(universal-obj-y)) - obj-$(CONFIG_GDBSTUB_XML) += gdbstub-xml.o + ifdef CONFIG_SOFTMMU + all-obj-y += $(addprefix ../, $(common-obj-y)) + all-obj-y += $(addprefix ../libdis/, $(libdis-y)) + all-obj-y += $(addprefix $(HWDIR)/, $(hw-obj-y)) + all-obj-y += $(addprefix ../, $(trace-obj-y)) + else + all-obj-y += $(addprefix ../libuser/, $(user-obj-y)) + all-obj-y += $(addprefix ../libdis-user/, $(libdis-y)) + endif #CONFIG_LINUX_USER ifdef QEMU_PROGW # The linker builds a windows executable. Make also a console executable. diff --cc arch_init.c index eb5bfcf,5a1173e..2035f7f --- a/arch_init.c +++ b/arch_init.c @@@ -765,11 -1082,12 +1082,21 @@@ int xen_available(void #endif } + + TargetInfo *qmp_query_target(Error **errp) + { + TargetInfo *info = g_malloc0(sizeof(*info)); + + info->arch = TARGET_TYPE; + + return info; + } ++ +int hax_available(void) +{ +#ifdef CONFIG_HAX + return 1; +#else + return 0; +#endif +} diff --cc arch_init.h index 5d03048,d9c572a..86283c1 --- a/arch_init.h +++ b/arch_init.h @@@ -29,5 -33,7 +33,6 @@@ void audio_init(ISABus *isa_bus, PCIBu int tcg_available(void); int kvm_available(void); int xen_available(void); - +int hax_available(void); + CpuDefinitionInfoList GCC_WEAK_DECL *arch_query_cpu_definitions(Error **errp); - #endif diff --cc configure index c7333f3,d97fd81..991490c --- a/configure +++ b/configure @@@ -144,11 -169,8 +169,10 @@@ xfs=" vhost_net="no" kvm="no" +hax="no" gprof="no" debug_tcg="no" - debug_mon="no" +debug_gles="no" debug="no" strip_opt="yes" tcg_interpreter="no" @@@ -203,11 -218,7 +227,12 @@@ zlib="yes guest_agent="yes" libiscsi="" coroutine="" + seccomp="" +gl="yes" + +# for TIZEN-maru +maru="no" +# # parse CC options first for opt do @@@ -872,10 -865,10 +913,14 @@@ for opt d ;; --disable-guest-agent) guest_agent="no" ;; + --enable-seccomp) seccomp="yes" + ;; + --disable-seccomp) seccomp="no" + ;; +# for TIZEN-maru + --enable-maru) maru="yes" + ;; +# *) echo "ERROR: unknown option $opt"; show_help="yes" ;; esac @@@ -3129,23 -3162,11 +3265,24 @@@ echo "xfsctl support $xfs echo "nss used $smartcard_nss" echo "usb net redir $usb_redir" echo "OpenGL support $opengl" +echo "OpenGLES support $opengles" +if test "$opengles" = "yes"; then + echo "OpenGLES incdir $glesincdir" + echo "OpenGLES libdir $gleslibdir" + echo "OpenGLES debug $debug_gles" +fi +echo "EFence support $efence" +echo "YaGL support $yagl" +echo "YaGL stats $yagl_stats" echo "libiscsi support $libiscsi" echo "build guest agent $guest_agent" + echo "seccomp support $seccomp" echo "coroutine backend $coroutine_backend" +# for TIZEN-maru +echo "TIZEN-maru support $maru" +# + if test "$sdl_too_old" = "yes"; then echo "-> Your SDL version is too old - please upgrade to have SDL support" fi @@@ -3884,40 -3884,10 +4039,44 @@@ case "$target_arch2" i fi fi esac + case "$target_arch2" in + i386|x86_64) + echo "CONFIG_HAVE_GET_MEMORY_MAPPING=y" >> $config_target_mak + esac +if test "$hax" = "yes" ; then + if test "$target_softmmu" = "yes" ; then + case "$target_arch2" in + i386|x86_64) + echo "CONFIG_HAX=y" >> $config_target_mak + ;; + *) + echo "CONFIG_NO_HAX=y" >> $config_target_mak + ;; + esac + else + echo "CONFIG_NO_HAX=y" >> $config_target_mak + fi +fi +if test "$ldst_optimization" = "yes" ; then + if test "$target_arch2" = "i386" -o "$target_arch2" = "x86_64"; then + echo "CONFIG_QEMU_LDST_OPTIMIZATION=y" >> $config_target_mak + fi +fi +if test "$gl" = "yes" ; then + case "$target_arch2" in + i386|x86_64) + echo "CONFIG_GL=y" >> $config_target_mak + if test "$mingw32" = "yes" ; then + echo "LIBS+=-lopengl32 -lglu32" >> $config_target_mak + else + echo "LIBS+=-lGLU -ldl" >> $config_target_mak + fi + ;; + *) + echo "CONFIG_NO_GL=y" >> $config_target_mak + ;; + esac +fi if test "$target_arch2" = "ppc64" -a "$fdt" = "yes"; then echo "CONFIG_PSERIES=y" >> $config_target_mak fi diff --cc cpu-exec.c index 1c858c3,134b3c4..d7bcde0 --- a/cpu-exec.c +++ b/cpu-exec.c @@@ -183,26 -179,11 +180,29 @@@ static void cpu_handle_debug_exception( volatile sig_atomic_t exit_request; +/* + * QEMU emulate can happens because of MMIO or emulation mode, i.e. non-PG mode, + * when it's because of MMIO, the MMIO, the interrupt should not be emulated, + * because MMIO is emulated for only one instruction now and then back to + * HAX kernel + */ +int need_handle_intr_request(CPUArchState *env) +{ +#ifdef CONFIG_HAX + if (!hax_enabled() || hax_vcpu_emulation_mode(env)) + return env->interrupt_request; + return 0; +#else + return env->interrupt_request; +#endif +} + + int cpu_exec(CPUArchState *env) { + #ifdef TARGET_PPC + CPUState *cpu = ENV_GET_CPU(env); + #endif int ret, interrupt_request; TranslationBlock *tb; uint8_t *tc_ptr; diff --cc cpus.c index 8bcd74f,e476a3c..9def8b8 --- a/cpus.c +++ b/cpus.c @@@ -62,6 -62,33 +63,33 @@@ static CPUArchState *next_cpu; + static bool cpu_thread_is_idle(CPUArchState *env) + { + if (env->stop || env->queued_work_first) { + return false; + } + if (env->stopped || !runstate_is_running()) { + return true; + } + if (!env->halted || qemu_cpu_has_work(env) || - kvm_async_interrupts_enabled()) { ++ kvm_async_interrupts_enabled() || hax_enabled()) { + return false; + } + return true; + } + + static bool all_cpu_threads_idle(void) + { + CPUArchState *env; + + for (env = first_cpu; env != NULL; env = env->next_cpu) { + if (!cpu_thread_is_idle(env)) { + return false; + } + } + return true; + } + /***********************************************************/ /* guest cycle counter */ @@@ -976,14 -985,11 +986,15 @@@ void resume_all_vcpus(void static void qemu_tcg_init_vcpu(void *_env) { CPUArchState *env = _env; + CPUState *cpu = ENV_GET_CPU(env); +#ifdef CONFIG_HAX + if (hax_enabled()) + hax_init_vcpu(env); +#endif /* share a single thread for all cpus with TCG */ if (!tcg_cpu_thread) { - env->thread = g_malloc0(sizeof(QemuThread)); + cpu->thread = g_malloc0(sizeof(QemuThread)); env->halt_cond = g_malloc0(sizeof(QemuCond)); qemu_cond_init(env->halt_cond); tcg_halt_cond = env->halt_cond; diff --cc default-configs/arm-softmmu.mak index dd64484,f335a72..3d860d9 --- a/default-configs/arm-softmmu.mak +++ b/default-configs/arm-softmmu.mak @@@ -28,3 -27,21 +28,23 @@@ CONFIG_SMC91C111= CONFIG_DS1338=y CONFIG_PFLASH_CFI01=y CONFIG_PFLASH_CFI02=y + + CONFIG_ARM_TIMER=y + CONFIG_PL011=y + CONFIG_PL022=y + CONFIG_PL031=y + CONFIG_PL041=y + CONFIG_PL050=y + CONFIG_PL061=y + CONFIG_PL080=y + CONFIG_PL110=y + CONFIG_PL181=y + CONFIG_PL190=y + CONFIG_PL310=y + CONFIG_CADENCE=y + CONFIG_XGMAC=y + + CONFIG_VERSATILE_PCI=y + CONFIG_VERSATILE_I2C=y ++ ++CONFIG_SOUND=y diff --cc exec.c index 23606a8,5834766..1a72296 --- a/exec.c +++ b/exec.c @@@ -2645,43 -2551,14 +2552,31 @@@ ram_addr_t qemu_ram_alloc_from_ptr(ram_ exit(1); #endif } else { - #if defined(TARGET_S390X) && defined(CONFIG_KVM) - /* S390 KVM requires the topmost vma of the RAM to be smaller than - an system defined value, which is at least 256GB. Larger systems - have larger values. We put the guest between the end of data - segment (system break) and this value. We use 32GB as a base to - have enough room for the system break to grow. */ - new_block->host = mmap((void*)0x800000000, size, - PROT_EXEC|PROT_READ|PROT_WRITE, - MAP_SHARED | MAP_ANONYMOUS | MAP_FIXED, -1, 0); - if (new_block->host == MAP_FAILED) { - fprintf(stderr, "Allocating RAM failed\n"); - abort(); - } - #else if (xen_enabled()) { xen_ram_alloc(new_block->offset, size, mr); + } else if (kvm_enabled()) { + /* some s390/kvm configurations have special constraints */ + new_block->host = kvm_vmalloc(size); } else { new_block->host = qemu_vmalloc(size); +#ifdef CONFIG_HAX + /* + * In Hax, the qemu allocate the virtual address, and HAX kernel + * populate the memory with physical memory. Currently we have no + * paging, so user should make sure enough free memory in advance + */ + if (hax_enabled()) + { + int ret; + ret = hax_populate_ram((uint64_t)new_block->host, size); + if (ret < 0) + { + fprintf(stderr, "Hax failed to populate ram\n"); + exit(-1); + } + } +#endif } - #endif qemu_madvise(new_block->host, size, QEMU_MADV_MERGEABLE); } } diff --cc hw/Makefile.objs index 0000000,6dfebd2..2eb520f mode 000000,100644..100644 --- a/hw/Makefile.objs +++ b/hw/Makefile.objs @@@ -1,0 -1,204 +1,208 @@@ + hw-obj-y = usb/ ide/ + hw-obj-y += loader.o + hw-obj-$(CONFIG_VIRTIO) += virtio-console.o + hw-obj-$(CONFIG_VIRTIO_PCI) += virtio-pci.o ++hw-obj-$(CONFIG_VIRTIO_PCI) += virtio-pci-new.o ++hw-obj-$(CONFIG_VIRTIO) += virtio-transport.o ++hw-obj-$(CONFIG_VIRTIO) += virtio-mmio.o + hw-obj-y += fw_cfg.o + hw-obj-$(CONFIG_PCI) += pci.o pci_bridge.o pci_bridge_dev.o + hw-obj-$(CONFIG_PCI) += msix.o msi.o + hw-obj-$(CONFIG_PCI) += shpc.o + hw-obj-$(CONFIG_PCI) += slotid_cap.o + hw-obj-$(CONFIG_PCI) += pci_host.o pcie_host.o + hw-obj-$(CONFIG_PCI) += ioh3420.o xio3130_upstream.o xio3130_downstream.o + hw-obj-y += watchdog.o + hw-obj-$(CONFIG_ISA_MMIO) += isa_mmio.o + hw-obj-$(CONFIG_ECC) += ecc.o + hw-obj-$(CONFIG_NAND) += nand.o + hw-obj-$(CONFIG_PFLASH_CFI01) += pflash_cfi01.o + hw-obj-$(CONFIG_PFLASH_CFI02) += pflash_cfi02.o + + hw-obj-$(CONFIG_M48T59) += m48t59.o + hw-obj-$(CONFIG_ESCC) += escc.o + hw-obj-$(CONFIG_EMPTY_SLOT) += empty_slot.o + + hw-obj-$(CONFIG_SERIAL) += serial.o + hw-obj-$(CONFIG_PARALLEL) += parallel.o + hw-obj-$(CONFIG_I8254) += i8254_common.o i8254.o + hw-obj-$(CONFIG_PCSPK) += pcspk.o + hw-obj-$(CONFIG_PCKBD) += pckbd.o + hw-obj-$(CONFIG_FDC) += fdc.o + hw-obj-$(CONFIG_ACPI) += acpi.o acpi_piix4.o + hw-obj-$(CONFIG_APM) += pm_smbus.o apm.o + hw-obj-$(CONFIG_DMA) += dma.o + hw-obj-$(CONFIG_I82374) += i82374.o + hw-obj-$(CONFIG_HPET) += hpet.o + hw-obj-$(CONFIG_APPLESMC) += applesmc.o + hw-obj-$(CONFIG_SMARTCARD) += ccid-card-passthru.o + hw-obj-$(CONFIG_SMARTCARD_NSS) += ccid-card-emulated.o + hw-obj-$(CONFIG_I8259) += i8259_common.o i8259.o + + # PPC devices + hw-obj-$(CONFIG_PREP_PCI) += prep_pci.o + hw-obj-$(CONFIG_I82378) += i82378.o + # Mac shared devices + hw-obj-$(CONFIG_MACIO) += macio.o + hw-obj-$(CONFIG_CUDA) += cuda.o + hw-obj-$(CONFIG_ADB) += adb.o + hw-obj-$(CONFIG_MAC_NVRAM) += mac_nvram.o + hw-obj-$(CONFIG_MAC_DBDMA) += mac_dbdma.o + # OldWorld PowerMac + hw-obj-$(CONFIG_HEATHROW_PIC) += heathrow_pic.o + hw-obj-$(CONFIG_GRACKLE_PCI) += grackle_pci.o + # NewWorld PowerMac + hw-obj-$(CONFIG_UNIN_PCI) += unin_pci.o + hw-obj-$(CONFIG_DEC_PCI) += dec_pci.o + # PowerPC E500 boards + hw-obj-$(CONFIG_PPCE500_PCI) += ppce500_pci.o + + # MIPS devices + hw-obj-$(CONFIG_PIIX4) += piix4.o + hw-obj-$(CONFIG_G364FB) += g364fb.o + hw-obj-$(CONFIG_JAZZ_LED) += jazz_led.o + + # Xilinx devices + hw-obj-$(CONFIG_XILINX) += xilinx_intc.o + hw-obj-$(CONFIG_XILINX) += xilinx_timer.o + hw-obj-$(CONFIG_XILINX) += xilinx_uartlite.o + hw-obj-$(CONFIG_XILINX_AXI) += xilinx_axidma.o + hw-obj-$(CONFIG_XILINX_AXI) += xilinx_axienet.o + hw-obj-$(CONFIG_XILINX_AXI) += stream.o + + # PKUnity SoC devices + hw-obj-$(CONFIG_PUV3) += puv3_intc.o + hw-obj-$(CONFIG_PUV3) += puv3_ost.o + hw-obj-$(CONFIG_PUV3) += puv3_gpio.o + hw-obj-$(CONFIG_PUV3) += puv3_pm.o + hw-obj-$(CONFIG_PUV3) += puv3_dma.o + + # ARM devices + hw-obj-$(CONFIG_ARM_TIMER) += arm_timer.o + hw-obj-$(CONFIG_PL011) += pl011.o + hw-obj-$(CONFIG_PL022) += pl022.o + hw-obj-$(CONFIG_PL031) += pl031.o + hw-obj-$(CONFIG_PL041) += pl041.o lm4549.o + hw-obj-$(CONFIG_PL050) += pl050.o + hw-obj-$(CONFIG_PL061) += pl061.o + hw-obj-$(CONFIG_PL080) += pl080.o + hw-obj-$(CONFIG_PL110) += pl110.o + hw-obj-$(CONFIG_PL181) += pl181.o + hw-obj-$(CONFIG_PL190) += pl190.o + hw-obj-$(CONFIG_PL310) += arm_l2x0.o + hw-obj-$(CONFIG_VERSATILE_PCI) += versatile_pci.o + hw-obj-$(CONFIG_VERSATILE_I2C) += versatile_i2c.o + hw-obj-$(CONFIG_CADENCE) += cadence_uart.o + hw-obj-$(CONFIG_CADENCE) += cadence_ttc.o + hw-obj-$(CONFIG_CADENCE) += cadence_gem.o + hw-obj-$(CONFIG_XGMAC) += xgmac.o + + # PCI watchdog devices + hw-obj-$(CONFIG_PCI) += wdt_i6300esb.o + + hw-obj-$(CONFIG_PCI) += pcie.o pcie_aer.o pcie_port.o + + # PCI network cards + hw-obj-$(CONFIG_NE2000_PCI) += ne2000.o + hw-obj-$(CONFIG_EEPRO100_PCI) += eepro100.o + hw-obj-$(CONFIG_PCNET_PCI) += pcnet-pci.o + hw-obj-$(CONFIG_PCNET_COMMON) += pcnet.o + hw-obj-$(CONFIG_E1000_PCI) += e1000.o + hw-obj-$(CONFIG_RTL8139_PCI) += rtl8139.o + + hw-obj-$(CONFIG_SMC91C111) += smc91c111.o + hw-obj-$(CONFIG_LAN9118) += lan9118.o + hw-obj-$(CONFIG_NE2000_ISA) += ne2000-isa.o + hw-obj-$(CONFIG_OPENCORES_ETH) += opencores_eth.o + + # SCSI layer + hw-obj-$(CONFIG_LSI_SCSI_PCI) += lsi53c895a.o + hw-obj-$(CONFIG_MEGASAS_SCSI_PCI) += megasas.o + hw-obj-$(CONFIG_ESP) += esp.o + hw-obj-$(CONFIG_ESP_PCI) += esp-pci.o + + hw-obj-y += sysbus.o isa-bus.o + hw-obj-y += qdev-addr.o + + # VGA + hw-obj-$(CONFIG_VGA_PCI) += vga-pci.o + hw-obj-$(CONFIG_VGA_ISA) += vga-isa.o + hw-obj-$(CONFIG_VGA_ISA_MM) += vga-isa-mm.o + hw-obj-$(CONFIG_VMWARE_VGA) += vmware_vga.o + hw-obj-$(CONFIG_VMMOUSE) += vmmouse.o + hw-obj-$(CONFIG_VGA_CIRRUS) += cirrus_vga.o + + hw-obj-$(CONFIG_RC4030) += rc4030.o + hw-obj-$(CONFIG_DP8393X) += dp8393x.o + hw-obj-$(CONFIG_DS1225Y) += ds1225y.o + hw-obj-$(CONFIG_MIPSNET) += mipsnet.o + + hw-obj-y += null-machine.o + + # Sound + sound-obj-y = + sound-obj-$(CONFIG_SB16) += sb16.o + sound-obj-$(CONFIG_ES1370) += es1370.o + sound-obj-$(CONFIG_AC97) += ac97.o + sound-obj-$(CONFIG_ADLIB) += fmopl.o adlib.o + sound-obj-$(CONFIG_GUS) += gus.o gusemu_hal.o gusemu_mixer.o + sound-obj-$(CONFIG_CS4231A) += cs4231a.o + sound-obj-$(CONFIG_HDA) += intel-hda.o hda-audio.o + + $(obj)/adlib.o $(obj)/fmopl.o: QEMU_CFLAGS += -DBUILD_Y8950=0 + + hw-obj-$(CONFIG_SOUND) += $(sound-obj-y) + + hw-obj-$(CONFIG_REALLY_VIRTFS) += 9pfs/ + + common-obj-y += usb/ + common-obj-y += irq.o + common-obj-$(CONFIG_PTIMER) += ptimer.o + common-obj-$(CONFIG_MAX7310) += max7310.o + common-obj-$(CONFIG_WM8750) += wm8750.o ++common-obj-$(CONFIG_WM8994) += wm8994.o + common-obj-$(CONFIG_TWL92230) += twl92230.o + common-obj-$(CONFIG_TSC2005) += tsc2005.o + common-obj-$(CONFIG_LM832X) += lm832x.o + common-obj-$(CONFIG_TMP105) += tmp105.o + common-obj-$(CONFIG_STELLARIS_INPUT) += stellaris_input.o + common-obj-$(CONFIG_SSD0303) += ssd0303.o + common-obj-$(CONFIG_SSD0323) += ssd0323.o + common-obj-$(CONFIG_ADS7846) += ads7846.o + common-obj-$(CONFIG_MAX111X) += max111x.o + common-obj-$(CONFIG_DS1338) += ds1338.o + common-obj-y += i2c.o smbus.o smbus_eeprom.o + common-obj-y += eeprom93xx.o + common-obj-y += scsi-disk.o cdrom.o hd-geometry.o block-common.o + common-obj-y += scsi-generic.o scsi-bus.o + common-obj-y += hid.o + common-obj-$(CONFIG_SSI) += ssi.o + common-obj-$(CONFIG_SSI_SD) += ssi-sd.o + common-obj-$(CONFIG_SD) += sd.o + common-obj-y += bt.o bt-l2cap.o bt-sdp.o bt-hci.o bt-hid.o + common-obj-y += bt-hci-csr.o + common-obj-y += msmouse.o ps2.o + common-obj-y += qdev.o qdev-properties.o qdev-monitor.o + common-obj-$(CONFIG_BRLAPI) += baum.o + + # xen backend driver support + common-obj-$(CONFIG_XEN_BACKEND) += xen_backend.o xen_devconfig.o + common-obj-$(CONFIG_XEN_BACKEND) += xen_console.o xenfb.o xen_disk.o xen_nic.o + + # Per-target files + # virtio has to be here due to weird dependency between PCI and virtio-net. + # need to fix this properly + obj-$(CONFIG_VIRTIO) += virtio.o virtio-blk.o virtio-balloon.o virtio-net.o + obj-$(CONFIG_VIRTIO) += virtio-serial-bus.o virtio-scsi.o + obj-$(CONFIG_SOFTMMU) += vhost_net.o + obj-$(CONFIG_VHOST_NET) += vhost.o + obj-$(CONFIG_REALLY_VIRTFS) += 9pfs/ + obj-$(CONFIG_NO_PCI) += pci-stub.o + obj-$(CONFIG_VGA) += vga.o + obj-$(CONFIG_SOFTMMU) += device-hotplug.o + obj-$(CONFIG_XEN) += xen_domainbuild.o xen_machine_pv.o + + # Inter-VM PCI shared memory + ifeq ($(CONFIG_PCI), y) + obj-$(CONFIG_KVM) += ivshmem.o + endif diff --cc hw/arm/Makefile.objs index 0000000,2b39fb3..70895c5 mode 000000,100644..100644 --- a/hw/arm/Makefile.objs +++ b/hw/arm/Makefile.objs @@@ -1,0 -1,34 +1,36 @@@ + obj-y = integratorcp.o versatilepb.o arm_pic.o + obj-y += arm_boot.o + obj-y += xilinx_zynq.o zynq_slcr.o + obj-y += arm_gic.o arm_gic_common.o + obj-y += realview_gic.o realview.o arm_sysctl.o arm11mpcore.o a9mpcore.o + obj-y += exynos4210_gic.o exynos4210_combiner.o exynos4210.o + obj-y += exynos4_boards.o exynos4210_uart.o exynos4210_pwm.o + obj-y += exynos4210_pmu.o exynos4210_mct.o exynos4210_fimd.o + obj-y += exynos4210_rtc.o exynos4210_i2c.o ++obj-y += exynos4210_cmu.o exynos4210_g3d.o ++obj-y += exynos4210_i2s.o exynos4210_audio.o + obj-y += arm_mptimer.o a15mpcore.o + obj-y += armv7m.o armv7m_nvic.o stellaris.o stellaris_enet.o + obj-y += highbank.o + obj-y += pxa2xx.o pxa2xx_pic.o pxa2xx_gpio.o pxa2xx_timer.o pxa2xx_dma.o + obj-y += pxa2xx_lcd.o pxa2xx_mmci.o pxa2xx_pcmcia.o pxa2xx_keypad.o + obj-y += gumstix.o + obj-y += zaurus.o ide/microdrive.o spitz.o tosa.o tc6393xb.o + obj-y += omap1.o omap_lcdc.o omap_dma.o omap_clk.o omap_mmc.o omap_i2c.o \ + omap_gpio.o omap_intc.o omap_uart.o + obj-y += omap2.o omap_dss.o soc_dma.o omap_gptimer.o omap_synctimer.o \ + omap_gpmc.o omap_sdrc.o omap_spi.o omap_tap.o omap_l4.o + obj-y += omap_sx1.o palm.o tsc210x.o + obj-y += nseries.o blizzard.o onenand.o cbus.o tusb6010.o usb/hcd-musb.o + obj-y += mst_fpga.o mainstone.o + obj-y += z2.o + obj-y += musicpal.o bitbang_i2c.o marvell_88w8618_audio.o + obj-y += framebuffer.o + obj-y += vexpress.o + obj-y += strongarm.o + obj-y += collie.o + obj-y += imx_serial.o imx_ccm.o imx_timer.o imx_avic.o + obj-y += kzm.o + obj-$(CONFIG_FDT) += ../device_tree.o + + obj-y := $(addprefix ../,$(obj-y)) diff --cc hw/exynos4210.c index b71c15c,00d4db8..70fcdd6 --- a/hw/exynos4210.c +++ b/hw/exynos4210.c @@@ -26,6 -26,6 +26,7 @@@ #include "sysbus.h" #include "arm-misc.h" #include "loader.h" ++#include "virtio-transport.h" #include "exynos4210.h" #define EXYNOS4210_CHIPID_ADDR 0x10000000 @@@ -62,6 -72,6 +73,10 @@@ /* Display controllers (FIMD) */ #define EXYNOS4210_FIMD0_BASE_ADDR 0x11C00000 ++/* VirtIO MMIO */ ++#define EXYNOS4210_VIRTIO_MMIO0_BASE_ADDR 0x10AD0000 ++#define EXYNOS4210_VIRTIO_MMIO1_BASE_ADDR 0x10AC0000 ++ static uint8_t chipid_and_omr[] = { 0x11, 0x02, 0x21, 0x43, 0x09, 0x00, 0x00, 0x00 }; @@@ -296,5 -334,5 +339,13 @@@ Exynos4210State *exynos4210_init(Memory s->irq_table[exynos4210_get_irq(11, 2)], NULL); ++ sysbus_create_simple(VIRTIO_MMIO, ++ EXYNOS4210_VIRTIO_MMIO0_BASE_ADDR, ++ s->irq_table[exynos4210_get_irq(37, 3)]); ++ ++ sysbus_create_simple(VIRTIO_MMIO, ++ EXYNOS4210_VIRTIO_MMIO1_BASE_ADDR, ++ s->irq_table[exynos4210_get_irq(37, 2)]); ++ return s; } diff --cc hw/exynos4210.h index 1a37565,a43ba3a..6e96507 --- a/hw/exynos4210.h +++ b/hw/exynos4210.h @@@ -102,13 -97,10 +104,13 @@@ typedef struct Exynos4210State MemoryRegion dram1_mem; MemoryRegion boot_secondary; MemoryRegion bootreg_mem; + MemoryRegion audss_intmem; i2c_bus *i2c_if[EXYNOS4210_I2C_NUMBER]; + BusState *i2s_bus[3]; + SysBusDevice *vpci_bus; } Exynos4210State; - void exynos4210_write_secondary(CPUARMState *env, + void exynos4210_write_secondary(ARMCPU *cpu, const struct arm_boot_info *info); Exynos4210State *exynos4210_init(MemoryRegion *system_mem, @@@ -134,54 -126,8 +136,53 @@@ void exynos4210_combiner_get_gpioin(Exy int ext); /* + * Interface for exynos4210 Clock Management Units (CMUs) + */ +typedef enum { + UNSPECIFIED_CMU = -1, + EXYNOS4210_CMU_LEFTBUS, + EXYNOS4210_CMU_RIGHTBUS, + EXYNOS4210_CMU_TOP, + EXYNOS4210_CMU_DMC, + EXYNOS4210_CMU_CPU, + EXYNOS4210_CMU_NUMBER +} Exynos4210Cmu; + +typedef enum { + UNSPECIFIED_CLOCK, + EXYNOS4210_XXTI, + EXYNOS4210_XUSBXTI, +// EXYNOS4210_USB_PHY, +// EXYNOS4210_USB_HOST_PHY, +// EXYNOS4210_HDMI_PHY, + EXYNOS4210_APLL, + EXYNOS4210_MPLL, + EXYNOS4210_SCLK_HDMI24M, + EXYNOS4210_SCLK_USBPHY0, + EXYNOS4210_SCLK_USBPHY1, + EXYNOS4210_SCLK_HDMIPHY, + EXYNOS4210_SCLK_APLL, + EXYNOS4210_SCLK_MPLL, + EXYNOS4210_ACLK_100, + EXYNOS4210_SCLK_UART0, + EXYNOS4210_SCLK_UART1, + EXYNOS4210_SCLK_UART2, + EXYNOS4210_SCLK_UART3, + EXYNOS4210_SCLK_UART4, + EXYNOS4210_CLOCKS_NUMBER +} Exynos4210Clock; + +typedef void ClockChangeHandler(void *opaque); + +DeviceState *exynos4210_cmu_create(target_phys_addr_t addr, Exynos4210Cmu cmu); +uint64_t exynos4210_cmu_get_rate(Exynos4210Clock clock_id); +void exynos4210_register_clock_handler(ClockChangeHandler *func, + Exynos4210Clock clock_id, + void *opaque); + +/* * exynos4210 UART */ - DeviceState *exynos4210_uart_create(target_phys_addr_t addr, int fifo_size, int channel, diff --cc hw/exynos4210_i2s.c index 236cc57,0000000..705643f mode 100644,000000..100644 --- a/hw/exynos4210_i2s.c +++ b/hw/exynos4210_i2s.c @@@ -1,577 -1,0 +1,592 @@@ +/* + * Samsung exynos4210 I2S driver + * + * Copyright (c) 2012 Samsung Electronics Co., Ltd. + * Vorobiov Stanislav + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * 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. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, see . + * + */ + +#include "exynos4210_i2s.h" +#include "exec-memory.h" + +/* #define DEBUG_I2S */ + +#ifdef DEBUG_I2S +#define DPRINTF(fmt, ...) \ + do { \ + fprintf(stdout, "I2S: [%s:%d] " fmt, __func__, __LINE__, \ + ## __VA_ARGS__); \ + } while (0) +#else +#define DPRINTF(fmt, ...) do {} while (0) +#endif + +/* Registers */ +#define IISCON 0x00 +#define IISMOD 0x04 +#define IISFIC 0x08 +#define IISPSR 0x0C +#define IISTXD 0x10 +#define IISRXD 0x14 +#define IISFICS 0x18 +#define IISTXDS 0x1C +#define IISAHB 0x20 +#define IISSTR0 0x24 +#define IISSIZE 0x28 +#define IISTRNCNT 0x2C +#define IISLVL0ADDR 0x30 +#define IISLVL1ADDR 0x34 +#define IISLVL2ADDR 0x38 +#define IISLVL3ADDR 0x3C +#define IISSTR1 0x40 + +#define I2S_REGS_MEM_SIZE 0x44 +#define I2S_REGS_NUM (I2S_REGS_MEM_SIZE >> 2) + +#define I_(reg) (reg / sizeof(uint32_t)) + +/* Interface Control Register */ +#define IISCON_I2SACTIVE (1 << 0) +#define IISCON_RXDMACTIVE (1 << 1) +#define IISCON_TXDMACTIVE (1 << 2) +#define IISCON_RXCHPAUSE (1 << 3) +#define IISCON_TXCHPAUSE (1 << 4) +#define IISCON_RXDMAPAUSE (1 << 5) +#define IISCON_TXDMAPAUSE (1 << 6) +#define IISCON_FRXFULL (1 << 7) +#define IISCON_FTX0FULL (1 << 8) +#define IISCON_FRXEMPT (1 << 9) +#define IISCON_FTX0EMPT (1 << 10) +#define IISCON_LRI (1 << 11) +#define IISCON_FTX1FULL (1 << 12) +#define IISCON_FTX2FULL (1 << 13) +#define IISCON_FTX1EMPT (1 << 14) +#define IISCON_FTX2EMPT (1 << 15) +#define IISCON_FTXURINTEN (1 << 16) +#define IISCON_FTXURSTATUS (1 << 17) +#define IISCON_TXSDMACTIVE (1 << 18) +#define IISCON_TXSDMAPAUSE (1 << 20) +#define IISCON_FTXSFULL (1 << 21) +#define IISCON_FTXSEMPT (1 << 22) +#define IISCON_FTXSURINTEN (1 << 23) +#define IISCON_FTXSURSTATUS (1 << 24) +#define IISCON_FRXOFINTEN (1 << 25) +#define IISCON_FRXOFSTATUS (1 << 26) +#define IISCON_SW_RST (1 << 31) + +#define IISCON_WRITE_MASK (0x8295007F) + +/* AHB DMA Control Register */ +#define IISAHB_WRITE_MASK 0xFF0000FB +#define IISAHB_LVL3EN (1 << 27) +#define IISAHB_LVL2EN (1 << 26) +#define IISAHB_LVL1EN (1 << 25) +#define IISAHB_LVL0EN (1 << 24) +#define IISAHB_LVL3INT (1 << 23) +#define IISAHB_LVL2INT (1 << 22) +#define IISAHB_LVL1INT (1 << 21) +#define IISAHB_LVL0INT (1 << 20) +#define IISAHB_LVL3CLR (1 << 19) +#define IISAHB_LVL2CLR (1 << 18) +#define IISAHB_LVL1CLR (1 << 17) +#define IISAHB_LVL0CLR (1 << 16) +#define IISAHB_DMA_STRADDRRST (1 << 7) +#define IISAHB_DMA_STRADDRTOG (1 << 6) +#define IISAHB_DMARLD (1 << 5) +#define IISAHB_INTMASK (1 << 3) +#define IISAHB_DMAINT (1 << 2) +#define IISAHB_DMACLR (1 << 1) +#define IISAHB_DMAEN (1 << 0) + +/* AHB DMA Size Register */ +#define IISSIZE_TRNS_SIZE_OFFSET 16 +#define IISSIZE_TRNS_SIZE_MASK 0xFFFF + +/* AHB DMA Transfer Count Register */ +#define IISTRNCNT_OFFSET 0 +#define IISTRNCNT_MASK 0xFFFFFF + +typedef struct { + const char *name; + target_phys_addr_t offset; + uint32_t reset_value; +} Exynos4210I2SReg; + +static Exynos4210I2SReg exynos4210_i2s_regs[I2S_REGS_NUM] = { + {"IISCON", IISCON, 0x00000000}, + {"IISMOD", IISMOD, 0x00000000}, + {"IISFIC", IISFIC, 0x00000000}, + {"IISPSR", IISPSR, 0x00000000}, + {"IISTXD", IISTXD, 0x00000000}, + {"IISRXD", IISRXD, 0x00000000}, + {"IISFICS", IISFICS, 0x00000000}, + {"IISTXDS", IISTXDS, 0x00000000}, + {"IISAHB", IISAHB, 0x00000000}, + {"IISSTR0", IISSTR0, 0x00000000}, + {"IISSIZE", IISSIZE, 0x7FFF0000}, + {"IISTRNCNT", IISTRNCNT, 0x00000000}, + {"IISLVL0ADDR", IISLVL0ADDR, 0x00000000}, + {"IISLVL1ADDR", IISLVL1ADDR, 0x00000000}, + {"IISLVL2ADDR", IISLVL2ADDR, 0x00000000}, + {"IISLVL3ADDR", IISLVL3ADDR, 0x00000000}, + {"IISSTR1", IISSTR1, 0x00000000}, +}; + +static struct { + uint32_t ahb_en_bit; + uint32_t ahb_int_bit; + uint32_t ahb_clr_bit; + int reg_offset; +} lvl_regs[] = { + { IISAHB_LVL3EN, IISAHB_LVL3INT, IISAHB_LVL3CLR, IISLVL3ADDR }, + { IISAHB_LVL2EN, IISAHB_LVL2INT, IISAHB_LVL2CLR, IISLVL2ADDR }, + { IISAHB_LVL1EN, IISAHB_LVL1INT, IISAHB_LVL1CLR, IISLVL1ADDR }, + { IISAHB_LVL0EN, IISAHB_LVL0INT, IISAHB_LVL0CLR, IISLVL0ADDR }, +}; + ++#define TYPE_EXYNOS4210_I2S_BUS "exynos4210-i2s" ++ +typedef struct { + BusState qbus; + + MemoryRegion iomem; + qemu_irq irq; + uint32_t reg[I2S_REGS_NUM]; +} Exynos4210I2SBus; + +static Exynos4210I2SSlave *get_slave(Exynos4210I2SBus *bus) +{ - DeviceState *dev = QTAILQ_FIRST(&bus->qbus.children); ++ BusChild *kid = QTAILQ_FIRST(&bus->qbus.children); ++ DeviceState *dev; + - if (dev) { - return EXYNOS4210_I2S_SLAVE_FROM_QDEV(dev); ++ if (kid) { ++ dev = kid->child; ++ if (dev) { ++ return EXYNOS4210_I2S_SLAVE_FROM_QDEV(dev); ++ } + } + + return NULL; +} + +static void reset_internal(BusState *qbus, bool reset_slave) +{ + Exynos4210I2SBus *bus = DO_UPCAST(Exynos4210I2SBus, qbus, qbus); + Exynos4210I2SSlave *s; + int i; + + DPRINTF("enter\n"); + + qemu_irq_lower(bus->irq); + + for (i = 0; i < ARRAY_SIZE(exynos4210_i2s_regs); i++) { + bus->reg[i] = exynos4210_i2s_regs[i].reset_value; + } + + if (reset_slave) { + s = get_slave(bus); + + if (s != NULL) { + device_reset(&s->qdev); + } + } +} + +static uint32_t get_dma_size_words(Exynos4210I2SBus *bus) +{ + return (bus->reg[I_(IISSIZE)] >> IISSIZE_TRNS_SIZE_OFFSET) & + IISSIZE_TRNS_SIZE_MASK; +} + +static uint32_t get_dma_trncnt_words(Exynos4210I2SBus *bus) +{ + return (bus->reg[I_(IISTRNCNT)] >> IISTRNCNT_OFFSET) & + IISTRNCNT_MASK; +} + +static void set_dma_trncnt_words(Exynos4210I2SBus *bus, uint32_t trncnt_words) +{ + bus->reg[I_(IISTRNCNT)] &= ~(IISTRNCNT_MASK << IISTRNCNT_OFFSET); + bus->reg[I_(IISTRNCNT)] |= + ((trncnt_words & IISTRNCNT_MASK) << IISTRNCNT_OFFSET); +} + +static int exynos4210_i2s_bus_reset(BusState *qbus); + - static struct BusInfo exynos4210_i2s_bus_info = { - .name = "Exynos4210.I2S", - .size = sizeof(Exynos4210I2SBus), - .reset = exynos4210_i2s_bus_reset ++static void exynos4210_i2s_bus_class_init(ObjectClass *klass, void *data) ++{ ++ BusClass *k = BUS_CLASS(klass); ++ ++ k->reset = exynos4210_i2s_bus_reset; ++} ++ ++static struct TypeInfo exynos4210_i2s_bus_info = { ++ .name = TYPE_EXYNOS4210_I2S_BUS, ++ .parent = TYPE_BUS, ++ .instance_size = sizeof(Exynos4210I2SBus), ++ .class_init = exynos4210_i2s_bus_class_init, +}; + +static const VMStateDescription vmstate_exynos4210_i2s_bus = { + .name = "exynos4210.i2s_bus", + .version_id = 1, + .minimum_version_id = 1, + .minimum_version_id_old = 1, + .fields = (VMStateField[]) { + VMSTATE_UINT32_ARRAY(reg, Exynos4210I2SBus, + I2S_REGS_NUM), + VMSTATE_END_OF_LIST() + } +}; + +#ifdef DEBUG_I2S +static const char *exynos4210_i2s_regname(Exynos4210I2SBus *bus, + target_phys_addr_t offset) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(exynos4210_i2s_regs); i++) { + if (offset == exynos4210_i2s_regs[i].offset) { + return exynos4210_i2s_regs[i].name; + } + } + + return NULL; +} +#endif + +static void exynos4210_i2s_bus_write(void *opaque, + target_phys_addr_t offset, + uint64_t value, + unsigned size) +{ + Exynos4210I2SBus *bus = opaque; + Exynos4210I2SSlave *s; + Exynos4210I2SSlaveClass *sc; + int i; + + s = get_slave(bus); + + assert(s != NULL); + + if (s == NULL) { + hw_error("Exynos I2S cannot operate without a slave\n"); + } + + sc = EXYNOS4210_I2S_SLAVE_GET_CLASS(s); + + switch (offset) { + case IISCON: + if (!(value & IISCON_SW_RST) && + (bus->reg[I_(IISCON)] & IISCON_SW_RST)) { + reset_internal(&bus->qbus, 1); + } + + bus->reg[I_(offset)] = (bus->reg[I_(offset)] & ~IISCON_WRITE_MASK) | + (value & IISCON_WRITE_MASK); + + DPRINTF("0x%.8X -> %s\n", + bus->reg[I_(offset)], + exynos4210_i2s_regname(bus, offset)); + + break; + case IISAHB: + if (((value & IISAHB_DMAEN) != 0) && ((value & IISAHB_DMARLD) == 0)) { + hw_error("Non auto-reload DMA is not supported\n"); + } + + if (((value & IISAHB_DMAEN) != 0) && ((value & IISAHB_INTMASK) == 0)) { + hw_error("Non buffer level DMA interrupt is not supported\n"); + } + + if (((value & IISAHB_DMAEN) != 0) && + ((value & IISAHB_DMA_STRADDRTOG) != 0)) { + hw_error("DMA start address toggle is not supported\n"); + } + + for (i = 0; i < ARRAY_SIZE(lvl_regs); ++i) { + if ((value & lvl_regs[i].ahb_clr_bit) && + (bus->reg[I_(IISAHB)] & lvl_regs[i].ahb_int_bit)) { + qemu_irq_lower(bus->irq); + bus->reg[I_(IISAHB)] &= ~lvl_regs[i].ahb_int_bit; + } + } + + if ((value & IISAHB_DMACLR) && + (bus->reg[I_(IISAHB)] & IISAHB_DMAINT)) { + qemu_irq_lower(bus->irq); + bus->reg[I_(IISAHB)] &= ~IISAHB_DMAINT; + } + + if ((value & IISAHB_DMAEN) != + (bus->reg[I_(IISAHB)] & IISAHB_DMAEN)) { + if ((value & IISAHB_DMAEN) == 0) { + qemu_irq_lower(bus->irq); + } + if (sc->dma_enable) { + sc->dma_enable(s, ((value & IISAHB_DMAEN) != 0)); + } + } + + bus->reg[I_(offset)] = (bus->reg[I_(offset)] & ~IISAHB_WRITE_MASK) | + (value & IISAHB_WRITE_MASK); + + DPRINTF("0x%.8X -> %s\n", + bus->reg[I_(offset)], + exynos4210_i2s_regname(bus, offset)); + + break; + case IISTRNCNT: + hw_error("Cannot write IISTRNCNT\n"); + break; + case IISSIZE: + if (value == 0) { + hw_error("IISSIZE cannot be 0\n"); + } + + bus->reg[I_(offset)] = value; + + if (get_dma_size_words(bus) <= get_dma_trncnt_words(bus)) { + set_dma_trncnt_words(bus, 0); + } + + DPRINTF("0x%.8X -> %s\n", + bus->reg[I_(offset)], + exynos4210_i2s_regname(bus, offset)); + + break; + case IISLVL0ADDR: + case IISLVL1ADDR: + case IISLVL2ADDR: + case IISLVL3ADDR: + case IISTXD: + case IISMOD: + case IISFIC: + case IISPSR: + case IISTXDS: + case IISFICS: + case IISSTR0: + case IISSTR1: + bus->reg[I_(offset)] = value; + + DPRINTF("0x%.8X -> %s\n", + bus->reg[I_(offset)], + exynos4210_i2s_regname(bus, offset)); + + break; + default: + hw_error("Bad offset: 0x%X\n", (int)offset); + } +} + +static uint64_t exynos4210_i2s_bus_read(void *opaque, + target_phys_addr_t offset, + unsigned size) +{ + Exynos4210I2SBus *bus = opaque; + + if (offset > (I2S_REGS_MEM_SIZE - sizeof(uint32_t))) { + hw_error("Bad offset: 0x%X\n", (int)offset); + return 0; + } + + DPRINTF("%s -> 0x%.8X\n", + exynos4210_i2s_regname(bus, offset), + bus->reg[I_(offset)]); + + return bus->reg[I_(offset)]; +} + +static int exynos4210_i2s_bus_reset(BusState *qbus) +{ + reset_internal(qbus, 0); + + return 0; +} + +static const MemoryRegionOps exynos4210_i2s_bus_ops = { + .read = exynos4210_i2s_bus_read, + .write = exynos4210_i2s_bus_write, + .endianness = DEVICE_NATIVE_ENDIAN, + .valid = { + .max_access_size = 4, + .unaligned = false + }, +}; + +BusState *exynos4210_i2s_bus_new(const char *name, + target_phys_addr_t addr, + qemu_irq irq) +{ + Exynos4210I2SBus *bus; + + bus = FROM_QBUS(Exynos4210I2SBus, - qbus_create(&exynos4210_i2s_bus_info, NULL, name)); ++ qbus_create(TYPE_EXYNOS4210_I2S_BUS, NULL, name)); + vmstate_register(NULL, -1, &vmstate_exynos4210_i2s_bus, bus); + + memory_region_init_io(&bus->iomem, + &exynos4210_i2s_bus_ops, + bus, + "exynos4210.i2s", + I2S_REGS_MEM_SIZE); + + memory_region_add_subregion(get_system_memory(), + addr, + &bus->iomem); + + bus->irq = irq; + + return &bus->qbus; +} + +bool exynos4210_i2s_dma_enabled(BusState *qbus) +{ + Exynos4210I2SBus *bus = DO_UPCAST(Exynos4210I2SBus, qbus, qbus); + + return ((bus->reg[I_(IISAHB)] & IISAHB_DMAEN) != 0); +} + +uint32_t exynos4210_i2s_dma_get_words_available(BusState *qbus) +{ + Exynos4210I2SBus *bus = DO_UPCAST(Exynos4210I2SBus, qbus, qbus); + + return get_dma_size_words(bus); +} + +void exynos4210_i2s_dma_read(BusState *qbus, void *buf, uint32_t num_words) +{ + Exynos4210I2SBus *bus = DO_UPCAST(Exynos4210I2SBus, qbus, qbus); + target_phys_addr_t addr; + uint32_t size_words, trncnt_words; + + assert(num_words <= exynos4210_i2s_dma_get_words_available(qbus)); + + if (num_words > exynos4210_i2s_dma_get_words_available(qbus)) { + hw_error("Bad DMA read length: %d\n", num_words); + } + + size_words = get_dma_size_words(bus); + addr = bus->reg[I_(IISSTR0)]; + trncnt_words = get_dma_trncnt_words(bus); + + assert(trncnt_words < size_words); + + if (num_words > (size_words - trncnt_words)) { + cpu_physical_memory_read(addr + + (trncnt_words * EXYNOS4210_I2S_WORD_LEN), + buf, + (size_words - trncnt_words) * EXYNOS4210_I2S_WORD_LEN); + num_words -= (size_words - trncnt_words); + buf += (size_words - trncnt_words) * EXYNOS4210_I2S_WORD_LEN; + trncnt_words = 0; + } + + cpu_physical_memory_read(addr + (trncnt_words * EXYNOS4210_I2S_WORD_LEN), + buf, + num_words * EXYNOS4210_I2S_WORD_LEN); +} + +void exynos4210_i2s_dma_advance(BusState *qbus, uint32_t num_words) +{ + Exynos4210I2SBus *bus = DO_UPCAST(Exynos4210I2SBus, qbus, qbus); + uint32_t size_words, trncnt_words; + int i; + + assert(num_words <= exynos4210_i2s_dma_get_words_available(qbus)); + + if (num_words > exynos4210_i2s_dma_get_words_available(qbus)) { + hw_error("Bad DMA read length: %d\n", num_words); + } + + size_words = get_dma_size_words(bus); + trncnt_words = get_dma_trncnt_words(bus); + + for (i = 0; i < ARRAY_SIZE(lvl_regs); ++i) { + target_phys_addr_t dma_offset; + uint32_t tmp_num_words = num_words, tmp_trncnt_words = trncnt_words; + + if ((bus->reg[I_(IISAHB)] & lvl_regs[i].ahb_en_bit) == 0) { + continue; + } + + if (bus->reg[I_(lvl_regs[i].reg_offset)] < bus->reg[I_(IISSTR0)]) { + continue; + } + + dma_offset = bus->reg[I_(lvl_regs[i].reg_offset)] - + bus->reg[I_(IISSTR0)]; + + if (tmp_num_words > (size_words - tmp_trncnt_words)) { + if ((dma_offset >= (tmp_trncnt_words * EXYNOS4210_I2S_WORD_LEN)) && + (dma_offset < size_words * EXYNOS4210_I2S_WORD_LEN)) { + bus->reg[I_(IISAHB)] |= lvl_regs[i].ahb_int_bit; + qemu_irq_raise(bus->irq); + break; + } + + tmp_num_words -= (size_words - tmp_trncnt_words); + tmp_trncnt_words = 0; + } + + if ((dma_offset >= (tmp_trncnt_words * EXYNOS4210_I2S_WORD_LEN)) && + (dma_offset < + (tmp_trncnt_words + tmp_num_words) * EXYNOS4210_I2S_WORD_LEN)) { + bus->reg[I_(IISAHB)] |= lvl_regs[i].ahb_int_bit; + qemu_irq_raise(bus->irq); + } + } + + set_dma_trncnt_words(bus, (trncnt_words + num_words) % size_words); +} + +const VMStateDescription vmstate_exynos4210_i2s_slave = { + .name = "Exynos4210I2SSlave", + .version_id = 1, + .minimum_version_id = 1, + .minimum_version_id_old = 1 +}; + +static int exynos4210_i2s_slave_qdev_init(DeviceState *dev) +{ + Exynos4210I2SSlave *s = EXYNOS4210_I2S_SLAVE_FROM_QDEV(dev); + Exynos4210I2SSlaveClass *sc = EXYNOS4210_I2S_SLAVE_GET_CLASS(s); + + return sc->init ? sc->init(s) : 0; +} + +static void exynos4210_i2s_slave_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *k = DEVICE_CLASS(klass); + k->init = exynos4210_i2s_slave_qdev_init; - k->bus_info = &exynos4210_i2s_bus_info; ++ k->bus_type = TYPE_EXYNOS4210_I2S_BUS; +} + +static TypeInfo exynos4210_i2s_slave_type_info = { + .name = TYPE_EXYNOS4210_I2S_SLAVE, + .parent = TYPE_DEVICE, + .instance_size = sizeof(Exynos4210I2SSlave), + .abstract = true, + .class_size = sizeof(Exynos4210I2SSlaveClass), + .class_init = exynos4210_i2s_slave_class_init, +}; + +static void exynos4210_i2s_slave_register_types(void) +{ ++ type_register_static(&exynos4210_i2s_bus_info); + type_register_static(&exynos4210_i2s_slave_type_info); +} + +type_init(exynos4210_i2s_slave_register_types) diff --cc hw/pc.c index f2f5b23,112739a..12642d8 --- a/hw/pc.c +++ b/hw/pc.c @@@ -48,13 -50,9 +50,15 @@@ #include "memory.h" #include "exec-memory.h" #include "arch_init.h" + #include "bitmap.h" + #include "vga-pci.h" +#ifdef CONFIG_MARU +#include "../tizen/src/hw/maru_overlay.h" +#include "../tizen/src/hw/maru_brightness.h" +#include "../tizen/src/maru_err_table.h" +#endif + /* output Bochs bios info messages */ //#define DEBUG_BIOS diff --cc hw/pc.h index 3c04209,e4db071..374c775 --- a/hw/pc.h +++ b/hw/pc.h @@@ -189,12 -189,6 +189,11 @@@ static inline DeviceState *isa_vga_init return &dev->qdev; } +#ifdef CONFIG_MARU +DeviceState *pci_maru_vga_init(PCIBus *bus); +#endif + - DeviceState *pci_vga_init(PCIBus *bus); + int isa_vga_mm_init(target_phys_addr_t vram_base, target_phys_addr_t ctrl_base, int it_shift, MemoryRegion *address_space); diff --cc hw/pci.c index c1ebdde,4d95984..476eab8 --- a/hw/pci.c +++ b/hw/pci.c @@@ -66,7 -77,7 +77,6 @@@ static const TypeInfo pci_bus_info = static PCIBus *pci_find_bus_nr(PCIBus *bus, int bus_num); static void pci_update_mappings(PCIDevice *d); static void pci_set_irq(void *opaque, int irq_num, int level); --static int pci_add_option_rom(PCIDevice *pdev, bool is_default_rom); static void pci_del_option_rom(PCIDevice *pdev); static uint16_t pci_default_sub_vendor_id = PCI_SUBVENDOR_ID_REDHAT_QUMRANET; @@@ -1668,7 -1733,7 +1732,7 @@@ static void pci_patch_ids(PCIDevice *pd } /* Add an option rom for the device */ --static int pci_add_option_rom(PCIDevice *pdev, bool is_default_rom) ++int pci_add_option_rom(PCIDevice *pdev, bool is_default_rom) { int size; char *path; diff --cc hw/pci.h index 84df8f4,4b6ab3d..5071d3a --- a/hw/pci.h +++ b/hw/pci.h @@@ -251,6 -274,6 +276,8 @@@ void pci_register_bar(PCIDevice *pci_de uint8_t attr, MemoryRegion *memory); pcibus_t pci_get_bar_addr(PCIDevice *pci_dev, int region_num); ++int pci_add_option_rom(PCIDevice *pdev, bool is_default_rom); ++ int pci_add_capability(PCIDevice *pdev, uint8_t cap_id, uint8_t offset, uint8_t size); diff --cc hw/qdev-properties.c index b7b5597,8aca0d4..4226a02 --- a/hw/qdev-properties.c +++ b/hw/qdev-properties.c @@@ -2,6 -2,8 +2,9 @@@ #include "qdev.h" #include "qerror.h" #include "blockdev.h" ++#include "virtio-transport.h" + #include "hw/block-common.h" + #include "net/hub.h" void *qdev_get_prop_ptr(DeviceState *dev, Property *prop) { @@@ -528,6 -526,6 +527,34 @@@ PropertyInfo qdev_prop_drive = .release = release_drive, }; ++/* --- virtio transport --- */ ++ ++static int parse_transport(DeviceState *dev, const char *str, void **ptr) ++{ ++ VirtIOTransportLink *trl; ++ ++ trl = virtio_find_transport(str); ++ ++ if (trl == NULL) { ++ return -ENOENT; ++ } ++ ++ *ptr = trl; ++ ++ return 0; ++} ++ ++static void set_transport(Object *obj, Visitor *v, void *opaque, ++ const char *name, Error **errp) ++{ ++ set_pointer(obj, v, opaque, parse_transport, name, errp); ++} ++ ++PropertyInfo qdev_prop_transport = { ++ .name = "transport", ++ .set = set_transport, ++}; ++ /* --- character device --- */ static int parse_chr(DeviceState *dev, const char *str, void **ptr) diff --cc hw/qdev.h index 4e90119,d699194..bd6aa6e --- a/hw/qdev.h +++ b/hw/qdev.h @@@ -220,7 -231,8 +231,9 @@@ extern PropertyInfo qdev_prop_chr extern PropertyInfo qdev_prop_ptr; extern PropertyInfo qdev_prop_macaddr; extern PropertyInfo qdev_prop_losttickpolicy; + extern PropertyInfo qdev_prop_bios_chs_trans; extern PropertyInfo qdev_prop_drive; ++extern PropertyInfo qdev_prop_transport; extern PropertyInfo qdev_prop_netdev; extern PropertyInfo qdev_prop_vlan; extern PropertyInfo qdev_prop_pci_devfn; @@@ -276,11 -289,11 +290,13 @@@ extern PropertyInfo qdev_prop_pci_host_ #define DEFINE_PROP_STRING(_n, _s, _f) \ DEFINE_PROP(_n, _s, _f, qdev_prop_string, char*) #define DEFINE_PROP_NETDEV(_n, _s, _f) \ - DEFINE_PROP(_n, _s, _f, qdev_prop_netdev, VLANClientState*) + DEFINE_PROP(_n, _s, _f, qdev_prop_netdev, NetClientState*) #define DEFINE_PROP_VLAN(_n, _s, _f) \ - DEFINE_PROP(_n, _s, _f, qdev_prop_vlan, VLANState*) + DEFINE_PROP(_n, _s, _f, qdev_prop_vlan, NetClientState*) #define DEFINE_PROP_DRIVE(_n, _s, _f) \ DEFINE_PROP(_n, _s, _f, qdev_prop_drive, BlockDriverState *) ++#define DEFINE_PROP_TRANSPORT(_n, _s, _f) \ ++ DEFINE_PROP(_n, _s, _f, qdev_prop_transport, VirtIOTransportLink *) #define DEFINE_PROP_MACADDR(_n, _s, _f) \ DEFINE_PROP(_n, _s, _f, qdev_prop_macaddr, MACAddr) #define DEFINE_PROP_LOSTTICKPOLICY(_n, _s, _f, _d) \ diff --cc hw/usb/dev-storage.c index 1e88fad,ff48d91..38788d9 --- a/hw/usb/dev-storage.c +++ b/hw/usb/dev-storage.c @@@ -595,8 -599,8 +610,8 @@@ static USBDevice *usb_msd_init(USBBus * /* parse -usbdevice disk: syntax into drive opts */ snprintf(id, sizeof(id), "usb%d", nr++); - opts = qemu_opts_create(qemu_find_opts("drive"), id, 0); + opts = qemu_opts_create(qemu_find_opts("drive"), id, 0, NULL); - +#ifndef CONFIG_MARU p1 = strchr(filename, ':'); if (p1++) { const char *p2; diff --cc hw/vga-pci.c index 4444e92,9abbada..3c2278d --- a/hw/vga-pci.c +++ b/hw/vga-pci.c @@@ -100,59 -102,6 +106,60 @@@ static TypeInfo vga_info = .class_init = vga_class_init, }; +#ifdef CONFIG_MARU + +DeviceState *pci_maru_vga_init(PCIBus *bus) +{ + return &pci_create_simple(bus, -1, "MARU_VGA")->qdev; +} + +static int maru_pci_vga_initfn(PCIDevice *dev) +{ + PCIVGAState *d = DO_UPCAST(PCIVGAState, dev, dev); + VGACommonState *s = &d->vga; + + // vga + console init - maru_vga_common_init(s, VGA_RAM_SIZE); ++ maru_vga_common_init(s); + vga_init(s, pci_address_space(dev), pci_address_space_io(dev), true); + + s->ds = graphic_console_init(s->update, s->invalidate, + s->screen_dump, s->text_update, s); + + /* XXX: VGA_RAM_SIZE must be a power of two */ + pci_register_bar(&d->dev, 0, PCI_BASE_ADDRESS_MEM_PREFETCH, &s->vram); + + if (!dev->rom_bar) { + /* compatibility with pc-0.13 and older */ + vga_init_vbe(s, pci_address_space(dev)); + } + + return 0; +} + +static void maru_pci_vga_classinit(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); + + k->no_hotplug = 1; + k->init = maru_pci_vga_initfn; + k->romfile = "vgabios-maruvga.bin"; + k->vendor_id = PCI_VENDOR_ID_QEMU; + k->device_id = PCI_DEVICE_ID_QEMU_VGA; + k->class_id = PCI_CLASS_DISPLAY_VGA; + dc->vmsd = &vmstate_vga_pci; ++ dc->props = vga_pci_properties; +} + +static TypeInfo maru_vga_info = { + .name = "MARU_VGA", + .parent = TYPE_PCI_DEVICE, + .instance_size = sizeof(PCIVGAState), + .class_init = maru_pci_vga_classinit, +}; + +#endif // CONFIG_MARU + static void vga_register_types(void) { type_register_static(&vga_info); diff --cc hw/vga_int.h index 59ccac3,8938093..037b9e9 --- a/hw/vga_int.h +++ b/hw/vga_int.h @@@ -31,12 -31,8 +31,12 @@@ /* bochs VBE support */ #define CONFIG_BOCHS_VBE - #define VBE_DISPI_MAX_XRES 1600 + #define VBE_DISPI_MAX_XRES 16000 +#if CONFIG_MARU +#define VBE_DISPI_MAX_YRES 1600 +#else - #define VBE_DISPI_MAX_YRES 1200 + #define VBE_DISPI_MAX_YRES 12000 +#endif #define VBE_DISPI_MAX_BPP 32 #define VBE_DISPI_INDEX_ID 0x0 diff --cc hw/virtio-balloon.c index 699ed89,dd1a650..d6fe2aa --- a/hw/virtio-balloon.c +++ b/hw/virtio-balloon.c @@@ -268,36 -272,3 +273,44 @@@ void virtio_balloon_exit(VirtIODevice * unregister_savevm(s->qdev, "virtio-balloon", s); virtio_cleanup(vdev); } + +/******************** VirtIOBaloon Device **********************/ + +static int virtio_balloondev_init(DeviceState *dev) +{ + VirtIODevice *vdev; ++ VirtIOBaloonState *s = VIRTIO_BALLOON_FROM_QDEV(dev); + vdev = virtio_balloon_init(dev); + if (!vdev) { + return -1; + } - return virtio_init_transport(dev, vdev); ++ ++ assert(s->trl != NULL); ++ ++ return virtio_call_backend_init_cb(dev, s->trl, vdev); +} + ++static Property virtio_balloon_properties[] = { ++ DEFINE_PROP_END_OF_LIST(), ++}; ++ +static void virtio_balloon_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + dc->init = virtio_balloondev_init; - dc->bus_info = &virtio_transport_bus_info; ++ dc->props = virtio_balloon_properties; +} + +static TypeInfo virtio_balloon_info = { + .name = "virtio-balloon", + .parent = TYPE_DEVICE, + .instance_size = sizeof(VirtIOBaloonState), + .class_init = virtio_balloon_class_init, +}; + +static void virtio_baloon_register_types(void) +{ + type_register_static(&virtio_balloon_info); +} + +type_init(virtio_baloon_register_types) diff --cc hw/virtio-balloon.h index e134226,73300dd..b925186 --- a/hw/virtio-balloon.h +++ b/hw/virtio-balloon.h @@@ -15,9 -15,8 +15,10 @@@ #ifndef _QEMU_VIRTIO_BALLOON_H #define _QEMU_VIRTIO_BALLOON_H +#include "sysbus.h" #include "virtio.h" #include "pci.h" ++#include "virtio-transport.h" /* from Linux's linux/virtio_balloon.h */ @@@ -53,10 -52,4 +54,11 @@@ typedef struct VirtIOBalloonStat uint64_t val; } QEMU_PACKED VirtIOBalloonStat; +typedef struct { + DeviceState qdev; ++ VirtIOTransportLink *trl; +} VirtIOBaloonState; + +#define VIRTIO_BALLOON_FROM_QDEV(dev) DO_UPCAST(VirtIOBaloonState, qdev, dev) + #endif diff --cc hw/virtio-blk.c index 0a62a19,6f6d172..0a23352 --- a/hw/virtio-blk.c +++ b/hw/virtio-blk.c @@@ -14,8 -14,8 +14,10 @@@ #include "qemu-common.h" #include "qemu-error.h" #include "trace.h" + #include "hw/block-common.h" #include "blockdev.h" +#include "virtio-transport.h" ++#include "virtio-pci.h" #include "virtio-blk.h" #include "scsi-defs.h" #ifdef __linux__ @@@ -630,44 -665,3 +667,66 @@@ void virtio_blk_exit(VirtIODevice *vdev blockdev_mark_auto_del(s->bs); virtio_cleanup(vdev); } + +/******************** VirtIOBlk Device **********************/ + +static int virtio_blkdev_init(DeviceState *dev) +{ + VirtIODevice *vdev; - VirtIOBlockState *proxy = VIRTIO_BLK_FROM_QDEV(dev); - vdev = virtio_blk_init(dev, &proxy->block); ++ VirtIOBlockState *s = VIRTIO_BLK_FROM_QDEV(dev); ++ ++ assert(s->trl != NULL); ++ ++ vdev = virtio_blk_init(dev, &s->blk); + if (!vdev) { + return -1; + } - return virtio_init_transport(dev, vdev); ++ ++ /* Pass default host_features to transport */ ++ s->trl->host_features = s->host_features; ++ ++ if (virtio_call_backend_init_cb(dev, s->trl, vdev) != 0) { ++ return -1; ++ } ++ ++ /* Binding should be ready here, let's get final features */ ++ if (vdev->binding->get_features) { ++ s->host_features = vdev->binding->get_features(vdev->binding_opaque); ++ } ++ return 0; +} + +static Property virtio_blkdev_properties[] = { - DEFINE_BLOCK_PROPERTIES(VirtIOBlockState, block.conf), - DEFINE_PROP_STRING("serial", VirtIOBlockState, block.serial), ++ DEFINE_BLOCK_PROPERTIES(VirtIOBlockState, blk.conf), ++ DEFINE_BLOCK_CHS_PROPERTIES(VirtIOBlockState, blk.conf), ++ DEFINE_PROP_STRING("serial", VirtIOBlockState, blk.serial), ++#ifdef __linux__ ++ DEFINE_PROP_BIT("scsi", VirtIOBlockState, blk.scsi, 0, true), ++#endif ++ DEFINE_PROP_BIT("config-wce", VirtIOBlockState, blk.config_wce, 0, true), ++ DEFINE_VIRTIO_BLK_FEATURES(VirtIOBlockState, host_features), ++ ++ DEFINE_PROP_TRANSPORT("transport", VirtIOBlockState, trl), + DEFINE_PROP_END_OF_LIST(), +}; + +static void virtio_blkdev_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + dc->init = virtio_blkdev_init; + dc->props = virtio_blkdev_properties; - dc->bus_info = &virtio_transport_bus_info; +} + +static TypeInfo virtio_blkdev_info = { + .name = "virtio-blk", + .parent = TYPE_DEVICE, + .instance_size = sizeof(VirtIOBlockState), + .class_init = virtio_blkdev_class_init, +}; + +static void virtio_blk_register_types(void) +{ + type_register_static(&virtio_blkdev_info); +} + +type_init(virtio_blk_register_types) diff --cc hw/virtio-blk.h index e3bd8af,f0740d0..0886818 --- a/hw/virtio-blk.h +++ b/hw/virtio-blk.h @@@ -14,9 -14,8 +14,10 @@@ #ifndef _QEMU_VIRTIO_BLK_H #define _QEMU_VIRTIO_BLK_H +#include "sysbus.h" #include "virtio.h" - #include "block.h" ++#include "virtio-transport.h" + #include "hw/block-common.h" /* from Linux's linux/virtio_blk.h */ @@@ -106,15 -108,7 +110,20 @@@ struct VirtIOBlkCon }; #define DEFINE_VIRTIO_BLK_FEATURES(_state, _field) \ - DEFINE_VIRTIO_COMMON_FEATURES(_state, _field) + DEFINE_VIRTIO_COMMON_FEATURES(_state, _field), \ + DEFINE_PROP_BIT("config-wce", _state, _field, VIRTIO_BLK_F_CONFIG_WCE, true) + +typedef struct { + DeviceState qdev; + /* virtio-blk */ - VirtIOBlkConf block; ++ VirtIOBlkConf blk; ++ ++ uint32_t host_features; ++ ++ VirtIOTransportLink *trl; +} VirtIOBlockState; + +#define VIRTIO_BLK_FROM_QDEV(dev) DO_UPCAST(VirtIOBlockState, qdev, dev) + #endif diff --cc hw/virtio-mmio.c index c210806,0000000..88e5d9f mode 100644,000000..100644 --- a/hw/virtio-mmio.c +++ b/hw/virtio-mmio.c @@@ -1,439 -1,0 +1,400 @@@ +/* + * Virtio MMIO bindings + * + * Copyright (c) 2011 Linaro Limited + * + * Authors: + * Peter Maydell + * Evgeny Voevodin + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License; either version 2 + * of the License, or (at your option) any later version. + * + * 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. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, see . + */ + +/* TODO: + * * save/load support + * * test net, serial, balloon + */ + +#include "sysbus.h" +#include "virtio.h" +#include "virtio-transport.h" +#include "virtio-blk.h" +#include "virtio-net.h" +#include "virtio-serial.h" +#include "host-utils.h" + +/* #define DEBUG_VIRTIO_MMIO */ + +#ifdef DEBUG_VIRTIO_MMIO + +#define DPRINTF(fmt, ...) \ +do { printf("virtio_mmio: " fmt , ## __VA_ARGS__); } while (0) +#else +#define DPRINTF(fmt, ...) do {} while (0) +#endif + +/* Memory mapped register offsets */ +#define VIRTIO_MMIO_MAGIC 0x0 +#define VIRTIO_MMIO_VERSION 0x4 +#define VIRTIO_MMIO_DEVICEID 0x8 +#define VIRTIO_MMIO_VENDORID 0xc +#define VIRTIO_MMIO_HOSTFEATURES 0x10 +#define VIRTIO_MMIO_HOSTFEATURESSEL 0x14 +#define VIRTIO_MMIO_GUESTFEATURES 0x20 +#define VIRTIO_MMIO_GUESTFEATURESSEL 0x24 +#define VIRTIO_MMIO_GUESTPAGESIZE 0x28 +#define VIRTIO_MMIO_QUEUESEL 0x30 +#define VIRTIO_MMIO_QUEUENUMMAX 0x34 +#define VIRTIO_MMIO_QUEUENUM 0x38 +#define VIRTIO_MMIO_QUEUEALIGN 0x3c +#define VIRTIO_MMIO_QUEUEPFN 0x40 +#define VIRTIO_MMIO_QUEUENOTIFY 0x50 +#define VIRTIO_MMIO_INTERRUPTSTATUS 0x60 +#define VIRTIO_MMIO_INTERRUPTACK 0x64 +#define VIRTIO_MMIO_STATUS 0x70 +/* Device specific config space starts here */ +#define VIRTIO_MMIO_CONFIG 0x100 + +#define VIRT_MAGIC 0x74726976 /* 'virt' */ +#define VIRT_VERSION 1 +#define VIRT_VENDOR 0x554D4551 /* 'QEMU' */ + - #define VIRTIO_MMIO "virtio-mmio" - #define VIRTIO_MMIO_BUS "virtio-mmio-bus" - - struct BusInfo virtio_mmio_bus_info = { - .name = VIRTIO_MMIO_BUS, - .size = sizeof(BusState), - }; - +enum VIRTIO_MMIO_MAPPINGS { + VIRTIO_MMIO_IOMAP, + VIRTIO_MMIO_IOMEM, +}; + +typedef struct { + SysBusDevice busdev; + VirtIODevice *vdev; ++ VirtIOTransportLink *trl; ++ + MemoryRegion iomap; /* hold base address */ + MemoryRegion iomem; /* hold io funcs */ + MemoryRegion alias; + qemu_irq irq; + uint32_t int_enable; + uint32_t host_features; + uint32_t host_features_sel; + uint32_t guest_features_sel; + uint32_t guest_page_shift; - } VirtIOMMIOTransportState; ++} VirtIOMMIO; + +static uint64_t virtio_mmio_read(void *opaque, target_phys_addr_t offset, + unsigned size) +{ - VirtIOMMIOTransportState *transport = (VirtIOMMIOTransportState *)opaque; - VirtIODevice *vdev = transport->vdev; ++ VirtIOMMIO *s = (VirtIOMMIO *)opaque; ++ VirtIODevice *vdev = s->vdev; + DPRINTF("virtio_mmio_read offset 0x%x\n", (int)offset); + if (offset >= VIRTIO_MMIO_CONFIG) { + offset -= VIRTIO_MMIO_CONFIG; + switch (size) { + case 1: + return virtio_config_readb(vdev, offset); + case 2: + return virtio_config_readw(vdev, offset); + case 4: + return virtio_config_readl(vdev, offset); + default: + abort(); + } + } + if (size != 4) { + DPRINTF("wrong size access to register!\n"); + return 0; + } + switch (offset) { + case VIRTIO_MMIO_MAGIC: + return VIRT_MAGIC; + case VIRTIO_MMIO_VERSION: + return VIRT_VERSION; + case VIRTIO_MMIO_DEVICEID: + return vdev->device_id; + case VIRTIO_MMIO_VENDORID: + return VIRT_VENDOR; + case VIRTIO_MMIO_HOSTFEATURES: - if (transport->host_features_sel) { ++ if (s->host_features_sel) { + return 0; + } - return transport->host_features; ++ return s->host_features; + case VIRTIO_MMIO_QUEUENUMMAX: + return VIRTQUEUE_MAX_SIZE; + case VIRTIO_MMIO_QUEUEPFN: + return virtio_queue_get_addr(vdev, vdev->queue_sel) - >> transport->guest_page_shift; ++ >> s->guest_page_shift; + case VIRTIO_MMIO_INTERRUPTSTATUS: + return vdev->isr; + case VIRTIO_MMIO_STATUS: + return vdev->status; + case VIRTIO_MMIO_HOSTFEATURESSEL: + case VIRTIO_MMIO_GUESTFEATURES: + case VIRTIO_MMIO_GUESTFEATURESSEL: + case VIRTIO_MMIO_GUESTPAGESIZE: + case VIRTIO_MMIO_QUEUESEL: + case VIRTIO_MMIO_QUEUENUM: + case VIRTIO_MMIO_QUEUEALIGN: + case VIRTIO_MMIO_QUEUENOTIFY: + case VIRTIO_MMIO_INTERRUPTACK: + DPRINTF("read of write-only register\n"); + return 0; + default: + DPRINTF("bad register offset\n"); + return 0; + } + return 0; +} + +static void virtio_mmio_write(void *opaque, target_phys_addr_t offset, + uint64_t value, unsigned size) +{ - VirtIOMMIOTransportState *transport = (VirtIOMMIOTransportState *)opaque; - VirtIODevice *vdev = transport->vdev; ++ VirtIOMMIO *s = (VirtIOMMIO *)opaque; ++ VirtIODevice *vdev = s->vdev; + DPRINTF("virtio_mmio_write offset 0x%x value 0x%" PRIx64 "\n", + (int)offset, value); + if (offset >= VIRTIO_MMIO_CONFIG) { + offset -= VIRTIO_MMIO_CONFIG; + switch (size) { + case 1: + virtio_config_writeb(vdev, offset, value); + break; + case 2: + virtio_config_writew(vdev, offset, value); + break; + case 4: + virtio_config_writel(vdev, offset, value); + break; + default: + abort(); + } + return; + } + if (size != 4) { + DPRINTF("wrong size access to register!\n"); + return; + } + switch (offset) { + case VIRTIO_MMIO_HOSTFEATURESSEL: - transport->host_features_sel = value; ++ s->host_features_sel = value; + break; + case VIRTIO_MMIO_GUESTFEATURES: - if (!transport->guest_features_sel) { ++ if (!s->guest_features_sel) { + virtio_set_features(vdev, value); + } + break; + case VIRTIO_MMIO_GUESTFEATURESSEL: - transport->guest_features_sel = value; ++ s->guest_features_sel = value; + break; + case VIRTIO_MMIO_GUESTPAGESIZE: - transport->guest_page_shift = ctz32(value); - if (transport->guest_page_shift > 31) { - transport->guest_page_shift = 0; ++ s->guest_page_shift = ctz32(value); ++ if (s->guest_page_shift > 31) { ++ s->guest_page_shift = 0; + } + DPRINTF("guest page size %" PRIx64 " shift %d\n", value, - transport->guest_page_shift); ++ s->guest_page_shift); + break; + case VIRTIO_MMIO_QUEUESEL: + if (value < VIRTIO_PCI_QUEUE_MAX) { + vdev->queue_sel = value; + } + break; + case VIRTIO_MMIO_QUEUENUM: + DPRINTF("mmio_queue write %d max %d\n", (int)value, VIRTQUEUE_MAX_SIZE); + if (value <= VIRTQUEUE_MAX_SIZE) { + DPRINTF("calling virtio_queue_set_num\n"); + virtio_queue_set_num(vdev, vdev->queue_sel, value); + } + break; + case VIRTIO_MMIO_QUEUEALIGN: + virtio_queue_set_align(vdev, vdev->queue_sel, value); + break; + case VIRTIO_MMIO_QUEUEPFN: + if (value == 0) { + virtio_reset(vdev); + } else { + virtio_queue_set_addr(vdev, vdev->queue_sel, - value << transport->guest_page_shift); ++ value << s->guest_page_shift); + } + break; + case VIRTIO_MMIO_QUEUENOTIFY: + if (value < VIRTIO_PCI_QUEUE_MAX) { + virtio_queue_notify(vdev, value); + } + break; + case VIRTIO_MMIO_INTERRUPTACK: + vdev->isr &= ~value; + virtio_update_irq(vdev); + break; + case VIRTIO_MMIO_STATUS: + virtio_set_status(vdev, value & 0xff); + if (vdev->status == 0) { + virtio_reset(vdev); + } + break; + case VIRTIO_MMIO_MAGIC: + case VIRTIO_MMIO_VERSION: + case VIRTIO_MMIO_DEVICEID: + case VIRTIO_MMIO_VENDORID: + case VIRTIO_MMIO_HOSTFEATURES: + case VIRTIO_MMIO_QUEUENUMMAX: + case VIRTIO_MMIO_INTERRUPTSTATUS: + DPRINTF("write to readonly register\n"); + break; + + default: + DPRINTF("bad register offset\n"); + } +} + +static const MemoryRegionOps virtio_mem_ops = { + .read = virtio_mmio_read, + .write = virtio_mmio_write, + .endianness = DEVICE_NATIVE_ENDIAN, +}; + +static void virtio_mmio_update_irq(void *opaque, uint16_t vector) +{ - VirtIOMMIOTransportState *transport = opaque; - int level = (transport->vdev->isr != 0); ++ VirtIOMMIO *s = opaque; ++ int level = (s->vdev->isr != 0); + DPRINTF("virtio_mmio setting IRQ %d\n", level); - qemu_set_irq(transport->irq, level); ++ qemu_set_irq(s->irq, level); +} + +static unsigned int virtio_mmio_get_features(void *opaque) +{ - VirtIOMMIOTransportState *transport = opaque; - return transport->host_features; ++ VirtIOMMIO *s = opaque; ++ return s->host_features; +} + +static int virtio_mmio_load_config(void *opaque, QEMUFile *f) +{ - VirtIOMMIOTransportState *transport = opaque; - transport->int_enable = qemu_get_be32(f); - transport->host_features = qemu_get_be32(f); - transport->host_features_sel = qemu_get_be32(f); - transport->guest_features_sel = qemu_get_be32(f); - transport->guest_page_shift = qemu_get_be32(f); ++ VirtIOMMIO *s = opaque; ++ s->int_enable = qemu_get_be32(f); ++ s->host_features = qemu_get_be32(f); ++ s->host_features_sel = qemu_get_be32(f); ++ s->guest_features_sel = qemu_get_be32(f); ++ s->guest_page_shift = qemu_get_be32(f); + return 0; +} + +static void virtio_mmio_save_config(void *opaque, QEMUFile *f) +{ - VirtIOMMIOTransportState *transport = opaque; - qemu_put_be32(f, transport->int_enable); - qemu_put_be32(f, transport->host_features); - qemu_put_be32(f, transport->host_features_sel); - qemu_put_be32(f, transport->guest_features_sel); - qemu_put_be32(f, transport->guest_page_shift); ++ VirtIOMMIO *s = opaque; ++ qemu_put_be32(f, s->int_enable); ++ qemu_put_be32(f, s->host_features); ++ qemu_put_be32(f, s->host_features_sel); ++ qemu_put_be32(f, s->guest_features_sel); ++ qemu_put_be32(f, s->guest_page_shift); +} + +static VirtIOBindings virtio_mmio_bindings = { + .notify = virtio_mmio_update_irq, + .get_features = virtio_mmio_get_features, + .save_config = virtio_mmio_save_config, + .load_config = virtio_mmio_load_config, +}; + - static void virtio_mmio_attach_to_transport(DeviceState *dev) ++static int virtio_mmio_transport_cb(DeviceState *dev, VirtIODevice *vdev, ++ VirtIOTransportLink *trl) +{ - DeviceState *transport_dev = qdev_get_parent_bus(dev)->parent; - SysBusDevice *transport_sysbus = sysbus_from_qdev(transport_dev); - VirtIOMMIOTransportState *transport = - FROM_SYSBUS(VirtIOMMIOTransportState, transport_sysbus); ++ VirtIOMMIO *s = ++ FROM_SYSBUS(VirtIOMMIO, sysbus_from_qdev(trl->tr)); + - /* Create alias and add it as subregion to transport iomem */ - memory_region_init_alias(&transport->alias, ++ virtio_plug_into_transport(dev, trl); ++ ++ s->vdev = vdev; ++ s->vdev->nvectors = 0; ++ sysbus_init_irq(&s->busdev, &s->irq); ++ memory_region_init_io(&s->iomem, &virtio_mem_ops, s, ++ "virtio-mmio-iomem", 0x1000); ++ sysbus_init_mmio(&s->busdev, &s->iomem); ++ virtio_bind_device(vdev, &virtio_mmio_bindings, s); ++ s->host_features |= (0x1 << VIRTIO_F_NOTIFY_ON_EMPTY); ++ s->host_features = ++ vdev->get_features(vdev, s->host_features); ++ ++ /* Create alias and add it as subregion to s iomem */ ++ memory_region_init_alias(&s->alias, + "virtio-mmio-alias", - &transport->iomem, ++ &s->iomem, + 0, + 0x1000); - /* add alias as subregion to transport iomap */ - memory_region_add_subregion(&transport->iomap, ++ /* add alias as subregion to s iomap */ ++ memory_region_add_subregion(&s->iomap, + 0, - &transport->alias); - } - - static int virtio_init_mmio_transport(DeviceState *dev, VirtIODevice *vdev) - { - DeviceState *transport_dev = qdev_get_parent_bus(dev)->parent; - SysBusDevice *transport_sysbus = sysbus_from_qdev(transport_dev); - VirtIOMMIOTransportState *transport = - FROM_SYSBUS(VirtIOMMIOTransportState, transport_sysbus); - uint32_t i; - - /* Find a free transport where we will not have any siblings */ - i = virtio_count_siblings(qdev_get_parent_bus(dev), NULL); - if (i > 1) { - transport_dev = - virtio_get_free_transport(qdev_get_parent_bus(transport_dev), - VIRTIO_MMIO); - assert(transport_dev != NULL); - transport_sysbus = sysbus_from_qdev(transport_dev); - transport = FROM_SYSBUS(VirtIOMMIOTransportState, transport_sysbus); - - /* Reconnect back-end to free transport. Access by QLIST because we - * don't know actual suffix for virtio-pci.x */ - QTAILQ_REMOVE(&qdev_get_parent_bus(dev)->children, dev, sibling); - qdev_set_parent_bus(dev, qdev_get_child_bus(transport_dev, - ((BusState *)QLIST_FIRST(&transport_dev->child_bus))->name)); - } - - transport->vdev = vdev; - transport->vdev->nvectors = 0; - sysbus_init_irq(&transport->busdev, &transport->irq); - memory_region_init_io(&transport->iomem, &virtio_mem_ops, transport, - "virtio-mmio-iomem", 0x1000); - sysbus_init_mmio(&transport->busdev, &transport->iomem); - virtio_bind_device(vdev, &virtio_mmio_bindings, transport); - transport->host_features |= (0x1 << VIRTIO_F_NOTIFY_ON_EMPTY); - transport->host_features = - vdev->get_features(vdev, transport->host_features); - - virtio_mmio_attach_to_transport(dev); ++ &s->alias); + return 0; +} + - static void virtio_mmio_transport_handler(void *opaque, int irq, int level) ++static void virtio_mmio_handler(void *opaque, int irq, int level) +{ - VirtIOMMIOTransportState *s = (VirtIOMMIOTransportState *)opaque; ++ VirtIOMMIO *s = (VirtIOMMIO *)opaque; + + qemu_set_irq(s->irq, level); + + return; +} + - static int virtio_mmio_transport_device_init(SysBusDevice *busdev) ++static int sice_init(SysBusDevice *busdev) +{ - VirtIOMMIOTransportState *s = - DO_UPCAST(VirtIOMMIOTransportState, busdev, busdev); - BusState *parent_bus = qdev_get_parent_bus(&busdev->qdev); - BusState *child_bus; - VirtIOTransportBusState *virtio_transport_bus; ++ VirtIOMMIO *s = ++ DO_UPCAST(VirtIOMMIO, busdev, busdev); + char *buf; - int len; - uint32_t i; - - i = virtio_count_siblings(parent_bus, VIRTIO_MMIO); + - len = strlen(VIRTIO_MMIO) + 16; - buf = g_malloc(len); - snprintf(buf, len, "%s.%d", VIRTIO_MMIO, i); - child_bus = qbus_create(&virtio_transport_bus_info, &busdev->qdev, buf); ++ /* Count transports before we assigned a device ID to our new transport */ ++ buf = virtio_init_transport(&busdev->qdev, &s->trl, VIRTIO_MMIO, ++ virtio_mmio_transport_cb); + - /* Populate mmio init transport function */ - virtio_transport_bus = DO_UPCAST(VirtIOTransportBusState, bus, child_bus); - virtio_transport_bus->init_fn = virtio_init_mmio_transport; - - qdev_init_gpio_in(&s->busdev.qdev, virtio_mmio_transport_handler, 1); ++ /* assign new device id */ ++ busdev->qdev.id = buf; + ++ qdev_init_gpio_in(&s->busdev.qdev, virtio_mmio_handler, 1); + sysbus_init_irq(busdev, &s->irq); + memory_region_init(&s->iomap, "virtio-mmio-iomap", 0x1000); + sysbus_init_mmio(busdev, &s->iomap); ++ + return 0; +} + +static void virtio_mmio_reset(DeviceState *d) +{ - VirtIOMMIOTransportState *transport = - FROM_SYSBUS(VirtIOMMIOTransportState, sysbus_from_qdev(d)); - if (transport->vdev) { - virtio_reset(transport->vdev); ++ VirtIOMMIO *s = FROM_SYSBUS(VirtIOMMIO, sysbus_from_qdev(d)); ++ if (s->vdev) { ++ virtio_reset(s->vdev); + } +} + - static void virtio_mmio_transport_class_init(ObjectClass *klass, void *data) ++/******************** VirtIOMMIO Device *********************/ ++ ++static void virtio_mmio_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); - k->init = virtio_mmio_transport_device_init; ++ k->init = sice_init; + dc->reset = virtio_mmio_reset; +} + - static TypeInfo virtio_mmio_transport_info = { - .name = VIRTIO_MMIO_TRANSPORT, ++static TypeInfo virtio_mmio_info = { ++ .name = VIRTIO_MMIO, + .parent = TYPE_SYS_BUS_DEVICE, - .instance_size = sizeof(VirtIOMMIOTransportState), - .class_init = virtio_mmio_transport_class_init, ++ .instance_size = sizeof(VirtIOMMIO), ++ .class_init = virtio_mmio_class_init, +}; + ++/************************************************************/ ++ +static void virtio_mmio_register_types(void) +{ - type_register_static(&virtio_mmio_transport_info); ++ type_register_static(&virtio_mmio_info); +} + +type_init(virtio_mmio_register_types) diff --cc hw/virtio-net.c index 350fbb6,b1998b2..b7cfb1c --- a/hw/virtio-net.c +++ b/hw/virtio-net.c @@@ -13,7 -13,6 +13,8 @@@ #include "iov.h" #include "virtio.h" +#include "virtio-transport.h" ++#include "virtio-pci.h" #include "net.h" #include "net/checksum.h" #include "net/tap.h" @@@ -1078,51 -1077,6 +1079,63 @@@ void virtio_net_exit(VirtIODevice *vdev qemu_bh_delete(n->tx_bh); } - qemu_del_vlan_client(&n->nic->nc); + qemu_del_net_client(&n->nic->nc); virtio_cleanup(&n->vdev); } + +/******************** VirtIONet Device **********************/ + +static int virtio_netdev_init(DeviceState *dev) +{ + VirtIODevice *vdev; - VirtIONetState *proxy = VIRTIO_NET_FROM_QDEV(dev); - vdev = virtio_net_init(dev, &proxy->nic, &proxy->net); - if (!vdev) { ++ VirtIONetState *s = VIRTIO_NET_FROM_QDEV(dev); ++ ++ assert(s->trl != NULL); ++ ++ vdev = virtio_net_init(dev, &s->nic, &s->net); ++ ++ /* Pass default host_features to transport */ ++ s->trl->host_features = s->host_features; ++ ++ if (virtio_call_backend_init_cb(dev, s->trl, vdev) != 0) { + return -1; + } - return virtio_init_transport(dev, vdev); ++ ++ /* Binding should be ready here, let's get final features */ ++ if (vdev->binding->get_features) { ++ s->host_features = vdev->binding->get_features(vdev->binding_opaque); ++ } ++ return 0; +} + +static Property virtio_net_properties[] = { ++ DEFINE_VIRTIO_NET_FEATURES(VirtIONetState, host_features), + DEFINE_NIC_PROPERTIES(VirtIONetState, nic), - DEFINE_PROP_UINT32("x-txtimer", VirtIONetState, - net.txtimer, TX_TIMER_INTERVAL), - DEFINE_PROP_INT32("x-txburst", VirtIONetState, - net.txburst, TX_BURST), ++ DEFINE_PROP_UINT32("x-txtimer", VirtIONetState, net.txtimer, ++ TX_TIMER_INTERVAL), ++ DEFINE_PROP_INT32("x-txburst", VirtIONetState, net.txburst, TX_BURST), + DEFINE_PROP_STRING("tx", VirtIONetState, net.tx), ++ DEFINE_PROP_TRANSPORT("transport", VirtIONetState, trl), + DEFINE_PROP_END_OF_LIST(), +}; + +static void virtio_net_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + dc->init = virtio_netdev_init; + dc->props = virtio_net_properties; - dc->bus_info = &virtio_transport_bus_info; +} + +static TypeInfo virtio_net_info = { + .name = "virtio-net", + .parent = TYPE_DEVICE, + .instance_size = sizeof(VirtIONetState), + .class_init = virtio_net_class_init, +}; + +static void virtio_net_register_types(void) +{ + type_register_static(&virtio_net_info); +} + +type_init(virtio_net_register_types) diff --cc hw/virtio-net.h index 74a55c8,36aa463..8dd49d3 --- a/hw/virtio-net.h +++ b/hw/virtio-net.h @@@ -14,8 -14,7 +14,9 @@@ #ifndef _QEMU_VIRTIO_NET_H #define _QEMU_VIRTIO_NET_H +#include "sysbus.h" #include "virtio.h" ++#include "virtio-transport.h" #include "net.h" #include "pci.h" @@@ -188,14 -187,4 +189,18 @@@ struct virtio_net_ctrl_mac DEFINE_PROP_BIT("ctrl_rx", _state, _field, VIRTIO_NET_F_CTRL_RX, true), \ DEFINE_PROP_BIT("ctrl_vlan", _state, _field, VIRTIO_NET_F_CTRL_VLAN, true), \ DEFINE_PROP_BIT("ctrl_rx_extra", _state, _field, VIRTIO_NET_F_CTRL_RX_EXTRA, true) + +typedef struct { + DeviceState qdev; + /* virtio-net */ + NICConf nic; + virtio_net_conf net; ++ ++ uint32_t host_features; ++ ++ VirtIOTransportLink *trl; +} VirtIONetState; + +#define VIRTIO_NET_FROM_QDEV(dev) DO_UPCAST(VirtIONetState, qdev, dev) + #endif diff --cc hw/virtio-pci-new.c index 0000000,0000000..04f0da4 new file mode 100644 --- /dev/null +++ b/hw/virtio-pci-new.c @@@ -1,0 -1,0 +1,925 @@@ ++/* ++ * Virtio PCI Bindings ++ * ++ * Copyright IBM, Corp. 2007 ++ * Copyright (c) 2009 CodeSourcery ++ * ++ * Authors: ++ * Anthony Liguori ++ * Paul Brook ++ * ++ * This work is licensed under the terms of the GNU GPL, version 2. See ++ * the COPYING file in the top-level directory. ++ * ++ * Contributions after 2012-01-13 are licensed under the terms of the ++ * GNU GPL, version 2 or (at your option) any later version. ++ */ ++ ++#include ++ ++#include "virtio.h" ++#include "virtio-transport.h" ++#include "virtio-blk.h" ++#include "virtio-net.h" ++#include "virtio-serial.h" ++#include "virtio-scsi.h" ++#include "virtio-balloon.h" ++#include "pci.h" ++#include "qemu-error.h" ++#include "msi.h" ++#include "msix.h" ++#include "net.h" ++#include "loader.h" ++#include "kvm.h" ++#include "blockdev.h" ++#include "virtio-pci.h" ++#include "range.h" ++ ++/* from Linux's linux/virtio_pci.h */ ++ ++/* A 32-bit r/o bitmask of the features supported by the host */ ++#define VIRTIO_PCI_HOST_FEATURES 0 ++ ++/* A 32-bit r/w bitmask of features activated by the guest */ ++#define VIRTIO_PCI_GUEST_FEATURES 4 ++ ++/* A 32-bit r/w PFN for the currently selected queue */ ++#define VIRTIO_PCI_QUEUE_PFN 8 ++ ++/* A 16-bit r/o queue size for the currently selected queue */ ++#define VIRTIO_PCI_QUEUE_NUM 12 ++ ++/* A 16-bit r/w queue selector */ ++#define VIRTIO_PCI_QUEUE_SEL 14 ++ ++/* A 16-bit r/w queue notifier */ ++#define VIRTIO_PCI_QUEUE_NOTIFY 16 ++ ++/* An 8-bit device status register. */ ++#define VIRTIO_PCI_STATUS 18 ++ ++/* An 8-bit r/o interrupt status register. Reading the value will return the ++ * current contents of the ISR and will also clear it. This is effectively ++ * a read-and-acknowledge. */ ++#define VIRTIO_PCI_ISR 19 ++ ++/* MSI-X registers: only enabled if MSI-X is enabled. */ ++/* A 16-bit vector for configuration changes. */ ++#define VIRTIO_MSI_CONFIG_VECTOR 20 ++/* A 16-bit vector for selected queue notifications. */ ++#define VIRTIO_MSI_QUEUE_VECTOR 22 ++ ++/* Config space size */ ++#define VIRTIO_PCI_CONFIG_NOMSI 20 ++#define VIRTIO_PCI_CONFIG_MSI 24 ++#define VIRTIO_PCI_REGION_SIZE(dev) (msix_present(dev) ? \ ++ VIRTIO_PCI_CONFIG_MSI : \ ++ VIRTIO_PCI_CONFIG_NOMSI) ++ ++/* The remaining space is defined by each driver as the per-driver ++ * configuration space */ ++#define VIRTIO_PCI_CONFIG(dev) (msix_enabled(dev) ? \ ++ VIRTIO_PCI_CONFIG_MSI : \ ++ VIRTIO_PCI_CONFIG_NOMSI) ++ ++/* How many bits to shift physical queue address written to QUEUE_PFN. ++ * 12 is historical, and due to x86 page size. */ ++#define VIRTIO_PCI_QUEUE_ADDR_SHIFT 12 ++ ++/* Flags track per-device state like workarounds for quirks in older guests. */ ++#define VIRTIO_PCI_FLAG_BUS_MASTER_BUG (1 << 0) ++ ++/* QEMU doesn't strictly need write barriers since everything runs in ++ * lock-step. We'll leave the calls to wmb() in though to make it obvious for ++ * KVM or if kqemu gets SMP support. ++ */ ++#define wmb() do { } while (0) ++ ++/* HACK for virtio to determine if it's running a big endian guest */ ++bool virtio_is_big_endian(void); ++ ++/* virtio device */ ++ ++static void virtio_pci_notify(void *opaque, uint16_t vector) ++{ ++ VirtIOPCI *s = opaque; ++ if (msix_enabled(&s->pci_dev)) { ++ msix_notify(&s->pci_dev, vector); ++ } ++ else { ++ qemu_set_irq(s->pci_dev.irq[0], s->vdev->isr & 1); ++ } ++} ++ ++static void virtio_pci_save_config(void * opaque, QEMUFile *f) ++{ ++ VirtIOPCI *s = opaque; ++ pci_device_save(&s->pci_dev, f); ++ msix_save(&s->pci_dev, f); ++ if (msix_present(&s->pci_dev)) { ++ qemu_put_be16(f, s->vdev->config_vector); ++ } ++} ++ ++static void virtio_pci_save_queue(void * opaque, int n, QEMUFile *f) ++{ ++ VirtIOPCI *s = opaque; ++ if (msix_present(&s->pci_dev)) { ++ qemu_put_be16(f, virtio_queue_vector(s->vdev, n)); ++ } ++} ++ ++static int virtio_pci_load_config(void * opaque, QEMUFile *f) ++{ ++ VirtIOPCI *s = opaque; ++ int ret; ++ ret = pci_device_load(&s->pci_dev, f); ++ if (ret) { ++ return ret; ++ } ++ msix_unuse_all_vectors(&s->pci_dev); ++ msix_load(&s->pci_dev, f); ++ if (msix_present(&s->pci_dev)) { ++ qemu_get_be16s(f, &s->vdev->config_vector); ++ } else { ++ s->vdev->config_vector = VIRTIO_NO_VECTOR; ++ } ++ if (s->vdev->config_vector != VIRTIO_NO_VECTOR) { ++ return msix_vector_use(&s->pci_dev, s->vdev->config_vector); ++ } ++ return 0; ++} ++ ++static int virtio_pci_load_queue(void * opaque, int n, QEMUFile *f) ++{ ++ VirtIOPCI *s = opaque; ++ uint16_t vector; ++ if (msix_present(&s->pci_dev)) { ++ qemu_get_be16s(f, &vector); ++ } else { ++ vector = VIRTIO_NO_VECTOR; ++ } ++ virtio_queue_set_vector(s->vdev, n, vector); ++ if (vector != VIRTIO_NO_VECTOR) { ++ return msix_vector_use(&s->pci_dev, vector); ++ } ++ return 0; ++} ++ ++static int virtio_pci_set_host_notifier_internal(VirtIOPCI *s, int n, ++ bool assign, bool set_handler) ++{ ++ VirtQueue *vq = virtio_get_queue(s->vdev, n); ++ EventNotifier *notifier = virtio_queue_get_host_notifier(vq); ++ int r = 0; ++ ++ if (assign) { ++ r = event_notifier_init(notifier, 1); ++ if (r < 0) { ++ error_report("%s: unable to init event notifier: %d", __func__, r); ++ return r; ++ } ++ virtio_queue_set_host_notifier_fd_handler(vq, true, set_handler); ++ memory_region_add_eventfd(&s->bar, VIRTIO_PCI_QUEUE_NOTIFY, 2, true, n, ++ notifier); ++ } else { ++ memory_region_del_eventfd(&s->bar, VIRTIO_PCI_QUEUE_NOTIFY, 2, true, n, ++ notifier); ++ virtio_queue_set_host_notifier_fd_handler(vq, false, false); ++ event_notifier_cleanup(notifier); ++ } ++ return r; ++} ++ ++static void virtio_pci_start_ioeventfd(VirtIOPCI *s) ++{ ++ int n, r; ++ ++ if (!(s->flags & VIRTIO_PCI_FLAG_USE_IOEVENTFD) || ++ s->ioeventfd_disabled || ++ s->ioeventfd_started) { ++ return; ++ } ++ ++ for (n = 0; n < VIRTIO_PCI_QUEUE_MAX; n++) { ++ if (!virtio_queue_get_num(s->vdev, n)) { ++ continue; ++ } ++ ++ r = virtio_pci_set_host_notifier_internal(s, n, true, true); ++ if (r < 0) { ++ goto assign_error; ++ } ++ } ++ s->ioeventfd_started = true; ++ return; ++ ++assign_error: ++ while (--n >= 0) { ++ if (!virtio_queue_get_num(s->vdev, n)) { ++ continue; ++ } ++ ++ r = virtio_pci_set_host_notifier_internal(s, n, false, false); ++ assert(r >= 0); ++ } ++ s->ioeventfd_started = false; ++ error_report("%s: failed. Fallback to a userspace (slower).", __func__); ++} ++ ++static void virtio_pci_stop_ioeventfd(VirtIOPCI *s) ++{ ++ int r; ++ int n; ++ ++ if (!s->ioeventfd_started) { ++ return; ++ } ++ ++ for (n = 0; n < VIRTIO_PCI_QUEUE_MAX; n++) { ++ if (!virtio_queue_get_num(s->vdev, n)) { ++ continue; ++ } ++ ++ r = virtio_pci_set_host_notifier_internal(s, n, false, false); ++ assert(r >= 0); ++ } ++ s->ioeventfd_started = false; ++} ++ ++void virtio_pci_reset_(DeviceState *d) ++{ ++ VirtIOPCI *s = ++ container_of(d, VirtIOPCI, pci_dev.qdev); ++ virtio_pci_stop_ioeventfd(s); ++ if (s->vdev) { ++ virtio_reset(s->vdev); ++ } ++ msix_unuse_all_vectors(&s->pci_dev); ++ s->flags &= ~VIRTIO_PCI_FLAG_BUS_MASTER_BUG; ++} ++ ++static void virtio_ioport_write(void *opaque, uint32_t addr, uint32_t val) ++{ ++ VirtIOPCI *s = opaque; ++ VirtIODevice *vdev = s->vdev; ++ target_phys_addr_t pa; ++ ++ switch (addr) { ++ case VIRTIO_PCI_GUEST_FEATURES: ++ /* Guest does not negotiate properly? We have to assume nothing. */ ++ if (val & (1 << VIRTIO_F_BAD_FEATURE)) { ++ val = vdev->bad_features ? vdev->bad_features(vdev) : 0; ++ } ++ virtio_set_features(vdev, val); ++ break; ++ case VIRTIO_PCI_QUEUE_PFN: ++ pa = (target_phys_addr_t)val << VIRTIO_PCI_QUEUE_ADDR_SHIFT; ++ if (pa == 0) { ++ virtio_pci_stop_ioeventfd(s); ++ virtio_reset(s->vdev); ++ msix_unuse_all_vectors(&s->pci_dev); ++ } ++ else ++ virtio_queue_set_addr(vdev, vdev->queue_sel, pa); ++ break; ++ case VIRTIO_PCI_QUEUE_SEL: ++ if (val < VIRTIO_PCI_QUEUE_MAX) ++ vdev->queue_sel = val; ++ break; ++ case VIRTIO_PCI_QUEUE_NOTIFY: ++ if (val < VIRTIO_PCI_QUEUE_MAX) { ++ virtio_queue_notify(vdev, val); ++ } ++ break; ++ case VIRTIO_PCI_STATUS: ++ if (!(val & VIRTIO_CONFIG_S_DRIVER_OK)) { ++ virtio_pci_stop_ioeventfd(s); ++ } ++ ++ virtio_set_status(vdev, val & 0xFF); ++ ++ if (val & VIRTIO_CONFIG_S_DRIVER_OK) { ++ virtio_pci_start_ioeventfd(s); ++ } ++ ++ if (vdev->status == 0) { ++ virtio_reset(s->vdev); ++ msix_unuse_all_vectors(&s->pci_dev); ++ } ++ ++ /* Linux before 2.6.34 sets the device as OK without enabling ++ the PCI device bus master bit. In this case we need to disable ++ some safety checks. */ ++ if ((val & VIRTIO_CONFIG_S_DRIVER_OK) && ++ !(s->pci_dev.config[PCI_COMMAND] & PCI_COMMAND_MASTER)) { ++ s->flags |= VIRTIO_PCI_FLAG_BUS_MASTER_BUG; ++ } ++ break; ++ case VIRTIO_MSI_CONFIG_VECTOR: ++ msix_vector_unuse(&s->pci_dev, vdev->config_vector); ++ /* Make it possible for guest to discover an error took place. */ ++ if (msix_vector_use(&s->pci_dev, val) < 0) ++ val = VIRTIO_NO_VECTOR; ++ vdev->config_vector = val; ++ break; ++ case VIRTIO_MSI_QUEUE_VECTOR: ++ msix_vector_unuse(&s->pci_dev, ++ virtio_queue_vector(vdev, vdev->queue_sel)); ++ /* Make it possible for guest to discover an error took place. */ ++ if (msix_vector_use(&s->pci_dev, val) < 0) ++ val = VIRTIO_NO_VECTOR; ++ virtio_queue_set_vector(vdev, vdev->queue_sel, val); ++ break; ++ default: ++ error_report("%s: unexpected address 0x%x value 0x%x", ++ __func__, addr, val); ++ break; ++ } ++} ++ ++static uint32_t virtio_ioport_read(VirtIOPCI *s, uint32_t addr) ++{ ++ VirtIODevice *vdev = s->vdev; ++ uint32_t ret = 0xFFFFFFFF; ++ ++ switch (addr) { ++ case VIRTIO_PCI_HOST_FEATURES: ++ ret = s->host_features; ++ break; ++ case VIRTIO_PCI_GUEST_FEATURES: ++ ret = vdev->guest_features; ++ break; ++ case VIRTIO_PCI_QUEUE_PFN: ++ ret = virtio_queue_get_addr(vdev, vdev->queue_sel) ++ >> VIRTIO_PCI_QUEUE_ADDR_SHIFT; ++ break; ++ case VIRTIO_PCI_QUEUE_NUM: ++ ret = virtio_queue_get_num(vdev, vdev->queue_sel); ++ break; ++ case VIRTIO_PCI_QUEUE_SEL: ++ ret = vdev->queue_sel; ++ break; ++ case VIRTIO_PCI_STATUS: ++ ret = vdev->status; ++ break; ++ case VIRTIO_PCI_ISR: ++ /* reading from the ISR also clears it. */ ++ ret = vdev->isr; ++ vdev->isr = 0; ++ qemu_set_irq(s->pci_dev.irq[0], 0); ++ break; ++ case VIRTIO_MSI_CONFIG_VECTOR: ++ ret = vdev->config_vector; ++ break; ++ case VIRTIO_MSI_QUEUE_VECTOR: ++ ret = virtio_queue_vector(vdev, vdev->queue_sel); ++ break; ++ default: ++ break; ++ } ++ ++ return ret; ++} ++ ++static uint32_t virtio_pci_config_readb(void *opaque, uint32_t addr) ++{ ++ VirtIOPCI *s = opaque; ++ uint32_t config = VIRTIO_PCI_CONFIG(&s->pci_dev); ++ if (addr < config) ++ return virtio_ioport_read(s, addr); ++ addr -= config; ++ return virtio_config_readb(s->vdev, addr); ++} ++ ++static uint32_t virtio_pci_config_readw(void *opaque, uint32_t addr) ++{ ++ VirtIOPCI *s = opaque; ++ uint32_t config = VIRTIO_PCI_CONFIG(&s->pci_dev); ++ uint16_t val; ++ if (addr < config) ++ return virtio_ioport_read(s, addr); ++ addr -= config; ++ val = virtio_config_readw(s->vdev, addr); ++ if (virtio_is_big_endian()) { ++ /* ++ * virtio is odd, ioports are LE but config space is target native ++ * endian. However, in qemu, all PIO is LE, so we need to re-swap ++ * on BE targets ++ */ ++ val = bswap16(val); ++ } ++ return val; ++} ++ ++static uint32_t virtio_pci_config_readl(void *opaque, uint32_t addr) ++{ ++ VirtIOPCI *s = opaque; ++ uint32_t config = VIRTIO_PCI_CONFIG(&s->pci_dev); ++ uint32_t val; ++ if (addr < config) ++ return virtio_ioport_read(s, addr); ++ addr -= config; ++ val = virtio_config_readl(s->vdev, addr); ++ if (virtio_is_big_endian()) { ++ val = bswap32(val); ++ } ++ return val; ++} ++ ++static void virtio_pci_config_writeb(void *opaque, uint32_t addr, uint32_t val) ++{ ++ VirtIOPCI *s = opaque; ++ uint32_t config = VIRTIO_PCI_CONFIG(&s->pci_dev); ++ if (addr < config) { ++ virtio_ioport_write(s, addr, val); ++ return; ++ } ++ addr -= config; ++ virtio_config_writeb(s->vdev, addr, val); ++} ++ ++static void virtio_pci_config_writew(void *opaque, uint32_t addr, uint32_t val) ++{ ++ VirtIOPCI *s = opaque; ++ uint32_t config = VIRTIO_PCI_CONFIG(&s->pci_dev); ++ if (addr < config) { ++ virtio_ioport_write(s, addr, val); ++ return; ++ } ++ addr -= config; ++ if (virtio_is_big_endian()) { ++ val = bswap16(val); ++ } ++ virtio_config_writew(s->vdev, addr, val); ++} ++ ++static void virtio_pci_config_writel(void *opaque, uint32_t addr, uint32_t val) ++{ ++ VirtIOPCI *s = opaque; ++ uint32_t config = VIRTIO_PCI_CONFIG(&s->pci_dev); ++ if (addr < config) { ++ virtio_ioport_write(s, addr, val); ++ return; ++ } ++ addr -= config; ++ if (virtio_is_big_endian()) { ++ val = bswap32(val); ++ } ++ virtio_config_writel(s->vdev, addr, val); ++} ++ ++static const MemoryRegionPortio virtio_portio[] = { ++ { 0, 0x10000, 1, .write = virtio_pci_config_writeb, }, ++ { 0, 0x10000, 2, .write = virtio_pci_config_writew, }, ++ { 0, 0x10000, 4, .write = virtio_pci_config_writel, }, ++ { 0, 0x10000, 1, .read = virtio_pci_config_readb, }, ++ { 0, 0x10000, 2, .read = virtio_pci_config_readw, }, ++ { 0, 0x10000, 4, .read = virtio_pci_config_readl, }, ++ PORTIO_END_OF_LIST() ++}; ++ ++static const MemoryRegionOps virtio_pci_config_ops = { ++ .old_portio = virtio_portio, ++ .endianness = DEVICE_LITTLE_ENDIAN, ++}; ++ ++static void virtio_write_config(PCIDevice *pci_dev, uint32_t address, ++ uint32_t val, int len) ++{ ++ VirtIOPCI *s = DO_UPCAST(VirtIOPCI, ++ pci_dev, pci_dev); ++ ++ pci_default_write_config(pci_dev, address, val, len); ++ ++ if (range_covers_byte(address, len, PCI_COMMAND) && ++ !(pci_dev->config[PCI_COMMAND] & PCI_COMMAND_MASTER) && ++ !(s->flags & VIRTIO_PCI_FLAG_BUS_MASTER_BUG)) { ++ virtio_pci_stop_ioeventfd(s); ++ virtio_set_status(s->vdev, ++ s->vdev->status & ~VIRTIO_CONFIG_S_DRIVER_OK); ++ } ++} ++ ++static unsigned virtio_pci_get_features(void *opaque) ++{ ++ VirtIOPCI *s = opaque; ++ return s->host_features; ++} ++ ++static int kvm_virtio_pci_vq_vector_use(VirtIOPCI *s, ++ unsigned int queue_no, ++ unsigned int vector, ++ MSIMessage msg) ++{ ++ VirtQueue *vq = virtio_get_queue(s->vdev, queue_no); ++ EventNotifier *n = virtio_queue_get_guest_notifier(vq); ++ VirtIOIRQFD *irqfd = &s->vector_irqfd[vector]; ++ int ret; ++ ++ if (irqfd->users == 0) { ++ ret = kvm_irqchip_add_msi_route(kvm_state, msg); ++ if (ret < 0) { ++ return ret; ++ } ++ irqfd->virq = ret; ++ } ++ irqfd->users++; ++ ++ ret = kvm_irqchip_add_irq_notifier(kvm_state, n, irqfd->virq); ++ if (ret < 0) { ++ if (--irqfd->users == 0) { ++ kvm_irqchip_release_virq(kvm_state, irqfd->virq); ++ } ++ return ret; ++ } ++ ++ virtio_queue_set_guest_notifier_fd_handler(vq, true, true); ++ return 0; ++} ++ ++static void kvm_virtio_pci_vq_vector_release(VirtIOPCI *s, ++ unsigned int queue_no, ++ unsigned int vector) ++{ ++ VirtQueue *vq = virtio_get_queue(s->vdev, queue_no); ++ EventNotifier *n = virtio_queue_get_guest_notifier(vq); ++ VirtIOIRQFD *irqfd = &s->vector_irqfd[vector]; ++ int ret; ++ ++ ret = kvm_irqchip_remove_irq_notifier(kvm_state, n, irqfd->virq); ++ assert(ret == 0); ++ ++ if (--irqfd->users == 0) { ++ kvm_irqchip_release_virq(kvm_state, irqfd->virq); ++ } ++ ++ virtio_queue_set_guest_notifier_fd_handler(vq, true, false); ++} ++ ++static int kvm_virtio_pci_vector_use(PCIDevice *dev, unsigned vector, ++ MSIMessage msg) ++{ ++ VirtIOPCI *s = container_of(dev, VirtIOPCI, pci_dev); ++ VirtIODevice *vdev = s->vdev; ++ int ret, queue_no; ++ ++ for (queue_no = 0; queue_no < VIRTIO_PCI_QUEUE_MAX; queue_no++) { ++ if (!virtio_queue_get_num(vdev, queue_no)) { ++ break; ++ } ++ if (virtio_queue_vector(vdev, queue_no) != vector) { ++ continue; ++ } ++ ret = kvm_virtio_pci_vq_vector_use(s, queue_no, vector, msg); ++ if (ret < 0) { ++ goto undo; ++ } ++ } ++ return 0; ++ ++undo: ++ while (--queue_no >= 0) { ++ if (virtio_queue_vector(vdev, queue_no) != vector) { ++ continue; ++ } ++ kvm_virtio_pci_vq_vector_release(s, queue_no, vector); ++ } ++ return ret; ++} ++ ++static void kvm_virtio_pci_vector_release(PCIDevice *dev, unsigned vector) ++{ ++ VirtIOPCI *s = container_of(dev, VirtIOPCI, pci_dev); ++ VirtIODevice *vdev = s->vdev; ++ int queue_no; ++ ++ for (queue_no = 0; queue_no < VIRTIO_PCI_QUEUE_MAX; queue_no++) { ++ if (!virtio_queue_get_num(vdev, queue_no)) { ++ break; ++ } ++ if (virtio_queue_vector(vdev, queue_no) != vector) { ++ continue; ++ } ++ kvm_virtio_pci_vq_vector_release(s, queue_no, vector); ++ } ++} ++ ++static int virtio_pci_set_guest_notifier(void *opaque, int n, bool assign) ++{ ++ VirtIOPCI *s = opaque; ++ VirtQueue *vq = virtio_get_queue(s->vdev, n); ++ EventNotifier *notifier = virtio_queue_get_guest_notifier(vq); ++ ++ if (assign) { ++ int r = event_notifier_init(notifier, 0); ++ if (r < 0) { ++ return r; ++ } ++ virtio_queue_set_guest_notifier_fd_handler(vq, true, false); ++ } else { ++ virtio_queue_set_guest_notifier_fd_handler(vq, false, false); ++ event_notifier_cleanup(notifier); ++ } ++ ++ return 0; ++} ++ ++static bool virtio_pci_query_guest_notifiers(void *opaque) ++{ ++ VirtIOPCI *s = opaque; ++ return msix_enabled(&s->pci_dev); ++} ++ ++static int virtio_pci_set_guest_notifiers(void *opaque, bool assign) ++{ ++ VirtIOPCI *s = opaque; ++ VirtIODevice *vdev = s->vdev; ++ int r, n; ++ ++ /* Must unset vector notifier while guest notifier is still assigned */ ++ if (kvm_msi_via_irqfd_enabled() && !assign) { ++ msix_unset_vector_notifiers(&s->pci_dev); ++ g_free(s->vector_irqfd); ++ s->vector_irqfd = NULL; ++ } ++ ++ for (n = 0; n < VIRTIO_PCI_QUEUE_MAX; n++) { ++ if (!virtio_queue_get_num(vdev, n)) { ++ break; ++ } ++ ++ r = virtio_pci_set_guest_notifier(opaque, n, assign); ++ if (r < 0) { ++ goto assign_error; ++ } ++ } ++ ++ /* Must set vector notifier after guest notifier has been assigned */ ++ if (kvm_msi_via_irqfd_enabled() && assign) { ++ s->vector_irqfd = ++ g_malloc0(sizeof(*s->vector_irqfd) * ++ msix_nr_vectors_allocated(&s->pci_dev)); ++ r = msix_set_vector_notifiers(&s->pci_dev, ++ kvm_virtio_pci_vector_use, ++ kvm_virtio_pci_vector_release); ++ if (r < 0) { ++ goto assign_error; ++ } ++ } ++ ++ return 0; ++ ++assign_error: ++ /* We get here on assignment failure. Recover by undoing for VQs 0 .. n. */ ++ assert(assign); ++ while (--n >= 0) { ++ virtio_pci_set_guest_notifier(opaque, n, !assign); ++ } ++ return r; ++} ++ ++static int virtio_pci_set_host_notifier(void *opaque, int n, bool assign) ++{ ++ VirtIOPCI *s = opaque; ++ ++ /* Stop using ioeventfd for virtqueue kick if the device starts using host ++ * notifiers. This makes it easy to avoid stepping on each others' toes. ++ */ ++ s->ioeventfd_disabled = assign; ++ if (assign) { ++ virtio_pci_stop_ioeventfd(s); ++ } ++ /* We don't need to start here: it's not needed because backend ++ * currently only stops on status change away from ok, ++ * reset, vmstop and such. If we do add code to start here, ++ * need to check vmstate, device state etc. */ ++ return virtio_pci_set_host_notifier_internal(s, n, assign, false); ++} ++ ++static void virtio_pci_vmstate_change(void *opaque, bool running) ++{ ++ VirtIOPCI *s = opaque; ++ ++ if (running) { ++ /* Try to find out if the guest has bus master disabled, but is ++ in ready state. Then we have a buggy guest OS. */ ++ if ((s->vdev->status & VIRTIO_CONFIG_S_DRIVER_OK) && ++ !(s->pci_dev.config[PCI_COMMAND] & PCI_COMMAND_MASTER)) { ++ s->flags |= VIRTIO_PCI_FLAG_BUS_MASTER_BUG; ++ } ++ virtio_pci_start_ioeventfd(s); ++ } else { ++ virtio_pci_stop_ioeventfd(s); ++ } ++} ++ ++static const VirtIOBindings virtio_pci_bindings = { ++ .notify = virtio_pci_notify, ++ .save_config = virtio_pci_save_config, ++ .load_config = virtio_pci_load_config, ++ .save_queue = virtio_pci_save_queue, ++ .load_queue = virtio_pci_load_queue, ++ .get_features = virtio_pci_get_features, ++ .query_guest_notifiers = virtio_pci_query_guest_notifiers, ++ .set_host_notifier = virtio_pci_set_host_notifier, ++ .set_guest_notifiers = virtio_pci_set_guest_notifiers, ++ .vmstate_change = virtio_pci_vmstate_change, ++}; ++ ++static void virtio_init_pci_(VirtIOPCI *s, VirtIODevice *vdev) ++{ ++ uint8_t *config; ++ uint32_t size; ++ ++ s->vdev = vdev; ++ ++ config = s->pci_dev.config; ++ ++ if (s->class_code) { ++ pci_config_set_class(config, s->class_code); ++ } ++ pci_set_word(config + PCI_SUBSYSTEM_VENDOR_ID, ++ pci_get_word(config + PCI_VENDOR_ID)); ++ pci_set_word(config + PCI_SUBSYSTEM_ID, vdev->device_id); ++ config[PCI_INTERRUPT_PIN] = 1; ++ ++ if (vdev->nvectors && ++ msix_init_exclusive_bar(&s->pci_dev, vdev->nvectors, 1)) { ++ vdev->nvectors = 0; ++ } ++ ++ s->pci_dev.config_write = virtio_write_config; ++ ++ size = VIRTIO_PCI_REGION_SIZE(&s->pci_dev) + vdev->config_len; ++ if (size & (size-1)) ++ size = 1 << qemu_fls(size); ++ ++ memory_region_init_io(&s->bar, &virtio_pci_config_ops, s, ++ "virtio-pci", size); ++ pci_register_bar(&s->pci_dev, 0, PCI_BASE_ADDRESS_SPACE_IO, ++ &s->bar); ++ ++ if (!kvm_has_many_ioeventfds()) { ++ s->flags &= ~VIRTIO_PCI_FLAG_USE_IOEVENTFD; ++ } ++ ++ virtio_bind_device(vdev, &virtio_pci_bindings, s); ++ s->host_features |= 0x1 << VIRTIO_F_NOTIFY_ON_EMPTY; ++ s->host_features |= 0x1 << VIRTIO_F_BAD_FEATURE; ++ s->host_features = vdev->get_features(vdev, s->host_features); ++} ++ ++static void virtio_exit_pci(PCIDevice *pci_dev) ++{ ++ VirtIOPCI *s = DO_UPCAST(VirtIOPCI, pci_dev, pci_dev); ++ ++ memory_region_destroy(&s->bar); ++ msix_uninit_exclusive_bar(pci_dev); ++} ++ ++static int virtio_pci_transport_cb(DeviceState *dev, VirtIODevice *vdev, ++ VirtIOTransportLink *trl) ++{ ++ PCIDevice *pci_dev = DO_UPCAST(PCIDevice, qdev, trl->tr); ++ VirtIOPCI *s = DO_UPCAST(VirtIOPCI, pci_dev, pci_dev); ++ ++ virtio_plug_into_transport(dev, trl); ++ ++ // TODO: Figure out if props were explicitly set before ++ ++ /* Get default host_features passed from back-end */ ++ s->host_features = s->trl->host_features; ++ ++ switch (vdev->device_id) { ++ case VIRTIO_ID_BLOCK: ++ s->flags |= VIRTIO_PCI_FLAG_USE_IOEVENTFD; ++ s->nvectors = 2; ++ ++ if (s->class_code != PCI_CLASS_STORAGE_SCSI && ++ s->class_code != PCI_CLASS_STORAGE_OTHER) { ++ s->class_code = PCI_CLASS_STORAGE_SCSI; ++ } ++ ++ vdev->nvectors = s->nvectors; ++ pci_config_set_device_id(s->pci_dev.config, PCI_DEVICE_ID_VIRTIO_BLOCK); ++ pci_config_set_class(s->pci_dev.config, PCI_CLASS_STORAGE_SCSI); ++ virtio_init_pci_(s, vdev); ++ s->nvectors = vdev->nvectors; ++ break; ++ case VIRTIO_ID_NET: ++ s->nvectors = 3; ++ ++ /* load rom */ ++ pci_dev->romfile = g_strdup("pxe-virtio.rom"); ++ pci_add_option_rom(pci_dev, false); ++ ++ vdev->nvectors = s->nvectors; ++ pci_config_set_device_id(s->pci_dev.config, PCI_DEVICE_ID_VIRTIO_NET); ++ pci_config_set_class(s->pci_dev.config, PCI_CLASS_NETWORK_ETHERNET); ++ virtio_init_pci_(s, vdev); ++ s->nvectors = vdev->nvectors; ++ break; ++ case VIRTIO_ID_BALLOON: ++ break; ++ case VIRTIO_ID_SCSI: ++ break; ++ case VIRTIO_ID_CONSOLE: ++ { ++ break; ++ } ++ default: ++ fprintf(stderr, ++ "Unknown back-end device id: 0x%" PRIx16 "\n", vdev->device_id); ++ return -1; ++ } ++ ++ return 0; ++} ++ ++static int virtio_pci_device_init(PCIDevice *pci_dev) ++{ ++ VirtIOPCI *s = ++ DO_UPCAST(VirtIOPCI, pci_dev, pci_dev); ++ ++ virtio_init_transport(&pci_dev->qdev, &s->trl, VIRTIO_PCI, ++ virtio_pci_transport_cb); ++ ++ return 0; ++} ++ ++static void virtio_pci_device_exit(PCIDevice *pci_dev) ++{ ++ VirtIOPCI *s = ++ DO_UPCAST(VirtIOPCI, pci_dev, pci_dev); ++ ++ switch (s->vdev->device_id) { ++ case VIRTIO_ID_BLOCK: ++ virtio_pci_stop_ioeventfd(s); ++ virtio_blk_exit(s->vdev); ++ break; ++ case VIRTIO_ID_NET: ++ virtio_pci_stop_ioeventfd(s); ++ virtio_net_exit(s->vdev); ++ break; ++ case VIRTIO_ID_BALLOON: ++ virtio_pci_stop_ioeventfd(s); ++ virtio_balloon_exit(s->vdev); ++ break; ++ case VIRTIO_ID_SCSI: ++ virtio_scsi_exit(s->vdev); ++ break; ++ case VIRTIO_ID_CONSOLE: ++ virtio_pci_stop_ioeventfd(s); ++ virtio_serial_exit(s->vdev); ++ break; ++ default: ++ fprintf(stderr, ++ "Unknown back-end device id: 0x%" PRIx16 "\n", ++ s->vdev->device_id); ++ return; ++ } ++ ++ virtio_exit_pci(pci_dev); ++ ++ return; ++} ++ ++/******************** VirtIOPCI Device **********************/ ++ ++static Property virtio_pci_properties[] = { ++ DEFINE_PROP_HEX32("class", VirtIOPCI, class_code, 0), ++ DEFINE_PROP_BIT("ioeventfd", VirtIOPCI, flags, ++ VIRTIO_PCI_FLAG_USE_IOEVENTFD_BIT, false), ++ DEFINE_PROP_UINT32("vectors", VirtIOPCI, nvectors, 0), ++ DEFINE_PROP_END_OF_LIST(), ++}; ++ ++static void virtio_pci_class_init(ObjectClass *klass, void *data) ++{ ++ DeviceClass *dc = DEVICE_CLASS(klass); ++ PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); ++ k->init = virtio_pci_device_init; ++ k->exit = virtio_pci_device_exit; ++ k->vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET; ++ k->revision = VIRTIO_PCI_ABI_VERSION; ++ k->class_id = PCI_CLASS_OTHERS; ++ dc->reset = virtio_pci_reset_; ++ dc->props = virtio_pci_properties; ++} ++ ++static TypeInfo virtio_pci_info = { ++ .name = VIRTIO_PCI, ++ .parent = TYPE_PCI_DEVICE, ++ .instance_size = sizeof(VirtIOPCI), ++ .class_init = virtio_pci_class_init, ++}; ++ ++/************************************************************/ ++ ++static void virtio_pci_register_types(void) ++{ ++ type_register_static(&virtio_pci_info); ++} ++ ++type_init(virtio_pci_register_types) diff --cc hw/virtio-pci.c index e613eca,b3f0710..d6ec58b --- a/hw/virtio-pci.c +++ b/hw/virtio-pci.c @@@ -811,50 -877,9 +881,50 @@@ static void virtio_balloon_exit_pci(PCI virtio_pci_stop_ioeventfd(proxy); virtio_balloon_exit(proxy->vdev); - return virtio_exit_pci(pci_dev); + virtio_exit_pci(pci_dev); } +#ifdef CONFIG_VIRTIO_GL +#if defined(CONFIG_MARU) && (!defined(CONFIG_DARWIN)) +static int virtio_gl_init_pci(PCIDevice *pci_dev) +{ + VirtIOPCIProxy *proxy = DO_UPCAST(VirtIOPCIProxy, pci_dev, pci_dev); + VirtIODevice *vdev; + + vdev = virtio_gl_init(&pci_dev->qdev); + if (!vdev) { + return -1; + } + virtio_init_pci(proxy, vdev); + return 0; +} +#endif +#endif + +#ifdef CONFIG_MARU +static int maru_virtio_touchscreen_init_pci(PCIDevice *pci_dev) +{ + VirtIOPCIProxy *proxy = DO_UPCAST(VirtIOPCIProxy, pci_dev, pci_dev); + VirtIODevice *vdev; + + vdev = maru_virtio_touchscreen_init(&pci_dev->qdev); + if (!vdev) { + return -1; + } + virtio_init_pci(proxy, vdev); + return 0; +} + - static int maru_virtio_touchscreen_exit_pci(PCIDevice *pci_dev) ++static void maru_virtio_touchscreen_exit_pci(PCIDevice *pci_dev) +{ + VirtIOPCIProxy *proxy = DO_UPCAST(VirtIOPCIProxy, pci_dev, pci_dev); + + virtio_pci_stop_ioeventfd(proxy); + maru_virtio_touchscreen_exit(proxy->vdev); - return virtio_exit_pci(pci_dev); ++ virtio_exit_pci(pci_dev); +} +#endif + static Property virtio_blk_properties[] = { DEFINE_PROP_HEX32("class", VirtIOPCIProxy, class_code, 0), DEFINE_BLOCK_PROPERTIES(VirtIOPCIProxy, blk.conf), diff --cc hw/virtio-pci.h index 889e59e,ac9d522..2cddd67 --- a/hw/virtio-pci.h +++ b/hw/virtio-pci.h @@@ -44,10 -48,11 +48,29 @@@ typedef struct VirtIOSCSIConf scsi; bool ioeventfd_disabled; bool ioeventfd_started; + VirtIOIRQFD *vector_irqfd; } VirtIOPCIProxy; ++typedef struct { ++ PCIDevice pci_dev; ++ VirtIODevice *vdev; ++ MemoryRegion bar; ++ ++ uint32_t flags; ++ uint32_t class_code; ++ uint32_t nvectors; ++ uint32_t host_features; ++ ++ VirtIOTransportLink *trl; ++ ++ bool ioeventfd_disabled; ++ bool ioeventfd_started; ++ VirtIOIRQFD *vector_irqfd; ++} VirtIOPCI; ++ void virtio_init_pci(VirtIOPCIProxy *proxy, VirtIODevice *vdev); void virtio_pci_reset(DeviceState *d); ++void virtio_pci_reset_(DeviceState *d); /* Virtio ABI version, if we increment this, we break the guest driver. */ #define VIRTIO_PCI_ABI_VERSION 0 diff --cc hw/virtio-serial-bus.c index af63edb,82073f5..699a485 --- a/hw/virtio-serial-bus.c +++ b/hw/virtio-serial-bus.c @@@ -1001,44 -1014,3 +1015,46 @@@ static void virtio_serial_register_type } type_init(virtio_serial_register_types) + +/******************** VirtIOSer Device **********************/ + +static int virtio_serialdev_init(DeviceState *dev) +{ + VirtIODevice *vdev; - VirtIOSerState *proxy = VIRTIO_SERIAL_FROM_QDEV(dev); - vdev = virtio_serial_init(dev, &proxy->serial); ++ VirtIOSerState *s = VIRTIO_SERIAL_FROM_QDEV(dev); ++ vdev = virtio_serial_init(dev, &s->serial); + if (!vdev) { + return -1; + } - return virtio_init_transport(dev, vdev); ++ ++ assert(s->trl != NULL); ++ ++ return virtio_call_backend_init_cb(dev, s->trl, vdev); +} + +static Property virtio_serial_properties[] = { + DEFINE_PROP_UINT32("max_ports", VirtIOSerState, + serial.max_virtserial_ports, 31), + DEFINE_PROP_END_OF_LIST(), +}; + +static void virtio_serial_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + dc->init = virtio_serialdev_init; + dc->props = virtio_serial_properties; - dc->bus_info = &virtio_transport_bus_info; +} + +static TypeInfo virtio_serial_info = { + .name = "virtio-serial", + .parent = TYPE_DEVICE, + .instance_size = sizeof(VirtIOSerState), + .class_init = virtio_serial_class_init, +}; + +static void virtio_ser_register_types(void) +{ + type_register_static(&virtio_serial_info); +} + +type_init(virtio_ser_register_types) diff --cc hw/virtio-serial.h index 2290aac,16e3982..c6b916a --- a/hw/virtio-serial.h +++ b/hw/virtio-serial.h @@@ -15,9 -15,8 +15,10 @@@ #ifndef _QEMU_VIRTIO_SERIAL_H #define _QEMU_VIRTIO_SERIAL_H +#include "sysbus.h" #include "qdev.h" #include "virtio.h" ++#include "virtio-transport.h" /* == Interface shared between the guest kernel and qemu == */ @@@ -174,14 -173,6 +175,15 @@@ struct VirtIOSerialPort bool throttled; }; +typedef struct { + DeviceState qdev; + /* virtio-serial */ + virtio_serial_conf serial; ++ VirtIOTransportLink *trl; +} VirtIOSerState; + +#define VIRTIO_SERIAL_FROM_QDEV(dev) DO_UPCAST(VirtIOSerState, qdev, dev) + /* Interface to the virtio-serial bus */ /* diff --cc hw/virtio-transport.c index 078c726,0000000..76360ba mode 100644,000000..100644 --- a/hw/virtio-transport.c +++ b/hw/virtio-transport.c @@@ -1,100 -1,0 +1,147 @@@ +/* + * Virtio transport bindings + * + * Copyright (c) 2011 - 2012 Samsung Electronics Co., Ltd. + * + * Author: + * Evgeny Voevodin + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License; either version 2 + * of the License, or (at your option) any later version. + * + * 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. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, see . + */ + +#include "virtio-transport.h" + +#define VIRTIO_TRANSPORT_BUS "virtio-transport" + - struct BusInfo virtio_transport_bus_info = { - .name = VIRTIO_TRANSPORT_BUS, - .size = sizeof(VirtIOTransportBusState), - }; ++static QTAILQ_HEAD(, VirtIOTransportLink) transport_links = ++ QTAILQ_HEAD_INITIALIZER(transport_links); + - int virtio_init_transport(DeviceState *dev, VirtIODevice *vdev) ++/* ++ * Find transport device by its ID. ++ */ ++VirtIOTransportLink* virtio_find_transport(const char *name) +{ - DeviceState *transport_dev = qdev_get_parent_bus(dev)->parent; - BusState *bus; - VirtIOTransportBusState *virtio_transport_bus; ++ VirtIOTransportLink *trl; + - /* transport device has single child bus */ - bus = QLIST_FIRST(&transport_dev->child_bus); - virtio_transport_bus = DO_UPCAST(VirtIOTransportBusState, bus, bus); ++ assert(name != NULL); + - if (virtio_transport_bus->init_fn) { - return virtio_transport_bus->init_fn(dev, vdev); ++ QTAILQ_FOREACH(trl, &transport_links, sibling) { ++ if (trl->tr->id != NULL) { ++ if (!strcmp(name, trl->tr->id)) { ++ return trl; ++ } ++ } + } + - return 0; ++ return NULL; +} + - uint32_t virtio_count_siblings(BusState *parent_bus, const char *child_bus) ++/* ++ * Count transport devices by ID. ++ */ ++uint32_t virtio_count_transports(const char *name) +{ - DeviceState *dev; - BusState *bus; ++ VirtIOTransportLink *trl; + uint32_t i = 0; - char *buf; - int len; - - if (child_bus) { - len = strlen(child_bus) + 1; - buf = g_malloc(len); - snprintf(buf, len, "%s.", child_bus); - len = strlen(buf); - QTAILQ_FOREACH(dev, &parent_bus->children, sibling) { - QLIST_FOREACH(bus, &dev->child_bus, sibling) { - if (strncmp(buf, bus->name, len) == 0) { - i++; - } - } - } + - } else { - QTAILQ_FOREACH(dev, &parent_bus->children, sibling) { ++ QTAILQ_FOREACH(trl, &transport_links, sibling) { ++ if (name == NULL) { + i++; ++ continue; + } - } + ++ if (trl->tr->id != NULL) { ++ if (!strncmp(name, trl->tr->id,strlen(name))) { ++ i++; ++ } ++ } ++ } + return i; +} + +/* - * Get transport device which does not have a child. ++ * Initialize new transport device + */ - DeviceState* virtio_get_free_transport(BusState *parent_bus, - const char *child_bus) ++char* virtio_init_transport(DeviceState *dev, VirtIOTransportLink **trl, ++ const char* name, virtio_backend_init_cb cb) +{ - DeviceState *dev; - BusState *bus; ++ VirtIOTransportLink *link = g_malloc0(sizeof(VirtIOTransportLink)); ++ char *buf; ++ size_t len; ++ uint32_t i; + - assert(child_bus != NULL); ++ assert(dev != NULL); ++ assert(name != NULL); ++ assert(trl != NULL); + - QTAILQ_FOREACH(dev, &parent_bus->children, sibling) { - QLIST_FOREACH(bus, &dev->child_bus, sibling) { - if (strncmp(child_bus, bus->name, strlen(child_bus)) == 0) { - if (!virtio_count_siblings(bus, NULL)) { - return dev; - } - } ++ i = virtio_count_transports(name); ++ len = strlen(name) + 16; ++ buf = g_malloc(len); ++ snprintf(buf, len, "%s.%d", name, i); ++ qbus_create(TYPE_VIRTIO_BUS, dev, buf); ++ ++ /* Add new transport */ ++ QTAILQ_INSERT_TAIL(&transport_links, link, sibling); ++ link->tr = dev; ++ link->cb = cb; ++ // TODO: Add a link property ++ *trl = link; ++ return buf; ++} ++ ++/* ++ * Unplug back-end from system bus and plug it into transport bus. ++ */ ++void virtio_plug_into_transport(DeviceState *dev, VirtIOTransportLink *trl) ++{ ++ BusChild *kid; ++ ++ /* Unplug back-end from system bus */ ++ QTAILQ_FOREACH(kid, &qdev_get_parent_bus(dev)->children, sibling) { ++ if (kid->child == dev) { ++ QTAILQ_REMOVE(&qdev_get_parent_bus(dev)->children, kid, sibling); ++ break; + } + } + - return NULL; ++ /* Plug back-end into transport's bus */ ++ qdev_set_parent_bus(dev, QLIST_FIRST(&trl->tr->child_bus)); ++ ++} ++ ++/* ++ * Execute call-back on back-end initialization. ++ * Performs initialization of MMIO or PCI transport. ++ */ ++int virtio_call_backend_init_cb(DeviceState *dev, VirtIOTransportLink *trl, ++ VirtIODevice *vdev) ++{ ++ if (trl->cb) { ++ return trl->cb(dev, vdev, trl); ++ } ++ ++ return 0; ++} ++ ++static const TypeInfo virtio_bus_info = { ++ .name = TYPE_VIRTIO_BUS, ++ .parent = TYPE_BUS, ++ .instance_size = sizeof(BusState), ++}; ++ ++static void virtio_register_types(void) ++{ ++ type_register_static(&virtio_bus_info); +} ++ ++type_init(virtio_register_types) diff --cc hw/virtio-transport.h index e41a2fa,0000000..43200dc mode 100644,000000..100644 --- a/hw/virtio-transport.h +++ b/hw/virtio-transport.h @@@ -1,47 -1,0 +1,74 @@@ +/* + * Virtio transport header + * + * Copyright (c) 2011 - 2012 Samsung Electronics Co., Ltd. + * + * Author: + * Evgeny Voevodin + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License; either version 2 + * of the License, or (at your option) any later version. + * + * 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. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, see . + */ + +#ifndef VIRTIO_TRANSPORT_H_ +#define VIRTIO_TRANSPORT_H_ + - #include "sysbus.h" - #include "virtio.h" ++#include "qdev.h" ++#include "qemu-common.h" + - #define VIRTIO_MMIO_TRANSPORT "virtio-mmio-transport" ++#define VIRTIO_MMIO "virtio-mmio" ++#define VIRTIO_PCI "virtio-pci" + - extern struct BusInfo virtio_transport_bus_info; ++#define TYPE_VIRTIO_BUS "virtio-bus" ++#define VIRTIO_BUS(obj) OBJECT_CHECK(virtio_bus, (obj), TYPE_VIRTIO_BUS) + - typedef int (*virtio_init_transport_fn)(DeviceState *dev, VirtIODevice *vdev); ++struct VirtIOTransportLink; + - typedef struct VirtIOTransportBusState { - BusState bus; - virtio_init_transport_fn init_fn; - } VirtIOTransportBusState; ++typedef int (*virtio_backend_init_cb)(DeviceState *dev, VirtIODevice *vdev, ++ struct VirtIOTransportLink *trl); ++ ++typedef struct VirtIOTransportLink { ++ DeviceState *tr; ++ virtio_backend_init_cb cb; ++ uint32_t host_features; ++ QTAILQ_ENTRY(VirtIOTransportLink) sibling; ++} VirtIOTransportLink; ++ ++/* ++ * Find transport device by its ID. ++ */ ++VirtIOTransportLink* virtio_find_transport(const char *name); ++ ++/* ++ * Count transport devices by ID. ++ */ ++uint32_t virtio_count_transports(const char *name); ++ ++/* ++ * Initialize new transport device ++ */ ++char* virtio_init_transport(DeviceState *dev, VirtIOTransportLink **trl, ++ const char* name, virtio_backend_init_cb cb); ++ ++/* ++ * Unplug back-end from system bus and plug it into transport bus. ++ */ ++void virtio_plug_into_transport(DeviceState *dev, VirtIOTransportLink *trl); + - int virtio_init_transport(DeviceState *dev, VirtIODevice *vdev); - uint32_t virtio_count_siblings(BusState *parent_bus, const char *child_bus); +/* - * Get transport device which does not have a child. ++ * Execute call-back on back-end initialization. ++ * Performs initialization of MMIO or PCI transport. + */ - DeviceState* virtio_get_free_transport(BusState *parent_bus, - const char *child_bus); ++int virtio_call_backend_init_cb(DeviceState *dev, VirtIOTransportLink *trl, ++ VirtIODevice *vdev); + +#endif /* VIRTIO_TRANSPORT_H_ */ diff --cc hw/yagl_device.c index 6ab3476,0000000..a1723e7 mode 100644,000000..100644 --- a/hw/yagl_device.c +++ b/hw/yagl_device.c @@@ -1,313 -1,0 +1,311 @@@ +#include "yagl_server.h" +#include "yagl_log.h" +#include "yagl_handle_gen.h" +#include "yagl_marshal.h" +#include "yagl_stats.h" +#include "cpu-all.h" +#include "hw.h" +#include "pci.h" + +#define PCI_VENDOR_ID_YAGL 0x19B1 +#define PCI_DEVICE_ID_YAGL 0x1010 + +#define YAGL_REG_BUFFPTR 0 +#define YAGL_REG_TRIGGER 4 +#define YAGL_REGS_SIZE 8 + +#define YAGL_MEM_SIZE 0x1000 + +#define YAGL_MAX_USERS (YAGL_MEM_SIZE / YAGL_REGS_SIZE) + +struct yagl_user +{ + uint8_t *buff; + yagl_pid process_id; + yagl_tid thread_id; +}; + +typedef struct YaGLState +{ + PCIDevice dev; + MemoryRegion iomem; + struct yagl_server_state *ss; + struct yagl_user users[YAGL_MAX_USERS]; + + /* + * YAGL_MARSHAL_MAX_RESPONSE byte buffer to hold the response. + */ + uint8_t *in_buff; +} YaGLState; + +#define TYPE_YAGL_DEVICE "yagl" + +static void yagl_device_operate(YaGLState *s, + int user_index, + target_phys_addr_t buff_pa) +{ + yagl_pid target_pid; + yagl_tid target_tid; + target_phys_addr_t buff_len = YAGL_MARSHAL_SIZE; + uint8_t *buff = NULL, *tmp = NULL; + + YAGL_LOG_FUNC_ENTER_NPT(yagl_device_operate, + "user_index = %d, buff_ptr = 0x%X", + user_index, + (uint32_t)buff_pa); + + if (buff_pa && s->users[user_index].buff) { + YAGL_LOG_CRITICAL("user %d is already activated", user_index); + goto out; + } + + if (!buff_pa && !s->users[user_index].buff) { + YAGL_LOG_CRITICAL("user %d is not activated", user_index); + goto out; + } + + if (buff_pa) { + /* + * Activate user. + */ + + buff = cpu_physical_memory_map(buff_pa, &buff_len, false); + + if (!buff || (buff_len != YAGL_MARSHAL_SIZE)) { + YAGL_LOG_CRITICAL("cpu_physical_memory_map(read) failed for user %d, buff_ptr = 0x%X", + user_index, + (uint32_t)buff_pa); + goto out; + } + + tmp = buff; + + yagl_marshal_skip(&tmp); + + target_pid = yagl_marshal_get_pid(&tmp); + target_tid = yagl_marshal_get_tid(&tmp); + + YAGL_LOG_TRACE("pid = %u, tid = %u", target_pid, target_tid); + + if (!target_pid || !target_tid) { + YAGL_LOG_CRITICAL( + "target-host protocol error, zero pid or tid from target"); + goto out; + } + + if (yagl_server_dispatch_init(s->ss, + target_pid, + target_tid, + buff, + s->in_buff)) { + + memcpy(buff, s->in_buff, YAGL_MARSHAL_MAX_RESPONSE); + + s->users[user_index].buff = buff; + s->users[user_index].process_id = target_pid; + s->users[user_index].thread_id = target_tid; + + buff = NULL; + + YAGL_LOG_INFO("user %d activated", user_index); + } + } else { + /* + * Deactivate user. + */ + + yagl_server_dispatch_exit(s->ss, + s->users[user_index].process_id, + s->users[user_index].thread_id); + + cpu_physical_memory_unmap(s->users[user_index].buff, + YAGL_MARSHAL_SIZE, + 0, + YAGL_MARSHAL_SIZE); + + memset(&s->users[user_index], 0, sizeof(s->users[user_index])); + + YAGL_LOG_INFO("user %d deactivated", user_index); + } + +out: + if (buff) { + cpu_physical_memory_unmap(buff, + YAGL_MARSHAL_SIZE, + 0, + YAGL_MARSHAL_SIZE); + } + + YAGL_LOG_FUNC_EXIT(NULL); +} + +static void yagl_device_trigger(YaGLState *s, int user_index) +{ + YAGL_LOG_FUNC_ENTER_NPT(yagl_device_trigger, "%d", user_index); + + if (!s->users[user_index].buff) { + YAGL_LOG_CRITICAL("user %d not activated", user_index); + goto out; + } + + yagl_server_dispatch(s->ss, + s->users[user_index].process_id, + s->users[user_index].thread_id, + s->users[user_index].buff, + s->in_buff); + + memcpy(s->users[user_index].buff, s->in_buff, YAGL_MARSHAL_MAX_RESPONSE); + +out: + YAGL_LOG_FUNC_EXIT(NULL); +} + +static uint64_t yagl_device_read(void *opaque, target_phys_addr_t offset, + unsigned size) +{ + return 0; +} + +static void yagl_device_write(void *opaque, target_phys_addr_t offset, + uint64_t value, unsigned size) +{ + YaGLState *s = (YaGLState*)opaque; + int user_index = (offset / YAGL_REGS_SIZE); + offset -= user_index * YAGL_REGS_SIZE; + + assert(user_index < YAGL_MAX_USERS); + + if (user_index >= YAGL_MAX_USERS) { + YAGL_LOG_CRITICAL("bad user index = %d", user_index); + return; + } + + switch (offset) { + case YAGL_REG_BUFFPTR: + yagl_device_operate(s, user_index, value); + break; + case YAGL_REG_TRIGGER: + yagl_device_trigger(s, user_index); + break; + default: + YAGL_LOG_CRITICAL("user %d, bad offset = %d", user_index, offset); + break; + } +} + +static const MemoryRegionOps yagl_device_ops = +{ + .read = yagl_device_read, + .write = yagl_device_write, + .endianness = DEVICE_NATIVE_ENDIAN, +}; + +static int yagl_device_init(PCIDevice *dev) +{ + YaGLState *s = DO_UPCAST(YaGLState, dev, dev); + + yagl_log_init(); + + YAGL_LOG_FUNC_ENTER_NPT(yagl_device_init, NULL); + + memory_region_init_io(&s->iomem, + &yagl_device_ops, + s, + TYPE_YAGL_DEVICE, + YAGL_MEM_SIZE); + + yagl_handle_gen_init(); + + yagl_stats_init(); + + s->ss = yagl_server_state_create(); + + if (!s->ss) { + yagl_stats_cleanup(); + + yagl_handle_gen_cleanup(); + + YAGL_LOG_FUNC_EXIT(NULL); + + yagl_log_cleanup(); + + return -1; + } + + s->in_buff = g_malloc(YAGL_MARSHAL_MAX_RESPONSE); + + pci_register_bar(&s->dev, 0, PCI_BASE_ADDRESS_SPACE_MEMORY, &s->iomem); + + YAGL_LOG_FUNC_EXIT(NULL); + + return 0; +} + +static void yagl_device_reset(DeviceState *d) +{ + YaGLState *s = container_of(d, YaGLState, dev.qdev); + int i; + + YAGL_LOG_FUNC_ENTER_NPT(yagl_device_reset, NULL); + + yagl_server_reset(s->ss); + + yagl_handle_gen_reset(); + + for (i = 0; i < YAGL_MAX_USERS; ++i) { + memset(&s->users[i], 0, sizeof(s->users[i])); + } + + YAGL_LOG_FUNC_EXIT(NULL); +} + - static int yagl_device_exit(PCIDevice *dev) ++static void yagl_device_exit(PCIDevice *dev) +{ + YaGLState *s = DO_UPCAST(YaGLState, dev, dev); + + YAGL_LOG_FUNC_ENTER_NPT(yagl_device_exit, NULL); + + memory_region_destroy(&s->iomem); + + g_free(s->in_buff); + s->in_buff = NULL; + + yagl_server_state_destroy(s->ss); + + yagl_stats_cleanup(); + + yagl_handle_gen_cleanup(); + + YAGL_LOG_FUNC_EXIT(NULL); + + yagl_log_cleanup(); - - return 0; +} + +static void yagl_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); + + k->init = yagl_device_init; + k->exit = yagl_device_exit; + k->vendor_id = PCI_VENDOR_ID_YAGL; + k->device_id = PCI_DEVICE_ID_YAGL; + k->class_id = PCI_CLASS_OTHERS; + dc->reset = yagl_device_reset; + dc->desc = "YaGL device"; +} + +static TypeInfo yagl_device_info = +{ + .name = TYPE_YAGL_DEVICE, + .parent = TYPE_PCI_DEVICE, + .instance_size = sizeof(YaGLState), + .class_init = yagl_class_init, +}; + +static void yagl_register_types(void) +{ + type_register_static(&yagl_device_info); +} + +type_init(yagl_register_types) diff --cc target-arm/helper.c index cb0d72c,dceaa95..4193bdf --- a/target-arm/helper.c +++ b/target-arm/helper.c @@@ -965,17 -2424,32 +2424,40 @@@ static int get_phys_addr_mpu(CPUARMStat return 0; } + /* get_phys_addr - get the physical address for this virtual address + * + * Find the physical address corresponding to the given virtual address, + * by doing a translation table walk on MMU based systems or using the + * MPU state on MPU based systems. + * + * Returns 0 if the translation was successful. Otherwise, phys_ptr, + * prot and page_size are not filled in, and the return value provides + * information on why the translation aborted, in the format of a + * DFSR/IFSR fault register, with the following caveats: + * * we honour the short vs long DFSR format differences. + * * the WnR bit is never set (the caller must do this). + * * for MPU based systems we don't bother to return a full FSR format + * value. + * + * @env: CPUARMState + * @address: virtual address to get physical address for + * @access_type: 0 for read, 1 for write, 2 for execute + * @is_user: 0 for privileged access, 1 for user + * @phys_ptr: set to the physical address corresponding to the virtual address + * @prot: set to the permissions for the page containing phys_ptr + * @page_size: set to the size of the page containing phys_ptr + */ -static inline int get_phys_addr(CPUARMState *env, uint32_t address, +#ifdef CONFIG_BUILD_GLES +int get_phys_addr(CPUARMState *env, uint32_t address, + int access_type, int is_user, - uint32_t *phys_ptr, int *prot, ++ target_phys_addr_t *phys_ptr, int *prot, + target_ulong *page_size); +#else +static inline +#endif +int get_phys_addr(CPUARMState *env, uint32_t address, int access_type, int is_user, - uint32_t *phys_ptr, int *prot, + target_phys_addr_t *phys_ptr, int *prot, target_ulong *page_size) { /* Fast Context Switch Extension. */ diff --cc tizen/emulator_configure.sh index a98eabd,0000000..46e7cc4 mode 100755,000000..100755 --- a/tizen/emulator_configure.sh +++ b/tizen/emulator_configure.sh @@@ -1,76 -1,0 +1,76 @@@ +#!/bin/sh +# OS specific +targetos=`uname -s` +targetarch=`echo | gcc -E -dM - | grep __x86_64` +bindir="i386" +ffmpegarc="x86" +if test "$targetarch" != "" +then + bindir="x86_64" + ffmpegarc="x86_64" +fi + +echo "##### checking for os... targetos $targetos" + +case $targetos in +Linux*) +cd distrib/libav +echo "" +echo "##### FFMPEG configure for emulator" +./configure \ + --prefix=./$bindir --arch=${ffmpegarc} --enable-static --enable-pic --enable-optimizations --disable-doc --disable-gpl --disable-yasm --disable-postproc --disable-swscale --disable-ffmpeg --disable-ffprobe --disable-ffserver --disable-ffplay --disable-decoders --disable-encoders --disable-muxers --disable-demuxers --disable-parsers --disable-protocols --disable-network --disable-bsfs --disable-devices --disable-filters --enable-encoder=h263 --enable-encoder=h263p --enable-encoder=mpeg4 --enable-encoder=msmpeg4v2 --enable-encoder=msmpeg4v3 --enable-decoder=aac --enable-decoder=h263 --enable-decoder=h264 --enable-decoder=mp3 --enable-decoder=mp3adu --enable-decoder=mpeg4 --enable-decoder=mpegvideo --enable-decoder=msmpeg4v1 --enable-decoder=msmpeg4v2 --enable-decoder=msmpeg4v3 --enable-decoder=wmav1 --enable-decoder=wmav2 --enable-decoder=wmv3 --enable-decoder=vc1 +cd ../.. + +cd .. + +echo "" +echo "##### QEMU configure for emulator" +exec ./configure \ + --disable-werror \ + --audio-drv-list=alsa \ + --audio-card-list=ac97 \ - --enable-ldst-optimization \ + --enable-maru \ + --disable-vnc \ + --disable-pie $1 ++ # --enable-ldst-optimization \ +;; +MINGW*) +cd distrib/libav +echo "" +echo "##### FFMPEG configure for emulator" +./configure \ + --prefix=./$bindir --arch=x86 --enable-static --enable-w32threads --enable-optimizations --enable-memalign-hack --disable-doc --disable-gpl --disable-yasm --disable-postproc --disable-swscale --disable-ffmpeg --disable-ffprobe --disable-ffserver --disable-ffplay --disable-decoders --disable-encoders --disable-muxers --disable-demuxers --disable-parsers --disable-protocols --disable-network --disable-bsfs --disable-devices --disable-filters --enable-encoder=h263 --enable-encoder=h263p --enable-encoder=mpeg4 --enable-encoder=msmpeg4v2 --enable-encoder=msmpeg4v3 --enable-decoder=aac --enable-decoder=h263 --enable-decoder=h264 --enable-decoder=mp3 --enable-decoder=mp3adu --enable-decoder=mpeg4 --enable-decoder=mpegvideo --enable-decoder=msmpeg4v1 --enable-decoder=msmpeg4v2 --enable-decoder=msmpeg4v3 --enable-decoder=wmav1 --enable-decoder=wmav2 --enable-decoder=wmv3 --enable-decoder=vc1 +cd ../.. + +cd .. +echo "" +echo "##### QEMU configure for emulator" +exec ./configure \ + --audio-drv-list=winwave \ + --audio-card-list=ac97 \ - --enable-ldst-optimization \ + --enable-hax \ + --enable-maru \ + --disable-vnc $1 ++ # --enable-ldst-optimization \ +;; +Darwin*) +cd distrib/libav +echo "" +echo "##### FFMPEG configure for emulator" +./configure \ +--prefix=./$bindir --arch=x86 --enable-static --enable-pic --enable-optimizations --disable-doc --disable-gpl --disable-yasm --disable-postproc --disable-swscale --disable-ffmpeg --disable-ffprobe --disable-ffserver --disable-ffplay --disable-decoders --disable-encoders --disable-muxers --disable-demuxers --disable-parsers --disable-protocols --disable-network --disable-bsfs --disable-devices --disable-filters --enable-encoder=h263 --enable-encoder=h263p --enable-encoder=mpeg4 --enable-encoder=msmpeg4v2 --enable-encoder=msmpeg4v3 --enable-decoder=aac --enable-decoder=h263 --enable-decoder=h264 --enable-decoder=mp3 --enable-decoder=mp3adu --enable-decoder=mpeg4 --enable-decoder=mpegvideo --enable-decoder=msmpeg4v1 --enable-decoder=msmpeg4v2 --enable-decoder=msmpeg4v3 --enable-decoder=wmav1 --enable-decoder=wmav2 --enable-decoder=wmv3 --enable-decoder=vc1 --cc=cc +cd ../.. + +cd .. +echo "" +echo "##### QEMU configure for emulator" +./configure \ + --audio-drv-list=coreaudio \ + --enable-mixemu \ + --audio-card-list=ac97 \ + --enable-maru \ + --enable-hax \ + --disable-vnc \ + --disable-sdl $1 +;; +esac diff --cc tizen/src/Makefile.tizen index 6c69d10,0000000..e66e9c8 mode 100755,000000..100755 --- a/tizen/src/Makefile.tizen +++ b/tizen/src/Makefile.tizen @@@ -1,145 -1,0 +1,139 @@@ +# Makefile.tizen +# for TIZEN-maru board + + +$(call set-vpath, $(SRC_PATH):$(TARGET_PATH):$(SRC_PATH)/hw:$(SRC_PATH)/tizen/src:$(SRC_PATH)/tizen/src/hw:$(SRC_PATH)/tizen/src/skin) + +QEMU_CFLAGS += -I$(SRC_PATH)/hw -I$(SRC_PATH)/tizen/src +QEMU_CFLAGS += -I$(SRC_PATH)/tizen/distrib/libav/$(ARCH)/include +QEMU_CFLAGS += -L$(SRC_PATH)/tizen/distrib/libav/$(ARCH)/lib +QEMU_CFLAGS += $(SDL_CFLAGS) +QEMU_CFLAGS += $(GLIB_CFLAGS) +ifdef CONFIG_DARWIN +QEMU_CFLAGS += -framework Foundation -framework SystemConfiguration +endif +ifndef CONFIG_DEBUG_EXEC +CFLAGS += -g -O2 +else +CFLAGS += -g -O0 +endif + +ifdef CONFIG_WIN32 +LIBS += -lavformat -lavcodec -lavutil -lm -lcurl -lopengl32 -lglu32 -lgdi32 +endif +ifdef CONFIG_LINUX +LIBS += -lavformat -lavcodec -lavutil -lm -lcurl -lGL -lXcomposite -lXext +endif +ifdef CONFIG_DARWIN +# FIXME: disabled codec on Mac now +# LIBS += -lavformat -lavcodec -lavutil -lm +endif + +ifdef CONFIG_DEBUG_EXEC +GL_CFLAGS := -Wall -g -O0 -fno-strict-aliasing +else +GL_CFLAGS := -Wall -g -O2 -fno-strict-aliasing +endif + +ifndef CONFIG_DARWIN +########################################################### +## Build openGL +# i386 +ifdef CONFIG_GL + +GL_CUR_PATH = $(SRC_PATH)/tizen/src/hw + +GL_CFLAGS += -I$(GL_CUR_PATH) -I$(SRC_PATH)/fpu +GL_CFLAGS += -I$(SRC_PATH)/i386-softmmu $(QEMU_CFLAGS) $(CFLAGS) + +parse_gl_h: parse_gl_h.c + $(CC) -g -o $@ $< +server_stub.c: parse_gl_h + ./parse_gl_h 2>/dev/null +gl_func.h: parse_gl_h + ./parse_gl_h 2>/dev/null +opengl_func.h: gl_func.h +helper_opengl.o: helper_opengl.c opengl_func.h server_stub.c opengl_process.h + $(CC) $(GL_CFLAGS) $(DEFINES) $(GL_LDFLAGS) -c -o $@ $< +gl_beginend.h: $(GL_CUR_PATH)/beginend_funcs.sh + $< > $@ +mesa_mipmap.o : mesa_mipmap.c + $(CC) $(GL_CFLAGS) $(DEFINES) $(GL_LDFLAGS) -c -o $@ $< +opengl_exec.o : opengl_exec.c server_stub.c opengl_func.h gl_beginend.h opengl_process.h mesa_mipmap.o + $(CC) $(GL_CFLAGS) $(DEFINES) $(GL_LDFLAGS) -c -o $@ $< + +endif #CONFIG_GL + +ifdef CONFIG_OPENGLES + +parse_gl_h: parse_gl_h.c + $(CC) -g -o $@ $< + +gl_mangled.h: parse_gl_h + ./parse_gl_h mangle 2>/dev/null + +gl_mangled.c: gl_mangled.h + ./parse_gl_h mangle 2>/dev/null + +gloffscreen_glx.o gloffscreen_wgl.o gloffscreen_xcomposite.o: gl_mangled.h +maru_sdl.o gloffscreen_test.o gloffscreen_common.o: gl_mangled.h + +obj-y += gl_mangled.o + +endif #CONFIG_OPENGLES +########################################################### +endif #!CONFIG_DARWIN + +# maru loader +obj-y += emulator.o emul_state.o option.o maru_err_table.o + +# maru display +obj-y += maru_display.o maru_shm.o +ifndef CONFIG_DARWIN +obj-y += maru_sdl.o SDL_rotozoom.o maru_finger.o +endif + +# sdb +obj-y += sdb.o + +# mloop event +obj-y += mloop_event.o + +# debug channel +obj-y += debug_ch.o + +# maru hardware - obj-i386-y += maru_board.o - obj-i386-y += maru_overlay.o - obj-i386-y += maru_pm.o - obj-i386-y += maru_vga.o - obj-arm-y += maru_arm_soc.o - obj-arm-y += maru_arm_board.o - obj-arm-y += maru_arm_vpci.o - obj-arm-y += maru_arm_pmu.o ++include $(SRC_PATH)/tizen/src/Makefile.tizen.$(TARGET_BASE_ARCH) ++ +obj-y += maru_brightness.o +obj-y += maru_usb_touchscreen.o maru_virtio_touchscreen.o +ifndef CONFIG_DARWIN +obj-y += maru_codec.o +obj-$(CONFIG_PCI) += maru_camera_common_pci.o +obj-$(CONFIG_LINUX) += maru_camera_linux_pci.o +obj-$(CONFIG_WIN32) += maru_camera_win32_pci.o +endif + +ifdef CONFIG_LINUX # libs for maru camera on linux host +LIBS += -lv4l2 -lv4lconvert +endif + +ifdef CONFIG_WIN32 # libs for maru camera on windows host +LIBS += -lole32 -loleaut32 -luuid -lstrmiids +endif + +# maru skin +obj-y += maruskin_client.o maruskin_server.o maruskin_operation.o maruskin_keymap.o + +# guest server +obj-y += guest_server.o + +ifndef CONFIG_DARWIN +########################################################### +## opengl library for i386 +obj-$(CONFIG_GL) += virtio-gl.o +obj-$(CONFIG_GL) += helper_opengl.o opengl_exec.o mesa_mipmap.o gloffscreen_wgl.o +obj-$(CONFIG_NO_GL) += virtio-gl-stub.o +obj-y += gloffscreen_test.o gloffscreen_xcomposite.o gloffscreen_common.o +########################################################### +endif diff --cc tizen/src/Makefile.tizen.arm index 0000000,0000000..c5c0172 new file mode 100755 --- /dev/null +++ b/tizen/src/Makefile.tizen.arm @@@ -1,0 -1,0 +1,7 @@@ ++# Makefile.tizen ++# for TIZEN-maru board ++ ++obj-y += maru_arm_soc.o ++obj-y += maru_arm_board.o ++obj-y += maru_arm_vpci.o ++obj-y += maru_arm_pmu.o diff --cc tizen/src/Makefile.tizen.i386 index 0000000,0000000..c599b0f new file mode 100755 --- /dev/null +++ b/tizen/src/Makefile.tizen.i386 @@@ -1,0 -1,0 +1,7 @@@ ++# Makefile.tizen ++# for TIZEN-maru-x86 board ++ ++obj-y += maru_board.o ++obj-y += maru_overlay.o ++obj-y += maru_pm.o ++obj-y += maru_vga.o diff --cc tizen/src/hw/maru_arm.h index 8651fc3,0000000..6fa1a9d mode 100644,000000..100644 --- a/tizen/src/hw/maru_arm.h +++ b/tizen/src/hw/maru_arm.h @@@ -1,38 -1,0 +1,38 @@@ +/* + * Samsung Maru ARM SoC emulation + * + * Copyright (c) 2012 Samsung Electronics Co., Ltd. + * Evgeny Voevodin + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * 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. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, see . + * + */ + +#ifndef MARU_ARM_H_ +#define MARU_ARM_H_ + +#include "qemu-common.h" +#include "memory.h" +#include "exynos4210.h" + - void maru_arm_write_secondary(CPUARMState *env, ++void maru_arm_write_secondary(ARMCPU *cpu, + const struct arm_boot_info *info); + +Exynos4210State *maru_arm_soc_init(MemoryRegion *system_mem, + unsigned long ram_size); + +int codec_init(PCIBus *bus); +int maru_camera_pci_init(PCIBus *bus); + +#endif /* MARU_ARM_H_ */ diff --cc tizen/src/hw/maru_arm_board.c index c4c656f,0000000..32953f6 mode 100644,000000..100644 --- a/tizen/src/hw/maru_arm_board.c +++ b/tizen/src/hw/maru_arm_board.c @@@ -1,138 -1,0 +1,138 @@@ +/* + * TIZEN ARM base board + * + * Copyright (c) 2011 - 2012 Samsung Electronics Co., Ltd. + * + * Based on maru_board.c, exynos4210.c and exynos4210_boards.c + * + * Author: + * Evgeny Voevodin + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License; either version 2 + * of the License, or (at your option) any later version. + * + * 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. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, see . + */ + +#include + +#include "boards.h" +#include "arm-misc.h" +#include "sysbus.h" +#include "pci.h" +#include "maru_arm.h" +#include "i2c.h" +#include "exec-memory.h" +#include "../tizen/src/hw/maru_brightness.h" +#include "arch_init.h" + +#undef DEBUG +//#define DEBUG +#ifdef DEBUG + #undef PRINT_DEBUG + #define PRINT_DEBUG(fmt, args...) \ + do { \ + fprintf(stderr, " [%s:%d] "fmt, __func__, __LINE__, ##args); \ + } while (0) +#else + #define PRINT_DEBUG(fmt, args...) do {} while (0) +#endif + +#ifndef DEBUG_LOG_PATH +#define DEBUG_LOG_PATH "./debug.log" +#endif + +#define EXYNOS4210_WM8994_ADDR 0x1A +#define MARU_ARM_BOARD_ID 0xF3B +#define MARU_ARM_BOARD_SMP_BOOTREG_ADDR EXYNOS4210_SECOND_CPU_BOOTREG +#define MARU_ARM_BOARD_RAMSIZE_MIN 0x20000000 +#define MARU_ARM_BOARD_RAMSIZE_DEFAULT 0x40000000 + +static struct arm_boot_info maru_arm_board_binfo = { + .loader_start = EXYNOS4210_BASE_BOOT_ADDR, + .smp_loader_start = EXYNOS4210_SMP_BOOT_ADDR, + .nb_cpus = EXYNOS4210_NCPUS, + .write_secondary_boot = maru_arm_write_secondary, +}; + +static void maru_arm_machine_init(ram_addr_t ram_size, + const char *boot_device, + const char *kernel_filename, + const char *kernel_cmdline, + const char *initrd_filename, + const char *cpu_model) +{ + Exynos4210State *s; + DeviceState *dev, *i2c_dev; + PCIBus *pci_bus; + + if (ram_size < MARU_ARM_BOARD_RAMSIZE_MIN) { + ram_size = MARU_ARM_BOARD_RAMSIZE_DEFAULT; + fprintf(stderr, "RAM size is too small, setting to default value 0x%lx", + (long unsigned int)ram_size); + } + + maru_arm_board_binfo.ram_size = ram_size; + maru_arm_board_binfo.board_id = MARU_ARM_BOARD_ID; + maru_arm_board_binfo.smp_bootreg_addr = MARU_ARM_BOARD_SMP_BOOTREG_ADDR; + maru_arm_board_binfo.kernel_filename = kernel_filename; + maru_arm_board_binfo.initrd_filename = initrd_filename; + maru_arm_board_binfo.kernel_cmdline = kernel_cmdline; + maru_arm_board_binfo.gic_cpu_if_addr = + EXYNOS4210_SMP_PRIVATE_BASE_ADDR + 0x100; + + PRINT_DEBUG("\n ram_size: %luMiB [0x%08lx]\n" + " kernel_filename: %s\n" + " kernel_cmdline: %s\n" + " initrd_filename: %s\n", + (long unsigned int)ram_size / 1048576, + (long unsigned int)ram_size, + kernel_filename, + kernel_cmdline, + initrd_filename); + s = maru_arm_soc_init(get_system_memory(), ram_size); + + /* PCI config */ + dev = qdev_create(NULL, "tizen_vpci"); + s->vpci_bus = sysbus_from_qdev(dev); + qdev_init_nofail(dev); + sysbus_mmio_map(s->vpci_bus, 0, EXYNOS4210_VPCI_CFG_BASE_ADDR); + sysbus_connect_irq(s->vpci_bus, 0, s->irq_table[exynos4210_get_irq(38, 0)]); + sysbus_connect_irq(s->vpci_bus, 1, s->irq_table[exynos4210_get_irq(38, 1)]); + sysbus_connect_irq(s->vpci_bus, 2, s->irq_table[exynos4210_get_irq(38, 2)]); + sysbus_connect_irq(s->vpci_bus, 3, s->irq_table[exynos4210_get_irq(38, 3)]); + pci_bus = (PCIBus *)qdev_get_child_bus(dev, "pci"); + + pci_create_simple(pci_bus, -1, "pci-ohci"); + maru_camera_pci_init(pci_bus); + codec_init(pci_bus); + pci_maru_brightness_init(pci_bus); +#ifdef CONFIG_YAGL + pci_create_simple(pci_bus, -1, "yagl"); +#endif + + audio_init(NULL, pci_bus); + - arm_load_kernel(first_cpu, &maru_arm_board_binfo); ++ arm_load_kernel(arm_env_get_cpu(first_cpu), &maru_arm_board_binfo); +} + +static QEMUMachine maru_arm_machine = { + .name = "maru-arm-machine", + .desc = "maru board(ARM)", + .init = maru_arm_machine_init, + .max_cpus = 255, +}; + +static void maru_machine_init(void) +{ + qemu_register_machine(&maru_arm_machine); +} + +machine_init(maru_machine_init); diff --cc tizen/src/hw/maru_arm_soc.c index b229365,0000000..61976df mode 100644,000000..100644 --- a/tizen/src/hw/maru_arm_soc.c +++ b/tizen/src/hw/maru_arm_soc.c @@@ -1,444 -1,0 +1,440 @@@ +/* + * Samsung Maru ARM SoC emulation + * + * Based on exynos4210.c + * + * Copyright (c) 2011 Samsung Electronics Co., Ltd. + * Maksim Kozlov + * Evgeny Voevodin + * Igor Mitsyanko + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * 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. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, see . + * + */ + +#include "boards.h" +#include "arm-misc.h" +#include "sysbus.h" +#include "pci.h" +#include "maru_arm.h" +#include "i2c.h" +#include "exec-memory.h" +#ifdef CONFIG_BUILD_GLES +#include "gles2.h" +#endif + +#include "loader.h" +#include "virtio-transport.h" +#include "exynos4210_i2s.h" + +#define EXYNOS4210_CHIPID_ADDR 0x10000000 + +/* CMUs */ +#define EXYNOS4210_CMU_LEFTBUS_BASE_ADDR 0x10034000 +#define EXYNOS4210_CMU_RIGHTBUS_BASE_ADDR 0x10038000 +#define EXYNOS4210_CMU_TOP_BASE_ADDR 0x1003C000 +#define EXYNOS4210_CMU_DMC_BASE_ADDR 0x10040000 +#define EXYNOS4210_CMU_CPU_BASE_ADDR 0x10044000 + +/* PWM */ +#define EXYNOS4210_PWM_BASE_ADDR 0x139D0000 + +/* RTC */ +#define EXYNOS4210_RTC_BASE_ADDR 0x10070000 + +/* MCT */ +#define EXYNOS4210_MCT_BASE_ADDR 0x10050000 + +/* DMA */ +#define EXYNOS4210_DMAMEM_BASE_ADDR 0x12840000 +#define EXYNOS4210_DMAPERI0_BASE_ADDR 0x12680000 +#define EXYNOS4210_DMAPERI1_BASE_ADDR 0x12690000 + +/* I2C */ +#define EXYNOS4210_I2C_SHIFT 0x00010000 +#define EXYNOS4210_I2C_BASE_ADDR 0x13860000 +/* Interrupt Group of External Interrupt Combiner for I2C */ +#define EXYNOS4210_I2C_INTG 27 +#define EXYNOS4210_HDMI_INTG 16 + +/* There are two set of touch screen interfaces, which share one ADC */ +#define EXYNOS4210_TS0_BASE_ADDR 0x13910000 +#define EXYNOS4210_TS1_BASE_ADDR 0x13911000 +#define EXYNOS4210_TS_INTG 19 + +/* UART's definitions */ +#define EXYNOS4210_UART0_BASE_ADDR 0x13800000 +#define EXYNOS4210_UART1_BASE_ADDR 0x13810000 +#define EXYNOS4210_UART2_BASE_ADDR 0x13820000 +#define EXYNOS4210_UART3_BASE_ADDR 0x13830000 +#define EXYNOS4210_UART0_FIFO_SIZE 256 +#define EXYNOS4210_UART1_FIFO_SIZE 64 +#define EXYNOS4210_UART2_FIFO_SIZE 16 +#define EXYNOS4210_UART3_FIFO_SIZE 16 +/* Interrupt Group of External Interrupt Combiner for UART */ +#define EXYNOS4210_UART_INT_GRP 26 + +/* External GIC */ +#define EXYNOS4210_EXT_GIC_CPU_BASE_ADDR 0x10480000 +#define EXYNOS4210_EXT_GIC_DIST_BASE_ADDR 0x10490000 + +/* Combiner */ +#define EXYNOS4210_EXT_COMBINER_BASE_ADDR 0x10440000 +#define EXYNOS4210_INT_COMBINER_BASE_ADDR 0x10448000 + +/* SD/MMC host controllers SFR base addresses */ +#define EXYNOS4210_SDHC0_BASE_ADDR 0x12510000 +#define EXYNOS4210_SDHC1_BASE_ADDR 0x12520000 +#define EXYNOS4210_SDHC2_BASE_ADDR 0x12530000 +#define EXYNOS4210_SDHC3_BASE_ADDR 0x12540000 + +/* PMU SFR base address */ +#define EXYNOS4210_PMU_BASE_ADDR 0x10020000 + +/* Display controllers (FIMD) */ +#define EXYNOS4210_FIMD0_BASE_ADDR 0x11C00000 +#define EXYNOS4210_FIMD1_BASE_ADDR 0x12000000 + +/* MALI400 (G3D) */ +#define EXYNOS4210_G3D_BASE_ADDR 0x13000000 +#define EXYNOS4210_G3D_PIXEL_PROC_0_IRQ 0 +#define EXYNOS4210_G3D_PIXEL_PROC_1_IRQ 1 +#define EXYNOS4210_G3D_PIXEL_PROC_2_IRQ 2 +#define EXYNOS4210_G3D_PIXEL_PROC_3_IRQ 3 +#define EXYNOS4210_G3D_GEOM_PROC_IRQ 4 +#define EXYNOS4210_G3D_PMU_IRQ 5 +#define EXYNOS4210_G3D_PPMMU0_IRQ 0 +#define EXYNOS4210_G3D_PPMMU1_IRQ 1 +#define EXYNOS4210_G3D_PPMMU2_IRQ 2 +#define EXYNOS4210_G3D_PPMMU3_IRQ 3 +#define EXYNOS4210_G3D_GPMMU_IRQ 4 + +/* PPMU */ +#define EXYNOS4210_PPMU_CPU_BASE_ADDR 0x106C0000 +/* DMC */ +#define EXYNOS4210_DMC0_BASE_ADDR 0x10400000 +#define EXYNOS4210_DMC1_BASE_ADDR 0x10410000 + +/* I2S */ +#define EXYNOS4210_I2S0_BASE_ADDR 0x03830000 + +/* VirtIO MMIO */ +#define EXYNOS4210_VIRTIO_MMIO0_BASE_ADDR 0x10AD0000 +#define EXYNOS4210_VIRTIO_MMIO1_BASE_ADDR 0x10AC0000 + +/* pl050 ps/2 interface */ +#define EXYNOS4210_PL050_BASE_ADDR 0x12E30000 + +static uint8_t chipid_and_omr[TARGET_PAGE_SIZE] = { 0x11, 0x02, 0x21, 0x43, + 0x09, 0x00, 0x00, 0x00 }; + - void maru_arm_write_secondary(CPUARMState *env, ++void maru_arm_write_secondary(ARMCPU *cpu, + const struct arm_boot_info *info) +{ + int n; + uint32_t smpboot[] = { + 0xe59f3024, /* ldr r3, External gic_cpu_if */ + 0xe59f2024, /* ldr r2, Internal gic_cpu_if */ + 0xe59f0024, /* ldr r0, startaddr */ + 0xe3a01001, /* mov r1, #1 */ + 0xe5821000, /* str r1, [r2] */ + 0xe5831000, /* str r1, [r3] */ + 0xe320f003, /* wfi */ + 0xe5901000, /* ldr r1, [r0] */ + 0xe1110001, /* tst r1, r1 */ + 0x0afffffb, /* beq */ + 0xe12fff11, /* bx r1 */ + EXYNOS4210_EXT_GIC_CPU_BASE_ADDR, + 0, /* gic_cpu_if: base address of Internal GIC CPU interface */ + 0 /* bootreg: Boot register address is held here */ + }; + smpboot[ARRAY_SIZE(smpboot) - 1] = info->smp_bootreg_addr; + smpboot[ARRAY_SIZE(smpboot) - 2] = info->gic_cpu_if_addr; + for (n = 0; n < ARRAY_SIZE(smpboot); n++) { + smpboot[n] = tswap32(smpboot[n]); + } + rom_add_blob_fixed("smpboot", smpboot, sizeof(smpboot), + info->smp_loader_start); +} + +Exynos4210State *maru_arm_soc_init(MemoryRegion *system_mem, + unsigned long ram_size) +{ - qemu_irq cpu_irq[4]; - int n; ++ qemu_irq cpu_irq[EXYNOS4210_NCPUS]; ++ int i, n; + Exynos4210State *s = g_new(Exynos4210State, 1); + qemu_irq *irqp; - qemu_irq gate_irq[EXYNOS4210_IRQ_GATE_NINPUTS]; ++ qemu_irq gate_irq[EXYNOS4210_NCPUS][EXYNOS4210_IRQ_GATE_NINPUTS]; + unsigned long mem_size; + DeviceState *dev; + SysBusDevice *busdev; + + for (n = 0; n < EXYNOS4210_NCPUS; n++) { - s->env[n] = cpu_init("cortex-a9"); - if (!s->env[n]) { ++ s->cpu[n] = cpu_arm_init("cortex-a9"); ++ if (!s->cpu[n]) { + fprintf(stderr, "Unable to find CPU %d definition\n", n); + exit(1); + } ++ + /* Create PIC controller for each processor instance */ - irqp = arm_pic_init_cpu(s->env[n]); ++ irqp = arm_pic_init_cpu(s->cpu[n]); + + /* + * Get GICs gpio_in cpu_irq to connect a combiner to them later. + * Use only IRQ for a while. + */ + cpu_irq[n] = irqp[ARM_PIC_CPU_IRQ]; + } + + /*** IRQs ***/ + + s->irq_table = exynos4210_init_irq(&s->irqs); + + /* IRQ Gate */ - dev = qdev_create(NULL, "exynos4210.irq_gate"); - qdev_prop_set_uint32(dev, "n_out", EXYNOS4210_NCPUS); - qdev_prop_set_uint32(dev, "n_in", EXYNOS4210_IRQ_GATE_NINPUTS); - qdev_init_nofail(dev); - /* Get IRQ Gate input in gate_irq */ - for (n = 0; n < EXYNOS4210_IRQ_GATE_NINPUTS; n++) { - gate_irq[n] = qdev_get_gpio_in(dev, n); - } - busdev = sysbus_from_qdev(dev); - /* Connect IRQ Gate output to cpu_irq */ - for (n = 0; n < EXYNOS4210_NCPUS; n++) { - sysbus_connect_irq(busdev, n, cpu_irq[n]); ++ for (i = 0; i < EXYNOS4210_NCPUS; i++) { ++ dev = qdev_create(NULL, "exynos4210.irq_gate"); ++ qdev_prop_set_uint32(dev, "n_in", EXYNOS4210_IRQ_GATE_NINPUTS); ++ qdev_init_nofail(dev); ++ /* Get IRQ Gate input in gate_irq */ ++ for (n = 0; n < EXYNOS4210_IRQ_GATE_NINPUTS; n++) { ++ gate_irq[i][n] = qdev_get_gpio_in(dev, n); ++ } ++ busdev = sysbus_from_qdev(dev); ++ ++ /* Connect IRQ Gate output to cpu_irq */ ++ sysbus_connect_irq(busdev, 0, cpu_irq[i]); + } + + /* Private memory region and Internal GIC */ + dev = qdev_create(NULL, "a9mpcore_priv"); + qdev_prop_set_uint32(dev, "num-cpu", EXYNOS4210_NCPUS); + qdev_init_nofail(dev); + busdev = sysbus_from_qdev(dev); + sysbus_mmio_map(busdev, 0, EXYNOS4210_SMP_PRIVATE_BASE_ADDR); + for (n = 0; n < EXYNOS4210_NCPUS; n++) { - sysbus_connect_irq(busdev, n, gate_irq[n * 4]); ++ sysbus_connect_irq(busdev, n, gate_irq[n][0]); + } + for (n = 0; n < EXYNOS4210_INT_GIC_NIRQ; n++) { + s->irqs.int_gic_irq[n] = qdev_get_gpio_in(dev, n); + } + + /* Cache controller */ + sysbus_create_simple("l2x0", EXYNOS4210_L2X0_BASE_ADDR, NULL); + + /* External GIC */ + dev = qdev_create(NULL, "exynos4210.gic"); + qdev_prop_set_uint32(dev, "num-cpu", EXYNOS4210_NCPUS); + qdev_init_nofail(dev); + busdev = sysbus_from_qdev(dev); + /* Map CPU interface */ + sysbus_mmio_map(busdev, 0, EXYNOS4210_EXT_GIC_CPU_BASE_ADDR); + /* Map Distributer interface */ + sysbus_mmio_map(busdev, 1, EXYNOS4210_EXT_GIC_DIST_BASE_ADDR); + for (n = 0; n < EXYNOS4210_NCPUS; n++) { - sysbus_connect_irq(busdev, n, gate_irq[n * 4 + 1]); ++ sysbus_connect_irq(busdev, n, gate_irq[n][1]); + } + for (n = 0; n < EXYNOS4210_EXT_GIC_NIRQ; n++) { + s->irqs.ext_gic_irq[n] = qdev_get_gpio_in(dev, n); + } + + /* Internal Interrupt Combiner */ + dev = qdev_create(NULL, "exynos4210.combiner"); + qdev_init_nofail(dev); + busdev = sysbus_from_qdev(dev); + for (n = 0; n < EXYNOS4210_MAX_INT_COMBINER_OUT_IRQ; n++) { + sysbus_connect_irq(busdev, n, s->irqs.int_gic_irq[n]); + } + exynos4210_combiner_get_gpioin(&s->irqs, dev, 0); + sysbus_mmio_map(busdev, 0, EXYNOS4210_INT_COMBINER_BASE_ADDR); + + /* External Interrupt Combiner */ + dev = qdev_create(NULL, "exynos4210.combiner"); + qdev_prop_set_uint32(dev, "external", 1); + qdev_init_nofail(dev); + busdev = sysbus_from_qdev(dev); + for (n = 0; n < EXYNOS4210_MAX_INT_COMBINER_OUT_IRQ; n++) { + sysbus_connect_irq(busdev, n, s->irqs.ext_gic_irq[n]); + } + exynos4210_combiner_get_gpioin(&s->irqs, dev, 1); + sysbus_mmio_map(busdev, 0, EXYNOS4210_EXT_COMBINER_BASE_ADDR); + + /* Initialize board IRQs. */ + exynos4210_init_board_irqs(&s->irqs); + + /*** Memory ***/ + + /* Chip-ID and OMR */ + memory_region_init_ram_ptr(&s->chipid_mem, "exynos4210.chipid", + sizeof(chipid_and_omr), chipid_and_omr); + memory_region_set_readonly(&s->chipid_mem, true); - vmstate_register_ram_global(&s->chipid_mem); + memory_region_add_subregion(system_mem, EXYNOS4210_CHIPID_ADDR, + &s->chipid_mem); + + /* Internal ROM */ + memory_region_init_ram(&s->irom_mem, "exynos4210.irom", + EXYNOS4210_IROM_SIZE); + memory_region_set_readonly(&s->irom_mem, true); - vmstate_register_ram_global(&s->irom_mem); + memory_region_add_subregion(system_mem, EXYNOS4210_IROM_BASE_ADDR, + &s->irom_mem); + /* mirror of iROM */ + memory_region_init_alias(&s->irom_alias_mem, "exynos4210.irom_alias", + &s->irom_mem, + 0, + EXYNOS4210_IROM_SIZE); + memory_region_set_readonly(&s->irom_alias_mem, true); + memory_region_add_subregion(system_mem, EXYNOS4210_IROM_MIRROR_BASE_ADDR, + &s->irom_alias_mem); + + /* Internal RAM */ + memory_region_init_ram(&s->iram_mem, "exynos4210.iram", + EXYNOS4210_IRAM_SIZE); + vmstate_register_ram_global(&s->iram_mem); + memory_region_add_subregion(system_mem, EXYNOS4210_IRAM_BASE_ADDR, + &s->iram_mem); + + /* DRAM */ + mem_size = ram_size; + if (mem_size > EXYNOS4210_DRAM_MAX_SIZE) { + memory_region_init_ram(&s->dram1_mem, "exynos4210.dram1", + mem_size - EXYNOS4210_DRAM_MAX_SIZE); + vmstate_register_ram_global(&s->dram1_mem); + memory_region_add_subregion(system_mem, EXYNOS4210_DRAM1_BASE_ADDR, + &s->dram1_mem); + mem_size = EXYNOS4210_DRAM_MAX_SIZE; + } + memory_region_init_ram(&s->dram0_mem, "exynos4210.dram0", mem_size); + vmstate_register_ram_global(&s->dram0_mem); + memory_region_add_subregion(system_mem, EXYNOS4210_DRAM0_BASE_ADDR, + &s->dram0_mem); + + /* Audio Subsystem Internal Memory */ + memory_region_init_ram(&s->audss_intmem, "exynos4210.audss", + EXYNOS4210_AUDSS_INTMEM_SIZE); + vmstate_register_ram_global(&s->audss_intmem); + memory_region_add_subregion(system_mem, EXYNOS4210_AUDSS_INTMEM_BASE_ADDR, + &s->audss_intmem); + - /*** Clock devices ***/ - - /* PMU. Must be initialized before CMU. - * The only reason of existence at the moment is that secondary CPU boot - * loader uses PMU INFORM5 register as a holding pen. - */ ++ /* PMU. ++ * The only reason of existence at the moment is that secondary CPU boot ++ * loader uses PMU INFORM5 register as a holding pen. ++ */ + sysbus_create_simple("maru_arm.pmu", EXYNOS4210_PMU_BASE_ADDR, NULL); + + /* CMUs */ + exynos4210_cmu_create(EXYNOS4210_CMU_LEFTBUS_BASE_ADDR, + EXYNOS4210_CMU_LEFTBUS); + exynos4210_cmu_create(EXYNOS4210_CMU_RIGHTBUS_BASE_ADDR, + EXYNOS4210_CMU_RIGHTBUS); + exynos4210_cmu_create(EXYNOS4210_CMU_TOP_BASE_ADDR, EXYNOS4210_CMU_TOP); + exynos4210_cmu_create(EXYNOS4210_CMU_DMC_BASE_ADDR, EXYNOS4210_CMU_DMC); + exynos4210_cmu_create(EXYNOS4210_CMU_CPU_BASE_ADDR, EXYNOS4210_CMU_CPU); + + /* PWM */ + sysbus_create_varargs("exynos4210.pwm", EXYNOS4210_PWM_BASE_ADDR, - s->irq_table[exynos4210_get_irq(22, 0)], - s->irq_table[exynos4210_get_irq(22, 1)], - s->irq_table[exynos4210_get_irq(22, 2)], - s->irq_table[exynos4210_get_irq(22, 3)], - s->irq_table[exynos4210_get_irq(22, 4)], - NULL); - ++ s->irq_table[exynos4210_get_irq(22, 0)], ++ s->irq_table[exynos4210_get_irq(22, 1)], ++ s->irq_table[exynos4210_get_irq(22, 2)], ++ s->irq_table[exynos4210_get_irq(22, 3)], ++ s->irq_table[exynos4210_get_irq(22, 4)], ++ NULL); + /* RTC */ + sysbus_create_varargs("exynos4210.rtc", EXYNOS4210_RTC_BASE_ADDR, - s->irq_table[exynos4210_get_irq(23, 0)], - s->irq_table[exynos4210_get_irq(23, 1)], - NULL); ++ s->irq_table[exynos4210_get_irq(23, 0)], ++ s->irq_table[exynos4210_get_irq(23, 1)], ++ NULL); + + /* Multi Core Timer */ + dev = qdev_create(NULL, "exynos4210.mct"); + qdev_init_nofail(dev); + busdev = sysbus_from_qdev(dev); + for (n = 0; n < 4; n++) { + /* Connect global timer interrupts to Combiner gpio_in */ + sysbus_connect_irq(busdev, n, + s->irq_table[exynos4210_get_irq(1, 4 + n)]); + } + /* Connect local timer interrupts to Combiner gpio_in */ + sysbus_connect_irq(busdev, 4, + s->irq_table[exynos4210_get_irq(51, 0)]); + sysbus_connect_irq(busdev, 5, + s->irq_table[exynos4210_get_irq(35, 3)]); + sysbus_mmio_map(busdev, 0, EXYNOS4210_MCT_BASE_ADDR); + + /*** I2C ***/ + for (n = 0; n < EXYNOS4210_I2C_NUMBER; n++) { + uint32_t addr = EXYNOS4210_I2C_BASE_ADDR + EXYNOS4210_I2C_SHIFT * n; + qemu_irq i2c_irq; + + if (n < 8) { + i2c_irq = s->irq_table[exynos4210_get_irq(EXYNOS4210_I2C_INTG, n)]; + } else { + i2c_irq = s->irq_table[exynos4210_get_irq(EXYNOS4210_HDMI_INTG, 1)]; + } + + dev = qdev_create(NULL, "exynos4210.i2c"); + qdev_init_nofail(dev); + busdev = sysbus_from_qdev(dev); + sysbus_connect_irq(busdev, 0, i2c_irq); + sysbus_mmio_map(busdev, 0, addr); + s->i2c_if[n] = (i2c_bus *)qdev_get_child_bus(dev, "i2c"); + } + ++ + /*** UARTs ***/ + exynos4210_uart_create(EXYNOS4210_UART0_BASE_ADDR, + EXYNOS4210_UART0_FIFO_SIZE, 0, NULL, - s->irq_table[exynos4210_get_irq(EXYNOS4210_UART_INT_GRP, 0)]); ++ s->irq_table[exynos4210_get_irq(EXYNOS4210_UART_INT_GRP, 0)]); + + exynos4210_uart_create(EXYNOS4210_UART1_BASE_ADDR, + EXYNOS4210_UART1_FIFO_SIZE, 1, NULL, - s->irq_table[exynos4210_get_irq(EXYNOS4210_UART_INT_GRP, 1)]); ++ s->irq_table[exynos4210_get_irq(EXYNOS4210_UART_INT_GRP, 1)]); + + exynos4210_uart_create(EXYNOS4210_UART2_BASE_ADDR, + EXYNOS4210_UART2_FIFO_SIZE, 2, NULL, - s->irq_table[exynos4210_get_irq(EXYNOS4210_UART_INT_GRP, 2)]); ++ s->irq_table[exynos4210_get_irq(EXYNOS4210_UART_INT_GRP, 2)]); + + exynos4210_uart_create(EXYNOS4210_UART3_BASE_ADDR, + EXYNOS4210_UART3_FIFO_SIZE, 3, NULL, - s->irq_table[exynos4210_get_irq(EXYNOS4210_UART_INT_GRP, 3)]); - ++ s->irq_table[exynos4210_get_irq(EXYNOS4210_UART_INT_GRP, 3)]); + + /*** Display controller (FIMD) ***/ + sysbus_create_varargs("exynos4210.fimd", EXYNOS4210_FIMD0_BASE_ADDR, + s->irq_table[exynos4210_get_irq(11, 0)], + s->irq_table[exynos4210_get_irq(11, 1)], + s->irq_table[exynos4210_get_irq(11, 2)], + NULL); + + /*** GPU openGLES passthrough device ***/ +#ifdef CONFIG_BUILD_GLES + gles2_init(first_cpu); +#endif + + /* I2S0 */ + s->i2s_bus[0] = exynos4210_i2s_bus_new("exynos4210.i2s", + EXYNOS4210_I2S0_BASE_ADDR, + s->irqs.ext_gic_irq[97]); + - sysbus_create_simple(VIRTIO_MMIO_TRANSPORT, - EXYNOS4210_VIRTIO_MMIO0_BASE_ADDR, - s->irq_table[exynos4210_get_irq(37, 3)]); ++ sysbus_create_simple(VIRTIO_MMIO, ++ EXYNOS4210_VIRTIO_MMIO0_BASE_ADDR, ++ s->irq_table[exynos4210_get_irq(37, 3)]); + - sysbus_create_simple(VIRTIO_MMIO_TRANSPORT, - EXYNOS4210_VIRTIO_MMIO1_BASE_ADDR, - s->irq_table[exynos4210_get_irq(37, 2)]); ++ sysbus_create_simple(VIRTIO_MMIO, ++ EXYNOS4210_VIRTIO_MMIO1_BASE_ADDR, ++ s->irq_table[exynos4210_get_irq(37, 2)]); + + /* PL050 PS/2 if keyboard */ + sysbus_create_simple("pl050_keyboard", EXYNOS4210_PL050_BASE_ADDR, - s->irq_table[exynos4210_get_irq(28, 2)]); ++ s->irq_table[exynos4210_get_irq(28, 2)]); + + return s; +} diff --cc tizen/src/hw/maru_board.c index 6ae533c,0000000..5a55a22 mode 100644,000000..100644 --- a/tizen/src/hw/maru_board.c +++ b/tizen/src/hw/maru_board.c @@@ -1,367 -1,0 +1,365 @@@ +/* + * TIZEN base board + * + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Contact: + * YeongKyoon Lee + * DongKyun Yun + * DoHyung Hong + * SeokYeon Hwang + * Hyunjun Son + * SangJin Kim + * KiTae Kim + * JinHyung Jo + * SungMin Ha + * MunKyu Im + * JiHye Kim + * GiWoong Kim + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * Contributors: + * - S-Core Co., Ltd + * + * x86 board from pc_piix.c... + * add some TIZEN-speciaized device... + */ + +#include + +#include "hw.h" +#include "pc.h" +#include "apic.h" +#include "pci.h" ++#include "pci_ids.h" ++#include "usb.h" +#include "net.h" +#include "boards.h" +#include "ide.h" +#include "kvm.h" +#include "kvm/clock.h" +#include "sysemu.h" +#include "sysbus.h" +#include "arch_init.h" +#include "blockdev.h" +#include "smbus.h" +#include "xen.h" +#include "memory.h" +#include "exec-memory.h" +#ifdef CONFIG_XEN +# include +#endif + +#include "guest_debug.h" ++#include "maru_pm.h" + +int codec_init(PCIBus *bus); - i2c_bus *maru_pm_init(PCIBus *bus, int devfn, uint32_t smb_io_base, - qemu_irq sci_irq, qemu_irq smi_irq, - int kvm_enabled); ++ + +#define MAX_IDE_BUS 2 + +static const int ide_iobase[MAX_IDE_BUS] = { 0x1f0, 0x170 }; +static const int ide_iobase2[MAX_IDE_BUS] = { 0x3f6, 0x376 }; +static const int ide_irq[MAX_IDE_BUS] = { 14, 15 }; + +static void kvm_piix3_setup_irq_routing(bool pci_enabled) +{ +#ifdef CONFIG_KVM + KVMState *s = kvm_state; - int ret, i; ++ int i; + + if (kvm_check_extension(s, KVM_CAP_IRQ_ROUTING)) { + for (i = 0; i < 8; ++i) { + if (i == 2) { + continue; + } - kvm_irqchip_add_route(s, i, KVM_IRQCHIP_PIC_MASTER, i); ++ kvm_irqchip_add_irq_route(s, i, KVM_IRQCHIP_PIC_MASTER, i); + } + for (i = 8; i < 16; ++i) { - kvm_irqchip_add_route(s, i, KVM_IRQCHIP_PIC_SLAVE, i - 8); ++ kvm_irqchip_add_irq_route(s, i, KVM_IRQCHIP_PIC_SLAVE, i - 8); + } + if (pci_enabled) { + for (i = 0; i < 24; ++i) { + if (i == 0) { - kvm_irqchip_add_route(s, i, KVM_IRQCHIP_IOAPIC, 2); ++ kvm_irqchip_add_irq_route(s, i, KVM_IRQCHIP_IOAPIC, 2); + } else if (i != 2) { - kvm_irqchip_add_route(s, i, KVM_IRQCHIP_IOAPIC, i); ++ kvm_irqchip_add_irq_route(s, i, KVM_IRQCHIP_IOAPIC, i); + } + } + } - ret = kvm_irqchip_commit_routes(s); - if (ret < 0) { - hw_error("KVM IRQ routing setup failed"); - } + } +#endif /* CONFIG_KVM */ +} + +static void kvm_piix3_gsi_handler(void *opaque, int n, int level) +{ + GSIState *s = opaque; + + if (n < ISA_NUM_IRQS) { + /* Kernel will forward to both PIC and IOAPIC */ + qemu_set_irq(s->i8259_irq[n], level); + } else { + qemu_set_irq(s->ioapic_irq[n], level); + } +} + +static void ioapic_init(GSIState *gsi_state) +{ + DeviceState *dev; + SysBusDevice *d; + unsigned int i; + + if (kvm_irqchip_in_kernel()) { + dev = qdev_create(NULL, "kvm-ioapic"); + } else { + dev = qdev_create(NULL, "ioapic"); + } + /* FIXME: this should be under the piix3. */ + object_property_add_child(object_resolve_path("i440fx", NULL), + "ioapic", OBJECT(dev), NULL); + qdev_init_nofail(dev); + d = sysbus_from_qdev(dev); + sysbus_mmio_map(d, 0, 0xfec00000); + + for (i = 0; i < IOAPIC_NUM_PINS; i++) { + gsi_state->ioapic_irq[i] = qdev_get_gpio_in(dev, i); + } +} + +MemoryRegion *global_ram_memory; + +MemoryRegion *get_ram_memory(void) +{ + return global_ram_memory; +} + +static void maru_x86_machine_init(MemoryRegion *system_memory, + MemoryRegion *system_io, + ram_addr_t ram_size, + const char *boot_device, + const char *kernel_filename, + const char *kernel_cmdline, + const char *initrd_filename, + const char *cpu_model, + int pci_enabled, + int kvmclock_enabled) +{ + int i; + ram_addr_t below_4g_mem_size, above_4g_mem_size; + PCIBus *pci_bus; + ISABus *isa_bus; + PCII440FXState *i440fx_state; + int piix3_devfn = -1; + qemu_irq *cpu_irq; + qemu_irq *gsi; + qemu_irq *i8259; + qemu_irq *smi_irq; + GSIState *gsi_state; + DriveInfo *hd[MAX_IDE_BUS * MAX_IDE_DEVS]; + BusState *idebus[MAX_IDE_BUS]; + ISADevice *rtc_state; + ISADevice *floppy; + MemoryRegion *ram_memory; + MemoryRegion *pci_memory; + MemoryRegion *rom_memory; ++ void *fw_cfg = NULL; + + pc_cpus_init(cpu_model); + + if (kvmclock_enabled) { + kvmclock_create(); + } + + if (ram_size >= 0xe0000000 ) { + above_4g_mem_size = ram_size - 0xe0000000; + below_4g_mem_size = 0xe0000000; + } else { + above_4g_mem_size = 0; + below_4g_mem_size = ram_size; + } + + if (pci_enabled) { + pci_memory = g_new(MemoryRegion, 1); + memory_region_init(pci_memory, "pci", INT64_MAX); + rom_memory = pci_memory; + } else { + pci_memory = NULL; + rom_memory = system_memory; + } + + /* allocate ram and load rom/bios */ + if (!xen_enabled()) { - pc_memory_init(system_memory, ++ fw_cfg = pc_memory_init(system_memory, + kernel_filename, kernel_cmdline, initrd_filename, + below_4g_mem_size, above_4g_mem_size, + pci_enabled ? rom_memory : system_memory, &ram_memory); + } + + // for ramdump... + global_ram_memory = ram_memory; + + gsi_state = g_malloc0(sizeof(*gsi_state)); + if (kvm_irqchip_in_kernel()) { + kvm_piix3_setup_irq_routing(pci_enabled); + gsi = qemu_allocate_irqs(kvm_piix3_gsi_handler, gsi_state, + GSI_NUM_PINS); + } else { + gsi = qemu_allocate_irqs(gsi_handler, gsi_state, GSI_NUM_PINS); + } + + if (pci_enabled) { + pci_bus = i440fx_init(&i440fx_state, &piix3_devfn, &isa_bus, gsi, + system_memory, system_io, ram_size, + below_4g_mem_size, + 0x100000000ULL - below_4g_mem_size, + 0x100000000ULL + above_4g_mem_size, + (sizeof(target_phys_addr_t) == 4 + ? 0 + : ((uint64_t)1 << 62)), + pci_memory, ram_memory); + } else { + pci_bus = NULL; + i440fx_state = NULL; + isa_bus = isa_bus_new(NULL, system_io); + no_hpet = 1; + } + isa_bus_irqs(isa_bus, gsi); + + if (kvm_irqchip_in_kernel()) { + i8259 = kvm_i8259_init(isa_bus); + } else if (xen_enabled()) { + i8259 = xen_interrupt_controller_init(); + } else { + cpu_irq = pc_allocate_cpu_irq(); + i8259 = i8259_init(isa_bus, cpu_irq[0]); + } + + for (i = 0; i < ISA_NUM_IRQS; i++) { + gsi_state->i8259_irq[i] = i8259[i]; + } + if (pci_enabled) { + ioapic_init(gsi_state); + } + + + pc_register_ferr_irq(gsi[13]); + + pc_vga_init(isa_bus, pci_enabled ? pci_bus : NULL); + if (xen_enabled()) { + pci_create_simple(pci_bus, -1, "xen-platform"); + } + /* init basic PC hardware */ + pc_basic_device_init(isa_bus, gsi, &rtc_state, &floppy, xen_enabled()); + + for(i = 0; i < nb_nics; i++) { + NICInfo *nd = &nd_table[i]; + + if (!pci_enabled || (nd->model && strcmp(nd->model, "ne2k_isa") == 0)) + pc_init_ne2k_isa(isa_bus, nd); + else + pci_nic_init_nofail(nd, "e1000", NULL); + } + + ide_drive_get(hd, MAX_IDE_BUS); + if (pci_enabled) { + PCIDevice *dev; + if (xen_enabled()) { + dev = pci_piix3_xen_ide_init(pci_bus, hd, piix3_devfn + 1); + } else { + dev = pci_piix3_ide_init(pci_bus, hd, piix3_devfn + 1); + } + idebus[0] = qdev_get_child_bus(&dev->qdev, "ide.0"); + idebus[1] = qdev_get_child_bus(&dev->qdev, "ide.1"); + } else { + for(i = 0; i < MAX_IDE_BUS; i++) { + ISADevice *dev; + dev = isa_ide_init(isa_bus, ide_iobase[i], ide_iobase2[i], + ide_irq[i], + hd[MAX_IDE_DEVS * i], hd[MAX_IDE_DEVS * i + 1]); + idebus[i] = qdev_get_child_bus(&dev->qdev, "ide.0"); + } + } + +// commented out by caramis... for use 'tizen-ac97'... +// reopen for qemu 1.0 merging... + audio_init(isa_bus, pci_enabled ? pci_bus : NULL); + + pc_cmos_init(below_4g_mem_size, above_4g_mem_size, boot_device, + floppy, idebus[0], idebus[1], rtc_state); + + if (pci_enabled && usb_enabled) { + pci_create_simple(pci_bus, piix3_devfn + 2, "piix3-usb-uhci"); + } + + if (pci_enabled && acpi_enabled) { + i2c_bus *smbus; + + smi_irq = qemu_allocate_irqs(pc_acpi_smi_interrupt, first_cpu, 1); + /* TODO: Populate SPD eeprom data. */ +#if defined(__x86_64__) + smbus = piix4_pm_init(pci_bus, piix3_devfn + 3, 0xb100, - gsi[9], *smi_irq, kvm_enabled()); ++ gsi[9], *smi_irq, kvm_enabled(), fw_cfg); + +#else + smbus = maru_pm_init(pci_bus, piix3_devfn + 3, 0xb100, - gsi[9], *smi_irq, kvm_enabled()); ++ gsi[9], *smi_irq, kvm_enabled(), fw_cfg); +#endif + smbus_eeprom_init(smbus, 8, NULL, 0); + } + + if (pci_enabled) { + pc_pci_device_init(pci_bus); + } + +#ifndef CONFIG_DARWIN + // maru specialized device init... + if (pci_enabled) { + //tizen_ac97_init(pci_bus); + codec_init(pci_bus); + } +#endif +#ifdef CONFIG_YAGL + pci_create_simple(pci_bus, -1, "yagl"); +#endif +} + +static void maru_x86_board_init(ram_addr_t ram_size, + const char *boot_device, + const char *kernel_filename, + const char *kernel_cmdline, + const char *initrd_filename, + const char *cpu_model) +{ + maru_x86_machine_init(get_system_memory(), + get_system_io(), + ram_size, boot_device, + kernel_filename, kernel_cmdline, + initrd_filename, cpu_model, 1, 1); +} + +static QEMUMachine maru_x86_machine = { + .name = "maru-x86-machine", + .desc = "maru board(x86)", + .init = maru_x86_board_init, + .max_cpus = 255, +}; + +static void maru_machine_init(void) +{ + qemu_register_machine(&maru_x86_machine); +} + +machine_init(maru_machine_init); diff --cc tizen/src/hw/maru_pm.c index 45fb35e,0000000..5b84bda mode 100644,000000..100644 --- a/tizen/src/hw/maru_pm.c +++ b/tizen/src/hw/maru_pm.c @@@ -1,655 -1,0 +1,673 @@@ +/* + * Maru power management emulator + * Based on qemu/hw/acpi_piix4.c + * + * Copyright (C) 2011 - 2012 Samsung Electronics Co., Ltd. All rights reserved. + * + * Contact: + * Hyunjun Son + * GiWoong Kim + * YeongKyoon Lee + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * Contributors: + * - S-Core Co., Ltd + * + */ + +#include "maru_pm.h" +#include "hw.h" +#include "pc.h" +#include "apm.h" +#include "pm_smbus.h" +#include "pci.h" +#include "acpi.h" +#include "sysemu.h" +#include "range.h" +#include "ioport.h" +#include "debug_ch.h" + ++ +//#define DEBUG + +#ifdef DEBUG +# define PIIX4_DPRINTF(format, ...) printf(format, ## __VA_ARGS__) +#else +# define PIIX4_DPRINTF(format, ...) do { } while (0) +#endif + +/* define debug channel */ +MULTI_DEBUG_CHANNEL(qemu, maru_pm); + +#define ACPI_DBG_IO_ADDR 0xb044 + +#define GPE_BASE 0xafe0 +#define GPE_LEN 4 +#define PCI_UP_BASE 0xae00 +#define PCI_DOWN_BASE 0xae04 +#define PCI_EJ_BASE 0xae08 +#define PCI_RMV_BASE 0xae0c + +#define PIIX4_PCI_HOTPLUG_STATUS 2 + +struct pci_status { + uint32_t up; /* deprecated, maintained for migration compatibility */ + uint32_t down; +}; + +typedef struct PIIX4PMState { + PCIDevice dev; + IORange ioport; + ACPIREGS ar; + + APMState apm; + + PMSMBus smb; + uint32_t smb_io_base; + + qemu_irq irq; + qemu_irq smi_irq; + int kvm_enabled; + Notifier machine_ready; + + /* for pci hotplug */ + struct pci_status pci0_status; + uint32_t pci0_hotplug_enable; + uint32_t pci0_slot_device_present; ++ ++ uint8_t disable_s3; ++ uint8_t disable_s4; ++ uint8_t s4_val; +} PIIX4PMState; + +static int is_suspended; + +static void piix4_acpi_system_hot_add_init(PCIBus *bus, PIIX4PMState *s); + +#define ACPI_ENABLE 0xf1 +#define ACPI_DISABLE 0xf0 + +static void pm_update_sci(PIIX4PMState *s) +{ + int sci_level, pmsts; + + pmsts = acpi_pm1_evt_get_sts(&s->ar); + sci_level = (((pmsts & s->ar.pm1.evt.en) & + (ACPI_BITMASK_RT_CLOCK_ENABLE | + ACPI_BITMASK_POWER_BUTTON_ENABLE | + ACPI_BITMASK_GLOBAL_LOCK_ENABLE | + ACPI_BITMASK_TIMER_ENABLE)) != 0) || + (((s->ar.gpe.sts[0] & s->ar.gpe.en[0]) + & PIIX4_PCI_HOTPLUG_STATUS) != 0); + + qemu_set_irq(s->irq, sci_level); + /* schedule a timer interruption if needed */ + acpi_pm_tmr_update(&s->ar, (s->ar.pm1.evt.en & ACPI_BITMASK_TIMER_ENABLE) && + !(pmsts & ACPI_BITMASK_TIMER_STATUS)); +} + +static void pm_tmr_timer(ACPIREGS *ar) +{ + PIIX4PMState *s = container_of(ar, PIIX4PMState, ar); + pm_update_sci(s); +} + +void maru_pm1_cnt_write(ACPIREGS *ar, uint16_t val) +{ + ar->pm1.cnt.cnt = val & ~(ACPI_BITMASK_SLEEP_ENABLE); + + if (val & ACPI_BITMASK_SLEEP_ENABLE) { + /* change suspend type */ + uint16_t sus_typ = (val >> 10) & 7; + switch(sus_typ) { + case 0: /* soft power off */ + qemu_system_shutdown_request(); + break; + case 1: +#if 0 // changed suspend operation for emulator + qemu_system_suspend_request(); +#else + INFO( "suspend is requested.\n" ); + is_suspended = 1; +#endif// end : changed suspend operation for emulator + break; + default: + break; + } + } +} + +static void pm_ioport_write(IORange *ioport, uint64_t addr, unsigned width, + uint64_t val) +{ + PIIX4PMState *s = container_of(ioport, PIIX4PMState, ioport); + + if (width != 2) { + PIIX4_DPRINTF("PM write port=0x%04x width=%d val=0x%08x\n", + (unsigned)addr, width, (unsigned)val); + } + + switch(addr) { + case 0x00: + acpi_pm1_evt_write_sts(&s->ar, val); + pm_update_sci(s); + break; + case 0x02: + acpi_pm1_evt_write_en(&s->ar, val); + pm_update_sci(s); + break; + case 0x04: +#if 0 + acpi_pm1_cnt_write(&s->ar, val); +#else + maru_pm1_cnt_write(&s->ar, val); +#endif + break; + default: + break; + } + PIIX4_DPRINTF("PM writew port=0x%04x val=0x%04x\n", (unsigned int)addr, + (unsigned int)val); +} + +static void pm_ioport_read(IORange *ioport, uint64_t addr, unsigned width, + uint64_t *data) +{ + PIIX4PMState *s = container_of(ioport, PIIX4PMState, ioport); + uint32_t val; + + switch(addr) { + case 0x00: + val = acpi_pm1_evt_get_sts(&s->ar); + break; + case 0x02: + val = s->ar.pm1.evt.en; + break; + case 0x04: + val = s->ar.pm1.cnt.cnt; + break; + case 0x08: + val = acpi_pm_tmr_get(&s->ar); + break; + default: + val = 0; + break; + } + PIIX4_DPRINTF("PM readw port=0x%04x val=0x%04x\n", (unsigned int)addr, val); + *data = val; +} + +static const IORangeOps pm_iorange_ops = { + .read = pm_ioport_read, + .write = pm_ioport_write, +}; + +static void apm_ctrl_changed(uint32_t val, void *arg) +{ + PIIX4PMState *s = arg; + + /* ACPI specs 3.0, 4.7.2.5 */ + acpi_pm1_cnt_update(&s->ar, val == ACPI_ENABLE, val == ACPI_DISABLE); + + if (s->dev.config[0x5b] & (1 << 1)) { + if (s->smi_irq) { + qemu_irq_raise(s->smi_irq); + } + } +} + +static void acpi_dbg_writel(void *opaque, uint32_t addr, uint32_t val) +{ + PIIX4_DPRINTF("ACPI: DBG: 0x%08x\n", val); +} + +static void pm_io_space_update(PIIX4PMState *s) +{ + uint32_t pm_io_base; + + if (s->dev.config[0x80] & 1) { + pm_io_base = le32_to_cpu(*(uint32_t *)(s->dev.config + 0x40)); + pm_io_base &= 0xffc0; + + /* XXX: need to improve memory and ioport allocation */ + PIIX4_DPRINTF("PM: mapping to 0x%x\n", pm_io_base); + iorange_init(&s->ioport, &pm_iorange_ops, pm_io_base, 64); + ioport_register(&s->ioport); + } +} + +static void pm_write_config(PCIDevice *d, + uint32_t address, uint32_t val, int len) +{ + pci_default_write_config(d, address, val, len); + if (range_covers_byte(address, len, 0x80)) + pm_io_space_update((PIIX4PMState *)d); +} + +static void vmstate_pci_status_pre_save(void *opaque) +{ + struct pci_status *pci0_status = opaque; + PIIX4PMState *s = container_of(pci0_status, PIIX4PMState, pci0_status); + + /* We no longer track up, so build a safe value for migrating + * to a version that still does... of course these might get lost + * by an old buggy implementation, but we try. */ + pci0_status->up = s->pci0_slot_device_present & s->pci0_hotplug_enable; +} + +static int vmstate_acpi_post_load(void *opaque, int version_id) +{ + PIIX4PMState *s = opaque; + + pm_io_space_update(s); + return 0; +} + +#define VMSTATE_GPE_ARRAY(_field, _state) \ + { \ + .name = (stringify(_field)), \ + .version_id = 0, \ + .num = GPE_LEN, \ + .info = &vmstate_info_uint16, \ + .size = sizeof(uint16_t), \ + .flags = VMS_ARRAY | VMS_POINTER, \ + .offset = vmstate_offset_pointer(_state, _field, uint8_t), \ + } + +static const VMStateDescription vmstate_gpe = { + .name = "gpe", + .version_id = 1, + .minimum_version_id = 1, + .minimum_version_id_old = 1, + .fields = (VMStateField []) { + VMSTATE_GPE_ARRAY(sts, ACPIGPE), + VMSTATE_GPE_ARRAY(en, ACPIGPE), + VMSTATE_END_OF_LIST() + } +}; + +static const VMStateDescription vmstate_pci_status = { + .name = "pci_status", + .version_id = 1, + .minimum_version_id = 1, + .minimum_version_id_old = 1, + .pre_save = vmstate_pci_status_pre_save, + .fields = (VMStateField []) { + VMSTATE_UINT32(up, struct pci_status), + VMSTATE_UINT32(down, struct pci_status), + VMSTATE_END_OF_LIST() + } +}; + +static const VMStateDescription vmstate_acpi = { + .name = "piix4_pm", + .version_id = 2, + .minimum_version_id = 1, + .minimum_version_id_old = 1, + .post_load = vmstate_acpi_post_load, + .fields = (VMStateField []) { + VMSTATE_PCI_DEVICE(dev, PIIX4PMState), + VMSTATE_UINT16(ar.pm1.evt.sts, PIIX4PMState), + VMSTATE_UINT16(ar.pm1.evt.en, PIIX4PMState), + VMSTATE_UINT16(ar.pm1.cnt.cnt, PIIX4PMState), + VMSTATE_STRUCT(apm, PIIX4PMState, 0, vmstate_apm, APMState), + VMSTATE_TIMER(ar.tmr.timer, PIIX4PMState), + VMSTATE_INT64(ar.tmr.overflow_time, PIIX4PMState), + VMSTATE_STRUCT(ar.gpe, PIIX4PMState, 2, vmstate_gpe, ACPIGPE), + VMSTATE_STRUCT(pci0_status, PIIX4PMState, 2, vmstate_pci_status, + struct pci_status), + VMSTATE_END_OF_LIST() + } +}; + +static void acpi_piix_eject_slot(PIIX4PMState *s, unsigned slots) +{ - DeviceState *qdev, *next; ++ BusChild *kid, *next; + BusState *bus = qdev_get_parent_bus(&s->dev.qdev); + int slot = ffs(slots) - 1; + bool slot_free = true; + + /* Mark request as complete */ + s->pci0_status.down &= ~(1U << slot); + - QTAILQ_FOREACH_SAFE(qdev, &bus->children, sibling, next) { ++ QTAILQ_FOREACH_SAFE(kid, &bus->children, sibling, next) { ++ DeviceState *qdev = kid->child; + PCIDevice *dev = PCI_DEVICE(qdev); + PCIDeviceClass *pc = PCI_DEVICE_GET_CLASS(dev); + if (PCI_SLOT(dev->devfn) == slot) { + if (pc->no_hotplug) { + slot_free = false; + } else { - object_unparent(OBJECT(dev)); + qdev_free(qdev); + } + } + } + if (slot_free) { + s->pci0_slot_device_present &= ~(1U << slot); + } +} + +static void piix4_update_hotplug(PIIX4PMState *s) +{ + PCIDevice *dev = &s->dev; + BusState *bus = qdev_get_parent_bus(&dev->qdev); - DeviceState *qdev, *next; ++ BusChild *kid, *next; + + /* Execute any pending removes during reset */ + while (s->pci0_status.down) { + acpi_piix_eject_slot(s, s->pci0_status.down); + } + + s->pci0_hotplug_enable = ~0; + s->pci0_slot_device_present = 0; + - QTAILQ_FOREACH_SAFE(qdev, &bus->children, sibling, next) { ++ QTAILQ_FOREACH_SAFE(kid, &bus->children, sibling, next) { ++ DeviceState *qdev = kid->child; + PCIDevice *pdev = PCI_DEVICE(qdev); + PCIDeviceClass *pc = PCI_DEVICE_GET_CLASS(pdev); + int slot = PCI_SLOT(pdev->devfn); + + if (pc->no_hotplug) { + s->pci0_hotplug_enable &= ~(1U << slot); + } + + s->pci0_slot_device_present |= (1U << slot); + } +} + +static void piix4_reset(void *opaque) +{ + PIIX4PMState *s = opaque; + uint8_t *pci_conf = s->dev.config; + + pci_conf[0x58] = 0; + pci_conf[0x59] = 0; + pci_conf[0x5a] = 0; + pci_conf[0x5b] = 0; + ++ pci_conf[0x40] = 0x01; /* PM io base read only bit */ ++ pci_conf[0x80] = 0; ++ + if (s->kvm_enabled) { + /* Mark SMM as already inited (until KVM supports SMM). */ + pci_conf[0x5B] = 0x02; + } + piix4_update_hotplug(s); +} + +static void piix4_powerdown(void *opaque, int irq, int power_failing) +{ + PIIX4PMState *s = opaque; + + assert(s != NULL); + acpi_pm1_evt_power_down(&s->ar); +} + +static void piix4_pm_machine_ready(Notifier *n, void *opaque) +{ + PIIX4PMState *s = container_of(n, PIIX4PMState, machine_ready); + uint8_t *pci_conf; + + pci_conf = s->dev.config; + pci_conf[0x5f] = (isa_is_ioport_assigned(0x378) ? 0x80 : 0) | 0x10; + pci_conf[0x63] = 0x60; + pci_conf[0x67] = (isa_is_ioport_assigned(0x3f8) ? 0x08 : 0) | + (isa_is_ioport_assigned(0x2f8) ? 0x90 : 0); + +} + +static int piix4_pm_initfn(PCIDevice *dev) +{ + PIIX4PMState *s = DO_UPCAST(PIIX4PMState, dev, dev); + uint8_t *pci_conf; + + pci_conf = s->dev.config; + pci_conf[0x06] = 0x80; + pci_conf[0x07] = 0x02; + pci_conf[0x09] = 0x00; + pci_conf[0x3d] = 0x01; // interrupt pin 1 + - pci_conf[0x40] = 0x01; /* PM io base read only bit */ - + /* APM */ + apm_init(&s->apm, apm_ctrl_changed, s); + + register_ioport_write(ACPI_DBG_IO_ADDR, 4, 4, acpi_dbg_writel, s); + + if (s->kvm_enabled) { + /* Mark SMM as already inited to prevent SMM from running. KVM does not + * support SMM mode. */ + pci_conf[0x5B] = 0x02; + } + + /* XXX: which specification is used ? The i82731AB has different + mappings */ + pci_conf[0x90] = s->smb_io_base | 1; + pci_conf[0x91] = s->smb_io_base >> 8; + pci_conf[0xd2] = 0x09; + register_ioport_write(s->smb_io_base, 64, 1, smb_ioport_writeb, &s->smb); + register_ioport_read(s->smb_io_base, 64, 1, smb_ioport_readb, &s->smb); + + acpi_pm_tmr_init(&s->ar, pm_tmr_timer); + acpi_gpe_init(&s->ar, GPE_LEN); + + qemu_system_powerdown = *qemu_allocate_irqs(piix4_powerdown, s, 1); + + pm_smbus_init(&s->dev.qdev, &s->smb); + s->machine_ready.notify = piix4_pm_machine_ready; + qemu_add_machine_init_done_notifier(&s->machine_ready); + qemu_register_reset(piix4_reset, s); + piix4_acpi_system_hot_add_init(dev->bus, s); + + return 0; +} + +i2c_bus *maru_pm_init(PCIBus *bus, int devfn, uint32_t smb_io_base, + qemu_irq sci_irq, qemu_irq smi_irq, - int kvm_enabled) ++ int kvm_enabled, void *fw_cfg) +{ + PCIDevice *dev; + PIIX4PMState *s; + + dev = pci_create(bus, devfn, "MARU_PM"); + qdev_prop_set_uint32(&dev->qdev, "smb_io_base", smb_io_base); + + s = DO_UPCAST(PIIX4PMState, dev, dev); + s->irq = sci_irq; + acpi_pm1_cnt_init(&s->ar); + s->smi_irq = smi_irq; + s->kvm_enabled = kvm_enabled; + + qdev_init_nofail(&dev->qdev); + ++ if (fw_cfg) { ++ uint8_t suspend[6] = {128, 0, 0, 129, 128, 128}; ++ suspend[3] = 1 | ((!s->disable_s3) << 7); ++ suspend[4] = s->s4_val | ((!s->disable_s4) << 7); ++ ++ fw_cfg_add_file(fw_cfg, "etc/system-states", g_memdup(suspend, 6), 6); ++ } ++ + return s->smb.smbus; +} + +static Property piix4_pm_properties[] = { + DEFINE_PROP_UINT32("smb_io_base", PIIX4PMState, smb_io_base, 0), ++ DEFINE_PROP_UINT8("disable_s3", PIIX4PMState, disable_s3, 0), ++ DEFINE_PROP_UINT8("disable_s4", PIIX4PMState, disable_s4, 0), ++ DEFINE_PROP_UINT8("s4_val", PIIX4PMState, s4_val, 2), + DEFINE_PROP_END_OF_LIST(), +}; + +static void piix4_pm_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); + + k->no_hotplug = 1; + k->init = piix4_pm_initfn; + k->config_write = pm_write_config; + k->vendor_id = PCI_VENDOR_ID_INTEL; + k->device_id = PCI_DEVICE_ID_INTEL_82371AB_3; + k->revision = 0x03; + k->class_id = PCI_CLASS_BRIDGE_OTHER; + dc->desc = "PM"; + dc->no_user = 1; + dc->vmsd = &vmstate_acpi; + dc->props = piix4_pm_properties; +} + +static TypeInfo piix4_pm_info = { + .name = "MARU_PM", + .parent = TYPE_PCI_DEVICE, + .instance_size = sizeof(PIIX4PMState), + .class_init = piix4_pm_class_init, +}; + +static void piix4_pm_register_types(void) +{ + type_register_static(&piix4_pm_info); +} + +type_init(piix4_pm_register_types) + +static uint32_t gpe_readb(void *opaque, uint32_t addr) +{ + PIIX4PMState *s = opaque; + uint32_t val = acpi_gpe_ioport_readb(&s->ar, addr); + + PIIX4_DPRINTF("gpe read %x == %x\n", addr, val); + return val; +} + +static void gpe_writeb(void *opaque, uint32_t addr, uint32_t val) +{ + PIIX4PMState *s = opaque; + + acpi_gpe_ioport_writeb(&s->ar, addr, val); + pm_update_sci(s); + + PIIX4_DPRINTF("gpe write %x <== %d\n", addr, val); +} + +static uint32_t pci_up_read(void *opaque, uint32_t addr) +{ + PIIX4PMState *s = opaque; + uint32_t val; + + /* Manufacture an "up" value to cause a device check on any hotplug + * slot with a device. Extra device checks are harmless. */ + val = s->pci0_slot_device_present & s->pci0_hotplug_enable; + + PIIX4_DPRINTF("pci_up_read %x\n", val); + return val; +} + +static uint32_t pci_down_read(void *opaque, uint32_t addr) +{ + PIIX4PMState *s = opaque; + uint32_t val = s->pci0_status.down; + + PIIX4_DPRINTF("pci_down_read %x\n", val); + return val; +} + +static uint32_t pci_features_read(void *opaque, uint32_t addr) +{ + /* No feature defined yet */ + PIIX4_DPRINTF("pci_features_read %x\n", 0); + return 0; +} + +static void pciej_write(void *opaque, uint32_t addr, uint32_t val) +{ + acpi_piix_eject_slot(opaque, val); + + PIIX4_DPRINTF("pciej write %x <== %d\n", addr, val); +} + +static uint32_t pcirmv_read(void *opaque, uint32_t addr) +{ + PIIX4PMState *s = opaque; + + return s->pci0_hotplug_enable; +} + +static int piix4_device_hotplug(DeviceState *qdev, PCIDevice *dev, + PCIHotplugState state); + +static void piix4_acpi_system_hot_add_init(PCIBus *bus, PIIX4PMState *s) +{ + + register_ioport_write(GPE_BASE, GPE_LEN, 1, gpe_writeb, s); + register_ioport_read(GPE_BASE, GPE_LEN, 1, gpe_readb, s); + acpi_gpe_blk(&s->ar, GPE_BASE); + + register_ioport_read(PCI_UP_BASE, 4, 4, pci_up_read, s); + register_ioport_read(PCI_DOWN_BASE, 4, 4, pci_down_read, s); + + register_ioport_write(PCI_EJ_BASE, 4, 4, pciej_write, s); + register_ioport_read(PCI_EJ_BASE, 4, 4, pci_features_read, s); + + register_ioport_read(PCI_RMV_BASE, 4, 4, pcirmv_read, s); + + pci_bus_hotplug(bus, piix4_device_hotplug, &s->dev.qdev); +} + +static void enable_device(PIIX4PMState *s, int slot) +{ + s->ar.gpe.sts[0] |= PIIX4_PCI_HOTPLUG_STATUS; + s->pci0_slot_device_present |= (1U << slot); +} + +static void disable_device(PIIX4PMState *s, int slot) +{ + s->ar.gpe.sts[0] |= PIIX4_PCI_HOTPLUG_STATUS; + s->pci0_status.down |= (1U << slot); +} + +static int piix4_device_hotplug(DeviceState *qdev, PCIDevice *dev, + PCIHotplugState state) +{ + int slot = PCI_SLOT(dev->devfn); + PIIX4PMState *s = DO_UPCAST(PIIX4PMState, dev, + PCI_DEVICE(qdev)); + + /* Don't send event when device is enabled during qemu machine creation: + * it is present on boot, no hotplug event is necessary. We do send an + * event when the device is disabled later. */ + if (state == PCI_COLDPLUG_ENABLED) { + s->pci0_slot_device_present |= (1U << slot); + return 0; + } + + if (state == PCI_HOTPLUG_ENABLED) { + enable_device(s, slot); + } else { + disable_device(s, slot); + } + + pm_update_sci(s); + + return 0; +} + +void resume(void) +{ + is_suspended = 0; +} + +int is_suspended_state( void ) { + return is_suspended; +} diff --cc tizen/src/hw/maru_pm.h index 51356f1,0000000..8416fce mode 100644,000000..100644 --- a/tizen/src/hw/maru_pm.h +++ b/tizen/src/hw/maru_pm.h @@@ -1,54 -1,0 +1,54 @@@ +/* + * Maru power management emulator + * Based on qemu/hw/acpi_piix4.h + * + * Copyright (C) 2011 - 2012 Samsung Electronics Co., Ltd. All rights reserved. + * + * Contact: + * Hyunjun Son + * GiWoong Kim + * YeongKyoon Lee + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * Contributors: + * - S-Core Co., Ltd + * + */ + +#ifndef MARU_PM_H_ +#define MARU_PM_H_ + +#include "qemu-common.h" + +i2c_bus *maru_pm_init(PCIBus *bus, int devfn, uint32_t smb_io_base, + qemu_irq sci_irq, qemu_irq smi_irq, - int kvm_enabled); ++ int kvm_enabled, void *fw_cfg); + +#ifdef TARGET_ARM +static int is_suspended_state( void ) +{ + return 0; +} +static void resume( void ) +{ + return; +} +#else +void resume( void ); +int is_suspended_state( void ); +#endif + +#endif /* MARU_PM_H_ */ diff --cc tizen/src/hw/maru_vga.c index 0c82c26,0000000..56fe261 mode 100644,000000..100644 --- a/tizen/src/hw/maru_vga.c +++ b/tizen/src/hw/maru_vga.c @@@ -1,1649 -1,0 +1,1955 @@@ +/* + * Maru vga device + * Based on qemu/hw/vga.c + * + * Copyright (C) 2011 - 2012 Samsung Electronics Co., Ltd. All rights reserved. + * + * Contact: + * HyunJun Son + * GiWoong Kim + * YeongKyoon Lee + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * Contributors: + * - S-Core Co., Ltd + * + */ + + +#include "maru_common.h" + +#ifdef CONFIG_DARWIN +//shared memory +#define USE_SHM +#endif + +#include "hw.h" ++#include "vga.h" +#include "console.h" +#include "pc.h" +#include "pci.h" +#include "vga_int.h" +#include "pixel_ops.h" +#include "qemu-timer.h" ++#include "xen.h" ++#include "trace.h" ++ +#include "maru_vga_int.h" +#include "maru_brightness.h" +#include "maru_overlay.h" +#include "emul_state.h" +#include "debug_ch.h" + +#ifdef USE_SHM +#include +#endif + +MULTI_DEBUG_CHANNEL(qemu, maru_vga); + + +//#define DEBUG_VGA +//#define DEBUG_VGA_MEM +//#define DEBUG_VGA_REG + +//#define DEBUG_BOCHS_VBE + ++/* 16 state changes per vertical frame @60 Hz */ ++#define VGA_TEXT_CURSOR_PERIOD_MS (1000 * 2 * 16 / 60) ++ +#define cbswap_32(__x) \ +((uint32_t)( \ + (((uint32_t)(__x) & (uint32_t)0x000000ffUL) << 24) | \ + (((uint32_t)(__x) & (uint32_t)0x0000ff00UL) << 8) | \ + (((uint32_t)(__x) & (uint32_t)0x00ff0000UL) >> 8) | \ + (((uint32_t)(__x) & (uint32_t)0xff000000UL) >> 24) )) + +#ifdef HOST_WORDS_BIGENDIAN +#define PAT(x) cbswap_32(x) +#else +#define PAT(x) (x) +#endif + +#ifdef HOST_WORDS_BIGENDIAN +#define BIG 1 +#else +#define BIG 0 +#endif + +#ifdef HOST_WORDS_BIGENDIAN +#define GET_PLANE(data, p) (((data) >> (24 - (p) * 8)) & 0xff) +#else +#define GET_PLANE(data, p) (((data) >> ((p) * 8)) & 0xff) +#endif + +#define MARU_VGA + +#ifdef USE_SHM +/* shared memory */ +void *shared_memory = (void*)0; +int shmid; +#endif + + +static const uint32_t mask16[16] = { + PAT(0x00000000), + PAT(0x000000ff), + PAT(0x0000ff00), + PAT(0x0000ffff), + PAT(0x00ff0000), + PAT(0x00ff00ff), + PAT(0x00ffff00), + PAT(0x00ffffff), + PAT(0xff000000), + PAT(0xff0000ff), + PAT(0xff00ff00), + PAT(0xff00ffff), + PAT(0xffff0000), + PAT(0xffff00ff), + PAT(0xffffff00), + PAT(0xffffffff), +}; + +#undef PAT + +#ifdef HOST_WORDS_BIGENDIAN +#define PAT(x) (x) +#else +#define PAT(x) cbswap_32(x) +#endif + +static const uint32_t dmask16[16] = { + PAT(0x00000000), + PAT(0x000000ff), + PAT(0x0000ff00), + PAT(0x0000ffff), + PAT(0x00ff0000), + PAT(0x00ff00ff), + PAT(0x00ffff00), + PAT(0x00ffffff), + PAT(0xff000000), + PAT(0xff0000ff), + PAT(0xff00ff00), + PAT(0xff00ffff), + PAT(0xffff0000), + PAT(0xffff00ff), + PAT(0xffffff00), + PAT(0xffffffff), +}; + +static const uint32_t dmask4[4] = { + PAT(0x00000000), + PAT(0x0000ffff), + PAT(0xffff0000), + PAT(0xffffffff), +}; + +static uint32_t expand4[256]; +static uint16_t expand2[256]; +static uint8_t expand4to8[16]; + +static void vga_screen_dump(void *opaque, const char *filename, bool cswitch); - static const char *screen_dump_filename; - static DisplayChangeListener *screen_dump_dcl; ++ ++static void vga_update_memory_access(VGACommonState *s) ++{ ++ MemoryRegion *region, *old_region = s->chain4_alias; ++ target_phys_addr_t base, offset, size; ++ ++ s->chain4_alias = NULL; ++ ++ if ((s->sr[VGA_SEQ_PLANE_WRITE] & VGA_SR02_ALL_PLANES) == ++ VGA_SR02_ALL_PLANES && s->sr[VGA_SEQ_MEMORY_MODE] & VGA_SR04_CHN_4M) { ++ offset = 0; ++ switch ((s->gr[VGA_GFX_MISC] >> 2) & 3) { ++ case 0: ++ base = 0xa0000; ++ size = 0x20000; ++ break; ++ case 1: ++ base = 0xa0000; ++ size = 0x10000; ++ offset = s->bank_offset; ++ break; ++ case 2: ++ base = 0xb0000; ++ size = 0x8000; ++ break; ++ case 3: ++ default: ++ base = 0xb8000; ++ size = 0x8000; ++ break; ++ } ++ base += isa_mem_base; ++ region = g_malloc(sizeof(*region)); ++ memory_region_init_alias(region, "vga.chain4", &s->vram, offset, size); ++ memory_region_add_subregion_overlap(s->legacy_address_space, base, ++ region, 2); ++ s->chain4_alias = region; ++ } ++ if (old_region) { ++ memory_region_del_subregion(s->legacy_address_space, old_region); ++ memory_region_destroy(old_region); ++ g_free(old_region); ++ s->plane_updated = 0xf; ++ } ++} + +static void vga_dumb_update_retrace_info(VGACommonState *s) +{ + (void) s; +} + +static void vga_precise_update_retrace_info(VGACommonState *s) +{ + int htotal_chars; + int hretr_start_char; + int hretr_skew_chars; + int hretr_end_char; + + int vtotal_lines; + int vretr_start_line; + int vretr_end_line; + + int dots; +#if 0 + int div2, sldiv2; +#endif + int clocking_mode; + int clock_sel; + const int clk_hz[] = {25175000, 28322000, 25175000, 25175000}; + int64_t chars_per_sec; + struct vga_precise_retrace *r = &s->retrace_info.precise; + - htotal_chars = s->cr[0x00] + 5; - hretr_start_char = s->cr[0x04]; - hretr_skew_chars = (s->cr[0x05] >> 5) & 3; - hretr_end_char = s->cr[0x05] & 0x1f; ++ htotal_chars = s->cr[VGA_CRTC_H_TOTAL] + 5; ++ hretr_start_char = s->cr[VGA_CRTC_H_SYNC_START]; ++ hretr_skew_chars = (s->cr[VGA_CRTC_H_SYNC_END] >> 5) & 3; ++ hretr_end_char = s->cr[VGA_CRTC_H_SYNC_END] & 0x1f; + - vtotal_lines = (s->cr[0x06] - | (((s->cr[0x07] & 1) | ((s->cr[0x07] >> 4) & 2)) << 8)) + 2 - ; - vretr_start_line = s->cr[0x10] - | ((((s->cr[0x07] >> 2) & 1) | ((s->cr[0x07] >> 6) & 2)) << 8) - ; - vretr_end_line = s->cr[0x11] & 0xf; ++ vtotal_lines = (s->cr[VGA_CRTC_V_TOTAL] | ++ (((s->cr[VGA_CRTC_OVERFLOW] & 1) | ++ ((s->cr[VGA_CRTC_OVERFLOW] >> 4) & 2)) << 8)) + 2; ++ vretr_start_line = s->cr[VGA_CRTC_V_SYNC_START] | ++ ((((s->cr[VGA_CRTC_OVERFLOW] >> 2) & 1) | ++ ((s->cr[VGA_CRTC_OVERFLOW] >> 6) & 2)) << 8); ++ vretr_end_line = s->cr[VGA_CRTC_V_SYNC_END] & 0xf; + - - - clocking_mode = (s->sr[0x01] >> 3) & 1; ++ clocking_mode = (s->sr[VGA_SEQ_CLOCK_MODE] >> 3) & 1; + clock_sel = (s->msr >> 2) & 3; + dots = (s->msr & 1) ? 8 : 9; + + chars_per_sec = clk_hz[clock_sel] / dots; + + htotal_chars <<= clocking_mode; + + r->total_chars = vtotal_lines * htotal_chars; + if (r->freq) { + r->ticks_per_char = get_ticks_per_sec() / (r->total_chars * r->freq); + } else { + r->ticks_per_char = get_ticks_per_sec() / chars_per_sec; + } + + r->vstart = vretr_start_line; + r->vend = r->vstart + vretr_end_line + 1; + + r->hstart = hretr_start_char + hretr_skew_chars; + r->hend = r->hstart + hretr_end_char + 1; + r->htotal = htotal_chars; + +#if 0 - div2 = (s->cr[0x17] >> 2) & 1; - sldiv2 = (s->cr[0x17] >> 3) & 1; ++ div2 = (s->cr[VGA_CRTC_MODE] >> 2) & 1; ++ sldiv2 = (s->cr[VGA_CRTC_MODE] >> 3) & 1; + printf ( + "hz=%f\n" + "htotal = %d\n" + "hretr_start = %d\n" + "hretr_skew = %d\n" + "hretr_end = %d\n" + "vtotal = %d\n" + "vretr_start = %d\n" + "vretr_end = %d\n" + "div2 = %d sldiv2 = %d\n" + "clocking_mode = %d\n" + "clock_sel = %d %d\n" + "dots = %d\n" + "ticks/char = %" PRId64 "\n" + "\n", + (double) get_ticks_per_sec() / (r->ticks_per_char * r->total_chars), + htotal_chars, + hretr_start_char, + hretr_skew_chars, + hretr_end_char, + vtotal_lines, + vretr_start_line, + vretr_end_line, + div2, sldiv2, + clocking_mode, + clock_sel, + clk_hz[clock_sel], + dots, + r->ticks_per_char + ); +#endif +} + +static uint8_t vga_precise_retrace(VGACommonState *s) +{ + struct vga_precise_retrace *r = &s->retrace_info.precise; + uint8_t val = s->st01 & ~(ST01_V_RETRACE | ST01_DISP_ENABLE); + + if (r->total_chars) { + int cur_line, cur_line_char, cur_char; + int64_t cur_tick; + + cur_tick = qemu_get_clock_ns(vm_clock); + + cur_char = (cur_tick / r->ticks_per_char) % r->total_chars; + cur_line = cur_char / r->htotal; + + if (cur_line >= r->vstart && cur_line <= r->vend) { + val |= ST01_V_RETRACE | ST01_DISP_ENABLE; + } else { + cur_line_char = cur_char % r->htotal; + if (cur_line_char >= r->hstart && cur_line_char <= r->hend) { + val |= ST01_DISP_ENABLE; + } + } + + return val; + } else { + return s->st01 ^ (ST01_V_RETRACE | ST01_DISP_ENABLE); + } +} + +static uint8_t vga_dumb_retrace(VGACommonState *s) +{ + return s->st01 ^ (ST01_V_RETRACE | ST01_DISP_ENABLE); +} + ++#ifdef CONFIG_BOCHS_VBE ++static uint32_t vbe_ioport_read_index(void *opaque, uint32_t addr) ++{ ++ VGACommonState *s = opaque; ++ uint32_t val; ++ val = s->vbe_index; ++ return val; ++} ++ ++static uint32_t vbe_ioport_read_data(void *opaque, uint32_t addr) ++{ ++ VGACommonState *s = opaque; ++ uint32_t val; ++ ++ if (s->vbe_index < VBE_DISPI_INDEX_NB) { ++ if (s->vbe_regs[VBE_DISPI_INDEX_ENABLE] & VBE_DISPI_GETCAPS) { ++ switch(s->vbe_index) { ++ /* XXX: do not hardcode ? */ ++ case VBE_DISPI_INDEX_XRES: ++ val = VBE_DISPI_MAX_XRES; ++ break; ++ case VBE_DISPI_INDEX_YRES: ++ val = VBE_DISPI_MAX_YRES; ++ break; ++ case VBE_DISPI_INDEX_BPP: ++ val = VBE_DISPI_MAX_BPP; ++ break; ++ default: ++ val = s->vbe_regs[s->vbe_index]; ++ break; ++ } ++ } else { ++ val = s->vbe_regs[s->vbe_index]; ++ } ++ } else if (s->vbe_index == VBE_DISPI_INDEX_VIDEO_MEMORY_64K) { ++ val = s->vram_size / (64 * 1024); ++ } else { ++ val = 0; ++ } ++#ifdef DEBUG_BOCHS_VBE ++ printf("VBE: read index=0x%x val=0x%x\n", s->vbe_index, val); ++#endif ++ return val; ++} ++ ++static void vbe_ioport_write_index(void *opaque, uint32_t addr, uint32_t val) ++{ ++ VGACommonState *s = opaque; ++ s->vbe_index = val; ++} ++ ++static void vbe_ioport_write_data(void *opaque, uint32_t addr, uint32_t val) ++{ ++ VGACommonState *s = opaque; ++ ++ if (s->vbe_index <= VBE_DISPI_INDEX_NB) { ++#ifdef DEBUG_BOCHS_VBE ++ printf("VBE: write index=0x%x val=0x%x\n", s->vbe_index, val); ++#endif ++ switch(s->vbe_index) { ++ case VBE_DISPI_INDEX_ID: ++ if (val == VBE_DISPI_ID0 || ++ val == VBE_DISPI_ID1 || ++ val == VBE_DISPI_ID2 || ++ val == VBE_DISPI_ID3 || ++ val == VBE_DISPI_ID4) { ++ s->vbe_regs[s->vbe_index] = val; ++ } ++ break; ++ case VBE_DISPI_INDEX_XRES: ++ if ((val <= VBE_DISPI_MAX_XRES) && ((val & 7) == 0)) { ++ s->vbe_regs[s->vbe_index] = val; ++ } ++ break; ++ case VBE_DISPI_INDEX_YRES: ++ if (val <= VBE_DISPI_MAX_YRES) { ++ s->vbe_regs[s->vbe_index] = val; ++ } ++ break; ++ case VBE_DISPI_INDEX_BPP: ++ if (val == 0) ++ val = 8; ++ if (val == 4 || val == 8 || val == 15 || ++ val == 16 || val == 24 || val == 32) { ++ s->vbe_regs[s->vbe_index] = val; ++ } ++ break; ++ case VBE_DISPI_INDEX_BANK: ++ if (s->vbe_regs[VBE_DISPI_INDEX_BPP] == 4) { ++ val &= (s->vbe_bank_mask >> 2); ++ } else { ++ val &= s->vbe_bank_mask; ++ } ++ s->vbe_regs[s->vbe_index] = val; ++ s->bank_offset = (val << 16); ++ vga_update_memory_access(s); ++ break; ++ case VBE_DISPI_INDEX_ENABLE: ++ if ((val & VBE_DISPI_ENABLED) && ++ !(s->vbe_regs[VBE_DISPI_INDEX_ENABLE] & VBE_DISPI_ENABLED)) { ++ int h, shift_control; ++ ++ s->vbe_regs[VBE_DISPI_INDEX_VIRT_WIDTH] = ++ s->vbe_regs[VBE_DISPI_INDEX_XRES]; ++ s->vbe_regs[VBE_DISPI_INDEX_VIRT_HEIGHT] = ++ s->vbe_regs[VBE_DISPI_INDEX_YRES]; ++ s->vbe_regs[VBE_DISPI_INDEX_X_OFFSET] = 0; ++ s->vbe_regs[VBE_DISPI_INDEX_Y_OFFSET] = 0; ++ ++ if (s->vbe_regs[VBE_DISPI_INDEX_BPP] == 4) ++ s->vbe_line_offset = s->vbe_regs[VBE_DISPI_INDEX_XRES] >> 1; ++ else ++ s->vbe_line_offset = s->vbe_regs[VBE_DISPI_INDEX_XRES] * ++ ((s->vbe_regs[VBE_DISPI_INDEX_BPP] + 7) >> 3); ++ s->vbe_start_addr = 0; ++ ++ /* clear the screen (should be done in BIOS) */ ++ if (!(val & VBE_DISPI_NOCLEARMEM)) { ++ memset(s->vram_ptr, 0, ++ s->vbe_regs[VBE_DISPI_INDEX_YRES] * s->vbe_line_offset); ++ } ++ ++ /* we initialize the VGA graphic mode (should be done ++ in BIOS) */ ++ /* graphic mode + memory map 1 */ ++ s->gr[VGA_GFX_MISC] = (s->gr[VGA_GFX_MISC] & ~0x0c) | 0x04 | ++ VGA_GR06_GRAPHICS_MODE; ++ s->cr[VGA_CRTC_MODE] |= 3; /* no CGA modes */ ++ s->cr[VGA_CRTC_OFFSET] = s->vbe_line_offset >> 3; ++ /* width */ ++ s->cr[VGA_CRTC_H_DISP] = ++ (s->vbe_regs[VBE_DISPI_INDEX_XRES] >> 3) - 1; ++ /* height (only meaningful if < 1024) */ ++ h = s->vbe_regs[VBE_DISPI_INDEX_YRES] - 1; ++ s->cr[VGA_CRTC_V_DISP_END] = h; ++ s->cr[VGA_CRTC_OVERFLOW] = (s->cr[VGA_CRTC_OVERFLOW] & ~0x42) | ++ ((h >> 7) & 0x02) | ((h >> 3) & 0x40); ++ /* line compare to 1023 */ ++ s->cr[VGA_CRTC_LINE_COMPARE] = 0xff; ++ s->cr[VGA_CRTC_OVERFLOW] |= 0x10; ++ s->cr[VGA_CRTC_MAX_SCAN] |= 0x40; ++ ++ if (s->vbe_regs[VBE_DISPI_INDEX_BPP] == 4) { ++ shift_control = 0; ++ s->sr[VGA_SEQ_CLOCK_MODE] &= ~8; /* no double line */ ++ } else { ++ shift_control = 2; ++ /* set chain 4 mode */ ++ s->sr[VGA_SEQ_MEMORY_MODE] |= VGA_SR04_CHN_4M; ++ /* activate all planes */ ++ s->sr[VGA_SEQ_PLANE_WRITE] |= VGA_SR02_ALL_PLANES; ++ } ++ s->gr[VGA_GFX_MODE] = (s->gr[VGA_GFX_MODE] & ~0x60) | ++ (shift_control << 5); ++ s->cr[VGA_CRTC_MAX_SCAN] &= ~0x9f; /* no double scan */ ++ } else { ++ /* XXX: the bios should do that */ ++ s->bank_offset = 0; ++ } ++ s->dac_8bit = (val & VBE_DISPI_8BIT_DAC) > 0; ++ s->vbe_regs[s->vbe_index] = val; ++ vga_update_memory_access(s); ++ break; ++ case VBE_DISPI_INDEX_VIRT_WIDTH: ++ { ++ int w, h, line_offset; ++ ++ if (val < s->vbe_regs[VBE_DISPI_INDEX_XRES]) ++ return; ++ w = val; ++ if (s->vbe_regs[VBE_DISPI_INDEX_BPP] == 4) ++ line_offset = w >> 1; ++ else ++ line_offset = w * ((s->vbe_regs[VBE_DISPI_INDEX_BPP] + 7) >> 3); ++ h = s->vram_size / line_offset; ++ /* XXX: support weird bochs semantics ? */ ++ if (h < s->vbe_regs[VBE_DISPI_INDEX_YRES]) ++ return; ++ s->vbe_regs[VBE_DISPI_INDEX_VIRT_WIDTH] = w; ++ s->vbe_regs[VBE_DISPI_INDEX_VIRT_HEIGHT] = h; ++ s->vbe_line_offset = line_offset; ++ } ++ break; ++ case VBE_DISPI_INDEX_X_OFFSET: ++ case VBE_DISPI_INDEX_Y_OFFSET: ++ { ++ int x; ++ s->vbe_regs[s->vbe_index] = val; ++ s->vbe_start_addr = s->vbe_line_offset * s->vbe_regs[VBE_DISPI_INDEX_Y_OFFSET]; ++ x = s->vbe_regs[VBE_DISPI_INDEX_X_OFFSET]; ++ if (s->vbe_regs[VBE_DISPI_INDEX_BPP] == 4) ++ s->vbe_start_addr += x >> 1; ++ else ++ s->vbe_start_addr += x * ((s->vbe_regs[VBE_DISPI_INDEX_BPP] + 7) >> 3); ++ s->vbe_start_addr >>= 2; ++ } ++ break; ++ default: ++ break; ++ } ++ } ++} ++#endif ++ +typedef void maru_vga_draw_glyph8_func(uint8_t *d, int linesize, + const uint8_t *font_ptr, int h, + uint32_t fgcol, uint32_t bgcol); +typedef void maru_vga_draw_glyph9_func(uint8_t *d, int linesize, + const uint8_t *font_ptr, int h, + uint32_t fgcol, uint32_t bgcol, int dup9); +typedef void maru_vga_draw_line_func(VGACommonState *s1, uint8_t *d, + const uint8_t *s, int width); + +#define DEPTH 8 +#include "maru_vga_template.h" + +#define DEPTH 15 +#include "maru_vga_template.h" + +#define BGR_FORMAT +#define DEPTH 15 +#include "maru_vga_template.h" + +#define DEPTH 16 +#include "maru_vga_template.h" + +#define BGR_FORMAT +#define DEPTH 16 +#include "maru_vga_template.h" + +#define DEPTH 32 +#include "maru_vga_template.h" + +#define BGR_FORMAT +#define DEPTH 32 +#include "maru_vga_template.h" + +static unsigned int rgb_to_pixel8_dup(unsigned int r, unsigned int g, unsigned b) +{ + unsigned int col; + col = rgb_to_pixel8(r, g, b); + col |= col << 8; + col |= col << 16; + return col; +} + +static unsigned int rgb_to_pixel15_dup(unsigned int r, unsigned int g, unsigned b) +{ + unsigned int col; + col = rgb_to_pixel15(r, g, b); + col |= col << 16; + return col; +} + +static unsigned int rgb_to_pixel15bgr_dup(unsigned int r, unsigned int g, + unsigned int b) +{ + unsigned int col; + col = rgb_to_pixel15bgr(r, g, b); + col |= col << 16; + return col; +} + +static unsigned int rgb_to_pixel16_dup(unsigned int r, unsigned int g, unsigned b) +{ + unsigned int col; + col = rgb_to_pixel16(r, g, b); + col |= col << 16; + return col; +} + +static unsigned int rgb_to_pixel16bgr_dup(unsigned int r, unsigned int g, + unsigned int b) +{ + unsigned int col; + col = rgb_to_pixel16bgr(r, g, b); + col |= col << 16; + return col; +} + +static unsigned int rgb_to_pixel32_dup(unsigned int r, unsigned int g, unsigned b) +{ + unsigned int col; + col = rgb_to_pixel32(r, g, b); + return col; +} + +static unsigned int rgb_to_pixel32bgr_dup(unsigned int r, unsigned int g, unsigned b) +{ + unsigned int col; + col = rgb_to_pixel32bgr(r, g, b); + return col; +} + +/* return true if the palette was modified */ +static int update_palette16(VGACommonState *s) +{ + int full_update, i; + uint32_t v, col, *palette; + + full_update = 0; + palette = s->last_palette; + for(i = 0; i < 16; i++) { + v = s->ar[i]; - if (s->ar[0x10] & 0x80) - v = ((s->ar[0x14] & 0xf) << 4) | (v & 0xf); - else - v = ((s->ar[0x14] & 0xc) << 4) | (v & 0x3f); ++ if (s->ar[VGA_ATC_MODE] & 0x80) { ++ v = ((s->ar[VGA_ATC_COLOR_PAGE] & 0xf) << 4) | (v & 0xf); ++ } else { ++ v = ((s->ar[VGA_ATC_COLOR_PAGE] & 0xc) << 4) | (v & 0x3f); ++ } + v = v * 3; + col = s->rgb_to_pixel(c6_to_8(s->palette[v]), + c6_to_8(s->palette[v + 1]), + c6_to_8(s->palette[v + 2])); + if (col != palette[i]) { + full_update = 1; + palette[i] = col; + } + } + return full_update; +} + +/* return true if the palette was modified */ +static int update_palette256(VGACommonState *s) +{ + int full_update, i; + uint32_t v, col, *palette; + + full_update = 0; + palette = s->last_palette; + v = 0; + for(i = 0; i < 256; i++) { + if (s->dac_8bit) { + col = s->rgb_to_pixel(s->palette[v], + s->palette[v + 1], + s->palette[v + 2]); + } else { + col = s->rgb_to_pixel(c6_to_8(s->palette[v]), + c6_to_8(s->palette[v + 1]), + c6_to_8(s->palette[v + 2])); + } + if (col != palette[i]) { + full_update = 1; + palette[i] = col; + } + v += 3; + } + return full_update; +} + +static void vga_get_offsets(VGACommonState *s, + uint32_t *pline_offset, + uint32_t *pstart_addr, + uint32_t *pline_compare) +{ + uint32_t start_addr, line_offset, line_compare; +#ifdef CONFIG_BOCHS_VBE + if (s->vbe_regs[VBE_DISPI_INDEX_ENABLE] & VBE_DISPI_ENABLED) { + line_offset = s->vbe_line_offset; + start_addr = s->vbe_start_addr; + line_compare = 65535; + } else +#endif + { + /* compute line_offset in bytes */ - line_offset = s->cr[0x13]; ++ line_offset = s->cr[VGA_CRTC_OFFSET]; + line_offset <<= 3; + + /* starting address */ - start_addr = s->cr[0x0d] | (s->cr[0x0c] << 8); ++ start_addr = s->cr[VGA_CRTC_START_LO] | ++ (s->cr[VGA_CRTC_START_HI] << 8); + + /* line compare */ - line_compare = s->cr[0x18] | - ((s->cr[0x07] & 0x10) << 4) | - ((s->cr[0x09] & 0x40) << 3); ++ line_compare = s->cr[VGA_CRTC_LINE_COMPARE] | ++ ((s->cr[VGA_CRTC_OVERFLOW] & 0x10) << 4) | ++ ((s->cr[VGA_CRTC_MAX_SCAN] & 0x40) << 3); + } + *pline_offset = line_offset; + *pstart_addr = start_addr; + *pline_compare = line_compare; +} + +/* update start_addr and line_offset. Return TRUE if modified */ +static int update_basic_params(VGACommonState *s) +{ + int full_update; + uint32_t start_addr, line_offset, line_compare; + + full_update = 0; + + s->get_offsets(s, &line_offset, &start_addr, &line_compare); + + if (line_offset != s->line_offset || + start_addr != s->start_addr || + line_compare != s->line_compare) { + s->line_offset = line_offset; + s->start_addr = start_addr; + s->line_compare = line_compare; + full_update = 1; + } + return full_update; +} + +#define NB_DEPTHS 7 + +static inline int get_depth_index(DisplayState *s) +{ + switch(ds_get_bits_per_pixel(s)) { + default: + case 8: + return 0; + case 15: + return 1; + case 16: + return 2; + case 32: + if (is_surface_bgr(s->surface)) + return 4; + else + return 3; + } +} + +static maru_vga_draw_glyph8_func * const maru_vga_draw_glyph8_table[NB_DEPTHS] = { + maru_vga_draw_glyph8_8, + maru_vga_draw_glyph8_16, + maru_vga_draw_glyph8_16, + maru_vga_draw_glyph8_32, + maru_vga_draw_glyph8_32, + maru_vga_draw_glyph8_16, + maru_vga_draw_glyph8_16, +}; + +static maru_vga_draw_glyph8_func * const maru_vga_draw_glyph16_table[NB_DEPTHS] = { + maru_vga_draw_glyph16_8, + maru_vga_draw_glyph16_16, + maru_vga_draw_glyph16_16, + maru_vga_draw_glyph16_32, + maru_vga_draw_glyph16_32, + maru_vga_draw_glyph16_16, + maru_vga_draw_glyph16_16, +}; + +static maru_vga_draw_glyph9_func * const maru_vga_draw_glyph9_table[NB_DEPTHS] = { + maru_vga_draw_glyph9_8, + maru_vga_draw_glyph9_16, + maru_vga_draw_glyph9_16, + maru_vga_draw_glyph9_32, + maru_vga_draw_glyph9_32, + maru_vga_draw_glyph9_16, + maru_vga_draw_glyph9_16, +}; + +static const uint8_t cursor_glyph[32 * 4] = { + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, +}; + +static void vga_get_text_resolution(VGACommonState *s, int *pwidth, int *pheight, + int *pcwidth, int *pcheight) +{ + int width, cwidth, height, cheight; + + /* total width & height */ - cheight = (s->cr[9] & 0x1f) + 1; ++ cheight = (s->cr[VGA_CRTC_MAX_SCAN] & 0x1f) + 1; + cwidth = 8; - if (!(s->sr[1] & 0x01)) ++ if (!(s->sr[VGA_SEQ_CLOCK_MODE] & VGA_SR01_CHAR_CLK_8DOTS)) { + cwidth = 9; - if (s->sr[1] & 0x08) ++ } ++ if (s->sr[VGA_SEQ_CLOCK_MODE] & 0x08) { + cwidth = 16; /* NOTE: no 18 pixel wide */ - width = (s->cr[0x01] + 1); - if (s->cr[0x06] == 100) { ++ } ++ width = (s->cr[VGA_CRTC_H_DISP] + 1); ++ if (s->cr[VGA_CRTC_V_TOTAL] == 100) { + /* ugly hack for CGA 160x100x16 - explain me the logic */ + height = 100; + } else { - height = s->cr[0x12] | - ((s->cr[0x07] & 0x02) << 7) | - ((s->cr[0x07] & 0x40) << 3); ++ height = s->cr[VGA_CRTC_V_DISP_END] | ++ ((s->cr[VGA_CRTC_OVERFLOW] & 0x02) << 7) | ++ ((s->cr[VGA_CRTC_OVERFLOW] & 0x40) << 3); + height = (height + 1) / cheight; + } + + *pwidth = width; + *pheight = height; + *pcwidth = cwidth; + *pcheight = cheight; +} + +typedef unsigned int rgb_to_pixel_dup_func(unsigned int r, unsigned int g, unsigned b); + +static rgb_to_pixel_dup_func * const rgb_to_pixel_dup_table[NB_DEPTHS] = { + rgb_to_pixel8_dup, + rgb_to_pixel15_dup, + rgb_to_pixel16_dup, + rgb_to_pixel32_dup, + rgb_to_pixel32bgr_dup, + rgb_to_pixel15bgr_dup, + rgb_to_pixel16bgr_dup, +}; + +/* + * Text mode update + * Missing: + * - double scan + * - double width + * - underline + * - flashing + */ +static void vga_draw_text(VGACommonState *s, int full_update) +{ + int cx, cy, cheight, cw, ch, cattr, height, width, ch_attr; + int cx_min, cx_max, linesize, x_incr, line, line1; + uint32_t offset, fgcol, bgcol, v, cursor_offset; + uint8_t *d1, *d, *src, *dest, *cursor_ptr; + const uint8_t *font_ptr, *font_base[2]; + int dup9, line_offset, depth_index; + uint32_t *palette; + uint32_t *ch_attr_ptr; + maru_vga_draw_glyph8_func *maru_vga_draw_glyph8; + maru_vga_draw_glyph9_func *maru_vga_draw_glyph9; ++ int64_t now = qemu_get_clock_ms(vm_clock); + + /* compute font data address (in plane 2) */ - v = s->sr[3]; ++ v = s->sr[VGA_SEQ_CHARACTER_MAP]; + offset = (((v >> 4) & 1) | ((v << 1) & 6)) * 8192 * 4 + 2; + if (offset != s->font_offsets[0]) { + s->font_offsets[0] = offset; + full_update = 1; + } + font_base[0] = s->vram_ptr + offset; + + offset = (((v >> 5) & 1) | ((v >> 1) & 6)) * 8192 * 4 + 2; + font_base[1] = s->vram_ptr + offset; + if (offset != s->font_offsets[1]) { + s->font_offsets[1] = offset; + full_update = 1; + } + if (s->plane_updated & (1 << 2) || s->chain4_alias) { + /* if the plane 2 was modified since the last display, it + indicates the font may have been modified */ + s->plane_updated = 0; + full_update = 1; + } + full_update |= update_basic_params(s); + + line_offset = s->line_offset; + + vga_get_text_resolution(s, &width, &height, &cw, &cheight); ++ if ((height * width) <= 1) { ++ /* better than nothing: exit if transient size is too small */ ++ return; ++ } + if ((height * width) > CH_ATTR_SIZE) { + /* better than nothing: exit if transient size is too big */ + return; + } + + if (width != s->last_width || height != s->last_height || + cw != s->last_cw || cheight != s->last_ch || s->last_depth) { + s->last_scr_width = width * cw; + s->last_scr_height = height * cheight; + qemu_console_resize(s->ds, s->last_scr_width, s->last_scr_height); + s->last_depth = 0; + s->last_width = width; + s->last_height = height; + s->last_ch = cheight; + s->last_cw = cw; + full_update = 1; + } + s->rgb_to_pixel = + rgb_to_pixel_dup_table[get_depth_index(s->ds)]; + full_update |= update_palette16(s); + palette = s->last_palette; + x_incr = cw * ((ds_get_bits_per_pixel(s->ds) + 7) >> 3); + - cursor_offset = ((s->cr[0x0e] << 8) | s->cr[0x0f]) - s->start_addr; ++ cursor_offset = ((s->cr[VGA_CRTC_CURSOR_HI] << 8) | ++ s->cr[VGA_CRTC_CURSOR_LO]) - s->start_addr; + if (cursor_offset != s->cursor_offset || - s->cr[0xa] != s->cursor_start || - s->cr[0xb] != s->cursor_end) { ++ s->cr[VGA_CRTC_CURSOR_START] != s->cursor_start || ++ s->cr[VGA_CRTC_CURSOR_END] != s->cursor_end) { + /* if the cursor position changed, we update the old and new + chars */ + if (s->cursor_offset < CH_ATTR_SIZE) + s->last_ch_attr[s->cursor_offset] = -1; + if (cursor_offset < CH_ATTR_SIZE) + s->last_ch_attr[cursor_offset] = -1; + s->cursor_offset = cursor_offset; - s->cursor_start = s->cr[0xa]; - s->cursor_end = s->cr[0xb]; ++ s->cursor_start = s->cr[VGA_CRTC_CURSOR_START]; ++ s->cursor_end = s->cr[VGA_CRTC_CURSOR_END]; + } + cursor_ptr = s->vram_ptr + (s->start_addr + cursor_offset) * 4; ++ if (now >= s->cursor_blink_time) { ++ s->cursor_blink_time = now + VGA_TEXT_CURSOR_PERIOD_MS / 2; ++ s->cursor_visible_phase = !s->cursor_visible_phase; ++ } + + depth_index = get_depth_index(s->ds); + if (cw == 16) + maru_vga_draw_glyph8 = maru_vga_draw_glyph16_table[depth_index]; + else + maru_vga_draw_glyph8 = maru_vga_draw_glyph8_table[depth_index]; + maru_vga_draw_glyph9 = maru_vga_draw_glyph9_table[depth_index]; + + dest = ds_get_data(s->ds); + linesize = ds_get_linesize(s->ds); + ch_attr_ptr = s->last_ch_attr; + line = 0; + offset = s->start_addr * 4; + for(cy = 0; cy < height; cy++) { + d1 = dest; + src = s->vram_ptr + offset; + cx_min = width; + cx_max = -1; + for(cx = 0; cx < width; cx++) { + ch_attr = *(uint16_t *)src; - if (full_update || ch_attr != *ch_attr_ptr) { ++ if (full_update || ch_attr != *ch_attr_ptr || src == cursor_ptr) { + if (cx < cx_min) + cx_min = cx; + if (cx > cx_max) + cx_max = cx; + *ch_attr_ptr = ch_attr; +#ifdef HOST_WORDS_BIGENDIAN + ch = ch_attr >> 8; + cattr = ch_attr & 0xff; +#else + ch = ch_attr & 0xff; + cattr = ch_attr >> 8; +#endif + font_ptr = font_base[(cattr >> 3) & 1]; + font_ptr += 32 * 4 * ch; + bgcol = palette[cattr >> 4]; + fgcol = palette[cattr & 0x0f]; + if (cw != 9) { + maru_vga_draw_glyph8(d1, linesize, + font_ptr, cheight, fgcol, bgcol); + } else { + dup9 = 0; - if (ch >= 0xb0 && ch <= 0xdf && (s->ar[0x10] & 0x04)) ++ if (ch >= 0xb0 && ch <= 0xdf && ++ (s->ar[VGA_ATC_MODE] & 0x04)) { + dup9 = 1; ++ } + maru_vga_draw_glyph9(d1, linesize, + font_ptr, cheight, fgcol, bgcol, dup9); + } + if (src == cursor_ptr && - !(s->cr[0x0a] & 0x20)) { ++ !(s->cr[VGA_CRTC_CURSOR_START] & 0x20) && ++ s->cursor_visible_phase) { + int line_start, line_last, h; + /* draw the cursor */ - line_start = s->cr[0x0a] & 0x1f; - line_last = s->cr[0x0b] & 0x1f; ++ line_start = s->cr[VGA_CRTC_CURSOR_START] & 0x1f; ++ line_last = s->cr[VGA_CRTC_CURSOR_END] & 0x1f; + /* XXX: check that */ + if (line_last > cheight - 1) + line_last = cheight - 1; + if (line_last >= line_start && line_start < cheight) { + h = line_last - line_start + 1; + d = d1 + linesize * line_start; + if (cw != 9) { + maru_vga_draw_glyph8(d, linesize, + cursor_glyph, h, fgcol, bgcol); + } else { + maru_vga_draw_glyph9(d, linesize, + cursor_glyph, h, fgcol, bgcol, 1); + } + } + } + } + d1 += x_incr; + src += 4; + ch_attr_ptr++; + } + if (cx_max != -1) { + dpy_update(s->ds, cx_min * cw, cy * cheight, + (cx_max - cx_min + 1) * cw, cheight); + } + dest += linesize * cheight; + line1 = line + cheight; + offset += line_offset; + if (line < s->line_compare && line1 >= s->line_compare) { + offset = 0; + } + line = line1; + } +} + +enum { + maru_vga_draw_line2, + maru_vga_draw_line2D2, + maru_vga_draw_line4, + maru_vga_draw_line4D2, + maru_vga_draw_line8D2, + maru_vga_draw_line8, + maru_vga_draw_line15, + maru_vga_draw_line16, + maru_vga_draw_line24, + maru_vga_draw_line32, + maru_vga_draw_line_NB, +}; + +static maru_vga_draw_line_func * const maru_vga_draw_line_table[NB_DEPTHS * maru_vga_draw_line_NB] = { + maru_vga_draw_line2_8, + maru_vga_draw_line2_16, + maru_vga_draw_line2_16, + maru_vga_draw_line2_32, + maru_vga_draw_line2_32, + maru_vga_draw_line2_16, + maru_vga_draw_line2_16, + + maru_vga_draw_line2d2_8, + maru_vga_draw_line2d2_16, + maru_vga_draw_line2d2_16, + maru_vga_draw_line2d2_32, + maru_vga_draw_line2d2_32, + maru_vga_draw_line2d2_16, + maru_vga_draw_line2d2_16, + + maru_vga_draw_line4_8, + maru_vga_draw_line4_16, + maru_vga_draw_line4_16, + maru_vga_draw_line4_32, + maru_vga_draw_line4_32, + maru_vga_draw_line4_16, + maru_vga_draw_line4_16, + + maru_vga_draw_line4d2_8, + maru_vga_draw_line4d2_16, + maru_vga_draw_line4d2_16, + maru_vga_draw_line4d2_32, + maru_vga_draw_line4d2_32, + maru_vga_draw_line4d2_16, + maru_vga_draw_line4d2_16, + + maru_vga_draw_line8d2_8, + maru_vga_draw_line8d2_16, + maru_vga_draw_line8d2_16, + maru_vga_draw_line8d2_32, + maru_vga_draw_line8d2_32, + maru_vga_draw_line8d2_16, + maru_vga_draw_line8d2_16, + + maru_vga_draw_line8_8, + maru_vga_draw_line8_16, + maru_vga_draw_line8_16, + maru_vga_draw_line8_32, + maru_vga_draw_line8_32, + maru_vga_draw_line8_16, + maru_vga_draw_line8_16, + + maru_vga_draw_line15_8, + maru_vga_draw_line15_15, + maru_vga_draw_line15_16, + maru_vga_draw_line15_32, + maru_vga_draw_line15_32bgr, + maru_vga_draw_line15_15bgr, + maru_vga_draw_line15_16bgr, + + maru_vga_draw_line16_8, + maru_vga_draw_line16_15, + maru_vga_draw_line16_16, + maru_vga_draw_line16_32, + maru_vga_draw_line16_32bgr, + maru_vga_draw_line16_15bgr, + maru_vga_draw_line16_16bgr, + + maru_vga_draw_line24_8, + maru_vga_draw_line24_15, + maru_vga_draw_line24_16, + maru_vga_draw_line24_32, + maru_vga_draw_line24_32bgr, + maru_vga_draw_line24_15bgr, + maru_vga_draw_line24_16bgr, + + maru_vga_draw_line32_8, + maru_vga_draw_line32_15, + maru_vga_draw_line32_16, + maru_vga_draw_line32_32, + maru_vga_draw_line32_32bgr, + maru_vga_draw_line32_15bgr, + maru_vga_draw_line32_16bgr, +}; + +static int vga_get_bpp(VGACommonState *s) +{ + int ret; +#ifdef CONFIG_BOCHS_VBE + if (s->vbe_regs[VBE_DISPI_INDEX_ENABLE] & VBE_DISPI_ENABLED) { + ret = s->vbe_regs[VBE_DISPI_INDEX_BPP]; + } else +#endif + { + ret = 0; + } + return ret; +} + +static void vga_get_resolution(VGACommonState *s, int *pwidth, int *pheight) +{ + int width, height; + +#ifdef CONFIG_BOCHS_VBE + if (s->vbe_regs[VBE_DISPI_INDEX_ENABLE] & VBE_DISPI_ENABLED) { + width = s->vbe_regs[VBE_DISPI_INDEX_XRES]; + height = s->vbe_regs[VBE_DISPI_INDEX_YRES]; + } else +#endif + { - width = (s->cr[0x01] + 1) * 8; - height = s->cr[0x12] | - ((s->cr[0x07] & 0x02) << 7) | - ((s->cr[0x07] & 0x40) << 3); ++ width = (s->cr[VGA_CRTC_H_DISP] + 1) * 8; ++ height = s->cr[VGA_CRTC_V_DISP_END] | ++ ((s->cr[VGA_CRTC_OVERFLOW] & 0x02) << 7) | ++ ((s->cr[VGA_CRTC_OVERFLOW] & 0x40) << 3); + height = (height + 1); + } + *pwidth = width; + *pheight = height; +} + +static void vga_sync_dirty_bitmap(VGACommonState *s) +{ + memory_region_sync_dirty_bitmap(&s->vram); +} + +/* + * graphic modes + */ +static void vga_draw_graphic(VGACommonState *s, int full_update) +{ + int y1, y, update, linesize, y_start, double_scan, mask, depth; + int width, height, shift_control, line_offset, bwidth, bits; + ram_addr_t page0, page1, page_min, page_max; + int disp_width, multi_scan, multi_run; + uint8_t *d; + uint32_t v, addr1, addr; + maru_vga_draw_line_func *maru_vga_draw_line; + + full_update |= update_basic_params(s); + + if (!full_update) + vga_sync_dirty_bitmap(s); + + s->get_resolution(s, &width, &height); + + disp_width = width; + - shift_control = (s->gr[0x05] >> 5) & 3; - double_scan = (s->cr[0x09] >> 7); ++ shift_control = (s->gr[VGA_GFX_MODE] >> 5) & 3; ++ double_scan = (s->cr[VGA_CRTC_MAX_SCAN] >> 7); + if (shift_control != 1) { - multi_scan = (((s->cr[0x09] & 0x1f) + 1) << double_scan) - 1; ++ multi_scan = (((s->cr[VGA_CRTC_MAX_SCAN] & 0x1f) + 1) << double_scan) ++ - 1; + } else { + /* in CGA modes, multi_scan is ignored */ + /* XXX: is it correct ? */ + multi_scan = double_scan; + } + multi_run = multi_scan; + if (shift_control != s->shift_control || + double_scan != s->double_scan) { + full_update = 1; + s->shift_control = shift_control; + s->double_scan = double_scan; + } + + if (shift_control == 0) { - if (s->sr[0x01] & 8) { ++ if (s->sr[VGA_SEQ_CLOCK_MODE] & 8) { + disp_width <<= 1; + } + } else if (shift_control == 1) { - if (s->sr[0x01] & 8) { ++ if (s->sr[VGA_SEQ_CLOCK_MODE] & 8) { + disp_width <<= 1; + } + } + + depth = s->get_bpp(s); + if (s->line_offset != s->last_line_offset || + disp_width != s->last_width || + height != s->last_height || + s->last_depth != depth) { +#if defined(HOST_WORDS_BIGENDIAN) == defined(TARGET_WORDS_BIGENDIAN) + if (depth == 16 || depth == 32) { +#else + if (depth == 32) { +#endif + qemu_free_displaysurface(s->ds); + +#ifdef MARU_VGA // create new sufrace by malloc in MARU VGA + +#ifdef USE_SHM + s->ds->surface = qemu_create_displaysurface_from(disp_width, height, depth, + disp_width * 4, (uint8_t*)shared_memory); +#else + s->ds->surface = qemu_create_displaysurface(s->ds, disp_width, height); +#endif //USE_SHM + +#else //MARU_VGA + s->ds->surface = qemu_create_displaysurface_from(disp_width, height, depth, + s->line_offset, + s->vram_ptr + (s->start_addr * 4)); +#endif //MARU_VGA + +#if defined(HOST_WORDS_BIGENDIAN) != defined(TARGET_WORDS_BIGENDIAN) + s->ds->surface->pf = qemu_different_endianness_pixelformat(depth); +#endif + dpy_resize(s->ds); + } else { + qemu_console_resize(s->ds, disp_width, height); + } + s->last_scr_width = disp_width; + s->last_scr_height = height; + s->last_width = disp_width; + s->last_height = height; + s->last_line_offset = s->line_offset; + s->last_depth = depth; + full_update = 1; +#ifndef USE_SHM + } else if (is_buffer_shared(s->ds->surface) && + (full_update || s->ds->surface->data != s->vram_ptr + (s->start_addr * 4))) { + s->ds->surface->data = s->vram_ptr + (s->start_addr * 4); + dpy_setdata(s->ds); + } +#else + } +#endif + s->rgb_to_pixel = + rgb_to_pixel_dup_table[get_depth_index(s->ds)]; + + if (shift_control == 0) { + full_update |= update_palette16(s); - if (s->sr[0x01] & 8) { ++ if (s->sr[VGA_SEQ_CLOCK_MODE] & 8) { + v = maru_vga_draw_line4D2; + } else { + v = maru_vga_draw_line4; + } + bits = 4; + } else if (shift_control == 1) { + full_update |= update_palette16(s); - if (s->sr[0x01] & 8) { ++ if (s->sr[VGA_SEQ_CLOCK_MODE] & 8) { + v = maru_vga_draw_line2D2; + } else { + v = maru_vga_draw_line2; + } + bits = 4; + } else { + switch(s->get_bpp(s)) { + default: + case 0: + full_update |= update_palette256(s); + v = maru_vga_draw_line8D2; + bits = 4; + break; + case 8: + full_update |= update_palette256(s); + v = maru_vga_draw_line8; + bits = 8; + break; + case 15: + v = maru_vga_draw_line15; + bits = 16; + break; + case 16: + v = maru_vga_draw_line16; + bits = 16; + break; + case 24: + v = maru_vga_draw_line24; + bits = 24; + break; + case 32: + v = maru_vga_draw_line32; + bits = 32; + break; + } + } + maru_vga_draw_line = maru_vga_draw_line_table[v * NB_DEPTHS + get_depth_index(s->ds)]; + +#ifndef USE_SHM + if (!is_buffer_shared(s->ds->surface) && s->cursor_invalidate) +#else + if (s->cursor_invalidate) +#endif + s->cursor_invalidate(s); + + line_offset = s->line_offset; +#if 0 + printf("w=%d h=%d v=%d line_offset=%d cr[0x09]=0x%02x cr[0x17]=0x%02x linecmp=%d sr[0x01]=0x%02x\n", - width, height, v, line_offset, s->cr[9], s->cr[0x17], s->line_compare, s->sr[0x01]); ++ width, height, v, line_offset, s->cr[9], s->cr[VGA_CRTC_MODE], ++ s->line_compare, s->sr[VGA_SEQ_CLOCK_MODE]); +#endif + addr1 = (s->start_addr * 4); + bwidth = (width * bits + 7) / 8; + y_start = -1; + page_min = -1; + page_max = 0; + d = ds_get_data(s->ds); + linesize = ds_get_linesize(s->ds); + y1 = 0; + for(y = 0; y < height; y++) { + addr = addr1; + if (!(s->cr[0x17] & 1)) { + int shift; + /* CGA compatibility handling */ + shift = 14 + ((s->cr[0x17] >> 6) & 1); + addr = (addr & ~(1 << shift)) | ((y1 & 1) << shift); + } + if (!(s->cr[0x17] & 2)) { + addr = (addr & ~0x8000) | ((y1 & 2) << 14); + } + update = full_update; + page0 = addr; + page1 = addr + bwidth - 1; + update |= memory_region_get_dirty(&s->vram, page0, page1 - page0, + DIRTY_MEMORY_VGA); + /* explicit invalidation for the hardware cursor */ + update |= (s->invalidated_y_table[y >> 5] >> (y & 0x1f)) & 1; + +#ifdef MARU_VGA // needs full update + update |= 1; +#endif + + if (update) { + if (y_start < 0) + y_start = y; + if (page0 < page_min) + page_min = page0; + if (page1 > page_max) + page_max = page1; +#ifndef USE_SHM + if (!(is_buffer_shared(s->ds->surface))) { +#endif + maru_vga_draw_line(s, d, s->vram_ptr + addr, width); + if (s->cursor_draw_line) + s->cursor_draw_line(s, d, y); +#ifndef USE_SHM + } +#endif + +#ifdef MARU_VGA + + int i; + uint8_t *fb_sub; + uint8_t *over_sub; + uint8_t *dst_sub; + uint8_t alpha, c_alpha; + uint32_t *dst; + uint16_t overlay_bottom; + + if ( overlay0_power ) { + + overlay_bottom = overlay0_top + overlay0_height; + + if ( overlay0_top <= y && y < overlay_bottom ) { + + fb_sub = s->vram_ptr + addr + overlay0_left * 4; + over_sub = overlay_ptr + ( y - overlay0_top ) * overlay0_width * 4; + dst = (uint32_t*) ( s->ds->surface->data + addr + overlay0_left * 4 ); + + for ( i = 0; i < overlay0_width; i++, fb_sub += 4, over_sub += 4, dst++ ) { + + alpha = fb_sub[3]; + c_alpha = 0xff - alpha; + + *dst = ( ( c_alpha * over_sub[0] + alpha * fb_sub[0] ) >> 8 ) + | ( ( c_alpha * over_sub[1] + alpha * fb_sub[1] ) & 0xFF00 ) + | ( ( ( c_alpha * over_sub[2] + alpha * fb_sub[2] ) & 0xFF00 ) << 8 ); + } + + } + + } + + if ( overlay1_power ) { + + overlay_bottom = overlay1_top + overlay1_height; + + if ( overlay1_top <= y && y < overlay_bottom ) { + + fb_sub = s->vram_ptr + addr + overlay1_left * 4; + over_sub = overlay_ptr + ( y - overlay1_top ) * overlay1_width * 4 + 0x00400000; + dst = (uint32_t*) ( s->ds->surface->data + addr + overlay1_left * 4 ); + + for ( i = 0; i < overlay1_width; i++, fb_sub += 4, over_sub += 4, dst++ ) { + + alpha = fb_sub[3]; + c_alpha = 0xff - alpha; + + *dst = ( ( c_alpha * over_sub[0] + alpha * fb_sub[0] ) >> 8 ) + | ( ( c_alpha * over_sub[1] + alpha * fb_sub[1] ) & 0xFF00 ) + | ( ( ( c_alpha * over_sub[2] + alpha * fb_sub[2] ) & 0xFF00 ) << 8 ); + } + + } + + } + + if ( brightness_off ) { + + dst_sub = s->ds->surface->data + addr; + dst = (uint32_t*) ( s->ds->surface->data + addr ); + + for ( i = 0; i < disp_width; i++, dst_sub += 4, dst++ ) { + *dst = 0xFF000000; // black + } + + } else { + + if ( brightness_level < BRIGHTNESS_MAX ) { + + alpha = brightness_tbl[brightness_level]; + + dst_sub = s->ds->surface->data + addr; + dst = (uint32_t*) ( s->ds->surface->data + addr ); + + for ( i = 0; i < disp_width; i++, dst_sub += 4, dst++ ) { + *dst = ( ( alpha * dst_sub[0] ) >> 8 ) + | ( ( alpha * dst_sub[1] ) & 0xFF00 ) + | ( ( ( alpha * dst_sub[2] ) & 0xFF00 ) << 8 ); + } + } + + } + +#endif /* MARU_VGA */ + + } else { + if (y_start >= 0) { + /* flush to display */ + dpy_update(s->ds, 0, y_start, + disp_width, y - y_start); + y_start = -1; + } + } + if (!multi_run) { - mask = (s->cr[0x17] & 3) ^ 3; ++ mask = (s->cr[VGA_CRTC_MODE] & 3) ^ 3; + if ((y1 & mask) == mask) + addr1 += line_offset; + y1++; + multi_run = multi_scan; + } else { + multi_run--; + } + /* line compare acts on the displayed lines */ + if (y == s->line_compare) + addr1 = 0; + d += linesize; + } + if (y_start >= 0) { + /* flush to display */ + dpy_update(s->ds, 0, y_start, + disp_width, y - y_start); + } + + /* reset modified pages */ + if (page_max >= page_min) { + memory_region_reset_dirty(&s->vram, + page_min, + page_max - page_min, + DIRTY_MEMORY_VGA); + } + memset(s->invalidated_y_table, 0, ((height + 31) >> 5) * 4); +} + +static void vga_draw_blank(VGACommonState *s, int full_update) +{ + int i, w, val; + uint8_t *d; + + if (!full_update) + return; + if (s->last_scr_width <= 0 || s->last_scr_height <= 0) + return; + + s->rgb_to_pixel = + rgb_to_pixel_dup_table[get_depth_index(s->ds)]; + if (ds_get_bits_per_pixel(s->ds) == 8) + val = s->rgb_to_pixel(0, 0, 0); + else + val = 0; + w = s->last_scr_width * ((ds_get_bits_per_pixel(s->ds) + 7) >> 3); + d = ds_get_data(s->ds); + for(i = 0; i < s->last_scr_height; i++) { + memset(d, val, w); + d += ds_get_linesize(s->ds); + } + dpy_update(s->ds, 0, 0, + s->last_scr_width, s->last_scr_height); +} + +#define GMODE_TEXT 0 +#define GMODE_GRAPH 1 +#define GMODE_BLANK 2 + +static void vga_update_display(void *opaque) +{ + VGACommonState *s = opaque; + int full_update, graphic_mode; + + qemu_flush_coalesced_mmio_buffer(); + + if (ds_get_bits_per_pixel(s->ds) == 0) { + /* nothing to do */ + } else { + full_update = 0; + if (!(s->ar_index & 0x20)) { + graphic_mode = GMODE_BLANK; + } else { - graphic_mode = s->gr[6] & 1; ++ graphic_mode = s->gr[VGA_GFX_MISC] & VGA_GR06_GRAPHICS_MODE; + } + if (graphic_mode != s->graphic_mode) { + s->graphic_mode = graphic_mode; ++ s->cursor_blink_time = qemu_get_clock_ms(vm_clock); + full_update = 1; + } + switch(graphic_mode) { + case GMODE_TEXT: + vga_draw_text(s, full_update); + break; + case GMODE_GRAPH: + vga_draw_graphic(s, full_update); + break; + case GMODE_BLANK: + default: + vga_draw_blank(s, full_update); + break; + } + } +} + +/* force a full display refresh */ +static void vga_invalidate_display(void *opaque) +{ + VGACommonState *s = opaque; + + s->last_width = -1; + s->last_height = -1; +} + ++static void vga_reset(void *opaque) ++{ ++ VGACommonState *s = opaque; ++ vga_common_reset(s); ++} + +#define TEXTMODE_X(x) ((x) % width) +#define TEXTMODE_Y(x) ((x) / width) +#define VMEM2CHTYPE(v) ((v & 0xff0007ff) | \ + ((v & 0x00000800) << 10) | ((v & 0x00007000) >> 1)) +/* relay text rendering to the display driver + * instead of doing a full vga_update_display() */ +static void vga_update_text(void *opaque, console_ch_t *chardata) +{ + VGACommonState *s = opaque; + int graphic_mode, i, cursor_offset, cursor_visible; + int cw, cheight, width, height, size, c_min, c_max; + uint32_t *src; + console_ch_t *dst, val; + char msg_buffer[80]; + int full_update = 0; + + qemu_flush_coalesced_mmio_buffer(); + + if (!(s->ar_index & 0x20)) { + graphic_mode = GMODE_BLANK; + } else { - graphic_mode = s->gr[6] & 1; ++ graphic_mode = s->gr[VGA_GFX_MISC] & VGA_GR06_GRAPHICS_MODE; + } + if (graphic_mode != s->graphic_mode) { + s->graphic_mode = graphic_mode; + full_update = 1; + } + if (s->last_width == -1) { + s->last_width = 0; + full_update = 1; + } + + switch (graphic_mode) { + case GMODE_TEXT: + /* TODO: update palette */ + full_update |= update_basic_params(s); + + /* total width & height */ - cheight = (s->cr[9] & 0x1f) + 1; ++ cheight = (s->cr[VGA_CRTC_MAX_SCAN] & 0x1f) + 1; + cw = 8; - if (!(s->sr[1] & 0x01)) ++ if (!(s->sr[VGA_SEQ_CLOCK_MODE] & VGA_SR01_CHAR_CLK_8DOTS)) { + cw = 9; - if (s->sr[1] & 0x08) ++ } ++ if (s->sr[VGA_SEQ_CLOCK_MODE] & 0x08) { + cw = 16; /* NOTE: no 18 pixel wide */ - width = (s->cr[0x01] + 1); - if (s->cr[0x06] == 100) { ++ } ++ width = (s->cr[VGA_CRTC_H_DISP] + 1); ++ if (s->cr[VGA_CRTC_V_TOTAL] == 100) { + /* ugly hack for CGA 160x100x16 - explain me the logic */ + height = 100; + } else { - height = s->cr[0x12] | - ((s->cr[0x07] & 0x02) << 7) | - ((s->cr[0x07] & 0x40) << 3); ++ height = s->cr[VGA_CRTC_V_DISP_END] | ++ ((s->cr[VGA_CRTC_OVERFLOW] & 0x02) << 7) | ++ ((s->cr[VGA_CRTC_OVERFLOW] & 0x40) << 3); + height = (height + 1) / cheight; + } + + size = (height * width); + if (size > CH_ATTR_SIZE) { + if (!full_update) + return; + + snprintf(msg_buffer, sizeof(msg_buffer), "%i x %i Text mode", + width, height); + break; + } + + if (width != s->last_width || height != s->last_height || + cw != s->last_cw || cheight != s->last_ch) { + s->last_scr_width = width * cw; + s->last_scr_height = height * cheight; + s->ds->surface->width = width; + s->ds->surface->height = height; + dpy_resize(s->ds); + s->last_width = width; + s->last_height = height; + s->last_ch = cheight; + s->last_cw = cw; + full_update = 1; + } + + /* Update "hardware" cursor */ - cursor_offset = ((s->cr[0x0e] << 8) | s->cr[0x0f]) - s->start_addr; ++ cursor_offset = ((s->cr[VGA_CRTC_CURSOR_HI] << 8) | ++ s->cr[VGA_CRTC_CURSOR_LO]) - s->start_addr; + if (cursor_offset != s->cursor_offset || - s->cr[0xa] != s->cursor_start || - s->cr[0xb] != s->cursor_end || full_update) { - cursor_visible = !(s->cr[0xa] & 0x20); ++ s->cr[VGA_CRTC_CURSOR_START] != s->cursor_start || ++ s->cr[VGA_CRTC_CURSOR_END] != s->cursor_end || full_update) { ++ cursor_visible = !(s->cr[VGA_CRTC_CURSOR_START] & 0x20); + if (cursor_visible && cursor_offset < size && cursor_offset >= 0) + dpy_cursor(s->ds, + TEXTMODE_X(cursor_offset), + TEXTMODE_Y(cursor_offset)); + else + dpy_cursor(s->ds, -1, -1); + s->cursor_offset = cursor_offset; - s->cursor_start = s->cr[0xa]; - s->cursor_end = s->cr[0xb]; ++ s->cursor_start = s->cr[VGA_CRTC_CURSOR_START]; ++ s->cursor_end = s->cr[VGA_CRTC_CURSOR_END]; + } + + src = (uint32_t *) s->vram_ptr + s->start_addr; + dst = chardata; + + if (full_update) { + for (i = 0; i < size; src ++, dst ++, i ++) + console_write_ch(dst, VMEM2CHTYPE(le32_to_cpu(*src))); + + dpy_update(s->ds, 0, 0, width, height); + } else { + c_max = 0; + + for (i = 0; i < size; src ++, dst ++, i ++) { + console_write_ch(&val, VMEM2CHTYPE(le32_to_cpu(*src))); + if (*dst != val) { + *dst = val; + c_max = i; + break; + } + } + c_min = i; + for (; i < size; src ++, dst ++, i ++) { + console_write_ch(&val, VMEM2CHTYPE(le32_to_cpu(*src))); + if (*dst != val) { + *dst = val; + c_max = i; + } + } + + if (c_min <= c_max) { + i = TEXTMODE_Y(c_min); + dpy_update(s->ds, 0, i, width, TEXTMODE_Y(c_max) - i + 1); + } + } + + return; + case GMODE_GRAPH: + if (!full_update) + return; + + s->get_resolution(s, &width, &height); + snprintf(msg_buffer, sizeof(msg_buffer), "%i x %i Graphic mode", + width, height); + break; + case GMODE_BLANK: + default: + if (!full_update) + return; + + snprintf(msg_buffer, sizeof(msg_buffer), "VGA Blank mode"); + break; + } + + /* Display a message */ + s->last_width = 60; + s->last_height = height = 3; + dpy_cursor(s->ds, -1, -1); + s->ds->surface->width = s->last_width; + s->ds->surface->height = height; + dpy_resize(s->ds); + + for (dst = chardata, i = 0; i < s->last_width * height; i ++) + console_write_ch(dst ++, ' '); + + size = strlen(msg_buffer); + width = (s->last_width - size) / 2; + dst = chardata + s->last_width + width; + for (i = 0; i < size; i ++) + console_write_ch(dst ++, 0x00200100 | msg_buffer[i]); + + dpy_update(s->ds, 0, 0, s->last_width, height); +} + - void maru_vga_common_init(VGACommonState *s, int vga_ram_size) ++ ++static uint64_t vga_mem_read(void *opaque, target_phys_addr_t addr, ++ unsigned size) ++{ ++ VGACommonState *s = opaque; ++ ++ return vga_mem_readb(s, addr); ++} ++ ++static void vga_mem_write(void *opaque, target_phys_addr_t addr, ++ uint64_t data, unsigned size) ++{ ++ VGACommonState *s = opaque; ++ ++ return vga_mem_writeb(s, addr, data); ++} ++ ++static int vga_common_post_load(void *opaque, int version_id) ++{ ++ VGACommonState *s = opaque; ++ ++ /* force refresh */ ++ s->graphic_mode = -1; ++ return 0; ++} ++ ++void maru_vga_common_init(VGACommonState *s) +{ + int i, j, v, b; + + for(i = 0;i < 256; i++) { + v = 0; + for(j = 0; j < 8; j++) { + v |= ((i >> j) & 1) << (j * 4); + } + expand4[i] = v; + + v = 0; + for(j = 0; j < 4; j++) { + v |= ((i >> (2 * j)) & 3) << (j * 4); + } + expand2[i] = v; + } + for(i = 0; i < 16; i++) { + v = 0; + for(j = 0; j < 4; j++) { + b = ((i >> j) & 1); + v |= b << (2 * j); + v |= b << (2 * j + 1); + } + expand4to8[i] = v; + } + ++ /* valid range: 1 MB -> 256 MB */ ++ s->vram_size = 1024 * 1024; ++ while (s->vram_size < (s->vram_size_mb << 20) && ++ s->vram_size < (256 << 20)) { ++ s->vram_size <<= 1; ++ } ++ s->vram_size_mb = s->vram_size >> 20; ++ +#ifdef CONFIG_BOCHS_VBE + s->is_vbe_vmstate = 1; +#else + s->is_vbe_vmstate = 0; +#endif - memory_region_init_ram(&s->vram, "maru_vga.vram", vga_ram_size); ++ memory_region_init_ram(&s->vram, "maru_vga.vram", s->vram_size); ++ vmstate_register_ram_global(&s->vram); ++ xen_register_framebuffer(&s->vram); + s->vram_ptr = memory_region_get_ram_ptr(&s->vram); - s->vram_size = vga_ram_size; + s->get_bpp = vga_get_bpp; + s->get_offsets = vga_get_offsets; + s->get_resolution = vga_get_resolution; + s->update = vga_update_display; + s->invalidate = vga_invalidate_display; + s->screen_dump = vga_screen_dump; + s->text_update = vga_update_text; + switch (vga_retrace_method) { + case VGA_RETRACE_DUMB: + s->retrace = vga_dumb_retrace; + s->update_retrace_info = vga_dumb_update_retrace_info; + break; + + case VGA_RETRACE_PRECISE: + s->retrace = vga_precise_retrace; + s->update_retrace_info = vga_precise_update_retrace_info; + break; + } + vga_dirty_log_start(s); + +#ifdef USE_SHM + int mykey = getuid(); + shmid = shmget((key_t)mykey, (size_t)vga_ram_size, 0666 | IPC_CREAT); + if (shmid == -1) { + fprintf(stderr, "shmget failed\n"); + exit(1); + } + + shared_memory = shmat(shmid, (void*)0, 0); + if (shared_memory == (void *)-1) { + fprintf(stderr, "shmat failed\n"); + exit(1); + } + + printf("Memory attached at %X\n", (int)shared_memory); +#endif + +} + ++ ++static const MemoryRegionPortio vga_portio_list[] = { ++ { 0x04, 2, 1, .read = vga_ioport_read, .write = vga_ioport_write }, /* 3b4 */ ++ { 0x0a, 1, 1, .read = vga_ioport_read, .write = vga_ioport_write }, /* 3ba */ ++ { 0x10, 16, 1, .read = vga_ioport_read, .write = vga_ioport_write }, /* 3c0 */ ++ { 0x24, 2, 1, .read = vga_ioport_read, .write = vga_ioport_write }, /* 3d4 */ ++ { 0x2a, 1, 1, .read = vga_ioport_read, .write = vga_ioport_write }, /* 3da */ ++ PORTIO_END_OF_LIST(), ++}; ++ ++#ifdef CONFIG_BOCHS_VBE ++static const MemoryRegionPortio vbe_portio_list[] = { ++ { 0, 1, 2, .read = vbe_ioport_read_index, .write = vbe_ioport_write_index }, ++# ifdef TARGET_I386 ++ { 1, 1, 2, .read = vbe_ioport_read_data, .write = vbe_ioport_write_data }, ++# else ++ { 2, 1, 2, .read = vbe_ioport_read_data, .write = vbe_ioport_write_data }, ++# endif ++ PORTIO_END_OF_LIST(), ++}; ++#endif /* CONFIG_BOCHS_VBE */ ++ +/********************************************************/ +/* vga screen dump */ + +static int maru_ppm_save(const char *filename, struct DisplaySurface *ds) +{ + FILE *f; + uint8_t *d, *d1; + uint32_t v; + int y, x; + uint8_t r, g, b; + int ret; + char *linebuf, *pbuf; + ++ trace_ppm_save(filename, ds); + f = fopen(filename, "wb"); + if (!f) + return -1; + fprintf(f, "P6\n%d %d\n%d\n", + ds->width, ds->height, 255); + linebuf = g_malloc(ds->width * 3); + d1 = ds->data; + for(y = 0; y < ds->height; y++) { + d = d1; + pbuf = linebuf; + for(x = 0; x < ds->width; x++) { + if (ds->pf.bits_per_pixel == 32) + v = *(uint32_t *)d; + else + v = (uint32_t) (*(uint16_t *)d); - r = ((v >> ds->pf.rshift) & ds->pf.rmax) * 256 / - (ds->pf.rmax + 1); - g = ((v >> ds->pf.gshift) & ds->pf.gmax) * 256 / - (ds->pf.gmax + 1); - b = ((v >> ds->pf.bshift) & ds->pf.bmax) * 256 / - (ds->pf.bmax + 1); ++ /* Limited to 8 or fewer bits per channel: */ ++ r = ((v >> ds->pf.rshift) & ds->pf.rmax) << (8 - ds->pf.rbits); ++ g = ((v >> ds->pf.gshift) & ds->pf.gmax) << (8 - ds->pf.gbits); ++ b = ((v >> ds->pf.bshift) & ds->pf.bmax) << (8 - ds->pf.bbits); + *pbuf++ = r; + *pbuf++ = g; + *pbuf++ = b; + d += ds->pf.bytes_per_pixel; + } + d1 += ds->linesize; + ret = fwrite(linebuf, 1, pbuf - linebuf, f); + (void)ret; + } + g_free(linebuf); + fclose(f); + return 0; +} + - static void vga_save_dpy_update(DisplayState *ds, - int x, int y, int w, int h) - { - if (screen_dump_filename) { - maru_ppm_save(screen_dump_filename, ds->surface); - } - } - - static void vga_save_dpy_resize(DisplayState *s) - { - } - - static void vga_save_dpy_refresh(DisplayState *s) - { - } - - static DisplayChangeListener* vga_screen_dump_init(DisplayState *ds) - { - DisplayChangeListener *dcl; - - dcl = g_malloc0(sizeof(DisplayChangeListener)); - dcl->dpy_update = vga_save_dpy_update; - dcl->dpy_resize = vga_save_dpy_resize; - dcl->dpy_refresh = vga_save_dpy_refresh; - register_displaychangelistener(ds, dcl); - return dcl; - } - +/* save the vga display in a PPM image even if no display is + available */ +static void vga_screen_dump(void *opaque, const char *filename, bool cswitch) +{ + VGACommonState *s = opaque; + - if (!screen_dump_dcl) - screen_dump_dcl = vga_screen_dump_init(s->ds); - - screen_dump_filename = filename; - vga_invalidate_display(s); ++ if (cswitch) { ++ vga_invalidate_display(s); ++ } + vga_hw_update(); - screen_dump_filename = NULL; ++ ppm_save(filename, s->ds->surface); +} diff --cc tizen/src/hw/maru_vga_int.h index 2beeb53,0000000..c8a052e mode 100644,000000..100644 --- a/tizen/src/hw/maru_vga_int.h +++ b/tizen/src/hw/maru_vga_int.h @@@ -1,49 -1,0 +1,49 @@@ +/* + * Maru vga device + * Based on qemu/hw/vga_int.h + * + * Copyright (C) 2011 - 2012 Samsung Electronics Co., Ltd. All rights reserved. + * + * Contact: + * Hyunjun Son + * GiWoong Kim + * YeongKyoon Lee + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * Contributors: + * - S-Core Co., Ltd + * + */ + +#ifndef MARU_VGA_INT_H_ +#define MARU_VGA_INT_H_ + - void maru_vga_common_init(VGACommonState *s, int vga_ram_size); ++void maru_vga_common_init(VGACommonState *s); + +void maru_vga_draw_cursor_line_8(uint8_t *d1, const uint8_t *src1, + int poffset, int w, + unsigned int color0, unsigned int color1, + unsigned int color_xor); +void maru_vga_draw_cursor_line_16(uint8_t *d1, const uint8_t *src1, + int poffset, int w, + unsigned int color0, unsigned int color1, + unsigned int color_xor); +void maru_vga_draw_cursor_line_32(uint8_t *d1, const uint8_t *src1, + int poffset, int w, + unsigned int color0, unsigned int color1, + unsigned int color_xor); + +#endif /* MARU_VGA_INT_H_ */ diff --cc tizen/src/option.h index 128cacf,0000000..5bfac31 mode 100644,000000..100644 --- a/tizen/src/option.h +++ b/tizen/src/option.h @@@ -1,49 -1,0 +1,47 @@@ +/* + * Emulator + * + * Copyright (C) 2011, 2012 Samsung Electronics Co., Ltd. All rights reserved. + * + * Contact: + * SeokYeon Hwang + * HyunJun Son + * MunKyu Im + * GiWoong Kim + * YeongKyoon Lee + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * Contributors: + * - S-Core Co., Ltd + * + */ + +#ifndef __OPTION_H__ +#define __OPTION_H__ + +#include - #ifndef _WIN32 - #include - #endif ++ +#include +#include +#include +#include +#include +#include + +int gethostDNS(char *dns1, char *dns2); +int gethostproxy(char *http_proxy, char *https_proxy, char *ftp_proxy, char *socks_proxy); +#endif + diff --cc vl.c index 3a019a2,7c577fa..c469f54 --- a/vl.c +++ b/vl.c @@@ -3355,29 -3282,12 +3436,35 @@@ int main(int argc, char **argv, char ** case QEMU_OPTION_qtest_log: qtest_log = optarg; break; + case QEMU_OPTION_sandbox: + opts = qemu_opts_parse(qemu_find_opts("sandbox"), optarg, 1); + if (!opts) { + exit(0); + } + break; + case QEMU_OPTION_enable_hax: +#ifdef CONFIG_HAX_BACKEND + olist = qemu_find_opts("machine"); + qemu_opts_reset(olist); + hax_disable(0); + //qemu_opts_parse(olist, "accel=hax", 0); +#else + fprintf(stderr, + "HAX support is disabled, ignoring -enable-hax\n"); +#endif + break; +#ifdef CONFIG_MARU + case QEMU_OPTION_max_touch_point: + { + int cnt = atoi(optarg); + fprintf(stderr, "maxTouchPoint:%d\n", cnt); + set_emul_max_touch_point(cnt); + break; + } + case QEMU_OPTION_disable_skin: + skin_disabled = 1; + break; +#endif default: os_parse_cmd_args(popt->index, optarg); } @@@ -3576,8 -3440,11 +3671,13 @@@ ram_size = DEFAULT_RAM_SIZE * 1024 * 1024; } + hax_pre_init(ram_size); + + if (qemu_opts_foreach(qemu_find_opts("device"), device_help_func, NULL, 0) + != 0) { + exit(0); + } + configure_accelerator(); qemu_init_cpu_loop(); @@@ -3787,10 -3645,8 +3884,10 @@@ #elif defined(CONFIG_VNC) vnc_display = "localhost:0,to=99"; show_vnc_port = 1; +#elif defined(CONFIG_MARU) && defined (__APPLE__) + display_type = DT_MARU; #else - display_type = DT_NONE; + display_type = DT_NONE; #endif } @@@ -3825,19 -3669,8 +3922,19 @@@ cocoa_display_init(ds, full_screen); break; #endif +#if defined(CONFIG_MARU) && defined(__APPLE__) + case DT_MARU: + maru_display_init(ds); + if (skin_disabled == 1) { + //do not start skin client process + set_emul_skin_enable(0); + } else { + set_emul_skin_enable(1); + } + break; +#endif default: - break; + break; } /* must be after terminal init, SDL library changes signal handlers */