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
- 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
+# 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_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_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_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_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_gles1_calls.o
- obj-$(TARGET_BASE_ARCH)-y += yagl_host_gles1_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_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_gles1_calls.o
++obj-y += yagl_host_gles1_calls.o
+# GLESv2 api
- obj-$(TARGET_BASE_ARCH)-y += yagl_egl_glx.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_gles_ogl.o
++obj-y += yagl_egl_glx.o
+# GLES OpenGL common driver
- obj-$(TARGET_BASE_ARCH)-y += yagl_gles1_ogl.o
++obj-y += yagl_gles_ogl.o
+# GLESv1_CM OpenGL driver
- obj-$(TARGET_BASE_ARCH)-y += yagl_gles2_ogl.o
++obj-y += yagl_gles1_ogl.o
+# GLESv2 OpenGL driver
- endif # CONFIG_SOFTMMU
++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
+
+ # 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.
#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
+}
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
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"
guest_agent="yes"
libiscsi=""
coroutine=""
+ seccomp=""
+gl="yes"
+
+# for TIZEN-maru
+maru="no"
+#
# parse CC options first
for opt do
;;
--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
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
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
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;
static CPUArchState *next_cpu;
- kvm_async_interrupts_enabled()) {
+ 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() || 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 */
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;
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
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);
}
}
--- /dev/null
+ 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
--- /dev/null
+ 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))
#include "sysbus.h"
#include "arm-misc.h"
#include "loader.h"
++#include "virtio-transport.h"
#include "exynos4210.h"
#define EXYNOS4210_CHIPID_ADDR 0x10000000
/* 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 };
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;
}
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,
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,
--- /dev/null
- DeviceState *dev = QTAILQ_FIRST(&bus->qbus.children);
+/*
+ * Samsung exynos4210 I2S driver
+ *
+ * Copyright (c) 2012 Samsung Electronics Co., Ltd.
+ * Vorobiov Stanislav <s.vorobiov@samsung.com>
+ *
+ * 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 <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#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)
+{
- if (dev) {
- return EXYNOS4210_I2S_SLAVE_FROM_QDEV(dev);
++ BusChild *kid = QTAILQ_FIRST(&bus->qbus.children);
++ DeviceState *dev;
+
- static struct BusInfo exynos4210_i2s_bus_info = {
- .name = "Exynos4210.I2S",
- .size = sizeof(Exynos4210I2SBus),
- .reset = exynos4210_i2s_bus_reset
++ 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);
+
- qbus_create(&exynos4210_i2s_bus_info, NULL, name));
++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,
- k->bus_info = &exynos4210_i2s_bus_info;
++ 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_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)
#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
return &dev->qdev;
}
- DeviceState *pci_vga_init(PCIBus *bus);
+#ifdef CONFIG_MARU
+DeviceState *pci_maru_vga_init(PCIBus *bus);
+#endif
+
+
int isa_vga_mm_init(target_phys_addr_t vram_base,
target_phys_addr_t ctrl_base, int it_shift,
MemoryRegion *address_space);
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;
}
/* 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;
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);
#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)
{
.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)
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;
#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) \
/* 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;
.class_init = vga_class_init,
};
- maru_vga_common_init(s, VGA_RAM_SIZE);
+#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_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);
/* 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
unregister_savevm(s->qdev, "virtio-balloon", s);
virtio_cleanup(vdev);
}
- return virtio_init_transport(dev, 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;
+ }
- dc->bus_info = &virtio_transport_bus_info;
++
++ 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->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)
#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 */
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
#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__
blockdev_mark_auto_del(s->bs);
virtio_cleanup(vdev);
}
- VirtIOBlockState *proxy = VIRTIO_BLK_FROM_QDEV(dev);
- vdev = virtio_blk_init(dev, &proxy->block);
+
+/******************** VirtIOBlk Device **********************/
+
+static int virtio_blkdev_init(DeviceState *dev)
+{
+ VirtIODevice *vdev;
- return virtio_init_transport(dev, vdev);
++ VirtIOBlockState *s = VIRTIO_BLK_FROM_QDEV(dev);
++
++ assert(s->trl != NULL);
++
++ vdev = virtio_blk_init(dev, &s->blk);
+ if (!vdev) {
+ return -1;
+ }
- DEFINE_BLOCK_PROPERTIES(VirtIOBlockState, block.conf),
- DEFINE_PROP_STRING("serial", VirtIOBlockState, block.serial),
++
++ /* 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[] = {
- dc->bus_info = &virtio_transport_bus_info;
++ 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;
+}
+
+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)
#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 */
};
#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)
- VirtIOBlkConf block;
+
+typedef struct {
+ DeviceState qdev;
+ /* virtio-blk */
++ VirtIOBlkConf blk;
++
++ uint32_t host_features;
++
++ VirtIOTransportLink *trl;
+} VirtIOBlockState;
+
+#define VIRTIO_BLK_FROM_QDEV(dev) DO_UPCAST(VirtIOBlockState, qdev, dev)
+
#endif
--- /dev/null
- #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),
- };
-
+/*
+ * Virtio MMIO bindings
+ *
+ * Copyright (c) 2011 Linaro Limited
+ *
+ * Authors:
+ * Peter Maydell <peter.maydell@linaro.org>
+ * Evgeny Voevodin <e.voevodin@samsung.com>
+ *
+ * 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 <http://www.gnu.org/licenses/>.
+ */
+
+/* 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' */
+
- } VirtIOMMIOTransportState;
+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 *transport = (VirtIOMMIOTransportState *)opaque;
- VirtIODevice *vdev = transport->vdev;
++} VirtIOMMIO;
+
+static uint64_t virtio_mmio_read(void *opaque, target_phys_addr_t offset,
+ unsigned size)
+{
- if (transport->host_features_sel) {
++ 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:
- return transport->host_features;
++ if (s->host_features_sel) {
+ return 0;
+ }
- >> transport->guest_page_shift;
++ 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)
- VirtIOMMIOTransportState *transport = (VirtIOMMIOTransportState *)opaque;
- VirtIODevice *vdev = transport->vdev;
++ >> 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)
+{
- transport->host_features_sel = value;
++ 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:
- if (!transport->guest_features_sel) {
++ s->host_features_sel = value;
+ break;
+ case VIRTIO_MMIO_GUESTFEATURES:
- transport->guest_features_sel = value;
++ if (!s->guest_features_sel) {
+ virtio_set_features(vdev, value);
+ }
+ break;
+ case VIRTIO_MMIO_GUESTFEATURESSEL:
- transport->guest_page_shift = ctz32(value);
- if (transport->guest_page_shift > 31) {
- transport->guest_page_shift = 0;
++ s->guest_features_sel = value;
+ break;
+ case VIRTIO_MMIO_GUESTPAGESIZE:
- transport->guest_page_shift);
++ 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,
- 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,
- VirtIOMMIOTransportState *transport = opaque;
- int level = (transport->vdev->isr != 0);
++ 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)
+{
- qemu_set_irq(transport->irq, level);
++ VirtIOMMIO *s = opaque;
++ int level = (s->vdev->isr != 0);
+ DPRINTF("virtio_mmio setting IRQ %d\n", level);
- VirtIOMMIOTransportState *transport = opaque;
- return transport->host_features;
++ qemu_set_irq(s->irq, level);
+}
+
+static unsigned int virtio_mmio_get_features(void *opaque)
+{
- 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;
++ return s->host_features;
+}
+
+static int virtio_mmio_load_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;
++ 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)
+{
- static void virtio_mmio_attach_to_transport(DeviceState *dev)
++ 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,
+};
+
- DeviceState *transport_dev = qdev_get_parent_bus(dev)->parent;
- SysBusDevice *transport_sysbus = sysbus_from_qdev(transport_dev);
- VirtIOMMIOTransportState *transport =
- FROM_SYSBUS(VirtIOMMIOTransportState, transport_sysbus);
++static int virtio_mmio_transport_cb(DeviceState *dev, VirtIODevice *vdev,
++ VirtIOTransportLink *trl)
+{
- /* Create alias and add it as subregion to transport iomem */
- memory_region_init_alias(&transport->alias,
++ VirtIOMMIO *s =
++ FROM_SYSBUS(VirtIOMMIO, sysbus_from_qdev(trl->tr));
+
- &transport->iomem,
++ 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",
- /* add alias as subregion to transport iomap */
- memory_region_add_subregion(&transport->iomap,
++ &s->iomem,
+ 0,
+ 0x1000);
- &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);
++ /* add alias as subregion to s iomap */
++ memory_region_add_subregion(&s->iomap,
+ 0,
- static void virtio_mmio_transport_handler(void *opaque, int irq, int level)
++ &s->alias);
+ return 0;
+}
+
- VirtIOMMIOTransportState *s = (VirtIOMMIOTransportState *)opaque;
++static void virtio_mmio_handler(void *opaque, int irq, int level)
+{
- static int virtio_mmio_transport_device_init(SysBusDevice *busdev)
++ VirtIOMMIO *s = (VirtIOMMIO *)opaque;
+
+ qemu_set_irq(s->irq, level);
+
+ return;
+}
+
- VirtIOMMIOTransportState *s =
- DO_UPCAST(VirtIOMMIOTransportState, busdev, busdev);
- BusState *parent_bus = qdev_get_parent_bus(&busdev->qdev);
- BusState *child_bus;
- VirtIOTransportBusState *virtio_transport_bus;
++static int sice_init(SysBusDevice *busdev)
+{
- int len;
- uint32_t i;
-
- i = virtio_count_siblings(parent_bus, VIRTIO_MMIO);
++ VirtIOMMIO *s =
++ DO_UPCAST(VirtIOMMIO, busdev, busdev);
+ char *buf;
- 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);
+
- /* 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);
++ /* 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);
+
- VirtIOMMIOTransportState *transport =
- FROM_SYSBUS(VirtIOMMIOTransportState, sysbus_from_qdev(d));
- if (transport->vdev) {
- virtio_reset(transport->vdev);
++ /* 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)
+{
- static void virtio_mmio_transport_class_init(ObjectClass *klass, void *data)
++ VirtIOMMIO *s = FROM_SYSBUS(VirtIOMMIO, sysbus_from_qdev(d));
++ if (s->vdev) {
++ virtio_reset(s->vdev);
+ }
+}
+
- k->init = virtio_mmio_transport_device_init;
++/******************** VirtIOMMIO Device *********************/
++
++static void virtio_mmio_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
- static TypeInfo virtio_mmio_transport_info = {
- .name = VIRTIO_MMIO_TRANSPORT,
++ k->init = sice_init;
+ dc->reset = virtio_mmio_reset;
+}
+
- .instance_size = sizeof(VirtIOMMIOTransportState),
- .class_init = virtio_mmio_transport_class_init,
++static TypeInfo virtio_mmio_info = {
++ .name = VIRTIO_MMIO,
+ .parent = TYPE_SYS_BUS_DEVICE,
- type_register_static(&virtio_mmio_transport_info);
++ .instance_size = sizeof(VirtIOMMIO),
++ .class_init = virtio_mmio_class_init,
+};
+
++/************************************************************/
++
+static void virtio_mmio_register_types(void)
+{
++ type_register_static(&virtio_mmio_info);
+}
+
+type_init(virtio_mmio_register_types)
#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"
qemu_bh_delete(n->tx_bh);
}
- qemu_del_vlan_client(&n->nic->nc);
+ qemu_del_net_client(&n->nic->nc);
virtio_cleanup(&n->vdev);
}
- VirtIONetState *proxy = VIRTIO_NET_FROM_QDEV(dev);
- vdev = virtio_net_init(dev, &proxy->nic, &proxy->net);
- if (!vdev) {
+
+/******************** VirtIONet Device **********************/
+
+static int virtio_netdev_init(DeviceState *dev)
+{
+ VirtIODevice *vdev;
- return virtio_init_transport(dev, 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;
+ }
- DEFINE_PROP_UINT32("x-txtimer", VirtIONetState,
- net.txtimer, TX_TIMER_INTERVAL),
- DEFINE_PROP_INT32("x-txburst", VirtIONetState,
- net.txburst, TX_BURST),
++
++ /* 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),
- dc->bus_info = &virtio_transport_bus_info;
++ 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;
+}
+
+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)
#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"
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
--- /dev/null
--- /dev/null
++/*
++ * Virtio PCI Bindings
++ *
++ * Copyright IBM, Corp. 2007
++ * Copyright (c) 2009 CodeSourcery
++ *
++ * Authors:
++ * Anthony Liguori <aliguori@us.ibm.com>
++ * Paul Brook <paul@codesourcery.com>
++ *
++ * 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 <inttypes.h>
++
++#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)
virtio_pci_stop_ioeventfd(proxy);
virtio_balloon_exit(proxy->vdev);
- return virtio_exit_pci(pci_dev);
+ virtio_exit_pci(pci_dev);
}
- static int maru_virtio_touchscreen_exit_pci(PCIDevice *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;
+}
+
- return virtio_exit_pci(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);
++ 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),
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
}
type_init(virtio_serial_register_types)
- VirtIOSerState *proxy = VIRTIO_SERIAL_FROM_QDEV(dev);
- vdev = virtio_serial_init(dev, &proxy->serial);
+
+/******************** VirtIOSer Device **********************/
+
+static int virtio_serialdev_init(DeviceState *dev)
+{
+ VirtIODevice *vdev;
- return virtio_init_transport(dev, vdev);
++ VirtIOSerState *s = VIRTIO_SERIAL_FROM_QDEV(dev);
++ vdev = virtio_serial_init(dev, &s->serial);
+ if (!vdev) {
+ return -1;
+ }
- dc->bus_info = &virtio_transport_bus_info;
++
++ 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;
+}
+
+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)
#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 == */
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 */
/*
--- /dev/null
- struct BusInfo virtio_transport_bus_info = {
- .name = VIRTIO_TRANSPORT_BUS,
- .size = sizeof(VirtIOTransportBusState),
- };
+/*
+ * Virtio transport bindings
+ *
+ * Copyright (c) 2011 - 2012 Samsung Electronics Co., Ltd.
+ *
+ * Author:
+ * Evgeny Voevodin <e.voevodin@samsung.com>
+ *
+ * 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 <http://www.gnu.org/licenses/>.
+ */
+
+#include "virtio-transport.h"
+
+#define VIRTIO_TRANSPORT_BUS "virtio-transport"
+
- int virtio_init_transport(DeviceState *dev, VirtIODevice *vdev)
++static QTAILQ_HEAD(, VirtIOTransportLink) transport_links =
++ QTAILQ_HEAD_INITIALIZER(transport_links);
+
- DeviceState *transport_dev = qdev_get_parent_bus(dev)->parent;
- BusState *bus;
- VirtIOTransportBusState *virtio_transport_bus;
++/*
++ * Find transport device by its ID.
++ */
++VirtIOTransportLink* virtio_find_transport(const char *name)
+{
- /* transport device has single child bus */
- bus = QLIST_FIRST(&transport_dev->child_bus);
- virtio_transport_bus = DO_UPCAST(VirtIOTransportBusState, bus, bus);
++ VirtIOTransportLink *trl;
+
- if (virtio_transport_bus->init_fn) {
- return virtio_transport_bus->init_fn(dev, vdev);
++ assert(name != NULL);
+
- return 0;
++ QTAILQ_FOREACH(trl, &transport_links, sibling) {
++ if (trl->tr->id != NULL) {
++ if (!strcmp(name, trl->tr->id)) {
++ return trl;
++ }
++ }
+ }
+
- uint32_t virtio_count_siblings(BusState *parent_bus, const char *child_bus)
++ return NULL;
+}
+
- DeviceState *dev;
- BusState *bus;
++/*
++ * Count transport devices by ID.
++ */
++uint32_t virtio_count_transports(const char *name)
+{
- 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++;
- }
- }
- }
++ VirtIOTransportLink *trl;
+ uint32_t i = 0;
- } else {
- QTAILQ_FOREACH(dev, &parent_bus->children, sibling) {
+
- }
++ QTAILQ_FOREACH(trl, &transport_links, sibling) {
++ if (name == NULL) {
+ i++;
++ continue;
+ }
- * Get transport device which does not have a child.
+
++ if (trl->tr->id != NULL) {
++ if (!strncmp(name, trl->tr->id,strlen(name))) {
++ i++;
++ }
++ }
++ }
+ return i;
+}
+
+/*
- DeviceState* virtio_get_free_transport(BusState *parent_bus,
- const char *child_bus)
++ * Initialize new transport device
+ */
- DeviceState *dev;
- BusState *bus;
++char* virtio_init_transport(DeviceState *dev, VirtIOTransportLink **trl,
++ const char* name, virtio_backend_init_cb cb)
+{
- assert(child_bus != NULL);
++ VirtIOTransportLink *link = g_malloc0(sizeof(VirtIOTransportLink));
++ char *buf;
++ size_t len;
++ uint32_t i;
+
- 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;
- }
- }
++ assert(dev != NULL);
++ assert(name != NULL);
++ assert(trl != NULL);
+
- return NULL;
++ 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;
+ }
+ }
+
++ /* 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)
--- /dev/null
- #include "sysbus.h"
- #include "virtio.h"
+/*
+ * Virtio transport header
+ *
+ * Copyright (c) 2011 - 2012 Samsung Electronics Co., Ltd.
+ *
+ * Author:
+ * Evgeny Voevodin <e.voevodin@samsung.com>
+ *
+ * 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 <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef VIRTIO_TRANSPORT_H_
+#define VIRTIO_TRANSPORT_H_
+
- #define VIRTIO_MMIO_TRANSPORT "virtio-mmio-transport"
++#include "qdev.h"
++#include "qemu-common.h"
+
- extern struct BusInfo virtio_transport_bus_info;
++#define VIRTIO_MMIO "virtio-mmio"
++#define VIRTIO_PCI "virtio-pci"
+
- typedef int (*virtio_init_transport_fn)(DeviceState *dev, VirtIODevice *vdev);
++#define TYPE_VIRTIO_BUS "virtio-bus"
++#define VIRTIO_BUS(obj) OBJECT_CHECK(virtio_bus, (obj), TYPE_VIRTIO_BUS)
+
- typedef struct VirtIOTransportBusState {
- BusState bus;
- virtio_init_transport_fn init_fn;
- } VirtIOTransportBusState;
++struct VirtIOTransportLink;
+
- int virtio_init_transport(DeviceState *dev, VirtIODevice *vdev);
- uint32_t virtio_count_siblings(BusState *parent_bus, const char *child_bus);
++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);
+
- * Get transport device which does not have a child.
+/*
- DeviceState* virtio_get_free_transport(BusState *parent_bus,
- const char *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);
+
+#endif /* VIRTIO_TRANSPORT_H_ */
--- /dev/null
- static int yagl_device_exit(PCIDevice *dev)
+#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);
+}
+
-
- return 0;
++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();
+}
+
+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)
return 0;
}
-static inline int get_phys_addr(CPUARMState *env, uint32_t address,
+ /* 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
+ */
- uint32_t *phys_ptr, int *prot,
+#ifdef CONFIG_BUILD_GLES
+int get_phys_addr(CPUARMState *env, uint32_t address,
+ int access_type, int is_user,
++ 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. */
--- /dev/null
- --enable-ldst-optimization \
+#!/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-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
--- /dev/null
- 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
+# 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
++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
--- /dev/null
--- /dev/null
++# 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
--- /dev/null
--- /dev/null
++# 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
--- /dev/null
- void maru_arm_write_secondary(CPUARMState *env,
+/*
+ * Samsung Maru ARM SoC emulation
+ *
+ * Copyright (c) 2012 Samsung Electronics Co., Ltd.
+ * Evgeny Voevodin <e.voevodin@samsung.com>
+ *
+ * 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 <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#ifndef MARU_ARM_H_
+#define MARU_ARM_H_
+
+#include "qemu-common.h"
+#include "memory.h"
+#include "exynos4210.h"
+
++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_ */
--- /dev/null
- arm_load_kernel(first_cpu, &maru_arm_board_binfo);
+/*
+ * 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 <e.voevodin@samsung.com>
+ *
+ * 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 <http://www.gnu.org/licenses/>.
+ */
+
+#include <glib.h>
+
+#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(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);
--- /dev/null
- void maru_arm_write_secondary(CPUARMState *env,
+/*
+ * Samsung Maru ARM SoC emulation
+ *
+ * Based on exynos4210.c
+ *
+ * Copyright (c) 2011 Samsung Electronics Co., Ltd.
+ * Maksim Kozlov <m.kozlov@samsung.com>
+ * Evgeny Voevodin <e.voevodin@samsung.com>
+ * Igor Mitsyanko <i.mitsyanko@samsung.com>
+ *
+ * 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 <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#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 };
+
- qemu_irq cpu_irq[4];
- int n;
++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 <wfi> */
+ 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 gate_irq[EXYNOS4210_IRQ_GATE_NINPUTS];
++ qemu_irq cpu_irq[EXYNOS4210_NCPUS];
++ int i, n;
+ Exynos4210State *s = g_new(Exynos4210State, 1);
+ qemu_irq *irqp;
- s->env[n] = cpu_init("cortex-a9");
- if (!s->env[n]) {
++ 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++) {
- irqp = arm_pic_init_cpu(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 */
- 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]);
++ 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 */
- sysbus_connect_irq(busdev, n, gate_irq[n * 4]);
++ 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 + 1]);
++ 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++) {
- vmstate_register_ram_global(&s->chipid_mem);
++ 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->irom_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);
- /*** 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.
- */
+ 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);
+
- 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);
-
++ /* 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(23, 0)],
- s->irq_table[exynos4210_get_irq(23, 1)],
- 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(EXYNOS4210_UART_INT_GRP, 0)]);
++ 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, 1)]);
++ 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, 2)]);
++ 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, 3)]);
-
++ s->irq_table[exynos4210_get_irq(EXYNOS4210_UART_INT_GRP, 2)]);
+
+ exynos4210_uart_create(EXYNOS4210_UART3_BASE_ADDR,
+ EXYNOS4210_UART3_FIFO_SIZE, 3, NULL,
- sysbus_create_simple(VIRTIO_MMIO_TRANSPORT,
- EXYNOS4210_VIRTIO_MMIO0_BASE_ADDR,
- s->irq_table[exynos4210_get_irq(37, 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_MMIO1_BASE_ADDR,
- s->irq_table[exynos4210_get_irq(37, 2)]);
++ sysbus_create_simple(VIRTIO_MMIO,
++ EXYNOS4210_VIRTIO_MMIO0_BASE_ADDR,
++ s->irq_table[exynos4210_get_irq(37, 3)]);
+
- s->irq_table[exynos4210_get_irq(28, 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)]);
+
+ return s;
+}
--- /dev/null
- 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);
+/*
+ * TIZEN base board
+ *
+ * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Contact:
+ * YeongKyoon Lee <yeongkyoon.lee@samsung.com>
+ * DongKyun Yun <dk77.yun@samsung.com>
+ * DoHyung Hong <don.hong@samsung.com>
+ * SeokYeon Hwang <syeon.hwang@samsung.com>
+ * Hyunjun Son <hj79.son@samsung.com>
+ * SangJin Kim <sangjin3.kim@samsung.com>
+ * KiTae Kim <kt920.kim@samsung.com>
+ * JinHyung Jo <jinhyung.jo@samsung.com>
+ * SungMin Ha <sungmin82.ha@samsung.com>
+ * MunKyu Im <munkyu.im@samsung.com>
+ * JiHye Kim <jihye1128.kim@samsung.com>
+ * GiWoong Kim <giwoong.kim@samsung.com>
+ *
+ * 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 <glib.h>
+
+#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 <xen/hvm/hvm_info_table.h>
+#endif
+
+#include "guest_debug.h"
++#include "maru_pm.h"
+
+int codec_init(PCIBus *bus);
- int ret, i;
++
+
+#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;
- kvm_irqchip_add_route(s, i, KVM_IRQCHIP_PIC_MASTER, 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_SLAVE, i - 8);
++ 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_IOAPIC, 2);
++ 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, i);
++ kvm_irqchip_add_irq_route(s, i, KVM_IRQCHIP_IOAPIC, 2);
+ } else if (i != 2) {
- ret = kvm_irqchip_commit_routes(s);
- if (ret < 0) {
- hw_error("KVM IRQ routing setup failed");
- }
++ kvm_irqchip_add_irq_route(s, i, KVM_IRQCHIP_IOAPIC, i);
+ }
+ }
+ }
- pc_memory_init(system_memory,
+ }
+#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()) {
- gsi[9], *smi_irq, kvm_enabled());
++ 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(), 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);
--- /dev/null
- DeviceState *qdev, *next;
+/*
+ * 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 <hj79.son@samsung.com>
+ * GiWoong Kim <giwoong.kim@samsung.com>
+ * YeongKyoon Lee <yeongkyoon.lee@samsung.com>
+ *
+ * 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)
+{
- QTAILQ_FOREACH_SAFE(qdev, &bus->children, sibling, 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);
+
- object_unparent(OBJECT(dev));
++ 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 {
- DeviceState *qdev, *next;
+ 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);
- QTAILQ_FOREACH_SAFE(qdev, &bus->children, sibling, 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;
+
- pci_conf[0x40] = 0x01; /* PM io base read only bit */
-
++ 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
+
- int kvm_enabled)
+ /* 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, 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;
+}
--- /dev/null
- int kvm_enabled);
+/*
+ * 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 <hj79.son@samsung.com>
+ * GiWoong Kim <giwoong.kim@samsung.com>
+ * YeongKyoon Lee <yeongkyoon.lee@samsung.com>
+ *
+ * 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, 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_ */
--- /dev/null
- static const char *screen_dump_filename;
- static DisplayChangeListener *screen_dump_dcl;
+/*
+ * Maru vga device
+ * Based on qemu/hw/vga.c
+ *
+ * Copyright (C) 2011 - 2012 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Contact:
+ * HyunJun Son <hj79.son@samsung.com>
+ * GiWoong Kim <giwoong.kim@samsung.com>
+ * YeongKyoon Lee <yeongkyoon.lee@samsung.com>
+ *
+ * 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 <sys/shm.h>
+#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);
- 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;
++
++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;
+
- 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;
++ 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;
+
-
-
- clocking_mode = (s->sr[0x01] >> 3) & 1;
++ 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;
+
- div2 = (s->cr[0x17] >> 2) & 1;
- sldiv2 = (s->cr[0x17] >> 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
- if (s->ar[0x10] & 0x80)
- v = ((s->ar[0x14] & 0xf) << 4) | (v & 0xf);
- else
- v = ((s->ar[0x14] & 0xc) << 4) | (v & 0x3f);
++ 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];
- line_offset = s->cr[0x13];
++ 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 */
- start_addr = s->cr[0x0d] | (s->cr[0x0c] << 8);
++ line_offset = s->cr[VGA_CRTC_OFFSET];
+ line_offset <<= 3;
+
+ /* starting address */
- line_compare = s->cr[0x18] |
- ((s->cr[0x07] & 0x10) << 4) |
- ((s->cr[0x09] & 0x40) << 3);
++ start_addr = s->cr[VGA_CRTC_START_LO] |
++ (s->cr[VGA_CRTC_START_HI] << 8);
+
+ /* line compare */
- cheight = (s->cr[9] & 0x1f) + 1;
++ 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 */
- if (!(s->sr[1] & 0x01))
++ cheight = (s->cr[VGA_CRTC_MAX_SCAN] & 0x1f) + 1;
+ cwidth = 8;
- if (s->sr[1] & 0x08)
++ if (!(s->sr[VGA_SEQ_CLOCK_MODE] & VGA_SR01_CHAR_CLK_8DOTS)) {
+ cwidth = 9;
- width = (s->cr[0x01] + 1);
- if (s->cr[0x06] == 100) {
++ }
++ if (s->sr[VGA_SEQ_CLOCK_MODE] & 0x08) {
+ cwidth = 16; /* NOTE: no 18 pixel wide */
- height = s->cr[0x12] |
- ((s->cr[0x07] & 0x02) << 7) |
- ((s->cr[0x07] & 0x40) << 3);
++ }
++ 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 {
- v = s->sr[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) */
- cursor_offset = ((s->cr[0x0e] << 8) | s->cr[0x0f]) - s->start_addr;
++ 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);
+
- s->cr[0xa] != s->cursor_start ||
- s->cr[0xb] != s->cursor_end) {
++ 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->cursor_start = s->cr[0xa];
- s->cursor_end = s->cr[0xb];
++ 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;
- if (full_update || ch_attr != *ch_attr_ptr) {
++ 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 (ch >= 0xb0 && ch <= 0xdf && (s->ar[0x10] & 0x04))
++ 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;
- !(s->cr[0x0a] & 0x20)) {
++ 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 &&
- line_start = s->cr[0x0a] & 0x1f;
- line_last = s->cr[0x0b] & 0x1f;
++ !(s->cr[VGA_CRTC_CURSOR_START] & 0x20) &&
++ s->cursor_visible_phase) {
+ int line_start, line_last, h;
+ /* draw the cursor */
- width = (s->cr[0x01] + 1) * 8;
- height = s->cr[0x12] |
- ((s->cr[0x07] & 0x02) << 7) |
- ((s->cr[0x07] & 0x40) << 3);
++ 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
+ {
- shift_control = (s->gr[0x05] >> 5) & 3;
- double_scan = (s->cr[0x09] >> 7);
++ 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;
+
- multi_scan = (((s->cr[0x09] & 0x1f) + 1) << double_scan) - 1;
++ shift_control = (s->gr[VGA_GFX_MODE] >> 5) & 3;
++ double_scan = (s->cr[VGA_CRTC_MAX_SCAN] >> 7);
+ if (shift_control != 1) {
- if (s->sr[0x01] & 8) {
++ 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);
- width, height, v, line_offset, s->cr[9], s->cr[0x17], s->line_compare, s->sr[0x01]);
++ 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",
- mask = (s->cr[0x17] & 3) ^ 3;
++ 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) {
- graphic_mode = s->gr[6] & 1;
++ 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 {
- cheight = (s->cr[9] & 0x1f) + 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 */
- if (!(s->sr[1] & 0x01))
++ cheight = (s->cr[VGA_CRTC_MAX_SCAN] & 0x1f) + 1;
+ cw = 8;
- if (s->sr[1] & 0x08)
++ if (!(s->sr[VGA_SEQ_CLOCK_MODE] & VGA_SR01_CHAR_CLK_8DOTS)) {
+ cw = 9;
- width = (s->cr[0x01] + 1);
- if (s->cr[0x06] == 100) {
++ }
++ if (s->sr[VGA_SEQ_CLOCK_MODE] & 0x08) {
+ cw = 16; /* NOTE: no 18 pixel wide */
- height = s->cr[0x12] |
- ((s->cr[0x07] & 0x02) << 7) |
- ((s->cr[0x07] & 0x40) << 3);
++ }
++ 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 {
- cursor_offset = ((s->cr[0x0e] << 8) | s->cr[0x0f]) - s->start_addr;
++ 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 */
- s->cr[0xa] != s->cursor_start ||
- s->cr[0xb] != s->cursor_end || full_update) {
- cursor_visible = !(s->cr[0xa] & 0x20);
++ 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->cursor_start = s->cr[0xa];
- s->cursor_end = s->cr[0xb];
++ 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;
- void maru_vga_common_init(VGACommonState *s, int vga_ram_size)
++ 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);
+}
+
- memory_region_init_ram(&s->vram, "maru_vga.vram", 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
- s->vram_size = 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);
- 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);
+ 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);
- 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;
- }
-
++ /* 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;
+}
+
- if (!screen_dump_dcl)
- screen_dump_dcl = vga_screen_dump_init(s->ds);
-
- screen_dump_filename = filename;
- vga_invalidate_display(s);
+/* 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;
+
- screen_dump_filename = NULL;
++ if (cswitch) {
++ vga_invalidate_display(s);
++ }
+ vga_hw_update();
++ ppm_save(filename, s->ds->surface);
+}
--- /dev/null
- void maru_vga_common_init(VGACommonState *s, int vga_ram_size);
+/*
+ * Maru vga device
+ * Based on qemu/hw/vga_int.h
+ *
+ * Copyright (C) 2011 - 2012 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Contact:
+ * Hyunjun Son <hj79.son@samsung.com>
+ * GiWoong Kim <giwoong.kim@samsung.com>
+ * YeongKyoon Lee <yeongkyoon.lee@samsung.com>
+ *
+ * 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);
+
+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_ */
--- /dev/null
- #ifndef _WIN32
- #include <error.h>
- #endif
+/*
+ * Emulator
+ *
+ * Copyright (C) 2011, 2012 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Contact:
+ * SeokYeon Hwang <syeon.hwang@samsung.com>
+ * HyunJun Son <hj79.son@samsung.com>
+ * MunKyu Im <munkyu.im@samsung.com>
+ * GiWoong Kim <giwoong.kim@samsung.com>
+ * YeongKyoon Lee <yeongkyoon.lee@samsung.com>
+ *
+ * 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 <glib.h>
++
+#include <sys/types.h>
+#include <dirent.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+int gethostDNS(char *dns1, char *dns2);
+int gethostproxy(char *http_proxy, char *https_proxy, char *ftp_proxy, char *socks_proxy);
+#endif
+
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);
}
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();
#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
}
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 */