++config.status
config-devices.*
config-all-devices.*
config-all-disas.*
qemu-bridge-helper
qemu-monitor.texi
vscclient
- QMP/qmp-commands.txt
+ qmp-commands.txt
+ test-bitops
test-coroutine
+ test-int128
+ test-opts-visitor
test-qmp-input-visitor
test-qmp-output-visitor
test-string-input-visitor
*.la
*.pc
.libs
+ .sdk
*.swp
*.orig
.pc
tags
TAGS
*~
+tizen/emulator
+tizen/src/build_info.h
+tizen/src/skin/client/src/about.properties
+tizen/src/skin/client/bin
+tizen/src/skin/client/build
+tizen/src/skin/client/emulator-skin.jar
+tizen/src/skin/client/lib
+tizen/src/skin/client/native_src/*.so
+tizen/src/skin/client/native_src/*.dynlib
+tizen/src/check-cam
+fsdev/virtfs-proxy-helper
+.cproject
+.project
+tizen/src/check-hax
+tizen/src/check-cam
+
include $(SRC_PATH)/rules.mak
config-host.mak: $(SRC_PATH)/configure
@echo $@ is out-of-date, running configure
- @sed -n "/.*Configured with/s/[^:]*: //p" $@ | sh
+ @# TODO: The next lines include code which supports a smooth
+ @# transition from old configurations without config.status.
+ @# This code can be removed after QEMU 1.7.
+ @if test -x config.status; then \
+ ./config.status; \
+ else \
+ sed -n "/.*Configured with/s/[^:]*: //p" $@ | sh; \
+ fi
else
config-host.mak:
ifneq ($(filter-out %clean,$(MAKECMDGOALS)),$(if $(MAKECMDGOALS),,fail))
HELPERS-$(CONFIG_LINUX) = qemu-bridge-helper$(EXESUF)
ifdef BUILD_DOCS
- DOCS=qemu-doc.html qemu-tech.html qemu.1 qemu-img.1 qemu-nbd.8 QMP/qmp-commands.txt
+ DOCS=qemu-doc.html qemu-tech.html qemu.1 qemu-img.1 qemu-nbd.8 qmp-commands.txt
ifdef CONFIG_VIRTFS
DOCS+=fsdev/virtfs-proxy-helper.1
endif
bt-host.o: QEMU_CFLAGS += $(BLUEZ_CFLAGS)
$(BUILD_DIR)/version.o: $(SRC_PATH)/version.rc $(BUILD_DIR)/config-host.h | $(BUILD_DIR)/version.lo
+ $(call quiet-command,$(WINDRES) -I$(BUILD_DIR) -o $@ $<," RC version.o")
$(BUILD_DIR)/version.lo: $(SRC_PATH)/version.rc $(BUILD_DIR)/config-host.h
+ $(call quiet-command,$(WINDRES) -I$(BUILD_DIR) -o $@ $<," RC version.lo")
Makefile: $(version-obj-y) $(version-lobj-y)
rm -f qemu-options.def
find . -name '*.[oda]' -type f -exec rm -f {} +
find . -name '*.l[oa]' -type f -exec rm -f {} +
- rm -f $(TOOLS) $(HELPERS-y) qemu-ga TAGS cscope.* *.pod *~ */*~
- rm -Rf .libs
+ rm -f $(filter-out %.tlb,$(TOOLS)) $(HELPERS-y) qemu-ga TAGS cscope.* *.pod *~ */*~
+ rm -f fsdev/*.pod
+ rm -rf .libs */.libs
rm -f qemu-img-cmds.h
@# May not be present in GENERATED_HEADERS
rm -f trace/generated-tracers-dtrace.dtrace*
rm -f $(foreach f,$(GENERATED_SOURCES),$(f) $(f)-timestamp)
rm -rf qapi-generated
rm -rf qga/qapi-generated
- $(MAKE) -C tests/tcg clean
for d in $(ALL_SUBDIRS); do \
if test -d $$d; then $(MAKE) -C $$d $@ || exit 1; fi; \
rm -f $$d/qemu-options.def; \
distclean: clean
rm -f config-host.mak config-host.h* config-host.ld $(DOCS) qemu-options.texi qemu-img-cmds.texi qemu-monitor.texi
rm -f config-all-devices.mak config-all-disas.mak
+ rm -f po/*.mo
rm -f roms/seabios/config.mak roms/vgabios/config.mak
rm -f qemu-doc.info qemu-doc.aux qemu-doc.cp qemu-doc.cps qemu-doc.dvi
rm -f qemu-doc.fn qemu-doc.fns qemu-doc.info qemu-doc.ky qemu-doc.kys
for d in $(TARGET_DIRS); do \
rm -rf $$d || exit 1 ; \
done
+ rm -Rf .sdk
if test -f pixman/config.log; then make -C pixman distclean; fi
if test -f dtc/version_gen.h; then make $(DTC_MAKE_ARGS) clean; fi
KEYMAPS=da en-gb et fr fr-ch is lt modifiers no pt-br sv \
ar de en-us fi fr-be hr it lv nl pl ru th \
common de-ch es fo fr-ca hu ja mk nl-be pt sl tr \
- bepo
+ bepo cz
ifdef INSTALL_BLOBS
BLOBS=bios.bin sgabios.bin vgabios.bin vgabios-cirrus.bin \
vgabios-stdvga.bin vgabios-vmware.bin vgabios-qxl.bin \
acpi-dsdt.aml q35-acpi-dsdt.aml \
- ppc_rom.bin openbios-sparc32 openbios-sparc64 openbios-ppc \
+ ppc_rom.bin openbios-sparc32 openbios-sparc64 openbios-ppc QEMU,tcx.bin \
pxe-e1000.rom pxe-eepro100.rom pxe-ne2k_pci.rom \
pxe-pcnet.rom pxe-rtl8139.rom pxe-virtio.rom \
efi-e1000.rom efi-eepro100.rom efi-ne2k_pci.rom \
install-doc: $(DOCS)
$(INSTALL_DIR) "$(DESTDIR)$(qemu_docdir)"
$(INSTALL_DATA) qemu-doc.html qemu-tech.html "$(DESTDIR)$(qemu_docdir)"
- $(INSTALL_DATA) QMP/qmp-commands.txt "$(DESTDIR)$(qemu_docdir)"
+ $(INSTALL_DATA) qmp-commands.txt "$(DESTDIR)$(qemu_docdir)"
ifdef CONFIG_POSIX
$(INSTALL_DIR) "$(DESTDIR)$(mandir)/man1"
$(INSTALL_DATA) qemu.1 "$(DESTDIR)$(mandir)/man1"
$(INSTALL_DIR) "$(DESTDIR)$(mandir)/man1"
$(INSTALL_DATA) fsdev/virtfs-proxy-helper.1 "$(DESTDIR)$(mandir)/man1"
endif
-
install-datadir:
$(INSTALL_DIR) "$(DESTDIR)$(qemu_datadir)"
qemu-monitor.texi: $(SRC_PATH)/hmp-commands.hx
$(call quiet-command,sh $(SRC_PATH)/scripts/hxtool -t < $< > $@," GEN $@")
- QMP/qmp-commands.txt: $(SRC_PATH)/qmp-commands.hx
+ qmp-commands.txt: $(SRC_PATH)/qmp-commands.hx
$(call quiet-command,sh $(SRC_PATH)/scripts/hxtool -q < $< > $@," GEN $@")
qemu-img-cmds.texi: $(SRC_PATH)/qemu-img-cmds.hx
stap:
endif
-all: $(PROGS) stap
+all: $(PROGS) stap check-gl
# Dummy command so that make thinks it has done something
@true
- CONFIG_NO_PCI = $(if $(subst n,,$(CONFIG_PCI)),n,y)
- CONFIG_NO_KVM = $(if $(subst n,,$(CONFIG_KVM)),n,y)
- CONFIG_NO_XEN = $(if $(subst n,,$(CONFIG_XEN)),n,y)
-
#########################################################
# cpu emulator library
obj-y = exec.o translate-all.o cpu-exec.o
obj-y += fpu/softfloat.o
obj-y += target-$(TARGET_BASE_ARCH)/
obj-y += disas.o
- obj-$(CONFIG_GDBSTUB_XML) += gdbstub-xml.o
- obj-$(CONFIG_NO_KVM) += kvm-stub.o
+ obj-$(call notempty,$(TARGET_XML_FILES)) += gdbstub-xml.o
+ obj-$(call lnot,$(CONFIG_KVM)) += kvm-stub.o
#########################################################
# Linux user emulator target
# xen support
obj-$(CONFIG_XEN) += xen-all.o xen-mapcache.o
- obj-$(CONFIG_NO_XEN) += xen-stub.o
+ obj-$(call lnot,$(CONFIG_XEN)) += xen-stub.o
+# HAX support
+ifdef CONFIG_WIN32
+obj-$(CONFIG_HAX) += target-i386/hax-all.o target-i386/hax-windows.o
+obj-$(CONFIG_NO_HAX) += hax-stub.o
+endif
+ifdef CONFIG_DARWIN
+obj-$(CONFIG_HAX) += target-i386/hax-all.o target-i386/hax-darwin.o
+obj-$(CONFIG_NO_HAX) += hax-stub.o
+endif
+
# Hardware support
ifeq ($(TARGET_NAME), sparc64)
obj-y += hw/sparc64/
nested-vars += obj-y
+# Makefile for TIZEN-maru
+ifdef CONFIG_MARU
+include $(SRC_PATH)/tizen/src/Makefile.tizen
+endif
+##
+
# This resolves all nested paths, so it must come last
include $(SRC_PATH)/Makefile.objs
$(call LINK,$^)
endif
+CHECK_GL_OBJS = check_gl.o gloffscreen_test.o gloffscreen_common.o
+CHECK_GL_LDFLAGS =
+CHECK_GL_TARGET =
+ifdef CONFIG_LINUX
+CHECK_GL_OBJS += gloffscreen_xcomposite.o
+#CHECK_GL_LDFLAGS += -lGL -lXcomposite -lXext -lglib-2.0
+# Fix linking error on Ubuntu 13.04
+CHECK_GL_LDFLAGS += -lGL -lXcomposite -lX11 -lXext -lglib-2.0
+CHECK_GL_TARGET = check-gl
+endif
+ifdef CONFIG_WIN32
+CHECK_GL_OBJS += gloffscreen_wgl.o
+CHECK_GL_LDFLAGS += -fstack-protector `pkg-config --libs glib-2.0` -lopengl32 -lglu32 -lgdi32
+CHECK_GL_TARGET = check-gl.exe
+endif
+ifdef CONFIG_DARWIN
+CHECK_GL_OBJS += gloffscreen_agl.o
+CHECK_GL_LDFLAGS += -mmacosx-version-min=10.4 `pkg-config --cflags --libs glib-2.0` -framework GLUT -framework OpenGL -framework AGL
+CHECK_GL_TARGET = check-gl
+endif
+
+check-gl: check_gl.o
+ gcc -o $(CHECK_GL_TARGET) $(CHECK_GL_OBJS) $(CHECK_GL_LDFLAGS)
+check_gl.o: check_gl.c
+ gcc -c ../tizen/src/check_gl.c
+
gdbstub-xml.c: $(TARGET_XML_FILES) $(SRC_PATH)/scripts/feature_to_c.sh
$(call quiet-command,rm -f $@ && $(SHELL) $(SRC_PATH)/scripts/feature_to_c.sh $@ $(TARGET_XML_FILES)," GEN $(TARGET_DIR)$@")
return 0;
}
- static inline bool is_zero_page(uint8_t *p)
+ static inline bool is_zero_range(uint8_t *p, uint64_t size)
{
- return buffer_find_nonzero_offset(p, TARGET_PAGE_SIZE) ==
- TARGET_PAGE_SIZE;
+ return buffer_find_nonzero_offset(p, size) == size;
}
/* struct contains XBZRLE cache and a static page
{
unsigned long base = mr->ram_addr >> TARGET_PAGE_BITS;
unsigned long nr = base + (start >> TARGET_PAGE_BITS);
- unsigned long size = base + (int128_get64(mr->size) >> TARGET_PAGE_BITS);
+ uint64_t mr_size = TARGET_PAGE_ALIGN(memory_region_size(mr));
+ unsigned long size = base + (mr_size >> TARGET_PAGE_BITS);
unsigned long next;
}
if (!start_time) {
- start_time = qemu_get_clock_ms(rt_clock);
+ start_time = qemu_clock_get_ms(QEMU_CLOCK_REALTIME);
}
trace_migration_bitmap_sync_start();
trace_migration_bitmap_sync_end(migration_dirty_pages
- num_dirty_pages_init);
num_dirty_pages_period += migration_dirty_pages - num_dirty_pages_init;
- end_time = qemu_get_clock_ms(rt_clock);
+ end_time = qemu_clock_get_ms(QEMU_CLOCK_REALTIME);
/* more than 1 second = 1000 millisecons */
if (end_time > start_time + 1000) {
acct_info.dup_pages++;
}
}
- } else if (is_zero_page(p)) {
+ } else if (is_zero_range(p, TARGET_PAGE_SIZE)) {
acct_info.dup_pages++;
bytes_sent = save_block_hdr(f, block, offset, cont,
RAM_SAVE_FLAG_COMPRESS);
ram_control_before_iterate(f, RAM_CONTROL_ROUND);
- t0 = qemu_get_clock_ns(rt_clock);
+ t0 = qemu_clock_get_ns(QEMU_CLOCK_REALTIME);
i = 0;
while ((ret = qemu_file_rate_limit(f)) == 0) {
int bytes_sent;
iterations
*/
if ((i & 63) == 0) {
- uint64_t t1 = (qemu_get_clock_ns(rt_clock) - t0) / 1000000;
+ uint64_t t1 = (qemu_clock_get_ns(QEMU_CLOCK_REALTIME) - t0) / 1000000;
if (t1 > MAX_WAIT) {
DPRINTF("big wait: %" PRIu64 " milliseconds, %d iterations\n",
t1, i);
*/
ram_control_after_iterate(f, RAM_CONTROL_ROUND);
+ bytes_transferred += total_sent;
+
+ /*
+ * Do not count these 8 bytes into total_sent, so that we can
+ * return 0 if no page had been dirtied.
+ */
+ qemu_put_be64(f, RAM_SAVE_FLAG_EOS);
+ bytes_transferred += 8;
+
+ ret = qemu_file_get_error(f);
if (ret < 0) {
- bytes_transferred += total_sent;
return ret;
}
- qemu_put_be64(f, RAM_SAVE_FLAG_EOS);
- total_sent += 8;
- bytes_transferred += total_sent;
-
return total_sent;
}
*/
void ram_handle_compressed(void *host, uint8_t ch, uint64_t size)
{
- if (ch != 0 || !is_zero_page(host)) {
+ if (ch != 0 || !is_zero_range(host, size)) {
memset(host, ch, size);
- #ifndef _WIN32
- if (ch == 0 &&
- (!kvm_enabled() || kvm_has_sync_mmu()) &&
- getpagesize() <= TARGET_PAGE_SIZE) {
- qemu_madvise(host, TARGET_PAGE_SIZE, QEMU_MADV_DONTNEED);
- }
- #endif
}
}
if (ret != 16) {
return -1;
}
- #ifdef TARGET_I386
- smbios_add_field(1, offsetof(struct smbios_type_1, uuid), uuid, 16);
- #endif
return 0;
}
acpi_table_add(opts, &err);
if (err) {
- fprintf(stderr, "Wrong acpi table provided: %s\n",
- error_get_pretty(err));
+ error_report("Wrong acpi table provided: %s",
+ error_get_pretty(err));
error_free(err);
exit(1);
}
#endif
}
- void do_smbios_option(const char *optarg)
+ void do_smbios_option(QemuOpts *opts)
{
#ifdef TARGET_I386
- if (smbios_entry_add(optarg) < 0) {
- exit(1);
- }
+ smbios_entry_add(opts);
#endif
}
much time in the VM. The migration thread will try to catchup.
Workload will experience a performance drop.
*/
- static void mig_throttle_cpu_down(CPUState *cpu, void *data)
- {
- async_run_on_cpu(cpu, mig_sleep_cpu, NULL);
- }
-
static void mig_throttle_guest_down(void)
{
+ CPUState *cpu;
+
qemu_mutex_lock_iothread();
- qemu_for_each_cpu(mig_throttle_cpu_down, NULL);
+ CPU_FOREACH(cpu) {
+ async_run_on_cpu(cpu, mig_sleep_cpu, NULL);
+ }
qemu_mutex_unlock_iothread();
}
}
if (!t0) {
- t0 = qemu_get_clock_ns(rt_clock);
+ t0 = qemu_clock_get_ns(QEMU_CLOCK_REALTIME);
return;
}
- t1 = qemu_get_clock_ns(rt_clock);
+ t1 = qemu_clock_get_ns(QEMU_CLOCK_REALTIME);
/* If it has been more than 40 ms since the last time the guest
* was throttled then do it again.
t0 = t1;
}
}
+
+int hax_available(void)
+{
+#ifdef CONFIG_HAX
+ return 1;
+#else
+ return 0;
+#endif
+}
#define SW_NAME(sw) (sw)->name ? (sw)->name : "unknown"
+#ifdef CONFIG_MARU
+#include "../tizen/src/debug_ch.h"
+MULTI_DEBUG_CHANNEL(tizen, qemu_audio);
+#endif
+
/* Order of CONFIG_AUDIO_DRIVERS is import.
The 1st one is the one used by default, that is the reason
that we generate the list.
monitor_vprintf(default_mon, fmt, ap);
}
else {
+#ifdef CONFIG_MARU
+ TRACE(fmt, ap);
+#else
if (cap) {
fprintf (stderr, "%s: ", cap);
}
vfprintf (stderr, fmt, ap);
+#endif
}
}
static void audio_reset_timer (AudioState *s)
{
if (audio_is_timer_needed ()) {
- qemu_mod_timer (s->ts, qemu_get_clock_ns (vm_clock) + 1);
+ timer_mod (s->ts,
+ qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + conf.period.ticks);
}
else {
- qemu_del_timer (s->ts);
+ timer_del (s->ts);
}
}
QLIST_INIT (&s->cap_head);
atexit (audio_atexit);
- s->ts = qemu_new_timer_ns (vm_clock, audio_timer, s);
+ s->ts = timer_new_ns(QEMU_CLOCK_VIRTUAL, audio_timer, s);
if (!s->ts) {
hw_error("Could not create audio timer\n");
}
}
}
+#ifdef CONFIG_MARU
+// Try to avoid certain wave out locking action in recent Windows...
+// If wave out is locked (because nothing is wired to output jack, ...),
+// QEMU can find voice out device, but open will failed. And it will cause guest audio lock-up.
+// So, we test whether opening is success or not.
+// It can not prevent lock-up caused by runtime voice out lock.
+// To prevent it, QEMU audio backend structure must be changed.
+// We should do it, but now we used simple fix temporarily.
+ HWVoiceOut* hw = audio_calloc(AUDIO_FUNC, 1, s->drv->voice_size_out);
+ if (!hw) {
+ dolog ("Can not allocate voice `%s' size %d\n",
+ s->drv->name, s->drv->voice_size_out);
+ }
+ if(s->drv->pcm_ops->init_out(hw, &conf.fixed_out.settings)) {
+ INFO("Host audio out [%s] is malfunction. Change to noaudio driver\n",
+ s->drv->name);
+ done = 0;
+ }
+ else {
+ INFO("Host audio out [%s] is normal.\n", s->drv->name);
+ s->drv->pcm_ops->fini_out(hw);
+ }
+ g_free(hw);
+#endif
+
if (!done) {
done = !audio_driver_init (s, &no_audio_driver);
if (!done) {
static int coroutine_fn bdrv_co_do_write_zeroes(BlockDriverState *bs,
int64_t sector_num, int nb_sectors);
- static bool bdrv_exceed_bps_limits(BlockDriverState *bs, int nb_sectors,
- bool is_write, double elapsed_time, uint64_t *wait);
- static bool bdrv_exceed_iops_limits(BlockDriverState *bs, bool is_write,
- double elapsed_time, uint64_t *wait);
- static bool bdrv_exceed_io_limits(BlockDriverState *bs, int nb_sectors,
- bool is_write, int64_t *wait);
-
static QTAILQ_HEAD(, BlockDriverState) bdrv_states =
QTAILQ_HEAD_INITIALIZER(bdrv_states);
#endif
/* throttling disk I/O limits */
- void bdrv_io_limits_disable(BlockDriverState *bs)
+ void bdrv_set_io_limits(BlockDriverState *bs,
+ ThrottleConfig *cfg)
{
- bs->io_limits_enabled = false;
+ int i;
- do {} while (qemu_co_enter_next(&bs->throttled_reqs));
+ throttle_config(&bs->throttle_state, cfg);
- if (bs->block_timer) {
- qemu_del_timer(bs->block_timer);
- qemu_free_timer(bs->block_timer);
- bs->block_timer = NULL;
+ for (i = 0; i < 2; i++) {
+ qemu_co_enter_next(&bs->throttled_reqs[i]);
}
+ }
- bs->slice_start = 0;
- bs->slice_end = 0;
+ /* this function drain all the throttled IOs */
+ static bool bdrv_start_throttled_reqs(BlockDriverState *bs)
+ {
+ bool drained = false;
+ bool enabled = bs->io_limits_enabled;
+ int i;
+
+ bs->io_limits_enabled = false;
+
+ for (i = 0; i < 2; i++) {
+ while (qemu_co_enter_next(&bs->throttled_reqs[i])) {
+ drained = true;
+ }
+ }
+
+ bs->io_limits_enabled = enabled;
+
+ return drained;
}
- static void bdrv_block_timer(void *opaque)
+ void bdrv_io_limits_disable(BlockDriverState *bs)
{
- BlockDriverState *bs = opaque;
+ bs->io_limits_enabled = false;
- qemu_co_enter_next(&bs->throttled_reqs);
+ bdrv_start_throttled_reqs(bs);
+
+ throttle_destroy(&bs->throttle_state);
}
- void bdrv_io_limits_enable(BlockDriverState *bs)
+ static void bdrv_throttle_read_timer_cb(void *opaque)
{
- qemu_co_queue_init(&bs->throttled_reqs);
- bs->block_timer = qemu_new_timer_ns(vm_clock, bdrv_block_timer, bs);
- bs->io_limits_enabled = true;
+ BlockDriverState *bs = opaque;
+ qemu_co_enter_next(&bs->throttled_reqs[0]);
+ }
+
+ static void bdrv_throttle_write_timer_cb(void *opaque)
+ {
+ BlockDriverState *bs = opaque;
+ qemu_co_enter_next(&bs->throttled_reqs[1]);
}
- bool bdrv_io_limits_enabled(BlockDriverState *bs)
+ /* should be called before bdrv_set_io_limits if a limit is set */
+ void bdrv_io_limits_enable(BlockDriverState *bs)
{
- BlockIOLimit *io_limits = &bs->io_limits;
- return io_limits->bps[BLOCK_IO_LIMIT_READ]
- || io_limits->bps[BLOCK_IO_LIMIT_WRITE]
- || io_limits->bps[BLOCK_IO_LIMIT_TOTAL]
- || io_limits->iops[BLOCK_IO_LIMIT_READ]
- || io_limits->iops[BLOCK_IO_LIMIT_WRITE]
- || io_limits->iops[BLOCK_IO_LIMIT_TOTAL];
+ assert(!bs->io_limits_enabled);
+ throttle_init(&bs->throttle_state,
+ QEMU_CLOCK_VIRTUAL,
+ bdrv_throttle_read_timer_cb,
+ bdrv_throttle_write_timer_cb,
+ bs);
+ bs->io_limits_enabled = true;
}
+ /* This function makes an IO wait if needed
+ *
+ * @nb_sectors: the number of sectors of the IO
+ * @is_write: is the IO a write
+ */
static void bdrv_io_limits_intercept(BlockDriverState *bs,
- bool is_write, int nb_sectors)
+ int nb_sectors,
+ bool is_write)
{
- int64_t wait_time = -1;
+ /* does this io must wait */
+ bool must_wait = throttle_schedule_timer(&bs->throttle_state, is_write);
- if (!qemu_co_queue_empty(&bs->throttled_reqs)) {
- qemu_co_queue_wait(&bs->throttled_reqs);
+ /* if must wait or any request of this type throttled queue the IO */
+ if (must_wait ||
+ !qemu_co_queue_empty(&bs->throttled_reqs[is_write])) {
+ qemu_co_queue_wait(&bs->throttled_reqs[is_write]);
}
- /* In fact, we hope to keep each request's timing, in FIFO mode. The next
- * throttled requests will not be dequeued until the current request is
- * allowed to be serviced. So if the current request still exceeds the
- * limits, it will be inserted to the head. All requests followed it will
- * be still in throttled_reqs queue.
- */
+ /* the IO will be executed, do the accounting */
+ throttle_account(&bs->throttle_state,
+ is_write,
+ nb_sectors * BDRV_SECTOR_SIZE);
- while (bdrv_exceed_io_limits(bs, nb_sectors, is_write, &wait_time)) {
- qemu_mod_timer(bs->block_timer,
- wait_time + qemu_get_clock_ns(vm_clock));
- qemu_co_queue_wait_insert_head(&bs->throttled_reqs);
+ /* if the next request must wait -> do nothing */
+ if (throttle_schedule_timer(&bs->throttle_state, is_write)) {
+ return;
}
- qemu_co_queue_next(&bs->throttled_reqs);
+ /* else queue next request for execution */
+ qemu_co_queue_next(&bs->throttled_reqs[is_write]);
}
/* check if the path starts with "<protocol>:" */
bdrv_iostatus_disable(bs);
notifier_list_init(&bs->close_notifiers);
notifier_with_return_list_init(&bs->before_write_notifiers);
+ qemu_co_queue_init(&bs->throttled_reqs[0]);
+ qemu_co_queue_init(&bs->throttled_reqs[1]);
+ bs->refcnt = 1;
return bs;
}
char *filename;
QEMUOptionParameter *options;
int ret;
+ Error *err;
} CreateCo;
static void coroutine_fn bdrv_create_co_entry(void *opaque)
{
+ Error *local_err = NULL;
+ int ret;
+
CreateCo *cco = opaque;
assert(cco->drv);
- cco->ret = cco->drv->bdrv_create(cco->filename, cco->options);
+ ret = cco->drv->bdrv_create(cco->filename, cco->options, &local_err);
+ if (error_is_set(&local_err)) {
+ error_propagate(&cco->err, local_err);
+ }
+ cco->ret = ret;
}
int bdrv_create(BlockDriver *drv, const char* filename,
- QEMUOptionParameter *options)
+ QEMUOptionParameter *options, Error **errp)
{
int ret;
.filename = g_strdup(filename),
.options = options,
.ret = NOT_DONE,
+ .err = NULL,
};
if (!drv->bdrv_create) {
+ error_setg(errp, "Driver '%s' does not support image creation", drv->format_name);
ret = -ENOTSUP;
goto out;
}
}
ret = cco.ret;
+ if (ret < 0) {
+ if (error_is_set(&cco.err)) {
+ error_propagate(errp, cco.err);
+ } else {
+ error_setg_errno(errp, -ret, "Could not create image");
+ }
+ }
out:
g_free(cco.filename);
return ret;
}
- int bdrv_create_file(const char* filename, QEMUOptionParameter *options)
+ int bdrv_create_file(const char* filename, QEMUOptionParameter *options,
+ Error **errp)
{
BlockDriver *drv;
+ Error *local_err = NULL;
+ int ret;
drv = bdrv_find_protocol(filename, true);
if (drv == NULL) {
+ error_setg(errp, "Could not find protocol for file '%s'", filename);
return -ENOENT;
}
- return bdrv_create(drv, filename, options);
+ ret = bdrv_create(drv, filename, options, &local_err);
+ if (error_is_set(&local_err)) {
+ error_propagate(errp, local_err);
+ }
+ return ret;
}
/*
}
static int find_image_format(BlockDriverState *bs, const char *filename,
- BlockDriver **pdrv)
+ BlockDriver **pdrv, Error **errp)
{
int score, score_max;
BlockDriver *drv1, *drv;
if (bs->sg || !bdrv_is_inserted(bs) || bdrv_getlength(bs) == 0) {
drv = bdrv_find_format("raw");
if (!drv) {
+ error_setg(errp, "Could not find raw image format");
ret = -ENOENT;
}
*pdrv = drv;
ret = bdrv_pread(bs, 0, buf, sizeof(buf));
if (ret < 0) {
+ error_setg_errno(errp, -ret, "Could not read image for determining its "
+ "format");
*pdrv = NULL;
return ret;
}
}
}
if (!drv) {
+ error_setg(errp, "Could not determine image format: No compatible "
+ "driver found");
ret = -ENOENT;
}
*pdrv = drv;
if (length < 0) {
return length;
}
- hint = length >> BDRV_SECTOR_BITS;
+ hint = DIV_ROUND_UP(length, BDRV_SECTOR_SIZE);
}
bs->total_sectors = hint;
* Removes all processed options from *options.
*/
static int bdrv_open_common(BlockDriverState *bs, BlockDriverState *file,
- QDict *options, int flags, BlockDriver *drv)
+ QDict *options, int flags, BlockDriver *drv, Error **errp)
{
int ret, open_flags;
const char *filename;
+ Error *local_err = NULL;
assert(drv != NULL);
assert(bs->file == NULL);
bs->open_flags = flags;
bs->buffer_alignment = 512;
+ bs->zero_beyond_eof = true;
open_flags = bdrv_open_flags(bs, flags);
bs->read_only = !(open_flags & BDRV_O_RDWR);
if (use_bdrv_whitelist && !bdrv_is_whitelisted(drv, bs->read_only)) {
+ error_setg(errp,
+ !bs->read_only && bdrv_is_whitelisted(drv, true)
+ ? "Driver '%s' can only be used for read-only devices"
+ : "Driver '%s' is not whitelisted",
+ drv->format_name);
return -ENOTSUP;
}
assert(bs->copy_on_read == 0); /* bdrv_new() and bdrv_close() make it so */
- if (!bs->read_only && (flags & BDRV_O_COPY_ON_READ)) {
- bdrv_enable_copy_on_read(bs);
+ if (flags & BDRV_O_COPY_ON_READ) {
+ if (!bs->read_only) {
+ bdrv_enable_copy_on_read(bs);
+ } else {
+ error_setg(errp, "Can't use copy-on-read on read-only device");
+ return -EINVAL;
+ }
}
if (filename != NULL) {
/* Open the image, either directly or using a protocol */
if (drv->bdrv_file_open) {
assert(file == NULL);
- assert(drv->bdrv_parse_filename || filename != NULL);
- ret = drv->bdrv_file_open(bs, options, open_flags);
+ assert(!drv->bdrv_needs_filename || filename != NULL);
+ ret = drv->bdrv_file_open(bs, options, open_flags, &local_err);
} else {
if (file == NULL) {
- qerror_report(ERROR_CLASS_GENERIC_ERROR, "Can't use '%s' as a "
- "block driver for the protocol level",
- drv->format_name);
+ error_setg(errp, "Can't use '%s' as a block driver for the "
+ "protocol level", drv->format_name);
ret = -EINVAL;
goto free_and_fail;
}
- assert(file != NULL);
bs->file = file;
- ret = drv->bdrv_open(bs, options, open_flags);
+ ret = drv->bdrv_open(bs, options, open_flags, &local_err);
}
if (ret < 0) {
+ if (error_is_set(&local_err)) {
+ error_propagate(errp, local_err);
+ } else if (bs->filename[0]) {
+ error_setg_errno(errp, -ret, "Could not open '%s'", bs->filename);
+ } else {
+ error_setg_errno(errp, -ret, "Could not open image");
+ }
goto free_and_fail;
}
ret = refresh_total_sectors(bs, bs->total_sectors);
if (ret < 0) {
+ error_setg_errno(errp, -ret, "Could not refresh total sector count");
goto free_and_fail;
}
#ifndef _WIN32
if (bs->is_temporary) {
- assert(filename != NULL);
- unlink(filename);
+ assert(bs->filename[0] != '\0');
+ unlink(bs->filename);
}
#endif
return 0;
* dictionary, it needs to use QINCREF() before calling bdrv_file_open.
*/
int bdrv_file_open(BlockDriverState **pbs, const char *filename,
- QDict *options, int flags)
+ QDict *options, int flags, Error **errp)
{
BlockDriverState *bs;
BlockDriver *drv;
const char *drvname;
bool allow_protocol_prefix = false;
+ Error *local_err = NULL;
int ret;
/* NULL means an empty set of options */
qdict_put(options, "filename", qstring_from_str(filename));
allow_protocol_prefix = true;
} else {
- qerror_report(ERROR_CLASS_GENERIC_ERROR, "Can't specify 'file' and "
- "'filename' options at the same time");
+ error_setg(errp, "Can't specify 'file' and 'filename' options at the "
+ "same time");
ret = -EINVAL;
goto fail;
}
/* Find the right block driver */
drvname = qdict_get_try_str(options, "driver");
if (drvname) {
- drv = bdrv_find_whitelisted_format(drvname, !(flags & BDRV_O_RDWR));
+ drv = bdrv_find_format(drvname);
+ if (!drv) {
+ error_setg(errp, "Unknown driver '%s'", drvname);
+ }
qdict_del(options, "driver");
} else if (filename) {
drv = bdrv_find_protocol(filename, allow_protocol_prefix);
if (!drv) {
- qerror_report(ERROR_CLASS_GENERIC_ERROR, "Unknown protocol");
+ error_setg(errp, "Unknown protocol");
}
} else {
- qerror_report(ERROR_CLASS_GENERIC_ERROR,
- "Must specify either driver or file");
+ error_setg(errp, "Must specify either driver or file");
drv = NULL;
}
if (!drv) {
+ /* errp has been set already */
ret = -ENOENT;
goto fail;
}
/* Parse the filename and open it */
if (drv->bdrv_parse_filename && filename) {
- Error *local_err = NULL;
drv->bdrv_parse_filename(filename, options, &local_err);
if (error_is_set(&local_err)) {
- qerror_report_err(local_err);
- error_free(local_err);
+ error_propagate(errp, local_err);
ret = -EINVAL;
goto fail;
}
qdict_del(options, "filename");
- } else if (!drv->bdrv_parse_filename && !filename) {
- qerror_report(ERROR_CLASS_GENERIC_ERROR,
- "The '%s' block driver requires a file name",
- drv->format_name);
+ } else if (drv->bdrv_needs_filename && !filename) {
+ error_setg(errp, "The '%s' block driver requires a file name",
+ drv->format_name);
ret = -EINVAL;
goto fail;
}
- ret = bdrv_open_common(bs, NULL, options, flags, drv);
+ ret = bdrv_open_common(bs, NULL, options, flags, drv, &local_err);
if (ret < 0) {
+ error_propagate(errp, local_err);
goto fail;
}
/* Check if any unknown options were used */
if (qdict_size(options) != 0) {
const QDictEntry *entry = qdict_first(options);
- qerror_report(ERROR_CLASS_GENERIC_ERROR, "Block protocol '%s' doesn't "
- "support the option '%s'",
- drv->format_name, entry->key);
+ error_setg(errp, "Block protocol '%s' doesn't support the option '%s'",
+ drv->format_name, entry->key);
ret = -EINVAL;
goto fail;
}
if (!bs->drv) {
QDECREF(bs->options);
}
- bdrv_delete(bs);
+ bdrv_unref(bs);
return ret;
}
* function (even on failure), so if the caller intends to reuse the dictionary,
* it needs to use QINCREF() before calling bdrv_file_open.
*/
- int bdrv_open_backing_file(BlockDriverState *bs, QDict *options)
+ int bdrv_open_backing_file(BlockDriverState *bs, QDict *options, Error **errp)
{
char backing_filename[PATH_MAX];
int back_flags, ret;
BlockDriver *back_drv = NULL;
+ Error *local_err = NULL;
if (bs->backing_hd != NULL) {
QDECREF(options);
} else if (bs->backing_file[0] == '\0' && qdict_size(options) == 0) {
QDECREF(options);
return 0;
+ } else {
+ bdrv_get_full_backing_filename(bs, backing_filename,
+ sizeof(backing_filename));
}
bs->backing_hd = bdrv_new("");
- bdrv_get_full_backing_filename(bs, backing_filename,
- sizeof(backing_filename));
if (bs->backing_format[0] != '\0') {
back_drv = bdrv_find_format(bs->backing_format);
}
/* backing files always opened read-only */
- back_flags = bs->open_flags & ~(BDRV_O_RDWR | BDRV_O_SNAPSHOT);
+ back_flags = bs->open_flags & ~(BDRV_O_RDWR | BDRV_O_SNAPSHOT |
+ BDRV_O_COPY_ON_READ);
ret = bdrv_open(bs->backing_hd,
*backing_filename ? backing_filename : NULL, options,
- back_flags, back_drv);
+ back_flags, back_drv, &local_err);
if (ret < 0) {
- bdrv_delete(bs->backing_hd);
+ bdrv_unref(bs->backing_hd);
bs->backing_hd = NULL;
bs->open_flags |= BDRV_O_NO_BACKING;
+ error_setg(errp, "Could not open backing file: %s",
+ error_get_pretty(local_err));
+ error_free(local_err);
return ret;
}
+ pstrcpy(bs->backing_file, sizeof(bs->backing_file),
+ bs->backing_hd->file->filename);
return 0;
}
- static void extract_subqdict(QDict *src, QDict **dst, const char *start)
- {
- const QDictEntry *entry, *next;
- const char *p;
-
- *dst = qdict_new();
- entry = qdict_first(src);
-
- while (entry != NULL) {
- next = qdict_next(src, entry);
- if (strstart(entry->key, start, &p)) {
- qobject_incref(entry->value);
- qdict_put_obj(*dst, p, entry->value);
- qdict_del(src, entry->key);
- }
- entry = next;
- }
- }
-
/*
* Opens a disk image (raw, qcow2, vmdk, ...)
*
* dictionary, it needs to use QINCREF() before calling bdrv_open.
*/
int bdrv_open(BlockDriverState *bs, const char *filename, QDict *options,
- int flags, BlockDriver *drv)
+ int flags, BlockDriver *drv, Error **errp)
{
int ret;
/* TODO: extra byte is a hack to ensure MAX_PATH space on Windows. */
BlockDriverState *file = NULL;
QDict *file_options = NULL;
const char *drvname;
+ Error *local_err = NULL;
/* NULL means an empty set of options */
if (options == NULL) {
char backing_filename[PATH_MAX];
if (qdict_size(options) != 0) {
- error_report("Can't use snapshot=on with driver-specific options");
+ error_setg(errp, "Can't use snapshot=on with driver-specific options");
ret = -EINVAL;
goto fail;
}
/* if there is a backing file, use it */
bs1 = bdrv_new("");
- ret = bdrv_open(bs1, filename, NULL, 0, drv);
+ ret = bdrv_open(bs1, filename, NULL, 0, drv, &local_err);
if (ret < 0) {
- bdrv_delete(bs1);
+ bdrv_unref(bs1);
goto fail;
}
total_size = bdrv_getlength(bs1) & BDRV_SECTOR_MASK;
- bdrv_delete(bs1);
+ bdrv_unref(bs1);
ret = get_tmp_filename(tmp_filename, sizeof(tmp_filename));
if (ret < 0) {
+ error_setg_errno(errp, -ret, "Could not get temporary filename");
goto fail;
}
"%s", filename);
} else if (!realpath(filename, backing_filename)) {
ret = -errno;
+ error_setg_errno(errp, errno, "Could not resolve path '%s'", filename);
goto fail;
}
drv->format_name);
}
- ret = bdrv_create(bdrv_qcow2, tmp_filename, create_options);
+ ret = bdrv_create(bdrv_qcow2, tmp_filename, create_options, &local_err);
free_option_parameters(create_options);
if (ret < 0) {
+ error_setg_errno(errp, -ret, "Could not create temporary overlay "
+ "'%s': %s", tmp_filename,
+ error_get_pretty(local_err));
+ error_free(local_err);
+ local_err = NULL;
goto fail;
}
flags |= BDRV_O_ALLOW_RDWR;
}
- extract_subqdict(options, &file_options, "file.");
+ qdict_extract_subqdict(options, &file_options, "file.");
ret = bdrv_file_open(&file, filename, file_options,
- bdrv_open_flags(bs, flags | BDRV_O_UNMAP));
+ bdrv_open_flags(bs, flags | BDRV_O_UNMAP), &local_err);
if (ret < 0) {
goto fail;
}
/* Find the right image format driver */
drvname = qdict_get_try_str(options, "driver");
if (drvname) {
- drv = bdrv_find_whitelisted_format(drvname, !(flags & BDRV_O_RDWR));
+ drv = bdrv_find_format(drvname);
qdict_del(options, "driver");
+ if (!drv) {
+ error_setg(errp, "Invalid driver: '%s'", drvname);
+ ret = -EINVAL;
+ goto unlink_and_fail;
+ }
}
if (!drv) {
- ret = find_image_format(file, filename, &drv);
+ ret = find_image_format(file, filename, &drv, &local_err);
}
if (!drv) {
}
/* Open the image */
- ret = bdrv_open_common(bs, file, options, flags, drv);
+ ret = bdrv_open_common(bs, file, options, flags, drv, &local_err);
if (ret < 0) {
goto unlink_and_fail;
}
if (bs->file != file) {
- bdrv_delete(file);
+ bdrv_unref(file);
file = NULL;
}
if ((flags & BDRV_O_NO_BACKING) == 0) {
QDict *backing_options;
- extract_subqdict(options, &backing_options, "backing.");
- ret = bdrv_open_backing_file(bs, backing_options);
+ qdict_extract_subqdict(options, &backing_options, "backing.");
+ ret = bdrv_open_backing_file(bs, backing_options, &local_err);
if (ret < 0) {
goto close_and_fail;
}
/* Check if any unknown options were used */
if (qdict_size(options) != 0) {
const QDictEntry *entry = qdict_first(options);
- qerror_report(ERROR_CLASS_GENERIC_ERROR, "Block format '%s' used by "
- "device '%s' doesn't support the option '%s'",
- drv->format_name, bs->device_name, entry->key);
+ error_setg(errp, "Block format '%s' used by device '%s' doesn't "
+ "support the option '%s'", drv->format_name, bs->device_name,
+ entry->key);
ret = -EINVAL;
goto close_and_fail;
bdrv_dev_change_media_cb(bs, true);
}
- /* throttling disk I/O limits */
- if (bs->io_limits_enabled) {
- bdrv_io_limits_enable(bs);
- }
-
return 0;
unlink_and_fail:
if (file != NULL) {
- bdrv_delete(file);
+ bdrv_unref(file);
}
if (bs->is_temporary) {
unlink(filename);
QDECREF(bs->options);
QDECREF(options);
bs->options = NULL;
+ if (error_is_set(&local_err)) {
+ error_propagate(errp, local_err);
+ }
return ret;
close_and_fail:
bdrv_close(bs);
QDECREF(options);
+ if (error_is_set(&local_err)) {
+ error_propagate(errp, local_err);
+ }
return ret;
}
if (bs->drv) {
if (bs->backing_hd) {
- bdrv_delete(bs->backing_hd);
+ bdrv_unref(bs->backing_hd);
bs->backing_hd = NULL;
}
bs->drv->bdrv_close(bs);
bs->valid_key = 0;
bs->sg = 0;
bs->growable = 0;
+ bs->zero_beyond_eof = false;
QDECREF(bs->options);
bs->options = NULL;
if (bs->file != NULL) {
- bdrv_delete(bs->file);
+ bdrv_unref(bs->file);
bs->file = NULL;
}
}
}
}
+ /* Check if any requests are in-flight (including throttled requests) */
+ static bool bdrv_requests_pending(BlockDriverState *bs)
+ {
+ if (!QLIST_EMPTY(&bs->tracked_requests)) {
+ return true;
+ }
+ if (!qemu_co_queue_empty(&bs->throttled_reqs[0])) {
+ return true;
+ }
+ if (!qemu_co_queue_empty(&bs->throttled_reqs[1])) {
+ return true;
+ }
+ if (bs->file && bdrv_requests_pending(bs->file)) {
+ return true;
+ }
+ if (bs->backing_hd && bdrv_requests_pending(bs->backing_hd)) {
+ return true;
+ }
+ return false;
+ }
+
+ static bool bdrv_requests_pending_all(void)
+ {
+ BlockDriverState *bs;
+ QTAILQ_FOREACH(bs, &bdrv_states, list) {
+ if (bdrv_requests_pending(bs)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
/*
* Wait for pending requests to complete across all BlockDriverStates
*
*/
void bdrv_drain_all(void)
{
+ /* Always run first iteration so any pending completion BHs run */
+ bool busy = true;
BlockDriverState *bs;
- bool busy;
-
- do {
- busy = qemu_aio_wait();
+ while (busy) {
/* FIXME: We do not have timer support here, so this is effectively
* a busy wait.
*/
QTAILQ_FOREACH(bs, &bdrv_states, list) {
- while (qemu_co_enter_next(&bs->throttled_reqs)) {
+ if (bdrv_start_throttled_reqs(bs)) {
busy = true;
}
}
- } while (busy);
- /* If requests are still pending there is a bug somewhere */
- QTAILQ_FOREACH(bs, &bdrv_states, list) {
- assert(QLIST_EMPTY(&bs->tracked_requests));
- assert(qemu_co_queue_empty(&bs->throttled_reqs));
+ busy = bdrv_requests_pending_all();
+ busy |= aio_poll(qemu_get_aio_context(), busy);
}
}
bs_dest->enable_write_cache = bs_src->enable_write_cache;
- /* i/o timing parameters */
- bs_dest->slice_start = bs_src->slice_start;
- bs_dest->slice_end = bs_src->slice_end;
- bs_dest->slice_submitted = bs_src->slice_submitted;
- bs_dest->io_limits = bs_src->io_limits;
- bs_dest->throttled_reqs = bs_src->throttled_reqs;
- bs_dest->block_timer = bs_src->block_timer;
+ /* i/o throttled req */
+ memcpy(&bs_dest->throttle_state,
+ &bs_src->throttle_state,
+ sizeof(ThrottleState));
+ bs_dest->throttled_reqs[0] = bs_src->throttled_reqs[0];
+ bs_dest->throttled_reqs[1] = bs_src->throttled_reqs[1];
bs_dest->io_limits_enabled = bs_src->io_limits_enabled;
/* r/w error */
/* dirty bitmap */
bs_dest->dirty_bitmap = bs_src->dirty_bitmap;
+ /* reference count */
+ bs_dest->refcnt = bs_src->refcnt;
+
/* job */
bs_dest->in_use = bs_src->in_use;
bs_dest->job = bs_src->job;
assert(bs_new->dev == NULL);
assert(bs_new->in_use == 0);
assert(bs_new->io_limits_enabled == false);
- assert(bs_new->block_timer == NULL);
+ assert(!throttle_have_timer(&bs_new->throttle_state));
tmp = *bs_new;
*bs_new = *bs_old;
assert(bs_new->job == NULL);
assert(bs_new->in_use == 0);
assert(bs_new->io_limits_enabled == false);
- assert(bs_new->block_timer == NULL);
+ assert(!throttle_have_timer(&bs_new->throttle_state));
bdrv_rebind(bs_new);
bdrv_rebind(bs_old);
bs_new->drv ? bs_new->drv->format_name : "");
}
- void bdrv_delete(BlockDriverState *bs)
+ static void bdrv_delete(BlockDriverState *bs)
{
assert(!bs->dev);
assert(!bs->job);
assert(!bs->in_use);
+ assert(!bs->refcnt);
+
+ bdrv_close(bs);
+ bdrv_close(bs);
+
/* remove from list, if necessary */
bdrv_make_anon(bs);
QSIMPLEQ_FOREACH_SAFE(intermediate_state, &states_to_delete, entry, next) {
/* so that bdrv_close() does not recursively close the chain */
intermediate_state->bs->backing_hd = NULL;
- bdrv_delete(intermediate_state->bs);
+ bdrv_unref(intermediate_state->bs);
}
ret = 0;
return -EIO;
}
- /* throttling disk read I/O */
- if (bs->io_limits_enabled) {
- bdrv_io_limits_intercept(bs, false, nb_sectors);
- }
-
if (bs->copy_on_read) {
flags |= BDRV_REQ_COPY_ON_READ;
}
wait_for_overlapping_requests(bs, sector_num, nb_sectors);
}
+ /* throttling disk I/O */
+ if (bs->io_limits_enabled) {
+ bdrv_io_limits_intercept(bs, nb_sectors, false);
+ }
+
tracked_request_begin(&req, bs, sector_num, nb_sectors, false);
if (flags & BDRV_REQ_COPY_ON_READ) {
int pnum;
- ret = bdrv_co_is_allocated(bs, sector_num, nb_sectors, &pnum);
+ ret = bdrv_is_allocated(bs, sector_num, nb_sectors, &pnum);
if (ret < 0) {
goto out;
}
}
}
- ret = drv->bdrv_co_readv(bs, sector_num, nb_sectors, qiov);
+ if (!(bs->zero_beyond_eof && bs->growable)) {
+ ret = drv->bdrv_co_readv(bs, sector_num, nb_sectors, qiov);
+ } else {
+ /* Read zeros after EOF of growable BDSes */
+ int64_t len, total_sectors, max_nb_sectors;
+
+ len = bdrv_getlength(bs);
+ if (len < 0) {
+ ret = len;
+ goto out;
+ }
+
+ total_sectors = DIV_ROUND_UP(len, BDRV_SECTOR_SIZE);
+ max_nb_sectors = MAX(0, total_sectors - sector_num);
+ if (max_nb_sectors > 0) {
+ ret = drv->bdrv_co_readv(bs, sector_num,
+ MIN(nb_sectors, max_nb_sectors), qiov);
+ } else {
+ ret = 0;
+ }
+
+ /* Reading beyond end of file is supposed to produce zeroes */
+ if (ret == 0 && total_sectors < sector_num + nb_sectors) {
+ uint64_t offset = MAX(0, total_sectors - sector_num);
+ uint64_t bytes = (sector_num + nb_sectors - offset) *
+ BDRV_SECTOR_SIZE;
+ qemu_iovec_memset(qiov, offset * BDRV_SECTOR_SIZE, 0, bytes);
+ }
+ }
out:
tracked_request_end(&req);
return -EIO;
}
- /* throttling disk write I/O */
- if (bs->io_limits_enabled) {
- bdrv_io_limits_intercept(bs, true, nb_sectors);
- }
-
if (bs->copy_on_read_in_flight) {
wait_for_overlapping_requests(bs, sector_num, nb_sectors);
}
+ /* throttling disk I/O */
+ if (bs->io_limits_enabled) {
+ bdrv_io_limits_intercept(bs, nb_sectors, true);
+ }
+
tracked_request_begin(&req, bs, sector_num, nb_sectors, true);
ret = notifier_with_return_list_notify(&bs->before_write_notifiers, &req);
if (bs->wr_highest_sector < sector_num + nb_sectors - 1) {
bs->wr_highest_sector = sector_num + nb_sectors - 1;
}
+ if (bs->growable && ret >= 0) {
+ bs->total_sectors = MAX(bs->total_sectors, sector_num + nb_sectors);
+ }
tracked_request_end(&req);
if (!drv)
return -ENOMEDIUM;
- if (bs->growable || bdrv_dev_has_removable_media(bs)) {
- if (drv->bdrv_getlength) {
- return drv->bdrv_getlength(bs);
+ if (drv->has_variable_length) {
+ int ret = refresh_total_sectors(bs, bs->total_sectors);
+ if (ret < 0) {
+ return ret;
}
}
return bs->total_sectors * BDRV_SECTOR_SIZE;
*nb_sectors_ptr = length;
}
- /* throttling disk io limits */
- void bdrv_set_io_limits(BlockDriverState *bs,
- BlockIOLimit *io_limits)
- {
- bs->io_limits = *io_limits;
- bs->io_limits_enabled = bdrv_io_limits_enabled(bs);
- }
-
void bdrv_set_on_error(BlockDriverState *bs, BlockdevOnError on_read_error,
BlockdevOnError on_write_error)
{
{
assert(bs->drv);
+ /* If BS is a copy on write image, it is initialized to
+ the contents of the base image, which may not be zeroes. */
+ if (bs->backing_hd) {
+ return 0;
+ }
if (bs->drv->bdrv_has_zero_init) {
return bs->drv->bdrv_has_zero_init(bs);
}
return 0;
}
- typedef struct BdrvCoIsAllocatedData {
+ typedef struct BdrvCoGetBlockStatusData {
BlockDriverState *bs;
BlockDriverState *base;
int64_t sector_num;
int nb_sectors;
int *pnum;
- int ret;
+ int64_t ret;
bool done;
- } BdrvCoIsAllocatedData;
+ } BdrvCoGetBlockStatusData;
/*
* Returns true iff the specified sector is present in the disk image. Drivers
* 'nb_sectors' is the max value 'pnum' should be set to. If nb_sectors goes
* beyond the end of the disk image it will be clamped.
*/
- int coroutine_fn bdrv_co_is_allocated(BlockDriverState *bs, int64_t sector_num,
- int nb_sectors, int *pnum)
+ static int64_t coroutine_fn bdrv_co_get_block_status(BlockDriverState *bs,
+ int64_t sector_num,
+ int nb_sectors, int *pnum)
{
+ int64_t length;
int64_t n;
+ int64_t ret, ret2;
- if (sector_num >= bs->total_sectors) {
+ length = bdrv_getlength(bs);
+ if (length < 0) {
+ return length;
+ }
+
+ if (sector_num >= (length >> BDRV_SECTOR_BITS)) {
*pnum = 0;
return 0;
}
nb_sectors = n;
}
- if (!bs->drv->bdrv_co_is_allocated) {
+ if (!bs->drv->bdrv_co_get_block_status) {
*pnum = nb_sectors;
- return 1;
+ ret = BDRV_BLOCK_DATA;
+ if (bs->drv->protocol_name) {
+ ret |= BDRV_BLOCK_OFFSET_VALID | (sector_num * BDRV_SECTOR_SIZE);
+ }
+ return ret;
}
- return bs->drv->bdrv_co_is_allocated(bs, sector_num, nb_sectors, pnum);
+ ret = bs->drv->bdrv_co_get_block_status(bs, sector_num, nb_sectors, pnum);
+ if (ret < 0) {
+ *pnum = 0;
+ return ret;
+ }
+
+ if (ret & BDRV_BLOCK_RAW) {
+ assert(ret & BDRV_BLOCK_OFFSET_VALID);
+ return bdrv_get_block_status(bs->file, ret >> BDRV_SECTOR_BITS,
+ *pnum, pnum);
+ }
+
+ if (!(ret & BDRV_BLOCK_DATA)) {
+ if (bdrv_has_zero_init(bs)) {
+ ret |= BDRV_BLOCK_ZERO;
+ } else if (bs->backing_hd) {
+ BlockDriverState *bs2 = bs->backing_hd;
+ int64_t length2 = bdrv_getlength(bs2);
+ if (length2 >= 0 && sector_num >= (length2 >> BDRV_SECTOR_BITS)) {
+ ret |= BDRV_BLOCK_ZERO;
+ }
+ }
+ }
+
+ if (bs->file &&
+ (ret & BDRV_BLOCK_DATA) && !(ret & BDRV_BLOCK_ZERO) &&
+ (ret & BDRV_BLOCK_OFFSET_VALID)) {
+ ret2 = bdrv_co_get_block_status(bs->file, ret >> BDRV_SECTOR_BITS,
+ *pnum, pnum);
+ if (ret2 >= 0) {
+ /* Ignore errors. This is just providing extra information, it
+ * is useful but not necessary.
+ */
+ ret |= (ret2 & BDRV_BLOCK_ZERO);
+ }
+ }
+
+ return ret;
}
- /* Coroutine wrapper for bdrv_is_allocated() */
- static void coroutine_fn bdrv_is_allocated_co_entry(void *opaque)
+ /* Coroutine wrapper for bdrv_get_block_status() */
+ static void coroutine_fn bdrv_get_block_status_co_entry(void *opaque)
{
- BdrvCoIsAllocatedData *data = opaque;
+ BdrvCoGetBlockStatusData *data = opaque;
BlockDriverState *bs = data->bs;
- data->ret = bdrv_co_is_allocated(bs, data->sector_num, data->nb_sectors,
- data->pnum);
+ data->ret = bdrv_co_get_block_status(bs, data->sector_num, data->nb_sectors,
+ data->pnum);
data->done = true;
}
/*
- * Synchronous wrapper around bdrv_co_is_allocated().
+ * Synchronous wrapper around bdrv_co_get_block_status().
*
- * See bdrv_co_is_allocated() for details.
+ * See bdrv_co_get_block_status() for details.
*/
- int bdrv_is_allocated(BlockDriverState *bs, int64_t sector_num, int nb_sectors,
- int *pnum)
+ int64_t bdrv_get_block_status(BlockDriverState *bs, int64_t sector_num,
+ int nb_sectors, int *pnum)
{
Coroutine *co;
- BdrvCoIsAllocatedData data = {
+ BdrvCoGetBlockStatusData data = {
.bs = bs,
.sector_num = sector_num,
.nb_sectors = nb_sectors,
.done = false,
};
- co = qemu_coroutine_create(bdrv_is_allocated_co_entry);
- qemu_coroutine_enter(co, &data);
- while (!data.done) {
- qemu_aio_wait();
+ if (qemu_in_coroutine()) {
+ /* Fast-path if already in coroutine context */
+ bdrv_get_block_status_co_entry(&data);
+ } else {
+ co = qemu_coroutine_create(bdrv_get_block_status_co_entry);
+ qemu_coroutine_enter(co, &data);
+ while (!data.done) {
+ qemu_aio_wait();
+ }
}
return data.ret;
}
+ int coroutine_fn bdrv_is_allocated(BlockDriverState *bs, int64_t sector_num,
+ int nb_sectors, int *pnum)
+ {
+ int64_t ret = bdrv_get_block_status(bs, sector_num, nb_sectors, pnum);
+ if (ret < 0) {
+ return ret;
+ }
+ return
+ (ret & BDRV_BLOCK_DATA) ||
+ ((ret & BDRV_BLOCK_ZERO) && !bdrv_has_zero_init(bs));
+ }
+
/*
* Given an image chain: ... -> [BASE] -> [INTER1] -> [INTER2] -> [TOP]
*
* allocated/unallocated state.
*
*/
- int coroutine_fn bdrv_co_is_allocated_above(BlockDriverState *top,
- BlockDriverState *base,
- int64_t sector_num,
- int nb_sectors, int *pnum)
+ int bdrv_is_allocated_above(BlockDriverState *top,
+ BlockDriverState *base,
+ int64_t sector_num,
+ int nb_sectors, int *pnum)
{
BlockDriverState *intermediate;
int ret, n = nb_sectors;
intermediate = top;
while (intermediate && intermediate != base) {
int pnum_inter;
- ret = bdrv_co_is_allocated(intermediate, sector_num, nb_sectors,
- &pnum_inter);
+ ret = bdrv_is_allocated(intermediate, sector_num, nb_sectors,
+ &pnum_inter);
if (ret < 0) {
return ret;
} else if (ret) {
return 0;
}
- /* Coroutine wrapper for bdrv_is_allocated_above() */
- static void coroutine_fn bdrv_is_allocated_above_co_entry(void *opaque)
- {
- BdrvCoIsAllocatedData *data = opaque;
- BlockDriverState *top = data->bs;
- BlockDriverState *base = data->base;
-
- data->ret = bdrv_co_is_allocated_above(top, base, data->sector_num,
- data->nb_sectors, data->pnum);
- data->done = true;
- }
-
- /*
- * Synchronous wrapper around bdrv_co_is_allocated_above().
- *
- * See bdrv_co_is_allocated_above() for details.
- */
- int bdrv_is_allocated_above(BlockDriverState *top, BlockDriverState *base,
- int64_t sector_num, int nb_sectors, int *pnum)
- {
- Coroutine *co;
- BdrvCoIsAllocatedData data = {
- .bs = top,
- .base = base,
- .sector_num = sector_num,
- .nb_sectors = nb_sectors,
- .pnum = pnum,
- .done = false,
- };
-
- co = qemu_coroutine_create(bdrv_is_allocated_above_co_entry);
- qemu_coroutine_enter(co, &data);
- while (!data.done) {
- qemu_aio_wait();
- }
- return data.ret;
- }
-
const char *bdrv_get_encrypted_filename(BlockDriverState *bs)
{
if (bs->backing_hd && bs->backing_hd->encrypted)
return drv->bdrv_get_info(bs, bdi);
}
+ ImageInfoSpecific *bdrv_get_specific_info(BlockDriverState *bs)
+ {
+ BlockDriver *drv = bs->drv;
+ if (drv && drv->bdrv_get_specific_info) {
+ return drv->bdrv_get_specific_info(bs);
+ }
+ return NULL;
+ }
+
int bdrv_save_vmstate(BlockDriverState *bs, const uint8_t *buf,
int64_t pos, int size)
{
acb->aiocb_info->cancel(acb);
}
- /* block I/O throttling */
- static bool bdrv_exceed_bps_limits(BlockDriverState *bs, int nb_sectors,
- bool is_write, double elapsed_time, uint64_t *wait)
- {
- uint64_t bps_limit = 0;
- uint64_t extension;
- double bytes_limit, bytes_base, bytes_res;
- double slice_time, wait_time;
-
- if (bs->io_limits.bps[BLOCK_IO_LIMIT_TOTAL]) {
- bps_limit = bs->io_limits.bps[BLOCK_IO_LIMIT_TOTAL];
- } else if (bs->io_limits.bps[is_write]) {
- bps_limit = bs->io_limits.bps[is_write];
- } else {
- if (wait) {
- *wait = 0;
- }
-
- return false;
- }
-
- slice_time = bs->slice_end - bs->slice_start;
- slice_time /= (NANOSECONDS_PER_SECOND);
- bytes_limit = bps_limit * slice_time;
- bytes_base = bs->slice_submitted.bytes[is_write];
- if (bs->io_limits.bps[BLOCK_IO_LIMIT_TOTAL]) {
- bytes_base += bs->slice_submitted.bytes[!is_write];
- }
-
- /* bytes_base: the bytes of data which have been read/written; and
- * it is obtained from the history statistic info.
- * bytes_res: the remaining bytes of data which need to be read/written.
- * (bytes_base + bytes_res) / bps_limit: used to calcuate
- * the total time for completing reading/writting all data.
- */
- bytes_res = (unsigned) nb_sectors * BDRV_SECTOR_SIZE;
-
- if (bytes_base + bytes_res <= bytes_limit) {
- if (wait) {
- *wait = 0;
- }
-
- return false;
- }
-
- /* Calc approx time to dispatch */
- wait_time = (bytes_base + bytes_res) / bps_limit - elapsed_time;
-
- /* When the I/O rate at runtime exceeds the limits,
- * bs->slice_end need to be extended in order that the current statistic
- * info can be kept until the timer fire, so it is increased and tuned
- * based on the result of experiment.
- */
- extension = wait_time * NANOSECONDS_PER_SECOND;
- extension = DIV_ROUND_UP(extension, BLOCK_IO_SLICE_TIME) *
- BLOCK_IO_SLICE_TIME;
- bs->slice_end += extension;
- if (wait) {
- *wait = wait_time * NANOSECONDS_PER_SECOND;
- }
-
- return true;
- }
-
- static bool bdrv_exceed_iops_limits(BlockDriverState *bs, bool is_write,
- double elapsed_time, uint64_t *wait)
- {
- uint64_t iops_limit = 0;
- double ios_limit, ios_base;
- double slice_time, wait_time;
-
- if (bs->io_limits.iops[BLOCK_IO_LIMIT_TOTAL]) {
- iops_limit = bs->io_limits.iops[BLOCK_IO_LIMIT_TOTAL];
- } else if (bs->io_limits.iops[is_write]) {
- iops_limit = bs->io_limits.iops[is_write];
- } else {
- if (wait) {
- *wait = 0;
- }
-
- return false;
- }
-
- slice_time = bs->slice_end - bs->slice_start;
- slice_time /= (NANOSECONDS_PER_SECOND);
- ios_limit = iops_limit * slice_time;
- ios_base = bs->slice_submitted.ios[is_write];
- if (bs->io_limits.iops[BLOCK_IO_LIMIT_TOTAL]) {
- ios_base += bs->slice_submitted.ios[!is_write];
- }
-
- if (ios_base + 1 <= ios_limit) {
- if (wait) {
- *wait = 0;
- }
-
- return false;
- }
-
- /* Calc approx time to dispatch, in seconds */
- wait_time = (ios_base + 1) / iops_limit;
- if (wait_time > elapsed_time) {
- wait_time = wait_time - elapsed_time;
- } else {
- wait_time = 0;
- }
-
- /* Exceeded current slice, extend it by another slice time */
- bs->slice_end += BLOCK_IO_SLICE_TIME;
- if (wait) {
- *wait = wait_time * NANOSECONDS_PER_SECOND;
- }
-
- return true;
- }
-
- static bool bdrv_exceed_io_limits(BlockDriverState *bs, int nb_sectors,
- bool is_write, int64_t *wait)
- {
- int64_t now, max_wait;
- uint64_t bps_wait = 0, iops_wait = 0;
- double elapsed_time;
- int bps_ret, iops_ret;
-
- now = qemu_get_clock_ns(vm_clock);
- if (now > bs->slice_end) {
- bs->slice_start = now;
- bs->slice_end = now + BLOCK_IO_SLICE_TIME;
- memset(&bs->slice_submitted, 0, sizeof(bs->slice_submitted));
- }
-
- elapsed_time = now - bs->slice_start;
- elapsed_time /= (NANOSECONDS_PER_SECOND);
-
- bps_ret = bdrv_exceed_bps_limits(bs, nb_sectors,
- is_write, elapsed_time, &bps_wait);
- iops_ret = bdrv_exceed_iops_limits(bs, is_write,
- elapsed_time, &iops_wait);
- if (bps_ret || iops_ret) {
- max_wait = bps_wait > iops_wait ? bps_wait : iops_wait;
- if (wait) {
- *wait = max_wait;
- }
-
- now = qemu_get_clock_ns(vm_clock);
- if (bs->slice_end < now + max_wait) {
- bs->slice_end = now + max_wait;
- }
-
- return true;
- }
-
- if (wait) {
- *wait = 0;
- }
-
- bs->slice_submitted.bytes[is_write] += (int64_t)nb_sectors *
- BDRV_SECTOR_SIZE;
- bs->slice_submitted.ios[is_write]++;
-
- return false;
- }
-
/**************************************************************/
/* async block device emulation */
}
}
+ /* Get a reference to bs */
+ void bdrv_ref(BlockDriverState *bs)
+ {
+ bs->refcnt++;
+ }
+
+ /* Release a previously grabbed reference to bs.
+ * If after releasing, reference count is zero, the BlockDriverState is
+ * deleted. */
+ void bdrv_unref(BlockDriverState *bs)
+ {
+ assert(bs->refcnt > 0);
+ if (--bs->refcnt == 0) {
+ bdrv_delete(bs);
+ }
+ }
+
void bdrv_set_in_use(BlockDriverState *bs, int in_use)
{
assert(bs->in_use != in_use);
BlockDriverState *bs = NULL;
BlockDriver *drv, *proto_drv;
BlockDriver *backing_drv = NULL;
+ Error *local_err = NULL;
int ret = 0;
/* Find driver and parse its options */
bs = bdrv_new("");
ret = bdrv_open(bs, backing_file->value.s, NULL, back_flags,
- backing_drv);
+ backing_drv, &local_err);
if (ret < 0) {
- error_setg_errno(errp, -ret, "Could not open '%s'",
- backing_file->value.s);
+ error_setg_errno(errp, -ret, "Could not open '%s': %s",
+ backing_file->value.s,
+ error_get_pretty(local_err));
+ error_free(local_err);
+ local_err = NULL;
goto out;
}
bdrv_get_geometry(bs, &size);
print_option_parameters(param);
puts("");
}
- ret = bdrv_create(drv, filename, param);
- if (ret < 0) {
- if (ret == -ENOTSUP) {
- error_setg(errp,"Formatting or formatting option not supported for "
- "file format '%s'", fmt);
- } else if (ret == -EFBIG) {
- const char *cluster_size_hint = "";
- if (get_option_parameter(create_options, BLOCK_OPT_CLUSTER_SIZE)) {
- cluster_size_hint = " (try using a larger cluster size)";
- }
- error_setg(errp, "The image size is too large for file format '%s'%s",
- fmt, cluster_size_hint);
- } else {
- error_setg(errp, "%s: error while creating %s: %s", filename, fmt,
- strerror(-ret));
+ ret = bdrv_create(drv, filename, param, &local_err);
+ if (ret == -EFBIG) {
+ /* This is generally a better message than whatever the driver would
+ * deliver (especially because of the cluster_size_hint), since that
+ * is most probably not much different from "image too large". */
+ const char *cluster_size_hint = "";
+ if (get_option_parameter(create_options, BLOCK_OPT_CLUSTER_SIZE)) {
+ cluster_size_hint = " (try using a larger cluster size)";
}
+ error_setg(errp, "The image size is too large for file format '%s'"
+ "%s", fmt, cluster_size_hint);
+ error_free(local_err);
+ local_err = NULL;
}
out:
free_option_parameters(param);
if (bs) {
- bdrv_delete(bs);
+ bdrv_unref(bs);
+ }
+ if (error_is_set(&local_err)) {
+ error_propagate(errp, local_err);
}
}
{
notifier_with_return_list_add(&bs->before_write_notifiers, notifier);
}
+
+ int bdrv_amend_options(BlockDriverState *bs, QEMUOptionParameter *options)
+ {
+ if (bs->drv->bdrv_amend_options == NULL) {
+ return -ENOTSUP;
+ }
+ return bs->drv->bdrv_amend_options(bs, options);
+ }
+
+ ExtSnapshotPerm bdrv_check_ext_snapshot(BlockDriverState *bs)
+ {
+ if (bs->drv->bdrv_check_ext_snapshot) {
+ return bs->drv->bdrv_check_ext_snapshot(bs);
+ }
+
+ if (bs->file && bs->file->drv && bs->file->drv->bdrv_check_ext_snapshot) {
+ return bs->file->drv->bdrv_check_ext_snapshot(bs);
+ }
+
+ /* external snapshots are allowed by default */
+ return EXT_SNAPSHOT_ALLOWED;
+ }
+
+ ExtSnapshotPerm bdrv_check_ext_snapshot_forbidden(BlockDriverState *bs)
+ {
+ return EXT_SNAPSHOT_FORBIDDEN;
+ }
#include "qemu/iov.h"
#include <windows.h>
#include <winioctl.h>
+#ifdef CONFIG_MARU
+#include <errno.h>
+#endif
#define FTYPE_FILE 0
#define FTYPE_CD 1
ret_count = 0;
}
if (ret_count != len) {
+ offset += ret_count;
break;
}
offset += len;
NULL, 0, NULL, 0, &returned, NULL);
}
+#ifndef CONFIG_MARU
static void raw_parse_flags(int flags, int *access_flags, DWORD *overlapped)
{
assert(access_flags != NULL);
*overlapped |= FILE_FLAG_NO_BUFFERING;
}
}
+#endif
static QemuOptsList raw_runtime_opts = {
.name = "raw",
},
};
- static int raw_open(BlockDriverState *bs, QDict *options, int flags)
+ static int raw_open(BlockDriverState *bs, QDict *options, int flags,
+ Error **errp)
{
BDRVRawState *s = bs->opaque;
- int access_flags;
- DWORD overlapped;
QemuOpts *opts;
Error *local_err = NULL;
const char *filename;
int ret;
+#ifndef CONFIG_MARU
+ DWORD overlapped;
+ int access_flags;
+#else
+ int open_flags;
+#endif
s->type = FTYPE_FILE;
opts = qemu_opts_create_nofail(&raw_runtime_opts);
qemu_opts_absorb_qdict(opts, options, &local_err);
if (error_is_set(&local_err)) {
- qerror_report_err(local_err);
- error_free(local_err);
+ error_propagate(errp, local_err);
ret = -EINVAL;
goto fail;
}
filename = qemu_opt_get(opts, "filename");
+#ifndef CONFIG_MARU
raw_parse_flags(flags, &access_flags, &overlapped);
if ((flags & BDRV_O_NATIVE_AIO) && aio == NULL) {
aio = win32_aio_init();
if (aio == NULL) {
+ error_setg(errp, "Could not initialize AIO");
ret = -EINVAL;
goto fail;
}
s->hfile = CreateFile(filename, access_flags,
FILE_SHARE_READ, NULL,
OPEN_EXISTING, overlapped, NULL);
- if (s->hfile == INVALID_HANDLE_VALUE) {
+ if (s->hfile == INVALID_HANDLE_VALUE) {
int err = GetLastError();
if (err == ERROR_ACCESS_DENIED) {
}
goto fail;
}
+#else
+ open_flags = O_BINARY & ~O_ACCMODE;
+ if (flags & BDRV_O_RDWR) {
+ open_flags |= O_RDWR;
+ } else {
+ open_flags |= O_RDONLY;
+ }
+
+ /* Use O_DSYNC for write-through caching, no flags for write-back caching,
+ * and O_DIRECT for no caching. */
+ /*
+ if ((flags & BDRV_O_NOCACHE)) {
+ open_flags |= O_DIRECT;
+ }
+ if (!(flags & BDRV_O_CACHE_WB)) {
+ open_flags |= O_DSYNC;
+ }
+ */
+
+ if ((flags & BDRV_O_NATIVE_AIO) && aio == NULL) {
+ aio = win32_aio_init();
+ if (aio == NULL) {
+ ret = -EINVAL;
+ goto fail;
+ }
+ }
+
+ ret = qemu_open(filename, open_flags, 0644);
+ if (ret < 0) {
+ error_report("raw_open failed(%d) \n", ret);
+ return -errno;
+ }
+ s->hfile = (HANDLE)_get_osfhandle(ret);
+#endif
if (flags & BDRV_O_NATIVE_AIO) {
ret = win32_aio_attach(aio, s->hfile);
if (ret < 0) {
CloseHandle(s->hfile);
+ error_setg_errno(errp, -ret, "Could not enable AIO");
goto fail;
}
s->aio = aio;
return st.st_size;
}
- static int raw_create(const char *filename, QEMUOptionParameter *options)
+ static int raw_create(const char *filename, QEMUOptionParameter *options,
+ Error **errp)
{
int fd;
int64_t total_size = 0;
fd = qemu_open(filename, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY,
0644);
- if (fd < 0)
+ if (fd < 0) {
+ error_setg_errno(errp, errno, "Could not create file");
return -EIO;
+ }
set_sparse(fd);
ftruncate(fd, total_size * 512);
qemu_close(fd);
.format_name = "file",
.protocol_name = "file",
.instance_size = sizeof(BDRVRawState),
+ .bdrv_needs_filename = true,
.bdrv_file_open = raw_open,
.bdrv_close = raw_close,
.bdrv_create = raw_create,
return 0;
}
- static int hdev_open(BlockDriverState *bs, QDict *options, int flags)
+ static int hdev_open(BlockDriverState *bs, QDict *options, int flags,
+ Error **errp)
{
BDRVRawState *s = bs->opaque;
+#ifndef CONFIG_MARU
int access_flags, create_flags;
+ int ret = 0;
DWORD overlapped;
+#else
+ int open_flags;
+#endif
+ int ret = 0;
char device_name[64];
Error *local_err = NULL;
QemuOpts *opts = qemu_opts_create_nofail(&raw_runtime_opts);
qemu_opts_absorb_qdict(opts, options, &local_err);
if (error_is_set(&local_err)) {
- qerror_report_err(local_err);
- error_free(local_err);
+ error_propagate(errp, local_err);
ret = -EINVAL;
goto done;
}
if (strstart(filename, "/dev/cdrom", NULL)) {
if (find_cdrom(device_name, sizeof(device_name)) < 0) {
+ error_setg(errp, "Could not open CD-ROM drive");
ret = -ENOENT;
goto done;
}
}
s->type = find_device_type(bs, filename);
+#ifndef CONFIG_MARU
raw_parse_flags(flags, &access_flags, &overlapped);
create_flags = OPEN_EXISTING;
s->hfile = CreateFile(filename, access_flags,
FILE_SHARE_READ, NULL,
create_flags, overlapped, NULL);
- if (s->hfile == INVALID_HANDLE_VALUE) {
+ if (s->hfile == INVALID_HANDLE_VALUE) {
int err = GetLastError();
if (err == ERROR_ACCESS_DENIED) {
ret = -EACCES;
} else {
- ret = -1;
+ ret = -EINVAL;
}
+ error_setg_errno(errp, -ret, "Could not open device");
goto done;
}
+#else
+ /*
+ s->hfile = CreateFile(g_win32_locale_filename_from_utf8(filename),
+ access_flags,
+ FILE_SHARE_READ, NULL,
+ create_flags, overlapped, NULL);
+ */
+ open_flags = (O_BINARY & ~O_ACCMODE);
+ if (flags & BDRV_O_RDWR) {
+ open_flags |= O_RDWR;
+ } else {
+ open_flags |= O_RDONLY;
+ }
+
+ /* Use O_DSYNC for write-through caching, no flags for write-back caching,
+ * and O_DIRECT for no caching. */
+ /*
+ if ((flags & BDRV_O_NOCACHE)) {
+ open_flags |= O_DIRECT;
+ }
+ if (!(flags & BDRV_O_CACHE_WB)) {
+ open_flags |= O_DSYNC;
+ }
+ */
+
+ ret = qemu_open(filename, open_flags, 0644);
+ if (ret < 0) {
+ error_report("raw_open failed(%d) \n", ret);
+ return -errno;
+ }
+ s->hfile = (HANDLE)_get_osfhandle(ret);
+#endif
+ return 0;
done:
qemu_opts_del(opts);
.format_name = "host_device",
.protocol_name = "host_device",
.instance_size = sizeof(BDRVRawState),
+ .bdrv_needs_filename = true,
.bdrv_probe_device = hdev_probe_device,
.bdrv_file_open = hdev_open,
.bdrv_close = raw_close,
.bdrv_aio_writev = raw_aio_writev,
.bdrv_aio_flush = raw_aio_flush,
- .bdrv_getlength = raw_getlength,
+ .bdrv_getlength = raw_getlength,
+ .has_variable_length = true,
+
.bdrv_get_allocated_file_size
= raw_get_allocated_file_size,
};
#include "qemu/option.h"
#include "qemu/config-file.h"
#include "qapi/qmp/types.h"
+ #include "qapi-visit.h"
+ #include "qapi/qmp-output-visitor.h"
#include "sysemu/sysemu.h"
#include "block/block_int.h"
#include "qmp-commands.h"
#include "sysemu/arch_init.h"
static QTAILQ_HEAD(drivelist, DriveInfo) drives = QTAILQ_HEAD_INITIALIZER(drives);
- extern QemuOptsList qemu_common_drive_opts;
- extern QemuOptsList qemu_old_drive_opts;
static const char *const if_name[IF_COUNT] = {
[IF_NONE] = "none",
{
DriveInfo *dinfo = drive_get_by_blockdev(bs);
+ if (dinfo && !dinfo->enable_auto_del) {
+ return;
+ }
+
if (bs->job) {
block_job_cancel(bs->job);
}
static void drive_uninit(DriveInfo *dinfo)
{
- qemu_opts_del(dinfo->opts);
- bdrv_delete(dinfo->bdrv);
+ if (dinfo->opts) {
+ qemu_opts_del(dinfo->opts);
+ }
+
+ bdrv_unref(dinfo->bdrv);
g_free(dinfo->id);
QTAILQ_REMOVE(&drives, dinfo, next);
g_free(dinfo->serial);
typedef struct {
QEMUBH *bh;
- DriveInfo *dinfo;
- } DrivePutRefBH;
+ BlockDriverState *bs;
+ } BDRVPutRefBH;
- static void drive_put_ref_bh(void *opaque)
+ static void bdrv_put_ref_bh(void *opaque)
{
- DrivePutRefBH *s = opaque;
+ BDRVPutRefBH *s = opaque;
- drive_put_ref(s->dinfo);
+ bdrv_unref(s->bs);
qemu_bh_delete(s->bh);
g_free(s);
}
/*
- * Release a drive reference in a BH
+ * Release a BDS reference in a BH
*
- * It is not possible to use drive_put_ref() from a callback function when the
- * callers still need the drive. In such cases we schedule a BH to release the
- * reference.
+ * It is not safe to use bdrv_unref() from a callback function when the callers
+ * still need the BlockDriverState. In such cases we schedule a BH to release
+ * the reference.
*/
- static void drive_put_ref_bh_schedule(DriveInfo *dinfo)
+ static void bdrv_put_ref_bh_schedule(BlockDriverState *bs)
{
- DrivePutRefBH *s;
+ BDRVPutRefBH *s;
- s = g_new(DrivePutRefBH, 1);
- s->bh = qemu_bh_new(drive_put_ref_bh, s);
- s->dinfo = dinfo;
+ s = g_new(BDRVPutRefBH, 1);
+ s->bh = qemu_bh_new(bdrv_put_ref_bh, s);
+ s->bs = bs;
qemu_bh_schedule(s->bh);
}
- static int parse_block_error_action(const char *buf, bool is_read)
+ static int parse_block_error_action(const char *buf, bool is_read, Error **errp)
{
if (!strcmp(buf, "ignore")) {
return BLOCKDEV_ON_ERROR_IGNORE;
} else if (!strcmp(buf, "report")) {
return BLOCKDEV_ON_ERROR_REPORT;
} else {
- error_report("'%s' invalid %s error action",
- buf, is_read ? "read" : "write");
+ error_setg(errp, "'%s' invalid %s error action",
+ buf, is_read ? "read" : "write");
return -1;
}
}
- static bool do_check_io_limits(BlockIOLimit *io_limits, Error **errp)
+#ifdef CONFIG_MARU
+extern int start_simple_client(char* msg);
+extern char* maru_convert_path(char* msg, const char *path);
+#endif
+
+ static bool check_throttle_config(ThrottleConfig *cfg, Error **errp)
{
- bool bps_flag;
- bool iops_flag;
-
- assert(io_limits);
-
- bps_flag = (io_limits->bps[BLOCK_IO_LIMIT_TOTAL] != 0)
- && ((io_limits->bps[BLOCK_IO_LIMIT_READ] != 0)
- || (io_limits->bps[BLOCK_IO_LIMIT_WRITE] != 0));
- iops_flag = (io_limits->iops[BLOCK_IO_LIMIT_TOTAL] != 0)
- && ((io_limits->iops[BLOCK_IO_LIMIT_READ] != 0)
- || (io_limits->iops[BLOCK_IO_LIMIT_WRITE] != 0));
- if (bps_flag || iops_flag) {
- error_setg(errp, "bps(iops) and bps_rd/bps_wr(iops_rd/iops_wr) "
- "cannot be used at the same time");
+ if (throttle_conflicting(cfg)) {
+ error_setg(errp, "bps/iops/max total values and read/write values"
+ " cannot be used at the same time");
return false;
}
- if (io_limits->bps[BLOCK_IO_LIMIT_TOTAL] < 0 ||
- io_limits->bps[BLOCK_IO_LIMIT_WRITE] < 0 ||
- io_limits->bps[BLOCK_IO_LIMIT_READ] < 0 ||
- io_limits->iops[BLOCK_IO_LIMIT_TOTAL] < 0 ||
- io_limits->iops[BLOCK_IO_LIMIT_WRITE] < 0 ||
- io_limits->iops[BLOCK_IO_LIMIT_READ] < 0) {
- error_setg(errp, "bps and iops values must be 0 or greater");
+ if (!throttle_is_valid(cfg)) {
+ error_setg(errp, "bps/iops/maxs values must be 0 or greater");
return false;
}
return true;
}
- static DriveInfo *blockdev_init(QemuOpts *all_opts,
- BlockInterfaceType block_default_type)
+ typedef enum { MEDIA_DISK, MEDIA_CDROM } DriveMediaType;
+
+ /* Takes the ownership of bs_opts */
+ static DriveInfo *blockdev_init(QDict *bs_opts,
+ BlockInterfaceType type,
+ Error **errp)
{
const char *buf;
const char *file = NULL;
const char *serial;
- const char *mediastr = "";
- BlockInterfaceType type;
- enum { MEDIA_DISK, MEDIA_CDROM } media;
- int bus_id, unit_id;
- int cyls, heads, secs, translation;
- int max_devs;
- int index;
int ro = 0;
int bdrv_flags = 0;
int on_read_error, on_write_error;
- const char *devaddr;
DriveInfo *dinfo;
- BlockIOLimit io_limits;
+ ThrottleConfig cfg;
int snapshot = 0;
bool copy_on_read;
int ret;
Error *error = NULL;
QemuOpts *opts;
- QDict *bs_opts;
const char *id;
bool has_driver_specific_opts;
BlockDriver *drv = NULL;
- translation = BIOS_ATA_TRANSLATION_AUTO;
- media = MEDIA_DISK;
-
- /* Check common options by copying from all_opts to opts, all other options
- * are stored in bs_opts. */
- id = qemu_opts_id(all_opts);
+ /* Check common options by copying from bs_opts to opts, all other options
+ * stay in bs_opts for processing by bdrv_open(). */
+ id = qdict_get_try_str(bs_opts, "id");
opts = qemu_opts_create(&qemu_common_drive_opts, id, 1, &error);
if (error_is_set(&error)) {
- qerror_report_err(error);
- error_free(error);
+ error_propagate(errp, error);
return NULL;
}
- bs_opts = qdict_new();
- qemu_opts_to_qdict(all_opts, bs_opts);
qemu_opts_absorb_qdict(opts, bs_opts, &error);
if (error_is_set(&error)) {
- qerror_report_err(error);
- error_free(error);
- return NULL;
+ error_propagate(errp, error);
+ goto early_err;
}
if (id) {
has_driver_specific_opts = !!qdict_size(bs_opts);
/* extract parameters */
- bus_id = qemu_opt_get_number(opts, "bus", 0);
- unit_id = qemu_opt_get_number(opts, "unit", -1);
- index = qemu_opt_get_number(opts, "index", -1);
-
- cyls = qemu_opt_get_number(opts, "cyls", 0);
- heads = qemu_opt_get_number(opts, "heads", 0);
- secs = qemu_opt_get_number(opts, "secs", 0);
-
snapshot = qemu_opt_get_bool(opts, "snapshot", 0);
ro = qemu_opt_get_bool(opts, "read-only", 0);
copy_on_read = qemu_opt_get_bool(opts, "copy-on-read", false);
file = qemu_opt_get(opts, "file");
serial = qemu_opt_get(opts, "serial");
- if ((buf = qemu_opt_get(opts, "if")) != NULL) {
- for (type = 0; type < IF_COUNT && strcmp(buf, if_name[type]); type++)
- ;
- if (type == IF_COUNT) {
- error_report("unsupported bus type '%s'", buf);
- return NULL;
- }
- } else {
- type = block_default_type;
- }
-
- max_devs = if_max_devs[type];
-
- if (cyls || heads || secs) {
- if (cyls < 1) {
- error_report("invalid physical cyls number");
- return NULL;
- }
- if (heads < 1) {
- error_report("invalid physical heads number");
- return NULL;
- }
- if (secs < 1) {
- error_report("invalid physical secs number");
- return NULL;
- }
- }
-
- if ((buf = qemu_opt_get(opts, "trans")) != NULL) {
- if (!cyls) {
- error_report("'%s' trans must be used with cyls, heads and secs",
- buf);
- return NULL;
- }
- if (!strcmp(buf, "none"))
- translation = BIOS_ATA_TRANSLATION_NONE;
- else if (!strcmp(buf, "lba"))
- translation = BIOS_ATA_TRANSLATION_LBA;
- else if (!strcmp(buf, "auto"))
- translation = BIOS_ATA_TRANSLATION_AUTO;
- else {
- error_report("'%s' invalid translation type", buf);
- return NULL;
- }
- }
-
- if ((buf = qemu_opt_get(opts, "media")) != NULL) {
- if (!strcmp(buf, "disk")) {
- media = MEDIA_DISK;
- } else if (!strcmp(buf, "cdrom")) {
- if (cyls || secs || heads) {
- error_report("CHS can't be set with media=%s", buf);
- return NULL;
- }
- media = MEDIA_CDROM;
- } else {
- error_report("'%s' invalid media", buf);
- return NULL;
- }
- }
-
if ((buf = qemu_opt_get(opts, "discard")) != NULL) {
if (bdrv_parse_discard_flags(buf, &bdrv_flags) != 0) {
- error_report("invalid discard option");
- return NULL;
+ error_setg(errp, "invalid discard option");
+ goto early_err;
}
}
} else if (!strcmp(buf, "threads")) {
/* this is the default */
} else {
- error_report("invalid aio option");
- return NULL;
+ error_setg(errp, "invalid aio option");
+ goto early_err;
}
}
#endif
error_printf("Supported formats:");
bdrv_iterate_format(bdrv_format_print, NULL);
error_printf("\n");
- return NULL;
+ goto early_err;
}
- drv = bdrv_find_whitelisted_format(buf, ro);
+ drv = bdrv_find_format(buf);
if (!drv) {
- error_report("'%s' invalid format", buf);
- return NULL;
+ error_setg(errp, "'%s' invalid format", buf);
+ goto early_err;
}
}
/* disk I/O throttling */
- io_limits.bps[BLOCK_IO_LIMIT_TOTAL] =
+ memset(&cfg, 0, sizeof(cfg));
+ cfg.buckets[THROTTLE_BPS_TOTAL].avg =
qemu_opt_get_number(opts, "throttling.bps-total", 0);
- io_limits.bps[BLOCK_IO_LIMIT_READ] =
+ cfg.buckets[THROTTLE_BPS_READ].avg =
qemu_opt_get_number(opts, "throttling.bps-read", 0);
- io_limits.bps[BLOCK_IO_LIMIT_WRITE] =
+ cfg.buckets[THROTTLE_BPS_WRITE].avg =
qemu_opt_get_number(opts, "throttling.bps-write", 0);
- io_limits.iops[BLOCK_IO_LIMIT_TOTAL] =
+ cfg.buckets[THROTTLE_OPS_TOTAL].avg =
qemu_opt_get_number(opts, "throttling.iops-total", 0);
- io_limits.iops[BLOCK_IO_LIMIT_READ] =
+ cfg.buckets[THROTTLE_OPS_READ].avg =
qemu_opt_get_number(opts, "throttling.iops-read", 0);
- io_limits.iops[BLOCK_IO_LIMIT_WRITE] =
+ cfg.buckets[THROTTLE_OPS_WRITE].avg =
qemu_opt_get_number(opts, "throttling.iops-write", 0);
- if (!do_check_io_limits(&io_limits, &error)) {
- error_report("%s", error_get_pretty(error));
- error_free(error);
- return NULL;
- }
+ cfg.buckets[THROTTLE_BPS_TOTAL].max =
+ qemu_opt_get_number(opts, "throttling.bps-total-max", 0);
+ cfg.buckets[THROTTLE_BPS_READ].max =
+ qemu_opt_get_number(opts, "throttling.bps-read-max", 0);
+ cfg.buckets[THROTTLE_BPS_WRITE].max =
+ qemu_opt_get_number(opts, "throttling.bps-write-max", 0);
+ cfg.buckets[THROTTLE_OPS_TOTAL].max =
+ qemu_opt_get_number(opts, "throttling.iops-total-max", 0);
+ cfg.buckets[THROTTLE_OPS_READ].max =
+ qemu_opt_get_number(opts, "throttling.iops-read-max", 0);
+ cfg.buckets[THROTTLE_OPS_WRITE].max =
+ qemu_opt_get_number(opts, "throttling.iops-write-max", 0);
- if (qemu_opt_get(opts, "boot") != NULL) {
- fprintf(stderr, "qemu-kvm: boot=on|off is deprecated and will be "
- "ignored. Future versions will reject this parameter. Please "
- "update your scripts.\n");
+ cfg.op_size = qemu_opt_get_number(opts, "throttling.iops-size", 0);
+
+ if (!check_throttle_config(&cfg, &error)) {
+ error_propagate(errp, error);
+ goto early_err;
}
on_write_error = BLOCKDEV_ON_ERROR_ENOSPC;
if ((buf = qemu_opt_get(opts, "werror")) != NULL) {
if (type != IF_IDE && type != IF_SCSI && type != IF_VIRTIO && type != IF_NONE) {
- error_report("werror is not supported by this bus type");
- return NULL;
+ error_setg(errp, "werror is not supported by this bus type");
+ goto early_err;
}
- on_write_error = parse_block_error_action(buf, 0);
- if (on_write_error < 0) {
- return NULL;
+ on_write_error = parse_block_error_action(buf, 0, &error);
+ if (error_is_set(&error)) {
+ error_propagate(errp, error);
+ goto early_err;
}
}
if ((buf = qemu_opt_get(opts, "rerror")) != NULL) {
if (type != IF_IDE && type != IF_VIRTIO && type != IF_SCSI && type != IF_NONE) {
error_report("rerror is not supported by this bus type");
- return NULL;
+ goto early_err;
}
- on_read_error = parse_block_error_action(buf, 1);
- if (on_read_error < 0) {
- return NULL;
- }
- }
-
- if ((devaddr = qemu_opt_get(opts, "addr")) != NULL) {
- if (type != IF_VIRTIO) {
- error_report("addr is not supported by this bus type");
- return NULL;
+ on_read_error = parse_block_error_action(buf, 1, &error);
+ if (error_is_set(&error)) {
+ error_propagate(errp, error);
+ goto early_err;
}
}
- /* compute bus and unit according index */
-
- if (index != -1) {
- if (bus_id != 0 || unit_id != -1) {
- error_report("index cannot be used with bus and unit");
- return NULL;
- }
- bus_id = drive_index_to_bus_id(type, index);
- unit_id = drive_index_to_unit_id(type, index);
- }
-
- /* if user doesn't specify a unit_id,
- * try to find the first free
- */
-
- if (unit_id == -1) {
- unit_id = 0;
- while (drive_get(type, bus_id, unit_id) != NULL) {
- unit_id++;
- if (max_devs && unit_id >= max_devs) {
- unit_id -= max_devs;
- bus_id++;
- }
- }
- }
-
- /* check unit id */
-
- if (max_devs && unit_id >= max_devs) {
- error_report("unit %d too big (max is %d)",
- unit_id, max_devs - 1);
- return NULL;
- }
-
- /*
- * catch multiple definitions
- */
-
- if (drive_get(type, bus_id, unit_id) != NULL) {
- error_report("drive with bus=%d, unit=%d (index=%d) exists",
- bus_id, unit_id, index);
- return NULL;
- }
-
/* init */
-
dinfo = g_malloc0(sizeof(*dinfo));
- if ((buf = qemu_opts_id(opts)) != NULL) {
- dinfo->id = g_strdup(buf);
- } else {
- /* no id supplied -> create one */
- dinfo->id = g_malloc0(32);
- if (type == IF_IDE || type == IF_SCSI)
- mediastr = (media == MEDIA_CDROM) ? "-cd" : "-hd";
- if (max_devs)
- snprintf(dinfo->id, 32, "%s%i%s%i",
- if_name[type], bus_id, mediastr, unit_id);
- else
- snprintf(dinfo->id, 32, "%s%s%i",
- if_name[type], mediastr, unit_id);
- }
+ dinfo->id = g_strdup(qemu_opts_id(opts));
dinfo->bdrv = bdrv_new(dinfo->id);
dinfo->bdrv->open_flags = snapshot ? BDRV_O_SNAPSHOT : 0;
dinfo->bdrv->read_only = ro;
- dinfo->devaddr = devaddr;
dinfo->type = type;
- dinfo->bus = bus_id;
- dinfo->unit = unit_id;
- dinfo->cyls = cyls;
- dinfo->heads = heads;
- dinfo->secs = secs;
- dinfo->trans = translation;
- dinfo->opts = all_opts;
dinfo->refcount = 1;
if (serial != NULL) {
dinfo->serial = g_strdup(serial);
bdrv_set_on_error(dinfo->bdrv, on_read_error, on_write_error);
/* disk I/O throttling */
- bdrv_set_io_limits(dinfo->bdrv, &io_limits);
-
- switch(type) {
- case IF_IDE:
- case IF_SCSI:
- case IF_XEN:
- case IF_NONE:
- dinfo->media_cd = media == MEDIA_CDROM;
- break;
- case IF_SD:
- case IF_FLOPPY:
- case IF_PFLASH:
- case IF_MTD:
- break;
- case IF_VIRTIO:
- {
- /* add virtio block device */
- QemuOpts *devopts;
- devopts = qemu_opts_create_nofail(qemu_find_opts("device"));
- if (arch_type == QEMU_ARCH_S390X) {
- qemu_opt_set(devopts, "driver", "virtio-blk-s390");
- } else {
- qemu_opt_set(devopts, "driver", "virtio-blk-pci");
- }
- qemu_opt_set(devopts, "drive", dinfo->id);
- if (devaddr)
- qemu_opt_set(devopts, "addr", devaddr);
- break;
- }
- default:
- abort();
+ if (throttle_enabled(&cfg)) {
+ bdrv_io_limits_enable(dinfo->bdrv);
+ bdrv_set_io_limits(dinfo->bdrv, &cfg);
}
+
if (!file || !*file) {
if (has_driver_specific_opts) {
file = NULL;
} else {
+ QDECREF(bs_opts);
+ qemu_opts_del(opts);
return dinfo;
}
}
bdrv_flags |= BDRV_O_INCOMING;
}
- if (media == MEDIA_CDROM) {
- /* CDROM is fine for any interface, don't check. */
- ro = 1;
- } else if (ro == 1) {
- if (type != IF_SCSI && type != IF_VIRTIO && type != IF_FLOPPY &&
- type != IF_NONE && type != IF_PFLASH) {
- error_report("read-only not supported by this bus type");
- goto err;
- }
- }
-
bdrv_flags |= ro ? 0 : BDRV_O_RDWR;
- if (ro && copy_on_read) {
- error_report("warning: disabling copy_on_read on read-only drive");
- }
-
QINCREF(bs_opts);
- ret = bdrv_open(dinfo->bdrv, file, bs_opts, bdrv_flags, drv);
+ ret = bdrv_open(dinfo->bdrv, file, bs_opts, bdrv_flags, drv, &error);
if (ret < 0) {
- if (ret == -EMEDIUMTYPE) {
- error_report("could not open disk image %s: not in %s format",
- file ?: dinfo->id, drv ? drv->format_name :
- qdict_get_str(bs_opts, "driver"));
- } else {
- error_report("could not open disk image %s: %s",
- file ?: dinfo->id, strerror(-ret));
- }
+#ifdef CONFIG_MARU
+ const char _msg[] = "Failed to load disk file from the following path. Check if the file is corrupted or missing.\n\n";
+ char* err_msg = NULL;
+ err_msg = maru_convert_path((char*)_msg, file);
+ start_simple_client(err_msg);
+ if (err_msg) {
+ g_free(err_msg);
+ }
+#endif
+
+ error_setg(errp, "could not open disk image %s: %s",
+ file ?: dinfo->id, error_get_pretty(error));
+ error_free(error);
goto err;
}
return dinfo;
err:
- qemu_opts_del(opts);
- QDECREF(bs_opts);
- bdrv_delete(dinfo->bdrv);
+ bdrv_unref(dinfo->bdrv);
g_free(dinfo->id);
QTAILQ_REMOVE(&drives, dinfo, next);
g_free(dinfo);
+ early_err:
+ QDECREF(bs_opts);
+ qemu_opts_del(opts);
return NULL;
}
}
}
+ QemuOptsList qemu_legacy_drive_opts = {
+ .name = "drive",
+ .head = QTAILQ_HEAD_INITIALIZER(qemu_legacy_drive_opts.head),
+ .desc = {
+ {
+ .name = "bus",
+ .type = QEMU_OPT_NUMBER,
+ .help = "bus number",
+ },{
+ .name = "unit",
+ .type = QEMU_OPT_NUMBER,
+ .help = "unit number (i.e. lun for scsi)",
+ },{
+ .name = "index",
+ .type = QEMU_OPT_NUMBER,
+ .help = "index number",
+ },{
+ .name = "media",
+ .type = QEMU_OPT_STRING,
+ .help = "media type (disk, cdrom)",
+ },{
+ .name = "if",
+ .type = QEMU_OPT_STRING,
+ .help = "interface (ide, scsi, sd, mtd, floppy, pflash, virtio)",
+ },{
+ .name = "cyls",
+ .type = QEMU_OPT_NUMBER,
+ .help = "number of cylinders (ide disk geometry)",
+ },{
+ .name = "heads",
+ .type = QEMU_OPT_NUMBER,
+ .help = "number of heads (ide disk geometry)",
+ },{
+ .name = "secs",
+ .type = QEMU_OPT_NUMBER,
+ .help = "number of sectors (ide disk geometry)",
+ },{
+ .name = "trans",
+ .type = QEMU_OPT_STRING,
+ .help = "chs translation (auto, lba, none)",
+ },{
+ .name = "boot",
+ .type = QEMU_OPT_BOOL,
+ .help = "(deprecated, ignored)",
+ },{
+ .name = "addr",
+ .type = QEMU_OPT_STRING,
+ .help = "pci address (virtio only)",
+ },
+
+ /* Options that are passed on, but have special semantics with -drive */
+ {
+ .name = "read-only",
+ .type = QEMU_OPT_BOOL,
+ .help = "open drive file as read-only",
+ },{
+ .name = "copy-on-read",
+ .type = QEMU_OPT_BOOL,
+ .help = "copy read data from backing file into image file",
+ },
+
+ { /* end of list */ }
+ },
+ };
+
DriveInfo *drive_init(QemuOpts *all_opts, BlockInterfaceType block_default_type)
{
const char *value;
-
- /*
- * Check that only old options are used by copying into a QemuOpts with
- * stricter checks. Going through a QDict seems to be the easiest way to
- * achieve this...
- */
- QemuOpts* check_opts;
- QDict *qdict;
+ DriveInfo *dinfo = NULL;
+ QDict *bs_opts;
+ QemuOpts *legacy_opts;
+ DriveMediaType media = MEDIA_DISK;
+ BlockInterfaceType type;
+ int cyls, heads, secs, translation;
+ int max_devs, bus_id, unit_id, index;
+ const char *devaddr;
+ bool read_only = false;
+ bool copy_on_read;
Error *local_err = NULL;
- qdict = qemu_opts_to_qdict(all_opts, NULL);
- check_opts = qemu_opts_from_qdict(&qemu_old_drive_opts, qdict, &local_err);
- QDECREF(qdict);
-
- if (error_is_set(&local_err)) {
- qerror_report_err(local_err);
- error_free(local_err);
- return NULL;
- }
- qemu_opts_del(check_opts);
-
/* Change legacy command line options into QMP ones */
qemu_opt_rename(all_opts, "iops", "throttling.iops-total");
qemu_opt_rename(all_opts, "iops_rd", "throttling.iops-read");
qemu_opt_rename(all_opts, "bps_rd", "throttling.bps-read");
qemu_opt_rename(all_opts, "bps_wr", "throttling.bps-write");
+ qemu_opt_rename(all_opts, "iops_max", "throttling.iops-total-max");
+ qemu_opt_rename(all_opts, "iops_rd_max", "throttling.iops-read-max");
+ qemu_opt_rename(all_opts, "iops_wr_max", "throttling.iops-write-max");
+
+ qemu_opt_rename(all_opts, "bps_max", "throttling.bps-total-max");
+ qemu_opt_rename(all_opts, "bps_rd_max", "throttling.bps-read-max");
+ qemu_opt_rename(all_opts, "bps_wr_max", "throttling.bps-write-max");
+
+ qemu_opt_rename(all_opts,
+ "iops_size", "throttling.iops-size");
+
qemu_opt_rename(all_opts, "readonly", "read-only");
value = qemu_opt_get(all_opts, "cache");
qemu_opt_unset(all_opts, "cache");
}
- return blockdev_init(all_opts, block_default_type);
+ /* Get a QDict for processing the options */
+ bs_opts = qdict_new();
+ qemu_opts_to_qdict(all_opts, bs_opts);
+
+ legacy_opts = qemu_opts_create_nofail(&qemu_legacy_drive_opts);
+ qemu_opts_absorb_qdict(legacy_opts, bs_opts, &local_err);
+ if (error_is_set(&local_err)) {
+ qerror_report_err(local_err);
+ error_free(local_err);
+ goto fail;
+ }
+
+ /* Deprecated option boot=[on|off] */
+ if (qemu_opt_get(legacy_opts, "boot") != NULL) {
+ fprintf(stderr, "qemu-kvm: boot=on|off is deprecated and will be "
+ "ignored. Future versions will reject this parameter. Please "
+ "update your scripts.\n");
+ }
+
+ /* Media type */
+ value = qemu_opt_get(legacy_opts, "media");
+ if (value) {
+ if (!strcmp(value, "disk")) {
+ media = MEDIA_DISK;
+ } else if (!strcmp(value, "cdrom")) {
+ media = MEDIA_CDROM;
+ read_only = true;
+ } else {
+ error_report("'%s' invalid media", value);
+ goto fail;
+ }
+ }
+
+ /* copy-on-read is disabled with a warning for read-only devices */
+ read_only |= qemu_opt_get_bool(legacy_opts, "read-only", false);
+ copy_on_read = qemu_opt_get_bool(legacy_opts, "copy-on-read", false);
+
+ if (read_only && copy_on_read) {
+ error_report("warning: disabling copy-on-read on read-only drive");
+ copy_on_read = false;
+ }
+
+ qdict_put(bs_opts, "read-only",
+ qstring_from_str(read_only ? "on" : "off"));
+ qdict_put(bs_opts, "copy-on-read",
+ qstring_from_str(copy_on_read ? "on" :"off"));
+
+ /* Controller type */
+ value = qemu_opt_get(legacy_opts, "if");
+ if (value) {
+ for (type = 0;
+ type < IF_COUNT && strcmp(value, if_name[type]);
+ type++) {
+ }
+ if (type == IF_COUNT) {
+ error_report("unsupported bus type '%s'", value);
+ goto fail;
+ }
+ } else {
+ type = block_default_type;
+ }
+
+ /* Geometry */
+ cyls = qemu_opt_get_number(legacy_opts, "cyls", 0);
+ heads = qemu_opt_get_number(legacy_opts, "heads", 0);
+ secs = qemu_opt_get_number(legacy_opts, "secs", 0);
+
+ if (cyls || heads || secs) {
+ if (cyls < 1) {
+ error_report("invalid physical cyls number");
+ goto fail;
+ }
+ if (heads < 1) {
+ error_report("invalid physical heads number");
+ goto fail;
+ }
+ if (secs < 1) {
+ error_report("invalid physical secs number");
+ goto fail;
+ }
+ }
+
+ translation = BIOS_ATA_TRANSLATION_AUTO;
+ value = qemu_opt_get(legacy_opts, "trans");
+ if (value != NULL) {
+ if (!cyls) {
+ error_report("'%s' trans must be used with cyls, heads and secs",
+ value);
+ goto fail;
+ }
+ if (!strcmp(value, "none")) {
+ translation = BIOS_ATA_TRANSLATION_NONE;
+ } else if (!strcmp(value, "lba")) {
+ translation = BIOS_ATA_TRANSLATION_LBA;
+ } else if (!strcmp(value, "auto")) {
+ translation = BIOS_ATA_TRANSLATION_AUTO;
+ } else {
+ error_report("'%s' invalid translation type", value);
+ goto fail;
+ }
+ }
+
+ if (media == MEDIA_CDROM) {
+ if (cyls || secs || heads) {
+ error_report("CHS can't be set with media=cdrom");
+ goto fail;
+ }
+ }
+
+ /* Device address specified by bus/unit or index.
+ * If none was specified, try to find the first free one. */
+ bus_id = qemu_opt_get_number(legacy_opts, "bus", 0);
+ unit_id = qemu_opt_get_number(legacy_opts, "unit", -1);
+ index = qemu_opt_get_number(legacy_opts, "index", -1);
+
+ max_devs = if_max_devs[type];
+
+ if (index != -1) {
+ if (bus_id != 0 || unit_id != -1) {
+ error_report("index cannot be used with bus and unit");
+ goto fail;
+ }
+ bus_id = drive_index_to_bus_id(type, index);
+ unit_id = drive_index_to_unit_id(type, index);
+ }
+
+ if (unit_id == -1) {
+ unit_id = 0;
+ while (drive_get(type, bus_id, unit_id) != NULL) {
+ unit_id++;
+ if (max_devs && unit_id >= max_devs) {
+ unit_id -= max_devs;
+ bus_id++;
+ }
+ }
+ }
+
+ if (max_devs && unit_id >= max_devs) {
+ error_report("unit %d too big (max is %d)", unit_id, max_devs - 1);
+ goto fail;
+ }
+
+ if (drive_get(type, bus_id, unit_id) != NULL) {
+ error_report("drive with bus=%d, unit=%d (index=%d) exists",
+ bus_id, unit_id, index);
+ goto fail;
+ }
+
+ /* no id supplied -> create one */
+ if (qemu_opts_id(all_opts) == NULL) {
+ char *new_id;
+ const char *mediastr = "";
+ if (type == IF_IDE || type == IF_SCSI) {
+ mediastr = (media == MEDIA_CDROM) ? "-cd" : "-hd";
+ }
+ if (max_devs) {
+ new_id = g_strdup_printf("%s%i%s%i", if_name[type], bus_id,
+ mediastr, unit_id);
+ } else {
+ new_id = g_strdup_printf("%s%s%i", if_name[type],
+ mediastr, unit_id);
+ }
+ qdict_put(bs_opts, "id", qstring_from_str(new_id));
+ g_free(new_id);
+ }
+
+ /* Add virtio block device */
+ devaddr = qemu_opt_get(legacy_opts, "addr");
+ if (devaddr && type != IF_VIRTIO) {
+ error_report("addr is not supported by this bus type");
+ goto fail;
+ }
+
+ if (type == IF_VIRTIO) {
+ QemuOpts *devopts;
+ devopts = qemu_opts_create_nofail(qemu_find_opts("device"));
+ if (arch_type == QEMU_ARCH_S390X) {
+ qemu_opt_set(devopts, "driver", "virtio-blk-s390");
+ } else {
+ qemu_opt_set(devopts, "driver", "virtio-blk-pci");
+ }
+ qemu_opt_set(devopts, "drive", qdict_get_str(bs_opts, "id"));
+ if (devaddr) {
+ qemu_opt_set(devopts, "addr", devaddr);
+ }
+ }
+
+ /* Actual block device init: Functionality shared with blockdev-add */
+ dinfo = blockdev_init(bs_opts, type, &local_err);
+ if (dinfo == NULL) {
+ if (error_is_set(&local_err)) {
+ qerror_report_err(local_err);
+ error_free(local_err);
+ }
+ goto fail;
+ } else {
+ assert(!error_is_set(&local_err));
+ }
+
+ /* Set legacy DriveInfo fields */
+ dinfo->enable_auto_del = true;
+ dinfo->opts = all_opts;
+
+ dinfo->cyls = cyls;
+ dinfo->heads = heads;
+ dinfo->secs = secs;
+ dinfo->trans = translation;
+
+ dinfo->bus = bus_id;
+ dinfo->unit = unit_id;
+ dinfo->devaddr = devaddr;
+
+ switch(type) {
+ case IF_IDE:
+ case IF_SCSI:
+ case IF_XEN:
+ case IF_NONE:
+ dinfo->media_cd = media == MEDIA_CDROM;
+ break;
+ default:
+ break;
+ }
+
+ fail:
+ qemu_opts_del(legacy_opts);
+ return dinfo;
}
void do_commit(Monitor *mon, const QDict *qdict)
&snapshot, errp);
}
+ void qmp_blockdev_snapshot_internal_sync(const char *device,
+ const char *name,
+ Error **errp)
+ {
+ BlockdevSnapshotInternal snapshot = {
+ .device = (char *) device,
+ .name = (char *) name
+ };
+
+ blockdev_do_action(TRANSACTION_ACTION_KIND_BLOCKDEV_SNAPSHOT_INTERNAL_SYNC,
+ &snapshot, errp);
+ }
+
+ SnapshotInfo *qmp_blockdev_snapshot_delete_internal_sync(const char *device,
+ bool has_id,
+ const char *id,
+ bool has_name,
+ const char *name,
+ Error **errp)
+ {
+ BlockDriverState *bs = bdrv_find(device);
+ QEMUSnapshotInfo sn;
+ Error *local_err = NULL;
+ SnapshotInfo *info = NULL;
+ int ret;
+
+ if (!bs) {
+ error_set(errp, QERR_DEVICE_NOT_FOUND, device);
+ return NULL;
+ }
+
+ if (!has_id) {
+ id = NULL;
+ }
+
+ if (!has_name) {
+ name = NULL;
+ }
+
+ if (!id && !name) {
+ error_setg(errp, "Name or id must be provided");
+ return NULL;
+ }
+
+ ret = bdrv_snapshot_find_by_id_and_name(bs, id, name, &sn, &local_err);
+ if (error_is_set(&local_err)) {
+ error_propagate(errp, local_err);
+ return NULL;
+ }
+ if (!ret) {
+ error_setg(errp,
+ "Snapshot with id '%s' and name '%s' does not exist on "
+ "device '%s'",
+ STR_OR_NULL(id), STR_OR_NULL(name), device);
+ return NULL;
+ }
+
+ bdrv_snapshot_delete(bs, id, name, &local_err);
+ if (error_is_set(&local_err)) {
+ error_propagate(errp, local_err);
+ return NULL;
+ }
+
+ info = g_malloc0(sizeof(SnapshotInfo));
+ info->id = g_strdup(sn.id_str);
+ info->name = g_strdup(sn.name);
+ info->date_nsec = sn.date_nsec;
+ info->date_sec = sn.date_sec;
+ info->vm_state_size = sn.vm_state_size;
+ info->vm_clock_nsec = sn.vm_clock_nsec % 1000000000;
+ info->vm_clock_sec = sn.vm_clock_nsec / 1000000000;
+
+ return info;
+ }
/* New and old BlockDriverState structs for group snapshots */
QSIMPLEQ_ENTRY(BlkTransactionState) entry;
};
+ /* internal snapshot private data */
+ typedef struct InternalSnapshotState {
+ BlkTransactionState common;
+ BlockDriverState *bs;
+ QEMUSnapshotInfo sn;
+ } InternalSnapshotState;
+
+ static void internal_snapshot_prepare(BlkTransactionState *common,
+ Error **errp)
+ {
+ const char *device;
+ const char *name;
+ BlockDriverState *bs;
+ QEMUSnapshotInfo old_sn, *sn;
+ bool ret;
+ qemu_timeval tv;
+ BlockdevSnapshotInternal *internal;
+ InternalSnapshotState *state;
+ int ret1;
+
+ g_assert(common->action->kind ==
+ TRANSACTION_ACTION_KIND_BLOCKDEV_SNAPSHOT_INTERNAL_SYNC);
+ internal = common->action->blockdev_snapshot_internal_sync;
+ state = DO_UPCAST(InternalSnapshotState, common, common);
+
+ /* 1. parse input */
+ device = internal->device;
+ name = internal->name;
+
+ /* 2. check for validation */
+ bs = bdrv_find(device);
+ if (!bs) {
+ error_set(errp, QERR_DEVICE_NOT_FOUND, device);
+ return;
+ }
+
+ if (!bdrv_is_inserted(bs)) {
+ error_set(errp, QERR_DEVICE_HAS_NO_MEDIUM, device);
+ return;
+ }
+
+ if (bdrv_is_read_only(bs)) {
+ error_set(errp, QERR_DEVICE_IS_READ_ONLY, device);
+ return;
+ }
+
+ if (!bdrv_can_snapshot(bs)) {
+ error_set(errp, QERR_BLOCK_FORMAT_FEATURE_NOT_SUPPORTED,
+ bs->drv->format_name, device, "internal snapshot");
+ return;
+ }
+
+ if (!strlen(name)) {
+ error_setg(errp, "Name is empty");
+ return;
+ }
+
+ /* check whether a snapshot with name exist */
+ ret = bdrv_snapshot_find_by_id_and_name(bs, NULL, name, &old_sn, errp);
+ if (error_is_set(errp)) {
+ return;
+ } else if (ret) {
+ error_setg(errp,
+ "Snapshot with name '%s' already exists on device '%s'",
+ name, device);
+ return;
+ }
+
+ /* 3. take the snapshot */
+ sn = &state->sn;
+ pstrcpy(sn->name, sizeof(sn->name), name);
+ qemu_gettimeofday(&tv);
+ sn->date_sec = tv.tv_sec;
+ sn->date_nsec = tv.tv_usec * 1000;
+ sn->vm_clock_nsec = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
+
+ ret1 = bdrv_snapshot_create(bs, sn);
+ if (ret1 < 0) {
+ error_setg_errno(errp, -ret1,
+ "Failed to create snapshot '%s' on device '%s'",
+ name, device);
+ return;
+ }
+
+ /* 4. succeed, mark a snapshot is created */
+ state->bs = bs;
+ }
+
+ static void internal_snapshot_abort(BlkTransactionState *common)
+ {
+ InternalSnapshotState *state =
+ DO_UPCAST(InternalSnapshotState, common, common);
+ BlockDriverState *bs = state->bs;
+ QEMUSnapshotInfo *sn = &state->sn;
+ Error *local_error = NULL;
+
+ if (!bs) {
+ return;
+ }
+
+ if (bdrv_snapshot_delete(bs, sn->id_str, sn->name, &local_error) < 0) {
+ error_report("Failed to delete snapshot with id '%s' and name '%s' on "
+ "device '%s' in abort: %s",
+ sn->id_str,
+ sn->name,
+ bdrv_get_device_name(bs),
+ error_get_pretty(local_error));
+ error_free(local_error);
+ }
+ }
+
/* external snapshot private data */
typedef struct ExternalSnapshotState {
BlkTransactionState common;
}
}
+ if (bdrv_check_ext_snapshot(state->old_bs) != EXT_SNAPSHOT_ALLOWED) {
+ error_set(errp, QERR_FEATURE_DISABLED, "snapshot");
+ return;
+ }
+
flags = state->old_bs->open_flags;
/* create new image w/backing file */
/* TODO Inherit bs->options or only take explicit options with an
* extended QMP command? */
ret = bdrv_open(state->new_bs, new_image_file, NULL,
- flags | BDRV_O_NO_BACKING, drv);
+ flags | BDRV_O_NO_BACKING, drv, &local_err);
if (ret != 0) {
- error_setg_file_open(errp, -ret, new_image_file);
+ error_propagate(errp, local_err);
}
}
ExternalSnapshotState *state =
DO_UPCAST(ExternalSnapshotState, common, common);
if (state->new_bs) {
- bdrv_delete(state->new_bs);
+ bdrv_unref(state->new_bs);
}
}
.prepare = abort_prepare,
.commit = abort_commit,
},
+ [TRANSACTION_ACTION_KIND_BLOCKDEV_SNAPSHOT_INTERNAL_SYNC] = {
+ .instance_size = sizeof(InternalSnapshotState),
+ .prepare = internal_snapshot_prepare,
+ .abort = internal_snapshot_abort,
+ },
};
/*
assert(dev_info->kind < ARRAY_SIZE(actions));
ops = &actions[dev_info->kind];
+ assert(ops->instance_size > 0);
+
state = g_malloc0(ops->instance_size);
state->ops = ops;
state->action = dev_info;
int bdrv_flags, BlockDriver *drv,
const char *password, Error **errp)
{
+ Error *local_err = NULL;
int ret;
- ret = bdrv_open(bs, filename, NULL, bdrv_flags, drv);
+ ret = bdrv_open(bs, filename, NULL, bdrv_flags, drv, &local_err);
if (ret < 0) {
- error_setg_file_open(errp, -ret, filename);
+ error_propagate(errp, local_err);
return;
}
/* throttling disk I/O limits */
void qmp_block_set_io_throttle(const char *device, int64_t bps, int64_t bps_rd,
- int64_t bps_wr, int64_t iops, int64_t iops_rd,
- int64_t iops_wr, Error **errp)
+ int64_t bps_wr,
+ int64_t iops,
+ int64_t iops_rd,
+ int64_t iops_wr,
+ bool has_bps_max,
+ int64_t bps_max,
+ bool has_bps_rd_max,
+ int64_t bps_rd_max,
+ bool has_bps_wr_max,
+ int64_t bps_wr_max,
+ bool has_iops_max,
+ int64_t iops_max,
+ bool has_iops_rd_max,
+ int64_t iops_rd_max,
+ bool has_iops_wr_max,
+ int64_t iops_wr_max,
+ bool has_iops_size,
+ int64_t iops_size, Error **errp)
{
- BlockIOLimit io_limits;
+ ThrottleConfig cfg;
BlockDriverState *bs;
bs = bdrv_find(device);
return;
}
- io_limits.bps[BLOCK_IO_LIMIT_TOTAL] = bps;
- io_limits.bps[BLOCK_IO_LIMIT_READ] = bps_rd;
- io_limits.bps[BLOCK_IO_LIMIT_WRITE] = bps_wr;
- io_limits.iops[BLOCK_IO_LIMIT_TOTAL]= iops;
- io_limits.iops[BLOCK_IO_LIMIT_READ] = iops_rd;
- io_limits.iops[BLOCK_IO_LIMIT_WRITE]= iops_wr;
+ memset(&cfg, 0, sizeof(cfg));
+ cfg.buckets[THROTTLE_BPS_TOTAL].avg = bps;
+ cfg.buckets[THROTTLE_BPS_READ].avg = bps_rd;
+ cfg.buckets[THROTTLE_BPS_WRITE].avg = bps_wr;
- if (!do_check_io_limits(&io_limits, errp)) {
- return;
+ cfg.buckets[THROTTLE_OPS_TOTAL].avg = iops;
+ cfg.buckets[THROTTLE_OPS_READ].avg = iops_rd;
+ cfg.buckets[THROTTLE_OPS_WRITE].avg = iops_wr;
+
+ if (has_bps_max) {
+ cfg.buckets[THROTTLE_BPS_TOTAL].max = bps_max;
+ }
+ if (has_bps_rd_max) {
+ cfg.buckets[THROTTLE_BPS_READ].max = bps_rd_max;
+ }
+ if (has_bps_wr_max) {
+ cfg.buckets[THROTTLE_BPS_WRITE].max = bps_wr_max;
+ }
+ if (has_iops_max) {
+ cfg.buckets[THROTTLE_OPS_TOTAL].max = iops_max;
+ }
+ if (has_iops_rd_max) {
+ cfg.buckets[THROTTLE_OPS_READ].max = iops_rd_max;
+ }
+ if (has_iops_wr_max) {
+ cfg.buckets[THROTTLE_OPS_WRITE].max = iops_wr_max;
+ }
+
+ if (has_iops_size) {
+ cfg.op_size = iops_size;
}
- bs->io_limits = io_limits;
+ if (!check_throttle_config(&cfg, errp)) {
+ return;
+ }
- if (!bs->io_limits_enabled && bdrv_io_limits_enabled(bs)) {
+ if (!bs->io_limits_enabled && throttle_enabled(&cfg)) {
bdrv_io_limits_enable(bs);
- } else if (bs->io_limits_enabled && !bdrv_io_limits_enabled(bs)) {
+ } else if (bs->io_limits_enabled && !throttle_enabled(&cfg)) {
bdrv_io_limits_disable(bs);
- } else {
- if (bs->block_timer) {
- qemu_mod_timer(bs->block_timer, qemu_get_clock_ns(vm_clock));
- }
+ }
+
+ if (bs->io_limits_enabled) {
+ bdrv_set_io_limits(bs, &cfg);
}
}
}
qobject_decref(obj);
- drive_put_ref_bh_schedule(drive_get_by_blockdev(bs));
+ bdrv_put_ref_bh_schedule(bs);
}
void qmp_block_stream(const char *device, bool has_base,
return;
}
- /* Grab a reference so hotplug does not delete the BlockDriverState from
- * underneath us.
- */
- drive_get_ref(drive_get_by_blockdev(bs));
-
trace_qmp_block_stream(bs, bs->job);
}
error_propagate(errp, local_err);
return;
}
- /* Grab a reference so hotplug does not delete the BlockDriverState from
- * underneath us.
- */
- drive_get_ref(drive_get_by_blockdev(bs));
}
void qmp_drive_backup(const char *device, const char *target,
}
target_bs = bdrv_new("");
- ret = bdrv_open(target_bs, target, NULL, flags, drv);
+ ret = bdrv_open(target_bs, target, NULL, flags, drv, &local_err);
if (ret < 0) {
- bdrv_delete(target_bs);
- error_setg_file_open(errp, -ret, target);
+ bdrv_unref(target_bs);
+ error_propagate(errp, local_err);
return;
}
backup_start(bs, target_bs, speed, sync, on_source_error, on_target_error,
block_job_cb, bs, &local_err);
if (local_err != NULL) {
- bdrv_delete(target_bs);
+ bdrv_unref(target_bs);
error_propagate(errp, local_err);
return;
}
-
- /* Grab a reference so hotplug does not delete the BlockDriverState from
- * underneath us.
- */
- drive_get_ref(drive_get_by_blockdev(bs));
}
#define DEFAULT_MIRROR_BUF_SIZE (10 << 20)
if (!source && sync == MIRROR_SYNC_MODE_TOP) {
sync = MIRROR_SYNC_MODE_FULL;
}
+ if (sync == MIRROR_SYNC_MODE_NONE) {
+ source = bs;
+ }
size = bdrv_getlength(bs);
if (size < 0) {
return;
}
- if (sync == MIRROR_SYNC_MODE_FULL && mode != NEW_IMAGE_MODE_EXISTING) {
+ if ((sync == MIRROR_SYNC_MODE_FULL || !source)
+ && mode != NEW_IMAGE_MODE_EXISTING)
+ {
/* create new image w/o backing file */
assert(format && drv);
bdrv_img_create(target, format,
} else {
switch (mode) {
case NEW_IMAGE_MODE_EXISTING:
- ret = 0;
break;
case NEW_IMAGE_MODE_ABSOLUTE_PATHS:
/* create new image with backing file */
* file.
*/
target_bs = bdrv_new("");
- ret = bdrv_open(target_bs, target, NULL, flags | BDRV_O_NO_BACKING, drv);
+ ret = bdrv_open(target_bs, target, NULL, flags | BDRV_O_NO_BACKING, drv,
+ &local_err);
if (ret < 0) {
- bdrv_delete(target_bs);
- error_setg_file_open(errp, -ret, target);
+ bdrv_unref(target_bs);
+ error_propagate(errp, local_err);
return;
}
on_source_error, on_target_error,
block_job_cb, bs, &local_err);
if (local_err != NULL) {
- bdrv_delete(target_bs);
+ bdrv_unref(target_bs);
error_propagate(errp, local_err);
return;
}
-
- /* Grab a reference so hotplug does not delete the BlockDriverState from
- * underneath us.
- */
- drive_get_ref(drive_get_by_blockdev(bs));
}
static BlockJob *find_block_job(const char *device)
block_job_complete(job, errp);
}
+ void qmp_blockdev_add(BlockdevOptions *options, Error **errp)
+ {
+ QmpOutputVisitor *ov = qmp_output_visitor_new();
+ QObject *obj;
+ QDict *qdict;
+ Error *local_err = NULL;
+
+ /* Require an ID in the top level */
+ if (!options->has_id) {
+ error_setg(errp, "Block device needs an ID");
+ goto fail;
+ }
+
+ /* TODO Sort it out in raw-posix and drive_init: Reject aio=native with
+ * cache.direct=false instead of silently switching to aio=threads, except
+ * if called from drive_init.
+ *
+ * For now, simply forbidding the combination for all drivers will do. */
+ if (options->has_aio && options->aio == BLOCKDEV_AIO_OPTIONS_NATIVE) {
+ bool direct = options->cache->has_direct && options->cache->direct;
+ if (!options->has_cache && !direct) {
+ error_setg(errp, "aio=native requires cache.direct=true");
+ goto fail;
+ }
+ }
+
+ visit_type_BlockdevOptions(qmp_output_get_visitor(ov),
+ &options, NULL, &local_err);
+ if (error_is_set(&local_err)) {
+ error_propagate(errp, local_err);
+ goto fail;
+ }
+
+ obj = qmp_output_get_qobject(ov);
+ qdict = qobject_to_qdict(obj);
+
+ qdict_flatten(qdict);
+
+ blockdev_init(qdict, IF_NONE, &local_err);
+ if (error_is_set(&local_err)) {
+ error_propagate(errp, local_err);
+ goto fail;
+ }
+
+ fail:
+ qmp_output_visitor_cleanup(ov);
+ }
+
static void do_qmp_query_block_jobs_one(void *opaque, BlockDriverState *bs)
{
BlockJobInfoList **prev = opaque;
.head = QTAILQ_HEAD_INITIALIZER(qemu_common_drive_opts.head),
.desc = {
{
- .name = "bus",
- .type = QEMU_OPT_NUMBER,
- .help = "bus number",
- },{
- .name = "unit",
- .type = QEMU_OPT_NUMBER,
- .help = "unit number (i.e. lun for scsi)",
- },{
- .name = "if",
- .type = QEMU_OPT_STRING,
- .help = "interface (ide, scsi, sd, mtd, floppy, pflash, virtio)",
- },{
- .name = "index",
- .type = QEMU_OPT_NUMBER,
- .help = "index number",
- },{
- .name = "cyls",
- .type = QEMU_OPT_NUMBER,
- .help = "number of cylinders (ide disk geometry)",
- },{
- .name = "heads",
- .type = QEMU_OPT_NUMBER,
- .help = "number of heads (ide disk geometry)",
- },{
- .name = "secs",
- .type = QEMU_OPT_NUMBER,
- .help = "number of sectors (ide disk geometry)",
- },{
- .name = "trans",
- .type = QEMU_OPT_STRING,
- .help = "chs translation (auto, lba. none)",
- },{
- .name = "media",
- .type = QEMU_OPT_STRING,
- .help = "media type (disk, cdrom)",
- },{
.name = "snapshot",
.type = QEMU_OPT_BOOL,
.help = "enable/disable snapshot mode",
.type = QEMU_OPT_STRING,
.help = "write error action",
},{
- .name = "addr",
- .type = QEMU_OPT_STRING,
- .help = "pci address (virtio only)",
- },{
.name = "read-only",
.type = QEMU_OPT_BOOL,
.help = "open drive file as read-only",
.type = QEMU_OPT_NUMBER,
.help = "limit write bytes per second",
},{
- .name = "copy-on-read",
- .type = QEMU_OPT_BOOL,
- .help = "copy read data from backing file into image file",
- },{
- .name = "boot",
- .type = QEMU_OPT_BOOL,
- .help = "(deprecated, ignored)",
- },
- { /* end of list */ }
- },
- };
-
- QemuOptsList qemu_old_drive_opts = {
- .name = "drive",
- .head = QTAILQ_HEAD_INITIALIZER(qemu_old_drive_opts.head),
- .desc = {
- {
- .name = "bus",
- .type = QEMU_OPT_NUMBER,
- .help = "bus number",
- },{
- .name = "unit",
- .type = QEMU_OPT_NUMBER,
- .help = "unit number (i.e. lun for scsi)",
- },{
- .name = "if",
- .type = QEMU_OPT_STRING,
- .help = "interface (ide, scsi, sd, mtd, floppy, pflash, virtio)",
- },{
- .name = "index",
- .type = QEMU_OPT_NUMBER,
- .help = "index number",
- },{
- .name = "cyls",
- .type = QEMU_OPT_NUMBER,
- .help = "number of cylinders (ide disk geometry)",
- },{
- .name = "heads",
- .type = QEMU_OPT_NUMBER,
- .help = "number of heads (ide disk geometry)",
- },{
- .name = "secs",
+ .name = "throttling.iops-total-max",
.type = QEMU_OPT_NUMBER,
- .help = "number of sectors (ide disk geometry)",
- },{
- .name = "trans",
- .type = QEMU_OPT_STRING,
- .help = "chs translation (auto, lba. none)",
- },{
- .name = "media",
- .type = QEMU_OPT_STRING,
- .help = "media type (disk, cdrom)",
- },{
- .name = "snapshot",
- .type = QEMU_OPT_BOOL,
- .help = "enable/disable snapshot mode",
- },{
- .name = "file",
- .type = QEMU_OPT_STRING,
- .help = "disk image",
- },{
- .name = "discard",
- .type = QEMU_OPT_STRING,
- .help = "discard operation (ignore/off, unmap/on)",
- },{
- .name = "cache",
- .type = QEMU_OPT_STRING,
- .help = "host cache usage (none, writeback, writethrough, "
- "directsync, unsafe)",
- },{
- .name = "aio",
- .type = QEMU_OPT_STRING,
- .help = "host AIO implementation (threads, native)",
- },{
- .name = "format",
- .type = QEMU_OPT_STRING,
- .help = "disk format (raw, qcow2, ...)",
- },{
- .name = "serial",
- .type = QEMU_OPT_STRING,
- .help = "disk serial number",
- },{
- .name = "rerror",
- .type = QEMU_OPT_STRING,
- .help = "read error action",
- },{
- .name = "werror",
- .type = QEMU_OPT_STRING,
- .help = "write error action",
- },{
- .name = "addr",
- .type = QEMU_OPT_STRING,
- .help = "pci address (virtio only)",
- },{
- .name = "readonly",
- .type = QEMU_OPT_BOOL,
- .help = "open drive file as read-only",
+ .help = "I/O operations burst",
},{
- .name = "iops",
+ .name = "throttling.iops-read-max",
.type = QEMU_OPT_NUMBER,
- .help = "limit total I/O operations per second",
+ .help = "I/O operations read burst",
},{
- .name = "iops_rd",
+ .name = "throttling.iops-write-max",
.type = QEMU_OPT_NUMBER,
- .help = "limit read operations per second",
+ .help = "I/O operations write burst",
},{
- .name = "iops_wr",
+ .name = "throttling.bps-total-max",
.type = QEMU_OPT_NUMBER,
- .help = "limit write operations per second",
+ .help = "total bytes burst",
},{
- .name = "bps",
+ .name = "throttling.bps-read-max",
.type = QEMU_OPT_NUMBER,
- .help = "limit total bytes per second",
+ .help = "total bytes read burst",
},{
- .name = "bps_rd",
+ .name = "throttling.bps-write-max",
.type = QEMU_OPT_NUMBER,
- .help = "limit read bytes per second",
+ .help = "total bytes write burst",
},{
- .name = "bps_wr",
+ .name = "throttling.iops-size",
.type = QEMU_OPT_NUMBER,
- .help = "limit write bytes per second",
+ .help = "when limiting by iops max size of an I/O in bytes",
},{
.name = "copy-on-read",
.type = QEMU_OPT_BOOL,
.help = "copy read data from backing file into image file",
- },{
- .name = "boot",
- .type = QEMU_OPT_BOOL,
- .help = "(deprecated, ignored)",
},
{ /* end of list */ }
},
echo >> config.log
echo "#" >> config.log
+ # Save the configure command line for later reuse.
+ cat <<EOD >config.status
+ #!/bin/sh
+ # Generated by configure.
+ # Run this file to recreate the current configuration.
+ # Compiler output produced by configure, useful for debugging
+ # configure, is in config.log if it exists.
+ EOD
+ printf "exec" >>config.status
+ printf " '%s'" "$0" "$@" >>config.status
+ echo >>config.status
+ chmod +x config.status
+
error_exit() {
echo
echo "ERROR: $1"
# default parameters
source_path=`dirname "$0"`
cpu=""
+ iasl="iasl"
interp_prefix="/usr/gnemul/qemu-%M"
static="no"
cross_prefix=""
vhost_net="no"
vhost_scsi="no"
kvm="no"
+hax="no"
rdma=""
gprof="no"
debug_tcg="no"
bsd_user="no"
guest_base="yes"
uname_release=""
- mixemu="no"
aix="no"
blobs="yes"
pkgversion=""
smartcard_nss=""
libusb=""
usb_redir=""
+opengl=""
+efence="no"
+yagl="no"
+yagl_stats="no"
glx=""
+vigs="no"
zlib="yes"
guest_agent=""
+ guest_agent_with_vss="no"
+ vss_win32_sdk=""
+ win_sdk="no"
want_tools="yes"
libiscsi=""
coroutine=""
coroutine_pool=""
seccomp=""
+gl="yes"
+
+# for TIZEN-maru
+maru="no"
+shm="no"
+#
glusterfs=""
glusterfs_discard="no"
virtio_blk_data_plane=""
gtkabi="2.0"
tpm="no"
libssh2=""
+ vhdx=""
# parse CC options first
for opt do
;;
--cc=*) CC="$optarg"
;;
+ --cxx=*) CXX="$optarg"
+ ;;
--source-path=*) source_path="$optarg"
;;
--cpu=*) cpu="$optarg"
cc="${CC-${cross_prefix}gcc}"
fi
+ if test -z "${CXX}${cross_prefix}"; then
+ cxx="c++"
+ else
+ cxx="${CXX-${cross_prefix}g++}"
+ fi
+
ar="${AR-${cross_prefix}ar}"
as="${AS-${cross_prefix}as}"
cpp="${CPP-$cc -E}"
pkg_config=query_pkg_config
sdl_config="${SDL_CONFIG-${cross_prefix}sdl-config}"
+ # If the user hasn't specified ARFLAGS, default to 'rv', just as make does.
+ ARFLAGS="${ARFLAGS-rv}"
+
# default flags for all hosts
QEMU_CFLAGS="-fno-strict-aliasing $QEMU_CFLAGS"
QEMU_CFLAGS="-Wall -Wundef -Wwrite-strings -Wmissing-prototypes $QEMU_CFLAGS"
elif check_define __i386__ ; then
cpu="i386"
elif check_define __x86_64__ ; then
- cpu="x86_64"
+ if check_define __ILP32__ ; then
+ cpu="x32"
+ else
+ cpu="x86_64"
+ fi
elif check_define __sparc__ ; then
if check_define __arch64__ ; then
cpu="sparc64"
# Normalise host CPU name and set ARCH.
# Note that this case should only have supported host CPUs, not guests.
case "$cpu" in
- ia64|ppc|ppc64|s390|s390x|sparc64)
+ ia64|ppc|ppc64|s390|s390x|sparc64|x32)
cpu="$cpu"
;;
i386|i486|i586|i686|i86pc|BePC)
aarch64)
cpu="aarch64"
;;
- hppa|parisc|parisc64)
- cpu="hppa"
- ;;
mips*)
cpu="mips"
;;
audio_possible_drivers="oss alsa sdl esd pa"
linux="yes"
linux_user="yes"
- usb="linux"
kvm="yes"
vhost_net="yes"
vhost_scsi="yes"
- if [ "$cpu" = "i386" -o "$cpu" = "x86_64" ] ; then
+ if [ "$cpu" = "i386" -o "$cpu" = "x86_64" -o "$cpu" = "x32" ] ; then
audio_possible_drivers="$audio_possible_drivers fmod"
fi
+
+# fix linking error on Ubuntu 13.04
+# libs_qga="-lrt $libs_qga"
+# QEMU_INCLUDES="-I\$(SRC_PATH)/linux-headers $QEMU_INCLUDES"
QEMU_INCLUDES="-I\$(SRC_PATH)/linux-headers -I$(pwd)/linux-headers $QEMU_INCLUDES"
;;
esac
if [ "$bsd" = "yes" ] ; then
if [ "$darwin" != "yes" ] ; then
- if [ "$targetos" != "FreeBSD" ]; then
- usb="bsd"
- fi
bsd_user="yes"
fi
fi
;;
--host-cc=*) host_cc="$optarg"
;;
+ --cxx=*)
+ ;;
+ --iasl=*) iasl="$optarg"
+ ;;
--objcc=*) objcc="$optarg"
;;
--make=*) make="$optarg"
;;
--enable-kvm) kvm="yes"
;;
+ --disable-gl) gl="no"
+ ;;
+ --enable-gl) gl="yes"
+ ;;
+ --disable-hax) hax="no"
+ ;;
+ --enable-hax) hax="yes"
+ ;;
--disable-tcg-interpreter) tcg_interpreter="no"
;;
--enable-tcg-interpreter) tcg_interpreter="yes"
;;
--enable-fdt) fdt="yes"
;;
- --enable-mixemu) mixemu="yes"
- ;;
--disable-linux-aio) linux_aio="no"
;;
--enable-linux-aio) linux_aio="yes"
;;
--enable-vhost-net) vhost_net="yes"
;;
+ --enable-efence) efence="yes"
+ ;;
+ --disable-efence) efence="no"
+ ;;
+ --enable-yagl) yagl="yes"
+ ;;
+ --disable-yagl) yagl="no"
+ ;;
+ --enable-yagl-stats) yagl_stats="yes"
+ ;;
+ --disable-yagl-stats) yagl_stats="no"
+ ;;
+ --enable-opengl) opengl="yes"
+ ;;
+ --enable-vigs) vigs="yes"
+ ;;
+ --disable-vigs) vigs="no"
+ ;;
+ --disable-opengl) opengl="no"
+ ;;
--disable-vhost-scsi) vhost_scsi="no"
;;
--enable-vhost-scsi) vhost_scsi="yes"
;;
--disable-guest-agent) guest_agent="no"
;;
+ --with-vss-sdk) vss_win32_sdk=""
+ ;;
+ --with-vss-sdk=*) vss_win32_sdk="$optarg"
+ ;;
+ --without-vss-sdk) vss_win32_sdk="no"
+ ;;
+ --with-win-sdk) win_sdk=""
+ ;;
+ --with-win-sdk=*) win_sdk="$optarg"
+ ;;
+ --without-win-sdk) win_sdk="no"
+ ;;
--enable-tools) want_tools="yes"
;;
--disable-tools) want_tools="no"
;;
--disable-seccomp) seccomp="no"
;;
+# for TIZEN-maru
+ --enable-maru) maru="yes"
+ ;;
+ --enable-shm) shm="yes"
+ ;;
+#
--disable-glusterfs) glusterfs="no"
;;
--enable-glusterfs) glusterfs="yes"
;;
--enable-libssh2) libssh2="yes"
;;
+ --enable-vhdx) vhdx="yes"
+ ;;
+ --disable-vhdx) vhdx="no"
+ ;;
*) echo "ERROR: unknown option $opt"; show_help="yes"
;;
esac
done
case "$cpu" in
+ ppc)
+ CPU_CFLAGS="-m32"
+ LDFLAGS="-m32 $LDFLAGS"
+ ;;
+ ppc64)
+ CPU_CFLAGS="-m64"
+ LDFLAGS="-m64 $LDFLAGS"
+ ;;
sparc)
LDFLAGS="-m32 $LDFLAGS"
CPU_CFLAGS="-m32 -mcpu=ultrasparc"
LDFLAGS="-m64 $LDFLAGS"
cc_i386='$(CC) -m32'
;;
+ x32)
+ CPU_CFLAGS="-mx32"
+ LDFLAGS="-mx32 $LDFLAGS"
+ cc_i386='$(CC) -m32'
+ ;;
# No special flags required for other host CPUs
esac
echo " --source-path=PATH path of source code [$source_path]"
echo " --cross-prefix=PREFIX use PREFIX for compile tools [$cross_prefix]"
echo " --cc=CC use C compiler CC [$cc]"
+ echo " --iasl=IASL use ACPI compiler IASL [$iasl]"
echo " --host-cc=CC use C compiler CC [$host_cc] for code run at"
echo " build time"
+ echo " --cxx=CXX use C++ compiler CXX [$cxx]"
echo " --objcc=OBJCC use Objective-C compiler OBJCC [$objcc]"
echo " --extra-cflags=CFLAGS append extra C compiler flags QEMU_CFLAGS"
echo " --extra-ldflags=LDFLAGS append extra linker flags LDFLAGS"
echo " --block-drv-ro-whitelist=L"
echo " set block driver read-only whitelist"
echo " (affects only QEMU, not qemu-img)"
- echo " --enable-mixemu enable mixer emulation"
echo " --disable-xen disable xen backend driver support"
echo " --enable-xen enable xen backend driver support"
echo " --disable-xen-pci-passthrough"
echo " --disable-slirp disable SLIRP userspace network connectivity"
echo " --disable-kvm disable KVM acceleration support"
echo " --enable-kvm enable KVM acceleration support"
+
+echo " --disable-hax disable HAX acceleration support"
+echo " --enable-hax enable HAX acceleration support"
+
+echo " --disable-gl disable GL acceleration support"
+echo " --enable-gl enable GL acceleration support"
echo " --disable-rdma disable RDMA-based migration support"
echo " --enable-rdma enable RDMA-based migration support"
echo " --enable-tcg-interpreter enable TCG with bytecode interpreter (TCI)"
echo " --enable-rbd enable building the rados block device (rbd)"
echo " --disable-libiscsi disable iscsi support"
echo " --enable-libiscsi enable iscsi support"
+echo " --enable-efence enable Electic Fence"
+echo " --disable-efence disable Electic Fence"
+echo " --enable-yagl enable YaGL device"
+echo " --disable-yagl disable YaGL device"
+echo " --enable-yagl-stats enable YaGL stats"
+echo " --disable-yagl-stats disable YaGL stats"
+echo " --enable-vigs enable VIGS device"
+echo " --disable-vigs disable VIGS device"
+echo " --disable-smartcard disable smartcard support"
+echo " --enable-smartcard enable smartcard support"
echo " --disable-smartcard-nss disable smartcard nss support"
echo " --enable-smartcard-nss enable smartcard nss support"
echo " --disable-libusb disable libusb (for usb passthrough)"
echo " --enable-usb-redir enable usb network redirection support"
echo " --disable-guest-agent disable building of the QEMU Guest Agent"
echo " --enable-guest-agent enable building of the QEMU Guest Agent"
+ echo " --with-vss-sdk=SDK-path enable Windows VSS support in QEMU Guest Agent"
+ echo " --with-win-sdk=SDK-path path to Windows Platform SDK (to build VSS .tlb)"
echo " --disable-seccomp disable seccomp support"
echo " --enable-seccomp enables seccomp support"
echo " --with-coroutine=BACKEND coroutine backend. Supported options:"
echo " --enable-tpm enable TPM support"
echo " --disable-libssh2 disable ssh block device support"
echo " --enable-libssh2 enable ssh block device support"
+ echo " --disable-vhdx disables support for the Microsoft VHDX image format"
+ echo " --enable-vhdx enable support for the Microsoft VHDX image format"
echo ""
+# for TIZEN-maru
+echo "TIZEN-maru options:"
+echo " --enable-maru enable maru board"
+echo " --enable-shm enable shared memory for framebuffer"
echo "NOTE: The object files are built at the place where configure is launched"
exit 1
fi
gcc_flags="-Wmissing-include-dirs -Wempty-body -Wnested-externs $gcc_flags"
gcc_flags="-Wendif-labels $gcc_flags"
gcc_flags="-Wno-initializer-overrides $gcc_flags"
+ gcc_flags="-Wno-string-plus-int $gcc_flags"
# Note that we do not add -Werror to gcc_flags here, because that would
# enable it for all configure tests. If a configure test failed due
# to -Werror this would just silently disable some features,
if test "$pie" = ""; then
case "$cpu-$targetos" in
- i386-Linux|x86_64-Linux|i386-OpenBSD|x86_64-OpenBSD)
+ i386-Linux|x86_64-Linux|x32-Linux|i386-OpenBSD|x86_64-OpenBSD)
;;
*)
pie="no"
# Note that if the Python conditional here evaluates True we will exit
# with status 1 which is a shell 'false' value.
- if ! "$python" -c 'import sys; sys.exit(sys.version_info < (2,4) or sys.version_info >= (3,))'; then
+ if ! $python -c 'import sys; sys.exit(sys.version_info < (2,4) or sys.version_info >= (3,))'; then
error_exit "Cannot use '$python', Python 2.4 or later is required." \
"Note that Python 3 or later is not yet supported." \
"Use --python=/path/to/python to specify a supported Python."
fi
+ # The -B switch was added in Python 2.6.
+ # If it is supplied, compiled files are not written.
+ # Use it for Python versions which support it.
+ if $python -B -c 'import sys; sys.exit(0)' 2>/dev/null; then
+ python="$python -B"
+ fi
+
if test -z "${target_list+xxx}" ; then
target_list="$default_target_list"
else
"configure was not able to find it"
}
- if test -z "$cross_prefix" ; then
-
# ---
# big/little endian test
cat > $TMPC << EOF
- #include <inttypes.h>
- int main(void) {
- volatile uint32_t i=0x01234567;
- return (*((uint8_t*)(&i))) == 0x67;
+ short big_endian[] = { 0x4269, 0x4765, 0x4e64, 0x4961, 0x4e00, 0, };
+ short little_endian[] = { 0x694c, 0x7454, 0x654c, 0x6e45, 0x6944, 0x6e41, 0, };
+ extern int foo(short *, short *);
+ int main(int argc, char *argv[]) {
+ return foo(big_endian, little_endian);
}
EOF
- if compile_prog "" "" ; then
- $TMPE && bigendian="yes"
- else
- echo big/little test failed
- fi
-
- else
-
- # if cross compiling, cannot launch a program, so make a static guess
- case "$cpu" in
- arm)
- # ARM can be either way; ask the compiler which one we are
- if check_define __ARMEB__; then
- bigendian=yes
+ if compile_object ; then
+ if grep -q BiGeNdIaN $TMPO ; then
+ bigendian="yes"
+ elif grep -q LiTtLeEnDiAn $TMPO ; then
+ bigendian="no"
+ else
+ echo big/little test failed
fi
- ;;
- hppa|m68k|mips|mips64|ppc|ppc64|s390|s390x|sparc|sparc64)
- bigendian=yes
- ;;
- esac
-
+ else
+ echo big/little test failed
fi
##########################################
# libseccomp check
if test "$seccomp" != "no" ; then
- if $pkg_config --atleast-version=2.1.0 libseccomp --modversion >/dev/null 2>&1; then
+ if $pkg_config --atleast-version=2.1.0 libseccomp; then
libs_softmmu="$libs_softmmu `$pkg_config --libs libseccomp`"
QEMU_CFLAGS="$QEMU_CFLAGS `$pkg_config --cflags libseccomp`"
seccomp="yes"
fi
gtk="no"
else
- gtk_cflags=`$pkg_config --cflags $gtkpackage 2>/dev/null`
- gtk_libs=`$pkg_config --libs $gtkpackage 2>/dev/null`
- vte_cflags=`$pkg_config --cflags $vtepackage 2>/dev/null`
- vte_libs=`$pkg_config --libs $vtepackage 2>/dev/null`
+ gtk_cflags=`$pkg_config --cflags $gtkpackage`
+ gtk_libs=`$pkg_config --libs $gtkpackage`
+ vte_cflags=`$pkg_config --cflags $vtepackage`
+ vte_libs=`$pkg_config --libs $vtepackage`
libs_softmmu="$gtk_libs $vte_libs $libs_softmmu"
gtk="yes"
fi
sdl_config=sdl-config
fi
- if $pkg_config sdl --modversion >/dev/null 2>&1; then
+ if $pkg_config sdl --exists; then
sdlconfig="$pkg_config sdl"
_sdlversion=`$sdlconfig --modversion 2>/dev/null | sed 's/[^0-9]//g'`
elif has ${sdl_config}; then
return png_ptr != 0;
}
EOF
- if $pkg_config libpng --modversion >/dev/null 2>&1; then
- vnc_png_cflags=`$pkg_config libpng --cflags 2> /dev/null`
- vnc_png_libs=`$pkg_config libpng --libs 2> /dev/null`
+ if $pkg_config libpng --exists; then
+ vnc_png_cflags=`$pkg_config libpng --cflags`
+ vnc_png_libs=`$pkg_config libpng --libs`
else
vnc_png_cflags=""
vnc_png_libs="-lpng"
fi
fi
+ if test "$vhdx" = "yes" ; then
+ if test "$uuid" = "no" ; then
+ error_exit "uuid required for VHDX support"
+ fi
+ elif test "$vhdx" != "no" ; then
+ if test "$uuid" = "yes" ; then
+ vhdx=yes
+ else
+ vhdx=no
+ fi
+ fi
+
##########################################
# xfsctl() probe, used for raw-posix
if test "$xfs" != "no" ; then
##########################################
# curl probe
if test "$curl" != "no" ; then
- if $pkg_config libcurl --modversion >/dev/null 2>&1; then
+ if $pkg_config libcurl --exists; then
curlconfig="$pkg_config libcurl"
else
curlconfig=curl-config
else
glib_req_ver=2.12
fi
- if $pkg_config --atleast-version=$glib_req_ver gthread-2.0 > /dev/null 2>&1
- then
- glib_cflags=`$pkg_config --cflags gthread-2.0 2>/dev/null`
- glib_libs=`$pkg_config --libs gthread-2.0 2>/dev/null`
+ if $pkg_config --atleast-version=$glib_req_ver gthread-2.0; then
+ glib_cflags=`$pkg_config --cflags gthread-2.0`
+ glib_libs=`$pkg_config --libs gthread-2.0`
LIBS="$glib_libs $LIBS"
libs_qga="$glib_libs $libs_qga"
else
pixman_cflags=
pixman_libs=
elif test "$pixman" = "system"; then
- pixman_cflags=`$pkg_config --cflags pixman-1 2>/dev/null`
- pixman_libs=`$pkg_config --libs pixman-1 2>/dev/null`
+ pixman_cflags=`$pkg_config --cflags pixman-1`
+ pixman_libs=`$pkg_config --libs pixman-1`
else
if test ! -d ${source_path}/pixman/pixman; then
error_exit "pixman not present. Your options:" \
# libssh2 probe
min_libssh2_version=1.2.8
if test "$libssh2" != "no" ; then
- if $pkg_config --atleast-version=$min_libssh2_version libssh2 >/dev/null 2>&1
- then
+ if $pkg_config --atleast-version=$min_libssh2_version libssh2; then
libssh2_cflags=`$pkg_config libssh2 --cflags`
libssh2_libs=`$pkg_config libssh2 --libs`
libssh2=yes
fdt_required=no
for target in $target_list; do
case $target in
- arm*-softmmu|ppc*-softmmu|microblaze*-softmmu)
+ aarch64*-softmmu|arm*-softmmu|ppc*-softmmu|microblaze*-softmmu)
fdt_required=yes
;;
esac
##########################################
# glusterfs probe
if test "$glusterfs" != "no" ; then
- if $pkg_config --atleast-version=3 glusterfs-api >/dev/null 2>&1; then
+ if $pkg_config --atleast-version=3 glusterfs-api; then
glusterfs="yes"
- glusterfs_cflags=`$pkg_config --cflags glusterfs-api 2>/dev/null`
- glusterfs_libs=`$pkg_config --libs glusterfs-api 2>/dev/null`
+ glusterfs_cflags=`$pkg_config --cflags glusterfs-api`
+ glusterfs_libs=`$pkg_config --libs glusterfs-api`
CFLAGS="$CFLAGS $glusterfs_cflags"
libs_tools="$glusterfs_libs $libs_tools"
libs_softmmu="$glusterfs_libs $libs_softmmu"
- if $pkg_config --atleast-version=5 glusterfs-api >/dev/null 2>&1; then
+ if $pkg_config --atleast-version=5 glusterfs-api; then
glusterfs_discard="yes"
fi
else
dup3=yes
fi
+ # check for ppoll support
+ ppoll=no
+ cat > $TMPC << EOF
+ #include <poll.h>
+
+ int main(void)
+ {
+ struct pollfd pfd = { .fd = 0, .events = 0, .revents = 0 };
+ ppoll(&pfd, 1, 0, 0);
+ return 0;
+ }
+ EOF
+ if compile_prog "" "" ; then
+ ppoll=yes
+ fi
+
+ # check for prctl(PR_SET_TIMERSLACK , ... ) support
+ prctl_pr_set_timerslack=no
+ cat > $TMPC << EOF
+ #include <sys/prctl.h>
+
+ int main(void)
+ {
+ prctl(PR_SET_TIMERSLACK, 1, 0, 0, 0);
+ return 0;
+ }
+ EOF
+ if compile_prog "" "" ; then
+ prctl_pr_set_timerslack=yes
+ fi
+
# check for epoll support
epoll=no
cat > $TMPC << EOF
#include <iscsi/iscsi.h>
int main(void) { iscsi_unmap_sync(NULL,0,0,0,NULL,0); return 0; }
EOF
- if $pkg_config --atleast-version=1.7.0 libiscsi --modversion >/dev/null 2>&1; then
+ if $pkg_config --atleast-version=1.7.0 libiscsi; then
libiscsi="yes"
- libiscsi_cflags=$($pkg_config --cflags libiscsi 2>/dev/null)
- libiscsi_libs=$($pkg_config --libs libiscsi 2>/dev/null)
+ libiscsi_cflags=$($pkg_config --cflags libiscsi)
+ libiscsi_libs=$($pkg_config --libs libiscsi)
CFLAGS="$CFLAGS $libiscsi_cflags"
LIBS="$LIBS $libiscsi_libs"
elif compile_prog "" "-liscsi" ; then
EOF
spice_cflags=$($pkg_config --cflags spice-protocol spice-server 2>/dev/null)
spice_libs=$($pkg_config --libs spice-protocol spice-server 2>/dev/null)
- if $pkg_config --atleast-version=0.12.0 spice-server >/dev/null 2>&1 && \
- $pkg_config --atleast-version=0.12.3 spice-protocol > /dev/null 2>&1 && \
+ if $pkg_config --atleast-version=0.12.0 spice-server && \
+ $pkg_config --atleast-version=0.12.3 spice-protocol && \
compile_prog "$spice_cflags" "$spice_libs" ; then
spice="yes"
libs_softmmu="$libs_softmmu $spice_libs"
test_cflags="-Werror $test_cflags"
fi
if test -n "$libtool" &&
- $pkg_config --atleast-version=3.12.8 nss >/dev/null 2>&1 && \
+ $pkg_config --atleast-version=3.12.8 nss && \
compile_prog "$test_cflags" "$libcacard_libs"; then
smartcard_nss="yes"
QEMU_CFLAGS="$QEMU_CFLAGS $libcacard_cflags"
# check for libusb
if test "$libusb" != "no" ; then
- if $pkg_config --atleast-version=1.0.13 libusb-1.0 >/dev/null 2>&1 ; then
+ if $pkg_config --atleast-version=1.0.13 libusb-1.0; then
libusb="yes"
- usb="libusb"
- libusb_cflags=$($pkg_config --cflags libusb-1.0 2>/dev/null)
- libusb_libs=$($pkg_config --libs libusb-1.0 2>/dev/null)
+ libusb_cflags=$($pkg_config --cflags libusb-1.0)
+ libusb_libs=$($pkg_config --libs libusb-1.0)
QEMU_CFLAGS="$QEMU_CFLAGS $libusb_cflags"
libs_softmmu="$libs_softmmu $libusb_libs"
else
# check for usbredirparser for usb network redirection support
if test "$usb_redir" != "no" ; then
- if $pkg_config --atleast-version=0.6 libusbredirparser-0.5 >/dev/null 2>&1 ; then
+ if $pkg_config --atleast-version=0.6 libusbredirparser-0.5; then
usb_redir="yes"
- usb_redir_cflags=$($pkg_config --cflags libusbredirparser-0.5 2>/dev/null)
- usb_redir_libs=$($pkg_config --libs libusbredirparser-0.5 2>/dev/null)
+ usb_redir_cflags=$($pkg_config --cflags libusbredirparser-0.5)
+ usb_redir_libs=$($pkg_config --libs libusbredirparser-0.5)
QEMU_CFLAGS="$QEMU_CFLAGS $usb_redir_cflags"
libs_softmmu="$libs_softmmu $usb_redir_libs"
else
fi
##########################################
+ # check if we have VSS SDK headers for win
+
+ if test "$mingw32" = "yes" -a "$guest_agent" != "no" -a "$vss_win32_sdk" != "no" ; then
+ case "$vss_win32_sdk" in
+ "") vss_win32_include="-I$source_path" ;;
+ *\ *) # The SDK is installed in "Program Files" by default, but we cannot
+ # handle path with spaces. So we symlink the headers into ".sdk/vss".
+ vss_win32_include="-I$source_path/.sdk/vss"
+ symlink "$vss_win32_sdk/inc" "$source_path/.sdk/vss/inc"
+ ;;
+ *) vss_win32_include="-I$vss_win32_sdk"
+ esac
+ cat > $TMPC << EOF
+ #define __MIDL_user_allocate_free_DEFINED__
+ #include <inc/win2003/vss.h>
+ int main(void) { return VSS_CTX_BACKUP; }
+ EOF
+ if compile_prog "$vss_win32_include" "" ; then
+ guest_agent_with_vss="yes"
+ QEMU_CFLAGS="$QEMU_CFLAGS $vss_win32_include"
+ libs_qga="-lole32 -loleaut32 -lshlwapi -luuid -lstdc++ -Wl,--enable-stdcall-fixup $libs_qga"
+ else
+ if test "$vss_win32_sdk" != "" ; then
+ echo "ERROR: Please download and install Microsoft VSS SDK:"
+ echo "ERROR: http://www.microsoft.com/en-us/download/details.aspx?id=23490"
+ echo "ERROR: On POSIX-systems, you can extract the SDK headers by:"
+ echo "ERROR: scripts/extract-vsssdk-headers setup.exe"
+ echo "ERROR: The headers are extracted in the directory \`inc'."
+ feature_not_found "VSS support"
+ fi
+ guest_agent_with_vss="no"
+ fi
+ fi
+
+ ##########################################
+ # lookup Windows platform SDK (if not specified)
+ # The SDK is needed only to build .tlb (type library) file of guest agent
+ # VSS provider from the source. It is usually unnecessary because the
+ # pre-compiled .tlb file is included.
+
+ if test "$mingw32" = "yes" -a "$guest_agent" != "no" -a "$guest_agent_with_vss" = "yes" ; then
+ if test -z "$win_sdk"; then
+ programfiles="$PROGRAMFILES"
+ test -n "$PROGRAMW6432" && programfiles="$PROGRAMW6432"
+ if test -n "$programfiles"; then
+ win_sdk=$(ls -d "$programfiles/Microsoft SDKs/Windows/v"* | tail -1) 2>/dev/null
+ else
+ feature_not_found "Windows SDK"
+ fi
+ elif test "$win_sdk" = "no"; then
+ win_sdk=""
+ fi
+ fi
+
+ ##########################################
##########################################
# check if we have fdatasync
CFLAGS="-fprofile-arcs -ftest-coverage -g $CFLAGS"
LDFLAGS="-fprofile-arcs -ftest-coverage $LDFLAGS"
elif test "$debug" = "no" ; then
- CFLAGS="-O2 -D_FORTIFY_SOURCE=2 $CFLAGS"
+ CFLAGS="-O2 -U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=2 $CFLAGS"
fi
fi
fi
if [ "$guest_agent" != "no" ]; then
- if [ "$linux" = "yes" -o "$bsd" = "yes" -o "$solaris" = "yes" ] ; then
+ if [ "$linux" = "yes" -o "$bsd" = "yes" -o "$solaris" = "yes" -o "$mingw32" = "yes" ] ; then
tools="qemu-ga\$(EXESUF) $tools"
+ if [ "$mingw32" = "yes" -a "$guest_agent_with_vss" = "yes" ]; then
+ tools="qga/vss-win32/qga-vss.dll qga/vss-win32/qga-vss.tlb $tools"
+ fi
guest_agent=yes
elif [ "$guest_agent" != yes ]; then
guest_agent=no
if test "$pie" = "no" ; then
textseg_addr=
case "$cpu" in
- arm | hppa | i386 | m68k | ppc | ppc64 | s390* | sparc | sparc64 | x86_64)
+ arm | hppa | i386 | m68k | ppc | ppc64 | s390* | sparc | sparc64 | x86_64 | x32)
textseg_addr=0x60000000
;;
mips)
echo "ELF interp prefix $interp_prefix"
else
echo "local state directory queried at runtime"
+ echo "Windows SDK $win_sdk"
fi
echo "Source path $source_path"
echo "C compiler $cc"
echo "Host C compiler $host_cc"
+ echo "C++ compiler $cxx"
echo "Objective-C compiler $objcc"
+ echo "ARFLAGS $ARFLAGS"
echo "CFLAGS $CFLAGS"
echo "QEMU_CFLAGS $QEMU_CFLAGS"
echo "LDFLAGS $LDFLAGS"
echo "Audio drivers $audio_drv_list"
echo "Block whitelist (rw) $block_drv_rw_whitelist"
echo "Block whitelist (ro) $block_drv_ro_whitelist"
- echo "Mixer emulation $mixemu"
echo "VirtFS support $virtfs"
echo "VNC support $vnc"
if test "$vnc" = "yes" ; then
echo "ATTR/XATTR support $attr"
echo "Install blobs $blobs"
echo "KVM support $kvm"
+echo "HAX support $hax"
+echo "GL support $gl"
echo "RDMA support $rdma"
echo "TCG interpreter $tcg_interpreter"
echo "fdt support $fdt"
echo "nss used $smartcard_nss"
echo "libusb $libusb"
echo "usb net redir $usb_redir"
+echo "OpenGL support $opengl"
+echo "EFence support $efence"
+echo "YaGL support $yagl"
+echo "YaGL stats $yagl_stats"
echo "GLX support $glx"
+echo "VIGS support $vigs"
echo "libiscsi support $libiscsi"
echo "build guest agent $guest_agent"
+ echo "QGA VSS support $guest_agent_with_vss"
echo "seccomp support $seccomp"
echo "coroutine backend $coroutine"
echo "coroutine pool $coroutine_pool"
echo "libssh2 support $libssh2"
echo "TPM passthrough $tpm_passthrough"
echo "QOM debugging $qom_cast_debug"
+ echo "vhdx $vhdx"
+# for TIZEN-maru
+echo "TIZEN-maru support $maru"
+echo "TIZEN-maru shared framebuffer support $shm"
+#
+
if test "$sdl_too_old" = "yes"; then
echo "-> Your SDL version is too old - please upgrade to have SDL support"
fi
echo "# Automatically generated by configure - do not modify" >config-all-disas.mak
echo "# Automatically generated by configure - do not modify" > $config_host_mak
- printf "# Configured with:" >> $config_host_mak
- printf " '%s'" "$0" "$@" >> $config_host_mak
echo >> $config_host_mak
echo all: >> $config_host_mak
echo "ARCH=$ARCH" >> $config_host_mak
- case "$cpu" in
- arm|i386|x86_64|ppc|aarch64)
- # The TCG interpreter currently does not support ld/st optimization.
- if test "$tcg_interpreter" = "no" ; then
- echo "CONFIG_QEMU_LDST_OPTIMIZATION=y" >> $config_host_mak
- fi
- ;;
- esac
if test "$debug_tcg" = "yes" ; then
echo "CONFIG_DEBUG_TCG=y" >> $config_host_mak
fi
version_micro=0
echo "CONFIG_FILEVERSION=$version_major,$version_minor,$version_subminor,$version_micro" >> $config_host_mak
echo "CONFIG_PRODUCTVERSION=$version_major,$version_minor,$version_subminor,$version_micro" >> $config_host_mak
+ if test "$guest_agent_with_vss" = "yes" ; then
+ echo "CONFIG_QGA_VSS=y" >> $config_host_mak
+ echo "WIN_SDK=\"$win_sdk\"" >> $config_host_mak
+ fi
else
echo "CONFIG_POSIX=y" >> $config_host_mak
fi
fi
echo "CONFIG_BDRV_RW_WHITELIST=$block_drv_rw_whitelist" >> $config_host_mak
echo "CONFIG_BDRV_RO_WHITELIST=$block_drv_ro_whitelist" >> $config_host_mak
- if test "$mixemu" = "yes" ; then
- echo "CONFIG_MIXEMU=y" >> $config_host_mak
- fi
if test "$vnc" = "yes" ; then
echo "CONFIG_VNC=y" >> $config_host_mak
fi
if test "$dup3" = "yes" ; then
echo "CONFIG_DUP3=y" >> $config_host_mak
fi
+ if test "$ppoll" = "yes" ; then
+ echo "CONFIG_PPOLL=y" >> $config_host_mak
+ fi
+ if test "$prctl_pr_set_timerslack" = "yes" ; then
+ echo "CONFIG_PRCTL_PR_SET_TIMERSLACK=y" >> $config_host_mak
+ fi
if test "$epoll" = "yes" ; then
echo "CONFIG_EPOLL=y" >> $config_host_mak
fi
echo "CONFIG_SPICE=y" >> $config_host_mak
fi
+if test "$efence" = "yes" ; then
+ echo "CONFIG_EFENCE=y" >> $config_host_mak
+fi
+
+if test "$yagl" = "yes" ; then
+ echo "CONFIG_YAGL=y" >> $config_host_mak
+ if test "$linux" = "yes" ; then
+ echo -n;
+ elif test "$mingw32" = "yes" ; then
+ echo -n;
+ elif test "$darwin" = "yes" ; then
+ echo -n; else
+ echo "ERROR: YaGL is not available on $targetos"
+ exit 1
+ fi
+fi
+
+if test "$yagl_stats" = "yes" ; then
+ echo "CONFIG_YAGL_STATS=y" >> $config_host_mak
+fi
+
+if test "$vigs" = "yes" ; then
+ echo "CONFIG_VIGS=y" >> $config_host_mak
+fi
+
+if test "$smartcard" = "yes" ; then
+ echo "CONFIG_SMARTCARD=y" >> $config_host_mak
+fi
+
if test "$smartcard_nss" = "yes" ; then
echo "CONFIG_SMARTCARD_NSS=y" >> $config_host_mak
echo "libcacard_libs=$libcacard_libs" >> $config_host_mak
echo 'CONFIG_VIRTIO_BLK_DATA_PLANE=$(CONFIG_VIRTIO)' >> $config_host_mak
fi
+ if test "$vhdx" = "yes" ; then
+ echo "CONFIG_VHDX=y" >> $config_host_mak
+ fi
+
# USB host support
- case "$usb" in
- linux)
- echo "HOST_USB=linux legacy" >> $config_host_mak
- ;;
- bsd)
- echo "HOST_USB=bsd" >> $config_host_mak
- ;;
- libusb)
- if test "$linux" = "yes"; then
- echo "HOST_USB=libusb linux legacy" >> $config_host_mak
- else
- echo "HOST_USB=libusb legacy" >> $config_host_mak
- fi
- ;;
- *)
+ if test "$libusb" = "yes"; then
+ echo "HOST_USB=libusb legacy" >> $config_host_mak
+ else
echo "HOST_USB=stub" >> $config_host_mak
- ;;
- esac
+ fi
+# for TIZEN-maru
+if test "$maru" = "yes" ; then
+ echo "CONFIG_MARU=y" >> $config_host_mak
+fi
+if test "$shm" = "yes" ; then
+ echo "CONFIG_USE_SHM=y" >> $config_host_mak
+fi
+if test "$gl" = "yes" ; then
+ echo "CONFIG_GL_BACKEND=y" >> $config_host_mak
+fi
# TPM passthrough support?
if test "$tpm" = "yes"; then
echo 'CONFIG_TPM=$(CONFIG_SOFTMMU)' >> $config_host_mak
if test "$trace_default" = "yes"; then
echo "CONFIG_TRACE_DEFAULT=y" >> $config_host_mak
fi
+if test "$hax" = "yes" ; then
+ if test "$mingw32" = "yes" ; then
+ echo "CONFIG_HAX_BACKEND=y" >> $config_host_mak
+ elif test "$darwin" = "yes" ; then
+ echo "CONFIG_HAX_BACKEND=y" >> $config_host_mak
+ else
+ hax="no"
+ fi
+fi
if test "$rdma" = "yes" ; then
echo "CONFIG_RDMA=y" >> $config_host_mak
QEMU_INCLUDES="-I\$(SRC_PATH)/tcg/sparc $QEMU_INCLUDES"
elif test "$ARCH" = "s390x" ; then
QEMU_INCLUDES="-I\$(SRC_PATH)/tcg/s390 $QEMU_INCLUDES"
- elif test "$ARCH" = "x86_64" ; then
+ elif test "$ARCH" = "x86_64" -o "$ARCH" = "x32" ; then
QEMU_INCLUDES="-I\$(SRC_PATH)/tcg/i386 $QEMU_INCLUDES"
else
QEMU_INCLUDES="-I\$(SRC_PATH)/tcg/\$(ARCH) $QEMU_INCLUDES"
fi
echo "PYTHON=$python" >> $config_host_mak
echo "CC=$cc" >> $config_host_mak
+ if $iasl -h > /dev/null 2>&1; then
+ echo "IASL=$iasl" >> $config_host_mak
+ fi
echo "CC_I386=$cc_i386" >> $config_host_mak
echo "HOST_CC=$host_cc" >> $config_host_mak
+ echo "CXX=$cxx" >> $config_host_mak
echo "OBJCC=$objcc" >> $config_host_mak
echo "AR=$ar" >> $config_host_mak
+ echo "ARFLAGS=$ARFLAGS" >> $config_host_mak
echo "AS=$as" >> $config_host_mak
echo "CPP=$cpp" >> $config_host_mak
echo "OBJCOPY=$objcopy" >> $config_host_mak
if test "$linux" = "yes" ; then
mkdir -p linux-headers
case "$cpu" in
- i386|x86_64)
+ i386|x86_64|x32)
linux_arch=x86
;;
ppcemb|ppc|ppc64)
bflt="yes"
gdb_xml_files="arm-core.xml arm-vfp.xml arm-vfp3.xml arm-neon.xml"
;;
+ aarch64)
+ TARGET_BASE_ARCH=arm
+ bflt="yes"
+ gdb_xml_files="aarch64-core.xml"
+ ;;
cris)
;;
lm32)
fi
fi
esac
+case "$target_name" 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_name" 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 "$gl" = "yes" ; then
+ case "$target_name" in
+ i386|x86_64|arm)
+ echo "CONFIG_GL=y" >> $config_target_mak
+ if test "$mingw32" = "yes" ; then
+ echo "LIBS+=-lopengl32 -lglu32" >> $config_target_mak
+ elif test "$darwin" = "yes" ; then
+ echo "LIBS+=-framework OpenGL -framework AGL " >> $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_bigendian" = "yes" ; then
echo "TARGET_WORDS_BIGENDIAN=y" >> $config_target_mak
fi
cflags=""
ldflags=""
+if test "$tcg_interpreter" = "yes"; then
+ includes="-I\$(SRC_PATH)/tcg/tci $includes"
+elif test "$ARCH" = "sparc64" ; then
+ includes="-I\$(SRC_PATH)/tcg/sparc $includes"
+elif test "$ARCH" = "s390x" ; then
+ includes="-I\$(SRC_PATH)/tcg/s390 $includes"
+elif test "$ARCH" = "x86_64" ; then
+ includes="-I\$(SRC_PATH)/tcg/i386 $includes"
+else
+ includes="-I\$(SRC_PATH)/tcg/\$(ARCH) $includes"
+fi
+includes="-I\$(SRC_PATH)/tcg $includes"
+
+if test "$linux" = "yes" ; then
+ includes="-I\$(SRC_PATH)/linux-headers $includes"
+fi
+
+if test "$target_user_only" = "yes" ; then
+ libdis_config_mak=libdis-user/config.mak
+else
+ libdis_config_mak=libdis/config.mak
+fi
+
+if test "$efence" = "yes" ; then
+ echo "CONFIG_BUILD_WITH_EFENCE=y" >> $config_target_mak
+ echo "LIBS+=-lefence" >> $config_target_mak
+fi
+
+if test "$yagl" = "yes" ; then
+ echo "CONFIG_BUILD_YAGL=y" >> $config_target_mak
+fi
+
+if test "$vigs" = "yes" ; then
+ echo "CONFIG_BUILD_VIGS=y" >> $config_target_mak
+fi
+
for i in $ARCH $TARGET_BASE_ARCH ; do
case "$i" in
alpha)
echo "CONFIG_HPPA_DIS=y" >> $config_target_mak
echo "CONFIG_HPPA_DIS=y" >> config-all-disas.mak
;;
- i386|x86_64)
+ i386|x86_64|x32)
echo "CONFIG_I386_DIS=y" >> $config_target_mak
echo "CONFIG_I386_DIS=y" >> config-all-disas.mak
;;
;;
esac
+if test "$target_softmmu" = "yes" ; then
+ case "$TARGET_BASE_ARCH" in
+ arm)
+ cflags="-DHAS_AUDIO -DHAS_AUDIO_CHOICE $cflags"
+ ;;
+ lm32)
+ cflags="-DHAS_AUDIO $cflags"
+ ;;
+ i386|mips|ppc)
+ cflags="-DHAS_AUDIO -DHAS_AUDIO_CHOICE $cflags"
+ ;;
+ esac
+fi
+
if test "$gprof" = "yes" ; then
echo "TARGET_GPROF=yes" >> $config_target_mak
if test "$target_linux_user" = "yes" ; then
fi
# build tree in object directory in case the source is not in the current directory
- DIRS="tests tests/tcg tests/tcg/cris tests/tcg/lm32 tests/libqos tests/qapi-schema tests/tcg/xtensa"
+ DIRS="tests tests/tcg tests/tcg/cris tests/tcg/lm32 tests/libqos tests/qapi-schema tests/tcg/xtensa tests/qemu-iotests"
+ DIRS="$DIRS fsdev"
DIRS="$DIRS pc-bios/optionrom pc-bios/spapr-rtas pc-bios/s390-ccw"
DIRS="$DIRS roms/seabios roms/vgabios"
DIRS="$DIRS qapi-generated"
echo "BCC=bcc" >> $config_mak
echo "CPP=$cpp" >> $config_mak
echo "OBJCOPY=objcopy" >> $config_mak
- echo "IASL=iasl" >> $config_mak
+ echo "IASL=$iasl" >> $config_mak
echo "LD=$ld" >> $config_mak
done
#include "tcg.h"
#include "qemu/atomic.h"
#include "sysemu/qtest.h"
+#include "sysemu/hax.h"
bool qemu_cpu_has_work(CPUState *cpu)
{
static inline tcg_target_ulong cpu_tb_exec(CPUState *cpu, uint8_t *tb_ptr)
{
CPUArchState *env = cpu->env_ptr;
- tcg_target_ulong next_tb = tcg_qemu_tb_exec(env, tb_ptr);
+ uintptr_t next_tb = tcg_qemu_tb_exec(env, tb_ptr);
if ((next_tb & TB_EXIT_MASK) > TB_EXIT_IDX1) {
/* We didn't start executing this TB (eg because the instruction
* counter hit zero); we must restore the guest PC to the address
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
+ */
+static int need_handle_intr_request(CPUState *cpu)
+{
+#ifdef CONFIG_HAX
+ CPUArchState *env = cpu->env_ptr;
+ if (!hax_enabled() || hax_vcpu_emulation_mode(env))
+ return cpu->interrupt_request;
+ return 0;
+#else
+ return cpu->interrupt_request;
+#endif
+}
+
+
int cpu_exec(CPUArchState *env)
{
CPUState *cpu = ENV_GET_CPU(env);
int ret, interrupt_request;
TranslationBlock *tb;
uint8_t *tc_ptr;
- tcg_target_ulong next_tb;
+ uintptr_t next_tb;
if (cpu->halted) {
if (!cpu_has_work(cpu)) {
}
}
+#ifdef CONFIG_HAX
+ if (hax_enabled() && !hax_vcpu_exec(env))
+ longjmp(env->jmp_env, 1);
+#endif
+
next_tb = 0; /* force lookup of first TB */
for(;;) {
- interrupt_request = cpu->interrupt_request;
+ interrupt_request = need_handle_intr_request(cpu);
if (unlikely(interrupt_request)) {
if (unlikely(cpu->singlestep_enabled & SSTEP_NOIRQ)) {
/* Mask out external interrupts for this step. */
cpu_loop_exit(env);
} else if (interrupt_request & CPU_INTERRUPT_SIPI) {
do_cpu_sipi(x86_env_get_cpu(env));
+
} else if (env->hflags2 & HF2_GIF_MASK) {
if ((interrupt_request & CPU_INTERRUPT_SMI) &&
!(env->hflags & HF_SMM_MASK)) {
cpu_svm_check_intercept_param(env, SVM_EXIT_SMI,
0);
cpu->interrupt_request &= ~CPU_INTERRUPT_SMI;
+#ifdef CONFIG_HAX
+ if (hax_enabled())
+ env->hax_vcpu->resync = 1;
+#endif
do_smm_enter(x86_env_get_cpu(env));
next_tb = 0;
} else if ((interrupt_request & CPU_INTERRUPT_NMI) &&
}
}
cpu->current_tb = NULL;
+#ifdef CONFIG_HAX
+ if (hax_enabled() && hax_stop_emulation(env))
+ cpu_loop_exit(env);
+#endif
/* reset soft MMU for next block (it can currently
only be set by a memory fault) */
} /* for(;;) */
* local variables as longjmp is marked 'noreturn'. */
cpu = current_cpu;
env = cpu->env_ptr;
+ #if !(defined(CONFIG_USER_ONLY) && \
+ (defined(TARGET_M68K) || defined(TARGET_PPC) || defined(TARGET_S390X)))
+ cc = CPU_GET_CLASS(cpu);
+ #endif
}
} /* for(;;) */
#include "exec/gdbstub.h"
#include "sysemu/dma.h"
#include "sysemu/kvm.h"
+#include "sysemu/hax.h"
#include "qmp-commands.h"
#include "qemu/thread.h"
#include "sysemu/qtest.h"
#include "qemu/main-loop.h"
#include "qemu/bitmap.h"
+ #include "qemu/seqlock.h"
#ifndef _WIN32
#include "qemu/compatfd.h"
static CPUState *next_cpu;
+ bool cpu_is_stopped(CPUState *cpu)
+ {
+ return cpu->stopped || !runstate_is_running();
+ }
+
static bool cpu_thread_is_idle(CPUState *cpu)
{
if (cpu->stop || cpu->queued_work_first) {
return false;
}
- if (cpu->stopped || !runstate_is_running()) {
+ if (cpu_is_stopped(cpu)) {
return true;
}
if (!cpu->halted || qemu_cpu_has_work(cpu) ||
- kvm_halt_in_kernel()) {
+ kvm_halt_in_kernel() || hax_enabled()) {
return false;
}
return true;
{
CPUState *cpu;
- for (cpu = first_cpu; cpu != NULL; cpu = cpu->next_cpu) {
+ CPU_FOREACH(cpu) {
if (!cpu_thread_is_idle(cpu)) {
return false;
}
/***********************************************************/
/* guest cycle counter */
+ /* Protected by TimersState seqlock */
+
+ /* Compensate for varying guest execution speed. */
+ static int64_t qemu_icount_bias;
+ static int64_t vm_clock_warp_start;
/* Conversion factor from emulated instructions to virtual clock ticks. */
static int icount_time_shift;
/* Arbitrarily pick 1MIPS as the minimum allowable speed. */
#define MAX_ICOUNT_SHIFT 10
- /* Compensate for varying guest execution speed. */
- static int64_t qemu_icount_bias;
+
+ /* Only written by TCG thread */
+ static int64_t qemu_icount;
+
static QEMUTimer *icount_rt_timer;
static QEMUTimer *icount_vm_timer;
static QEMUTimer *icount_warp_timer;
- static int64_t vm_clock_warp_start;
- static int64_t qemu_icount;
typedef struct TimersState {
+ /* Protected by BQL. */
int64_t cpu_ticks_prev;
int64_t cpu_ticks_offset;
+
+ /* cpu_clock_offset can be read out of BQL, so protect it with
+ * this lock.
+ */
+ QemuSeqLock vm_clock_seqlock;
int64_t cpu_clock_offset;
int32_t cpu_ticks_enabled;
int64_t dummy;
static TimersState timers_state;
/* Return the virtual CPU time, based on the instruction counter. */
- int64_t cpu_get_icount(void)
+ static int64_t cpu_get_icount_locked(void)
{
int64_t icount;
CPUState *cpu = current_cpu;
return qemu_icount_bias + (icount << icount_time_shift);
}
+ int64_t cpu_get_icount(void)
+ {
+ int64_t icount;
+ unsigned start;
+
+ do {
+ start = seqlock_read_begin(&timers_state.vm_clock_seqlock);
+ icount = cpu_get_icount_locked();
+ } while (seqlock_read_retry(&timers_state.vm_clock_seqlock, start));
+
+ return icount;
+ }
+
/* return the host CPU cycle counter and handle stop/restart */
+ /* Caller must hold the BQL */
int64_t cpu_get_ticks(void)
{
+ int64_t ticks;
+
if (use_icount) {
return cpu_get_icount();
}
- if (!timers_state.cpu_ticks_enabled) {
- return timers_state.cpu_ticks_offset;
- } else {
- int64_t ticks;
- ticks = cpu_get_real_ticks();
- if (timers_state.cpu_ticks_prev > ticks) {
- /* Note: non increasing ticks may happen if the host uses
- software suspend */
- timers_state.cpu_ticks_offset += timers_state.cpu_ticks_prev - ticks;
- }
- timers_state.cpu_ticks_prev = ticks;
- return ticks + timers_state.cpu_ticks_offset;
+
+ ticks = timers_state.cpu_ticks_offset;
+ if (timers_state.cpu_ticks_enabled) {
+ ticks += cpu_get_real_ticks();
+ }
+
+ if (timers_state.cpu_ticks_prev > ticks) {
+ /* Note: non increasing ticks may happen if the host uses
+ software suspend */
+ timers_state.cpu_ticks_offset += timers_state.cpu_ticks_prev - ticks;
+ ticks = timers_state.cpu_ticks_prev;
}
+
+ timers_state.cpu_ticks_prev = ticks;
+ return ticks;
+ }
+
+ static int64_t cpu_get_clock_locked(void)
+ {
+ int64_t ticks;
+
+ ticks = timers_state.cpu_clock_offset;
+ if (timers_state.cpu_ticks_enabled) {
+ ticks += get_clock();
+ }
+
+ return ticks;
}
/* return the host CPU monotonic timer and handle stop/restart */
int64_t cpu_get_clock(void)
{
int64_t ti;
- if (!timers_state.cpu_ticks_enabled) {
- return timers_state.cpu_clock_offset;
- } else {
- ti = get_clock();
- return ti + timers_state.cpu_clock_offset;
- }
+ unsigned start;
+
+ do {
+ start = seqlock_read_begin(&timers_state.vm_clock_seqlock);
+ ti = cpu_get_clock_locked();
+ } while (seqlock_read_retry(&timers_state.vm_clock_seqlock, start));
+
+ return ti;
}
- /* enable cpu_get_ticks() */
+ /* enable cpu_get_ticks()
+ * Caller must hold BQL which server as mutex for vm_clock_seqlock.
+ */
void cpu_enable_ticks(void)
{
+ /* Here, the really thing protected by seqlock is cpu_clock_offset. */
+ seqlock_write_lock(&timers_state.vm_clock_seqlock);
if (!timers_state.cpu_ticks_enabled) {
timers_state.cpu_ticks_offset -= cpu_get_real_ticks();
timers_state.cpu_clock_offset -= get_clock();
timers_state.cpu_ticks_enabled = 1;
}
+ seqlock_write_unlock(&timers_state.vm_clock_seqlock);
}
/* disable cpu_get_ticks() : the clock is stopped. You must not call
- cpu_get_ticks() after that. */
+ * cpu_get_ticks() after that.
+ * Caller must hold BQL which server as mutex for vm_clock_seqlock.
+ */
void cpu_disable_ticks(void)
{
+ /* Here, the really thing protected by seqlock is cpu_clock_offset. */
+ seqlock_write_lock(&timers_state.vm_clock_seqlock);
if (timers_state.cpu_ticks_enabled) {
- timers_state.cpu_ticks_offset = cpu_get_ticks();
- timers_state.cpu_clock_offset = cpu_get_clock();
+ timers_state.cpu_ticks_offset += cpu_get_real_ticks();
+ timers_state.cpu_clock_offset = cpu_get_clock_locked();
timers_state.cpu_ticks_enabled = 0;
}
+ seqlock_write_unlock(&timers_state.vm_clock_seqlock);
}
/* Correlation between real and virtual time is always going to be
int64_t cur_time;
int64_t cur_icount;
int64_t delta;
+
+ /* Protected by TimersState mutex. */
static int64_t last_delta;
+
/* If the VM is not running, then do nothing. */
if (!runstate_is_running()) {
return;
}
- cur_time = cpu_get_clock();
- cur_icount = qemu_get_clock_ns(vm_clock);
+
+ seqlock_write_lock(&timers_state.vm_clock_seqlock);
+ cur_time = cpu_get_clock_locked();
+ cur_icount = cpu_get_icount_locked();
+
delta = cur_icount - cur_time;
/* FIXME: This is a very crude algorithm, somewhat prone to oscillation. */
if (delta > 0
}
last_delta = delta;
qemu_icount_bias = cur_icount - (qemu_icount << icount_time_shift);
+ seqlock_write_unlock(&timers_state.vm_clock_seqlock);
}
static void icount_adjust_rt(void *opaque)
{
- qemu_mod_timer(icount_rt_timer,
- qemu_get_clock_ms(rt_clock) + 1000);
+ timer_mod(icount_rt_timer,
+ qemu_clock_get_ms(QEMU_CLOCK_REALTIME) + 1000);
icount_adjust();
}
static void icount_adjust_vm(void *opaque)
{
- qemu_mod_timer(icount_vm_timer,
- qemu_get_clock_ns(vm_clock) + get_ticks_per_sec() / 10);
+ timer_mod(icount_vm_timer,
+ qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) +
+ get_ticks_per_sec() / 10);
icount_adjust();
}
static void icount_warp_rt(void *opaque)
{
- if (vm_clock_warp_start == -1) {
+ /* The icount_warp_timer is rescheduled soon after vm_clock_warp_start
+ * changes from -1 to another value, so the race here is okay.
+ */
+ if (atomic_read(&vm_clock_warp_start) == -1) {
return;
}
+ seqlock_write_lock(&timers_state.vm_clock_seqlock);
if (runstate_is_running()) {
- int64_t clock = qemu_get_clock_ns(rt_clock);
- int64_t warp_delta = clock - vm_clock_warp_start;
- if (use_icount == 1) {
- qemu_icount_bias += warp_delta;
- } else {
+ int64_t clock = qemu_clock_get_ns(QEMU_CLOCK_REALTIME);
+ int64_t warp_delta;
+
+ warp_delta = clock - vm_clock_warp_start;
+ if (use_icount == 2) {
/*
- * In adaptive mode, do not let the vm_clock run too
+ * In adaptive mode, do not let QEMU_CLOCK_VIRTUAL run too
* far ahead of real time.
*/
- int64_t cur_time = cpu_get_clock();
- int64_t cur_icount = qemu_get_clock_ns(vm_clock);
+ int64_t cur_time = cpu_get_clock_locked();
+ int64_t cur_icount = cpu_get_icount_locked();
int64_t delta = cur_time - cur_icount;
- qemu_icount_bias += MIN(warp_delta, delta);
- }
- if (qemu_clock_expired(vm_clock)) {
- qemu_notify_event();
+ warp_delta = MIN(warp_delta, delta);
}
+ qemu_icount_bias += warp_delta;
}
vm_clock_warp_start = -1;
+ seqlock_write_unlock(&timers_state.vm_clock_seqlock);
+
+ if (qemu_clock_expired(QEMU_CLOCK_VIRTUAL)) {
+ qemu_clock_notify(QEMU_CLOCK_VIRTUAL);
+ }
}
void qtest_clock_warp(int64_t dest)
{
- int64_t clock = qemu_get_clock_ns(vm_clock);
+ int64_t clock = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
assert(qtest_enabled());
while (clock < dest) {
- int64_t deadline = qemu_clock_deadline(vm_clock);
+ int64_t deadline = qemu_clock_deadline_ns_all(QEMU_CLOCK_VIRTUAL);
int64_t warp = MIN(dest - clock, deadline);
+ seqlock_write_lock(&timers_state.vm_clock_seqlock);
qemu_icount_bias += warp;
- qemu_run_timers(vm_clock);
- clock = qemu_get_clock_ns(vm_clock);
+ seqlock_write_unlock(&timers_state.vm_clock_seqlock);
+
+ qemu_clock_run_timers(QEMU_CLOCK_VIRTUAL);
+ clock = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
}
- qemu_notify_event();
+ qemu_clock_notify(QEMU_CLOCK_VIRTUAL);
}
- void qemu_clock_warp(QEMUClock *clock)
+ void qemu_clock_warp(QEMUClockType type)
{
+ int64_t clock;
int64_t deadline;
/*
* applicable to other clocks. But a clock argument removes the
* need for if statements all over the place.
*/
- if (clock != vm_clock || !use_icount) {
+ if (type != QEMU_CLOCK_VIRTUAL || !use_icount) {
return;
}
/*
- * If the CPUs have been sleeping, advance the vm_clock timer now. This
- * ensures that the deadline for the timer is computed correctly below.
+ * If the CPUs have been sleeping, advance QEMU_CLOCK_VIRTUAL timer now.
+ * This ensures that the deadline for the timer is computed correctly below.
* This also makes sure that the insn counter is synchronized before the
* CPU starts running, in case the CPU is woken by an event other than
- * the earliest vm_clock timer.
+ * the earliest QEMU_CLOCK_VIRTUAL timer.
*/
icount_warp_rt(NULL);
- if (!all_cpu_threads_idle() || !qemu_clock_has_timers(vm_clock)) {
- qemu_del_timer(icount_warp_timer);
+ timer_del(icount_warp_timer);
+ if (!all_cpu_threads_idle()) {
return;
}
return;
}
- vm_clock_warp_start = qemu_get_clock_ns(rt_clock);
- deadline = qemu_clock_deadline(vm_clock);
+ /* We want to use the earliest deadline from ALL vm_clocks */
+ clock = qemu_clock_get_ns(QEMU_CLOCK_REALTIME);
+ deadline = qemu_clock_deadline_ns_all(QEMU_CLOCK_VIRTUAL);
+ if (deadline < 0) {
+ return;
+ }
+
if (deadline > 0) {
/*
- * Ensure the vm_clock proceeds even when the virtual CPU goes to
+ * Ensure QEMU_CLOCK_VIRTUAL proceeds even when the virtual CPU goes to
* sleep. Otherwise, the CPU might be waiting for a future timer
* interrupt to wake it up, but the interrupt never comes because
* the vCPU isn't running any insns and thus doesn't advance the
- * vm_clock.
+ * QEMU_CLOCK_VIRTUAL.
*
* An extreme solution for this problem would be to never let VCPUs
- * sleep in icount mode if there is a pending vm_clock timer; rather
- * time could just advance to the next vm_clock event. Instead, we
- * do stop VCPUs and only advance vm_clock after some "real" time,
- * (related to the time left until the next event) has passed. This
- * rt_clock timer will do this. This avoids that the warps are too
- * visible externally---for example, you will not be sending network
- * packets continuously instead of every 100ms.
+ * sleep in icount mode if there is a pending QEMU_CLOCK_VIRTUAL
+ * timer; rather time could just advance to the next QEMU_CLOCK_VIRTUAL
+ * event. Instead, we do stop VCPUs and only advance QEMU_CLOCK_VIRTUAL
+ * after some e"real" time, (related to the time left until the next
+ * event) has passed. The QEMU_CLOCK_REALTIME timer will do this.
+ * This avoids that the warps are visible externally; for example,
+ * you will not be sending network packets continuously instead of
+ * every 100ms.
*/
- qemu_mod_timer(icount_warp_timer, vm_clock_warp_start + deadline);
- } else {
- qemu_notify_event();
+ seqlock_write_lock(&timers_state.vm_clock_seqlock);
+ if (vm_clock_warp_start == -1 || vm_clock_warp_start > clock) {
+ vm_clock_warp_start = clock;
+ }
+ seqlock_write_unlock(&timers_state.vm_clock_seqlock);
+ timer_mod_anticipate(icount_warp_timer, clock + deadline);
+ } else if (deadline == 0) {
+ qemu_clock_notify(QEMU_CLOCK_VIRTUAL);
}
}
void configure_icount(const char *option)
{
+ seqlock_init(&timers_state.vm_clock_seqlock, NULL);
vmstate_register(NULL, 0, &vmstate_timers, &timers_state);
if (!option) {
return;
}
- icount_warp_timer = qemu_new_timer_ns(rt_clock, icount_warp_rt, NULL);
+ icount_warp_timer = timer_new_ns(QEMU_CLOCK_REALTIME,
+ icount_warp_rt, NULL);
if (strcmp(option, "auto") != 0) {
icount_time_shift = strtol(option, NULL, 0);
use_icount = 1;
the virtual time trigger catches emulated time passing too fast.
Realtime triggers occur even when idle, so use them less frequently
than VM triggers. */
- icount_rt_timer = qemu_new_timer_ms(rt_clock, icount_adjust_rt, NULL);
- qemu_mod_timer(icount_rt_timer,
- qemu_get_clock_ms(rt_clock) + 1000);
- icount_vm_timer = qemu_new_timer_ns(vm_clock, icount_adjust_vm, NULL);
- qemu_mod_timer(icount_vm_timer,
- qemu_get_clock_ns(vm_clock) + get_ticks_per_sec() / 10);
+ icount_rt_timer = timer_new_ms(QEMU_CLOCK_REALTIME,
+ icount_adjust_rt, NULL);
+ timer_mod(icount_rt_timer,
+ qemu_clock_get_ms(QEMU_CLOCK_REALTIME) + 1000);
+ icount_vm_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL,
+ icount_adjust_vm, NULL);
+ timer_mod(icount_vm_timer,
+ qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) +
+ get_ticks_per_sec() / 10);
}
/***********************************************************/
fprintf(stderr, "qemu: hardware error: ");
vfprintf(stderr, fmt, ap);
fprintf(stderr, "\n");
- for (cpu = first_cpu; cpu != NULL; cpu = cpu->next_cpu) {
+ CPU_FOREACH(cpu) {
fprintf(stderr, "CPU #%d:\n", cpu->cpu_index);
cpu_dump_state(cpu, stderr, fprintf, CPU_DUMP_FPU);
}
{
CPUState *cpu;
- for (cpu = first_cpu; cpu; cpu = cpu->next_cpu) {
+ CPU_FOREACH(cpu) {
cpu_synchronize_state(cpu);
}
}
{
CPUState *cpu;
- for (cpu = first_cpu; cpu; cpu = cpu->next_cpu) {
+ CPU_FOREACH(cpu) {
cpu_synchronize_post_reset(cpu);
}
}
{
CPUState *cpu;
- for (cpu = first_cpu; cpu; cpu = cpu->next_cpu) {
+ CPU_FOREACH(cpu) {
cpu_synchronize_post_init(cpu);
}
}
- bool cpu_is_stopped(CPUState *cpu)
- {
- return !runstate_is_running() || cpu->stopped;
- }
-
static int do_vm_stop(RunState state)
{
int ret = 0;
if (cpu->stop) {
return false;
}
- if (cpu->stopped || !runstate_is_running()) {
+ if (cpu_is_stopped(cpu)) {
return false;
}
return true;
while (all_cpu_threads_idle()) {
/* Start accounting real time to the virtual clock if the CPUs
are idle. */
- qemu_clock_warp(vm_clock);
+ qemu_clock_warp(QEMU_CLOCK_VIRTUAL);
qemu_cond_wait(tcg_halt_cond, &qemu_global_mutex);
}
qemu_cond_wait(&qemu_io_proceeded_cond, &qemu_global_mutex);
}
- for (cpu = first_cpu; cpu != NULL; cpu = cpu->next_cpu) {
+ CPU_FOREACH(cpu) {
qemu_wait_io_event_common(cpu);
}
}
static void tcg_exec_all(void);
- static void tcg_signal_cpu_creation(CPUState *cpu, void *data)
- {
- cpu->thread_id = qemu_get_thread_id();
- cpu->created = true;
- }
-
static void *qemu_tcg_cpu_thread_fn(void *arg)
{
CPUState *cpu = arg;
qemu_thread_get_self(cpu->thread);
qemu_mutex_lock(&qemu_global_mutex);
- qemu_for_each_cpu(tcg_signal_cpu_creation, NULL);
+ CPU_FOREACH(cpu) {
+ cpu->thread_id = qemu_get_thread_id();
+ cpu->created = true;
+ }
qemu_cond_signal(&qemu_cpu_cond);
/* wait for initial kick-off after machine start */
- while (first_cpu->stopped) {
+ while (QTAILQ_FIRST(&cpus)->stopped) {
qemu_cond_wait(tcg_halt_cond, &qemu_global_mutex);
/* process any pending work */
- for (cpu = first_cpu; cpu != NULL; cpu = cpu->next_cpu) {
+ CPU_FOREACH(cpu) {
qemu_wait_io_event_common(cpu);
}
}
while (1) {
tcg_exec_all();
- if (use_icount && qemu_clock_deadline(vm_clock) <= 0) {
- qemu_notify_event();
+
+ if (use_icount) {
+ int64_t deadline = qemu_clock_deadline_ns_all(QEMU_CLOCK_VIRTUAL);
+
+ if (deadline == 0) {
+ qemu_clock_notify(QEMU_CLOCK_VIRTUAL);
+ }
}
qemu_tcg_wait_io_event();
}
fprintf(stderr, "qemu:%s: %s", __func__, strerror(err));
exit(1);
}
+/* The cpu thread cannot catch it reliably when shutdown the guest on Mac.
+ * We can double check it and resend it
+ */
+#ifdef CONFIG_DARWIN
+ if (!exit_request)
+ cpu_signal(0);
+#endif
#else /* _WIN32 */
if (!qemu_cpu_is_self(cpu)) {
CONTEXT tcgContext;
static int all_vcpus_paused(void)
{
- CPUState *cpu = first_cpu;
+ CPUState *cpu;
- while (cpu) {
+ CPU_FOREACH(cpu) {
if (!cpu->stopped) {
return 0;
}
- cpu = cpu->next_cpu;
}
return 1;
void pause_all_vcpus(void)
{
- CPUState *cpu = first_cpu;
+ CPUState *cpu;
- qemu_clock_enable(vm_clock, false);
- while (cpu) {
+ qemu_clock_enable(QEMU_CLOCK_VIRTUAL, false);
+ CPU_FOREACH(cpu) {
cpu->stop = true;
qemu_cpu_kick(cpu);
- cpu = cpu->next_cpu;
}
if (qemu_in_vcpu_thread()) {
cpu_stop_current();
if (!kvm_enabled()) {
- cpu = first_cpu;
- while (cpu) {
+ CPU_FOREACH(cpu) {
cpu->stop = false;
cpu->stopped = true;
- cpu = cpu->next_cpu;
}
return;
}
while (!all_vcpus_paused()) {
qemu_cond_wait(&qemu_pause_cond, &qemu_global_mutex);
- cpu = first_cpu;
- while (cpu) {
+ CPU_FOREACH(cpu) {
qemu_cpu_kick(cpu);
- cpu = cpu->next_cpu;
}
}
}
void resume_all_vcpus(void)
{
- CPUState *cpu = first_cpu;
+ CPUState *cpu;
- qemu_clock_enable(vm_clock, true);
- while (cpu) {
+ qemu_clock_enable(QEMU_CLOCK_VIRTUAL, true);
+ CPU_FOREACH(cpu) {
cpu_resume(cpu);
- cpu = cpu->next_cpu;
}
}
static void qemu_tcg_init_vcpu(CPUState *cpu)
{
+#ifdef CONFIG_HAX
+ if (hax_enabled())
+ hax_init_vcpu(cpu->env_ptr);
+#endif
/* share a single thread for all cpus with TCG */
if (!tcg_cpu_thread) {
cpu->thread = g_malloc0(sizeof(QemuThread));
#endif
if (use_icount) {
int64_t count;
+ int64_t deadline;
int decr;
qemu_icount -= (env->icount_decr.u16.low + env->icount_extra);
env->icount_decr.u16.low = 0;
env->icount_extra = 0;
- count = qemu_icount_round(qemu_clock_deadline(vm_clock));
+ deadline = qemu_clock_deadline_ns_all(QEMU_CLOCK_VIRTUAL);
+
+ /* Maintain prior (possibly buggy) behaviour where if no deadline
+ * was set (as there is no QEMU_CLOCK_VIRTUAL timer) or it is more than
+ * INT32_MAX nanoseconds ahead, we still use INT32_MAX
+ * nanoseconds.
+ */
+ if ((deadline < 0) || (deadline > INT32_MAX)) {
+ deadline = INT32_MAX;
+ }
+
+ count = qemu_icount_round(deadline);
qemu_icount += count;
decr = (count > 0xffff) ? 0xffff : count;
count -= decr;
{
int r;
- /* Account partial waits to the vm_clock. */
- qemu_clock_warp(vm_clock);
+ /* Account partial waits to QEMU_CLOCK_VIRTUAL. */
+ qemu_clock_warp(QEMU_CLOCK_VIRTUAL);
if (next_cpu == NULL) {
next_cpu = first_cpu;
}
- for (; next_cpu != NULL && !exit_request; next_cpu = next_cpu->next_cpu) {
+ for (; next_cpu != NULL && !exit_request; next_cpu = CPU_NEXT(next_cpu)) {
CPUState *cpu = next_cpu;
CPUArchState *env = cpu->env_ptr;
- qemu_clock_enable(vm_clock,
+ qemu_clock_enable(QEMU_CLOCK_VIRTUAL,
(cpu->singlestep_enabled & SSTEP_NOTIMER) == 0);
if (cpu_can_run(cpu)) {
CPUState *cpu;
int i;
- for (cpu = first_cpu; cpu != NULL; cpu = cpu->next_cpu) {
+ CPU_FOREACH(cpu) {
for (i = 0; i < nb_numa_nodes; i++) {
if (test_bit(cpu->cpu_index, node_cpumask[i])) {
cpu->numa_node = i;
CpuInfoList *head = NULL, *cur_item = NULL;
CPUState *cpu;
- for (cpu = first_cpu; cpu != NULL; cpu = cpu->next_cpu) {
+ CPU_FOREACH(cpu) {
CpuInfoList *info;
#if defined(TARGET_I386)
X86CPU *x86_cpu = X86_CPU(cpu);
l = sizeof(buf);
if (l > size)
l = size;
- cpu_memory_rw_debug(cpu, addr, buf, l, 0);
+ if (cpu_memory_rw_debug(cpu, addr, buf, l, 0) != 0) {
+ error_setg(errp, "Invalid addr 0x%016" PRIx64 "specified", addr);
+ goto exit;
+ }
if (fwrite(buf, 1, l, f) != l) {
error_set(errp, QERR_IO_ERROR);
goto exit;
#if defined(TARGET_I386)
CPUState *cs;
- for (cs = first_cpu; cs != NULL; cs = cs->next_cpu) {
+ CPU_FOREACH(cs) {
X86CPU *cpu = X86_CPU(cs);
CPUX86State *env = &cpu->env;
apic_deliver_nmi(env->apic_state);
}
}
+ #elif defined(TARGET_S390X)
+ CPUState *cs;
+ S390CPU *cpu;
+
+ CPU_FOREACH(cs) {
+ cpu = S390_CPU(cs);
+ if (cpu->env.cpu_num == monitor_get_cpu_index()) {
+ if (s390_cpu_restart(S390_CPU(cs)) == -1) {
+ error_set(errp, QERR_UNSUPPORTED);
+ return;
+ }
+ break;
+ }
+ }
#else
error_set(errp, QERR_UNSUPPORTED);
#endif
include pci.mak
include usb.mak
- CONFIG_GDBSTUB_XML=y
CONFIG_VGA=y
CONFIG_ISA_MMIO=y
CONFIG_NAND=y
CONFIG_SD=y
CONFIG_MAX7310=y
CONFIG_WM8750=y
+CONFIG_WM8994=y
CONFIG_TWL92230=y
CONFIG_TSC2005=y
CONFIG_LM832X=y
CONFIG_MICRODRIVE=y
CONFIG_USB_MUSB=y
- CONFIG_ARM9MPCORE=y
CONFIG_ARM11MPCORE=y
- CONFIG_ARM15MPCORE=y
+ CONFIG_A9MPCORE=y
+ CONFIG_A15MPCORE=y
CONFIG_ARM_GIC=y
CONFIG_ARM_GIC_KVM=$(CONFIG_KVM)
CONFIG_FRAMEBUFFER=y
CONFIG_XILINX_SPIPS=y
+ CONFIG_ARM11SCU=y
CONFIG_A9SCU=y
CONFIG_MARVELL_88W8618=y
CONFIG_OMAP=y
CONFIG_VERSATILE_PCI=y
CONFIG_VERSATILE_I2C=y
+CONFIG_SOUND=y
CONFIG_SDHCI=y
+ CONFIG_INTEGRATOR_DEBUG=y
#include "hw/qdev.h"
#include "qemu/osdep.h"
#include "sysemu/kvm.h"
+#include "sysemu/hax.h"
#include "sysemu/sysemu.h"
#include "hw/xen/xen.h"
#include "qemu/timer.h"
#endif
- CPUState *first_cpu;
+ struct CPUTailQ cpus = QTAILQ_HEAD_INITIALIZER(cpus);
/* current CPU in the current thread. It is only valid inside
cpu_exec() */
DEFINE_TLS(CPUState *, current_cpu);
static void io_mem_init(void);
static void memory_map_init(void);
- static void *qemu_safe_ram_ptr(ram_addr_t addr);
static MemoryRegion io_mem_watch;
#endif
CPUState *qemu_get_cpu(int index)
{
- CPUState *cpu = first_cpu;
+ CPUState *cpu;
- while (cpu) {
+ CPU_FOREACH(cpu) {
if (cpu->cpu_index == index) {
- break;
+ return cpu;
}
- cpu = cpu->next_cpu;
}
- return cpu;
- }
-
- void qemu_for_each_cpu(void (*func)(CPUState *cpu, void *data), void *data)
- {
- CPUState *cpu;
-
- cpu = first_cpu;
- while (cpu) {
- func(cpu, data);
- cpu = cpu->next_cpu;
- }
+ return NULL;
}
void cpu_exec_init(CPUArchState *env)
{
CPUState *cpu = ENV_GET_CPU(env);
CPUClass *cc = CPU_GET_CLASS(cpu);
- CPUState **pcpu;
+ CPUState *some_cpu;
int cpu_index;
#if defined(CONFIG_USER_ONLY)
cpu_list_lock();
#endif
- cpu->next_cpu = NULL;
- pcpu = &first_cpu;
cpu_index = 0;
- while (*pcpu != NULL) {
- pcpu = &(*pcpu)->next_cpu;
+ CPU_FOREACH(some_cpu) {
cpu_index++;
}
cpu->cpu_index = cpu_index;
#ifndef CONFIG_USER_ONLY
cpu->thread_id = qemu_get_thread_id();
#endif
- *pcpu = cpu;
+ QTAILQ_INSERT_TAIL(&cpus, cpu, node);
#if defined(CONFIG_USER_ONLY)
cpu_list_unlock();
#endif
#else
static void breakpoint_invalidate(CPUState *cpu, target_ulong pc)
{
- tb_invalidate_phys_addr(cpu_get_phys_page_debug(cpu, pc) |
- (pc & ~TARGET_PAGE_MASK));
+ hwaddr phys = cpu_get_phys_page_debug(cpu, pc);
+ if (phys != -1) {
+ tb_invalidate_phys_addr(phys | (pc & ~TARGET_PAGE_MASK));
+ }
}
#endif
#endif /* TARGET_HAS_ICE */
abort();
}
- CPUArchState *cpu_copy(CPUArchState *env)
+ #if !defined(CONFIG_USER_ONLY)
+ static RAMBlock *qemu_get_ram_block(ram_addr_t addr)
{
- CPUArchState *new_env = cpu_init(env->cpu_model_str);
- #if defined(TARGET_HAS_ICE)
- CPUBreakpoint *bp;
- CPUWatchpoint *wp;
- #endif
-
- /* Reset non arch specific state */
- cpu_reset(ENV_GET_CPU(new_env));
-
- /* Copy arch specific state into the new CPU */
- memcpy(new_env, env, sizeof(CPUArchState));
+ RAMBlock *block;
- /* Clone all break/watchpoints.
- Note: Once we support ptrace with hw-debug register access, make sure
- BP_CPU break/watchpoints are handled correctly on clone. */
- QTAILQ_INIT(&env->breakpoints);
- QTAILQ_INIT(&env->watchpoints);
- #if defined(TARGET_HAS_ICE)
- QTAILQ_FOREACH(bp, &env->breakpoints, entry) {
- cpu_breakpoint_insert(new_env, bp->pc, bp->flags, NULL);
+ /* The list is protected by the iothread lock here. */
+ block = ram_list.mru_block;
+ if (block && addr - block->offset < block->length) {
+ goto found;
}
- QTAILQ_FOREACH(wp, &env->watchpoints, entry) {
- cpu_watchpoint_insert(new_env, wp->vaddr, (~wp->len_mask) + 1,
- wp->flags, NULL);
+ QTAILQ_FOREACH(block, &ram_list.blocks, next) {
+ if (addr - block->offset < block->length) {
+ goto found;
+ }
}
- #endif
- return new_env;
+ fprintf(stderr, "Bad ram offset %" PRIx64 "\n", (uint64_t)addr);
+ abort();
+
+ found:
+ ram_list.mru_block = block;
+ return block;
}
- #if !defined(CONFIG_USER_ONLY)
static void tlb_reset_dirty_range_all(ram_addr_t start, ram_addr_t end,
uintptr_t length)
{
- uintptr_t start1;
+ RAMBlock *block;
+ ram_addr_t start1;
- /* we modify the TLB cache so that the dirty bit will be set again
- when accessing the range */
- start1 = (uintptr_t)qemu_safe_ram_ptr(start);
- /* Check that we don't span multiple blocks - this breaks the
- address comparisons below. */
- if ((uintptr_t)qemu_safe_ram_ptr(end - 1) - start1
- != (end - 1) - start) {
- abort();
- }
+ block = qemu_get_ram_block(start);
+ assert(block == qemu_get_ram_block(end - 1));
+ start1 = (uintptr_t)block->host + (start - block->offset);
cpu_tlb_reset_dirty_all(start1, length);
-
}
/* Note: start and end must be within the same ram block. */
uint16_t section);
static subpage_t *subpage_init(AddressSpace *as, hwaddr base);
+ static void *(*phys_mem_alloc)(size_t size) = qemu_anon_ram_alloc;
+
+ /*
+ * Set a custom physical guest memory alloator.
+ * Accelerators with unusual needs may need this. Hopefully, we can
+ * get rid of it eventually.
+ */
+ void phys_mem_set_alloc(void *(*alloc)(size_t))
+ {
+ phys_mem_alloc = alloc;
+ }
+
static uint16_t phys_section_add(MemoryRegionSection *section)
{
/* The physical section number is ORed with a page-aligned
qemu_mutex_unlock(&ram_list.mutex);
}
- #if defined(__linux__) && !defined(TARGET_S390X)
+ #ifdef __linux__
#include <sys/vfs.h>
block->fd = fd;
return area;
}
+ #else
+ static void *file_ram_alloc(RAMBlock *block,
+ ram_addr_t memory,
+ const char *path)
+ {
+ fprintf(stderr, "-mem-path not supported on this host\n");
+ exit(1);
+ }
#endif
static ram_addr_t find_ram_offset(ram_addr_t size)
size = TARGET_PAGE_ALIGN(size);
new_block = g_malloc0(sizeof(*new_block));
+ new_block->fd = -1;
/* This assumes the iothread lock is taken here too. */
qemu_mutex_lock_ramlist();
if (host) {
new_block->host = host;
new_block->flags |= RAM_PREALLOC_MASK;
- } else {
+ } else if (xen_enabled()) {
if (mem_path) {
- #if defined (__linux__) && !defined(TARGET_S390X)
- new_block->host = file_ram_alloc(new_block, size, mem_path);
- if (!new_block->host) {
- new_block->host = qemu_anon_ram_alloc(size);
- memory_try_enable_merging(new_block->host, size);
- }
- #else
- fprintf(stderr, "-mem-path option unsupported\n");
+ fprintf(stderr, "-mem-path not supported with Xen\n");
exit(1);
- #endif
- } 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_ram_alloc(size);
- } else {
- new_block->host = qemu_anon_ram_alloc(size);
- #ifdef CONFIG_HAX
+ }
+ xen_ram_alloc(new_block->offset, size, mr);
+ } else {
+ if (mem_path) {
+ if (phys_mem_alloc != qemu_anon_ram_alloc) {
/*
- * 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
+ * file_ram_alloc() needs to allocate just like
+ * phys_mem_alloc, but we haven't bothered to provide
+ * a hook there.
*/
- 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);
- }
+ fprintf(stderr,
+ "-mem-path not supported with this accelerator\n");
+ exit(1);
+ }
+ new_block->host = file_ram_alloc(new_block, size, mem_path);
+ }
+ if (!new_block->host) {
+ new_block->host = phys_mem_alloc(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
+ if (!new_block->host) {
+ fprintf(stderr, "Cannot set up guest memory '%s': %s\n",
+ new_block->mr->name, strerror(errno));
+ exit(1);
}
memory_try_enable_merging(new_block->host, size);
}
ram_list.version++;
if (block->flags & RAM_PREALLOC_MASK) {
;
- } else if (mem_path) {
- #if defined (__linux__) && !defined(TARGET_S390X)
- if (block->fd) {
- munmap(block->host, block->length);
- close(block->fd);
- } else {
- qemu_anon_ram_free(block->host, block->length);
- }
- #else
- abort();
+ } else if (xen_enabled()) {
+ xen_invalidate_map_cache_entry(block->host);
+ #ifndef _WIN32
+ } else if (block->fd >= 0) {
+ munmap(block->host, block->length);
+ close(block->fd);
#endif
} else {
- if (xen_enabled()) {
- xen_invalidate_map_cache_entry(block->host);
- } else {
- qemu_anon_ram_free(block->host, block->length);
- }
+ qemu_anon_ram_free(block->host, block->length);
}
g_free(block);
break;
vaddr = block->host + offset;
if (block->flags & RAM_PREALLOC_MASK) {
;
+ } else if (xen_enabled()) {
+ abort();
} else {
flags = MAP_FIXED;
munmap(vaddr, length);
- if (mem_path) {
- #if defined(__linux__) && !defined(TARGET_S390X)
- if (block->fd) {
+ if (block->fd >= 0) {
#ifdef MAP_POPULATE
- flags |= mem_prealloc ? MAP_POPULATE | MAP_SHARED :
- MAP_PRIVATE;
- #else
- flags |= MAP_PRIVATE;
- #endif
- area = mmap(vaddr, length, PROT_READ | PROT_WRITE,
- flags, block->fd, offset);
- } else {
- flags |= MAP_PRIVATE | MAP_ANONYMOUS;
- area = mmap(vaddr, length, PROT_READ | PROT_WRITE,
- flags, -1, 0);
- }
+ flags |= mem_prealloc ? MAP_POPULATE | MAP_SHARED :
+ MAP_PRIVATE;
#else
- abort();
+ flags |= MAP_PRIVATE;
#endif
+ area = mmap(vaddr, length, PROT_READ | PROT_WRITE,
+ flags, block->fd, offset);
} else {
- #if defined(TARGET_S390X) && defined(CONFIG_KVM)
- flags |= MAP_SHARED | MAP_ANONYMOUS;
- area = mmap(vaddr, length, PROT_EXEC|PROT_READ|PROT_WRITE,
- flags, -1, 0);
- #else
+ /*
+ * Remap needs to match alloc. Accelerators that
+ * set phys_mem_alloc never remap. If they did,
+ * we'd need a remap hook here.
+ */
+ assert(phys_mem_alloc == qemu_anon_ram_alloc);
+
flags |= MAP_PRIVATE | MAP_ANONYMOUS;
area = mmap(vaddr, length, PROT_READ | PROT_WRITE,
flags, -1, 0);
- #endif
}
if (area != vaddr) {
fprintf(stderr, "Could not remap addr: "
}
#endif /* !_WIN32 */
- static RAMBlock *qemu_get_ram_block(ram_addr_t addr)
- {
- RAMBlock *block;
-
- /* The list is protected by the iothread lock here. */
- block = ram_list.mru_block;
- if (block && addr - block->offset < block->length) {
- goto found;
- }
- QTAILQ_FOREACH(block, &ram_list.blocks, next) {
- if (addr - block->offset < block->length) {
- goto found;
- }
- }
-
- fprintf(stderr, "Bad ram offset %" PRIx64 "\n", (uint64_t)addr);
- abort();
-
- found:
- ram_list.mru_block = block;
- return block;
- }
-
/* Return a host pointer to ram allocated with qemu_ram_alloc.
With the exception of the softmmu code in this file, this should
only be used for local memory (e.g. video ram) that the device owns,
return block->host + (addr - block->offset);
}
- /* Return a host pointer to ram allocated with qemu_ram_alloc. Same as
- * qemu_get_ram_ptr but do not touch ram_list.mru_block.
- *
- * ??? Is this still necessary?
- */
- static void *qemu_safe_ram_ptr(ram_addr_t addr)
- {
- RAMBlock *block;
-
- /* The list is protected by the iothread lock here. */
- QTAILQ_FOREACH(block, &ram_list.blocks, next) {
- if (addr - block->offset < block->length) {
- if (xen_enabled()) {
- /* We need to check if the requested address is in the RAM
- * because we don't want to map the entire memory in QEMU.
- * In that case just map until the end of the page.
- */
- if (block->offset == 0) {
- return xen_map_cache(addr, 0, 0);
- } else if (block->host == NULL) {
- block->host =
- xen_map_cache(block->offset, block->length, 1);
- }
- }
- return block->host + (addr - block->offset);
- }
- }
-
- fprintf(stderr, "Bad ram offset %" PRIx64 "\n", (uint64_t)addr);
- abort();
-
- return NULL;
- }
-
/* Return a host pointer to guest's ram. Similar to qemu_get_ram_ptr
* but takes a size argument */
static void *qemu_ram_ptr_length(ram_addr_t addr, hwaddr *size)
uint8_t buf[4];
#if defined(DEBUG_SUBPAGE)
- printf("%s: subpage %p len %d addr " TARGET_FMT_plx "\n", __func__,
+ printf("%s: subpage %p len %u addr " TARGET_FMT_plx "\n", __func__,
subpage, len, addr);
#endif
address_space_read(subpage->as, addr + subpage->base, buf, len);
uint8_t buf[4];
#if defined(DEBUG_SUBPAGE)
- printf("%s: subpage %p len %d addr " TARGET_FMT_plx
+ printf("%s: subpage %p len %u addr " TARGET_FMT_plx
" value %"PRIx64"\n",
__func__, subpage, len, addr, value);
#endif
}
static bool subpage_accepts(void *opaque, hwaddr addr,
- unsigned size, bool is_write)
+ unsigned len, bool is_write)
{
subpage_t *subpage = opaque;
#if defined(DEBUG_SUBPAGE)
- printf("%s: subpage %p %c len %d addr " TARGET_FMT_plx "\n",
+ printf("%s: subpage %p %c len %u addr " TARGET_FMT_plx "\n",
__func__, subpage, is_write ? 'w' : 'r', len, addr);
#endif
return address_space_access_valid(subpage->as, addr + subpage->base,
- size, is_write);
+ len, is_write);
}
static const MemoryRegionOps subpage_ops = {
idx = SUBPAGE_IDX(start);
eidx = SUBPAGE_IDX(end);
#if defined(DEBUG_SUBPAGE)
- printf("%s: %p start %08x end %08x idx %08x eidx %08x mem %ld\n", __func__,
- mmio, start, end, idx, eidx, memory);
+ printf("%s: %p start %08x end %08x idx %08x eidx %08x section %d\n",
+ __func__, mmio, start, end, idx, eidx, section);
#endif
for (; idx <= eidx; idx++) {
mmio->sub_section[idx] = section;
"subpage", TARGET_PAGE_SIZE);
mmio->iomem.subpage = true;
#if defined(DEBUG_SUBPAGE)
- printf("%s: %p base " TARGET_FMT_plx " len %08x %d\n", __func__,
- mmio, base, TARGET_PAGE_SIZE, subpage_memory);
+ printf("%s: %p base " TARGET_FMT_plx " len %08x\n", __func__,
+ mmio, base, TARGET_PAGE_SIZE);
#endif
subpage_register(mmio, 0, TARGET_PAGE_SIZE-1, PHYS_SECTION_UNASSIGNED);
/* since each CPU stores ram addresses in its TLB cache, we must
reset the modified entries */
/* XXX: slow ! */
- for (cpu = first_cpu; cpu != NULL; cpu = cpu->next_cpu) {
+ CPU_FOREACH(cpu) {
CPUArchState *env = cpu->env_ptr;
tlb_flush(env, 1);
address_space_init(&address_space_io, system_io, "I/O");
memory_listener_register(&core_memory_listener, &address_space_memory);
- memory_listener_register(&tcg_memory_listener, &address_space_memory);
+ if (tcg_enabled()) {
+ memory_listener_register(&tcg_memory_listener, &address_space_memory);
+ }
}
MemoryRegion *get_system_memory(void)
if (bounce.buffer) {
return NULL;
}
- bounce.buffer = qemu_memalign(TARGET_PAGE_SIZE, TARGET_PAGE_SIZE);
+ /* Avoid unbounded allocations */
+ l = MIN(l, TARGET_PAGE_SIZE);
+ bounce.buffer = qemu_memalign(TARGET_PAGE_SIZE, l);
bounce.addr = addr;
bounce.len = l;
devices-dirs-$(CONFIG_SOFTMMU) += nvram/
devices-dirs-$(CONFIG_SOFTMMU) += pci/
devices-dirs-$(CONFIG_PCI) += pci-bridge/ pci-host/
+ devices-dirs-$(CONFIG_SOFTMMU) += pcmcia/
devices-dirs-$(CONFIG_SOFTMMU) += scsi/
devices-dirs-$(CONFIG_SOFTMMU) += sd/
devices-dirs-$(CONFIG_SOFTMMU) += ssi/
devices-dirs-$(CONFIG_VIRTIO) += virtio/
devices-dirs-$(CONFIG_SOFTMMU) += watchdog/
devices-dirs-$(CONFIG_SOFTMMU) += xen/
+devices-dirs-$(CONFIG_BUILD_VIGS) += yagl/
+devices-dirs-$(CONFIG_BUILD_VIGS) += vigs/
devices-dirs-y += core/
common-obj-y += $(devices-dirs-y)
obj-y += $(devices-dirs-y)
#include "exec/ioport.h"
#include "hw/nvram/fw_cfg.h"
#include "exec/address-spaces.h"
+ #include "hw/acpi/piix4.h"
+#ifdef CONFIG_MARU
+#include "tizen/src/hw/maru_pm.h"
+#endif
+
//#define DEBUG
#ifdef DEBUG
/*< public >*/
MemoryRegion io;
+ uint32_t io_base;
+
MemoryRegion io_gpe;
MemoryRegion io_pci;
MemoryRegion io_cpu;
static void pm_io_space_update(PIIX4PMState *s)
{
PCIDevice *d = PCI_DEVICE(s);
- uint32_t pm_io_base;
- pm_io_base = le32_to_cpu(*(uint32_t *)(d->config + 0x40));
- pm_io_base &= 0xffc0;
+ s->io_base = le32_to_cpu(*(uint32_t *)(d->config + 0x40));
+ s->io_base &= 0xffc0;
memory_region_transaction_begin();
memory_region_set_enabled(&s->io, d->config[0x80] & 1);
- memory_region_set_address(&s->io, pm_io_base);
+ memory_region_set_address(&s->io, s->io_base);
memory_region_transaction_commit();
}
return ret;
}
- qemu_get_timer(f, s->ar.tmr.timer);
+ timer_get(f, s->ar.tmr.timer);
qemu_get_sbe64s(f, &s->ar.tmr.overflow_time);
qemu_get_be16s(f, (uint16_t *)s->ar.gpe.sts);
if (pc->no_hotplug) {
slot_free = false;
} else {
- qdev_free(qdev);
+ object_unparent(OBJECT(qdev));
}
}
}
(memory_region_present(io_as, 0x2f8) ? 0x90 : 0);
}
+ static void piix4_pm_add_propeties(PIIX4PMState *s)
+ {
+ static const uint8_t acpi_enable_cmd = ACPI_ENABLE;
+ static const uint8_t acpi_disable_cmd = ACPI_DISABLE;
+ static const uint32_t gpe0_blk = GPE_BASE;
+ static const uint32_t gpe0_blk_len = GPE_LEN;
+ static const uint16_t sci_int = 9;
+
+ object_property_add_uint8_ptr(OBJECT(s), ACPI_PM_PROP_ACPI_ENABLE_CMD,
+ &acpi_enable_cmd, NULL);
+ object_property_add_uint8_ptr(OBJECT(s), ACPI_PM_PROP_ACPI_DISABLE_CMD,
+ &acpi_disable_cmd, NULL);
+ object_property_add_uint32_ptr(OBJECT(s), ACPI_PM_PROP_GPE0_BLK,
+ &gpe0_blk, NULL);
+ object_property_add_uint32_ptr(OBJECT(s), ACPI_PM_PROP_GPE0_BLK_LEN,
+ &gpe0_blk_len, NULL);
+ object_property_add_uint16_ptr(OBJECT(s), ACPI_PM_PROP_SCI_INT,
+ &sci_int, NULL);
+ object_property_add_uint32_ptr(OBJECT(s), ACPI_PM_PROP_PM_IO_BASE,
+ &s->io_base, NULL);
+ }
+
static int piix4_pm_initfn(PCIDevice *dev)
{
PIIX4PMState *s = PIIX4_PM(dev);
acpi_pm1_evt_init(&s->ar, pm_tmr_timer, &s->io);
acpi_pm1_cnt_init(&s->ar, &s->io, s->s4_val);
acpi_gpe_init(&s->ar, GPE_LEN);
+#ifdef CONFIG_MARU
+ acpi_maru_pm_init(&s->ar, pm_tmr_timer);
+#endif
s->powerdown_notifier.notify = piix4_pm_powerdown_req;
qemu_register_powerdown_notifier(&s->powerdown_notifier);
piix4_acpi_system_hot_add_init(pci_address_space_io(dev), dev->bus, s);
+ piix4_pm_add_propeties(s);
return 0;
}
+ Object *piix4_pm_find(void)
+ {
+ bool ambig;
+ Object *o = object_resolve_path_type("", TYPE_PIIX4_PM, &ambig);
+
+ if (ambig || !o) {
+ return NULL;
+ }
+ return o;
+ }
+
i2c_bus *piix4_pm_init(PCIBus *bus, int devfn, uint32_t smb_io_base,
qemu_irq sci_irq, qemu_irq smi_irq,
int kvm_enabled, FWCfgState *fw_cfg)
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_UINT8(ACPI_PM_PROP_S3_DISABLED, PIIX4PMState, disable_s3, 0),
+ DEFINE_PROP_UINT8(ACPI_PM_PROP_S4_DISABLED, PIIX4PMState, disable_s4, 0),
+ DEFINE_PROP_UINT8(ACPI_PM_PROP_S4_VAL, PIIX4PMState, s4_val, 2),
DEFINE_PROP_END_OF_LIST(),
};
piix4_cpu_hotplug_req(s, CPU(opaque), PLUG);
}
- static void piix4_init_cpu_status(CPUState *cpu, void *data)
- {
- CPUStatus *g = (CPUStatus *)data;
- CPUClass *k = CPU_GET_CLASS(cpu);
- int64_t id = k->get_arch_id(cpu);
-
- g_assert((id / 8) < PIIX4_PROC_LEN);
- g->sts[id / 8] |= (1 << (id % 8));
- }
-
static int piix4_device_hotplug(DeviceState *qdev, PCIDevice *dev,
PCIHotplugState state);
static void piix4_acpi_system_hot_add_init(MemoryRegion *parent,
PCIBus *bus, PIIX4PMState *s)
{
+ CPUState *cpu;
+
memory_region_init_io(&s->io_gpe, OBJECT(s), &piix4_gpe_ops, s,
"acpi-gpe0", GPE_LEN);
memory_region_add_subregion(parent, GPE_BASE, &s->io_gpe);
&s->io_pci);
pci_bus_hotplug(bus, piix4_device_hotplug, DEVICE(s));
- qemu_for_each_cpu(piix4_init_cpu_status, &s->gpe_cpu);
+ CPU_FOREACH(cpu) {
+ CPUClass *cc = CPU_GET_CLASS(cpu);
+ int64_t id = cc->get_arch_id(cpu);
+
+ g_assert((id / 8) < PIIX4_PROC_LEN);
+ s->gpe_cpu.sts[id / 8] |= (1 << (id % 8));
+ }
memory_region_init_io(&s->io_cpu, OBJECT(s), &cpu_hotplug_ops, s,
"acpi-cpu-hotplug", PIIX4_PROC_LEN);
memory_region_add_subregion(parent, PIIX4_PROC_BASE, &s->io_cpu);
+obj-y = arm_pic.o
+obj-y += arm_boot.o
+obj-y += zynq_slcr.o
+obj-y += arm_gic.o arm_gic_common.o
+obj-y += realview_gic.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_enet.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 += zaurus.o ide/microdrive.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 += tsc210x.o
+obj-y += blizzard.o onenand.o cbus.o tusb6010.o usb/hcd-musb.o
+obj-y += mst_fpga.o
+obj-y += bitbang_i2c.o marvell_88w8618_audio.o
+obj-y += framebuffer.o
+obj-y += strongarm.o
+obj-y += imx_serial.o imx_ccm.o imx_timer.o imx_avic.o
+obj-$(CONFIG_FDT) += ../device_tree.o
obj-y += boot.o collie.o exynos4_boards.o gumstix.o highbank.o
obj-y += integratorcp.o kzm.o mainstone.o musicpal.o nseries.o
- obj-y += omap_sx1.o palm.o pic_cpu.o realview.o spitz.o stellaris.o
+ obj-y += omap_sx1.o palm.o realview.o spitz.o stellaris.o
obj-y += tosa.o versatilepb.o vexpress.o xilinx_zynq.o z2.o
obj-y += armv7m.o exynos4210.o pxa2xx.o pxa2xx_gpio.o pxa2xx_pic.o
int cur_line, cur_line_char, cur_char;
int64_t cur_tick;
- cur_tick = qemu_get_clock_ns(vm_clock);
+ cur_tick = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
cur_char = (cur_tick / r->ticks_per_char) % r->total_chars;
cur_line = cur_char / r->htotal;
VGACommonState *s = opaque;
int val, index;
- qemu_flush_coalesced_mmio_buffer();
-
if (vga_ioport_invalid(s, addr)) {
val = 0xff;
} else {
VGACommonState *s = opaque;
int index;
- qemu_flush_coalesced_mmio_buffer();
-
/* check port range access depending on color/monochrome mode */
if (vga_ioport_invalid(s, addr)) {
return;
}
break;
case VBE_DISPI_INDEX_XRES:
+#ifdef CONFIG_MARU
+ if (val <= VBE_DISPI_MAX_XRES) {
+#else
if ((val <= VBE_DISPI_MAX_XRES) && ((val & 7) == 0)) {
+#endif
s->vbe_regs[s->vbe_index] = val;
}
break;
uint32_t *ch_attr_ptr;
vga_draw_glyph8_func *vga_draw_glyph8;
vga_draw_glyph9_func *vga_draw_glyph9;
- int64_t now = qemu_get_clock_ms(vm_clock);
+ int64_t now = qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL);
/* compute font data address (in plane 2) */
v = s->sr[VGA_SEQ_CHARACTER_MAP];
} else if (is_buffer_shared(surface) &&
(full_update || surface_data(surface) != s->vram_ptr
+ (s->start_addr * 4))) {
- DisplaySurface *surface;
surface = qemu_create_displaysurface_from(disp_width,
height, depth, s->line_offset,
s->vram_ptr + (s->start_addr * 4), byteswap);
}
if (graphic_mode != s->graphic_mode) {
s->graphic_mode = graphic_mode;
- s->cursor_blink_time = qemu_get_clock_ms(vm_clock);
+ s->cursor_blink_time = qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL);
full_update = 1;
}
switch(graphic_mode) {
memory_region_set_coalescing(vga_io_memory);
if (init_vga_ports) {
portio_list_init(vga_port_list, obj, vga_ports, s, "vga");
+ portio_list_set_flush_coalesced(vga_port_list);
portio_list_add(vga_port_list, address_space_io, 0x3b0);
}
if (vbe_ports) {
#include "hw/cpu/icc_bus.h"
#include "hw/boards.h"
#include "hw/pci/pci_host.h"
+ #include "acpi-build.h"
+#ifdef CONFIG_MARU
+#include "../../tizen/src/maru_err_table.h"
+#endif
/* debug PC/ISA interrupts */
//#define DEBUG_IRQ
struct e820_entry entry[E820_NR_ENTRIES];
} QEMU_PACKED __attribute((__aligned__(4)));
- static struct e820_table e820_table;
+ static struct e820_table e820_reserve;
+ static struct e820_entry *e820_table;
+ static unsigned e820_entries;
struct hpet_fw_config hpet_cfg = {.count = UINT8_MAX};
void gsi_handler(void *opaque, int n, int level)
DPRINTF("pic_irqs: %s irq %d\n", level? "raise" : "lower", irq);
if (env->apic_state) {
- while (cs) {
+ CPU_FOREACH(cs) {
cpu = X86_CPU(cs);
env = &cpu->env;
if (apic_accept_pic_intr(env->apic_state)) {
apic_deliver_pic_intr(env->apic_state, level);
}
- cs = cs->next_cpu;
}
} else {
if (level) {
int e820_add_entry(uint64_t address, uint64_t length, uint32_t type)
{
- int index = le32_to_cpu(e820_table.count);
+ int index = le32_to_cpu(e820_reserve.count);
struct e820_entry *entry;
- if (index >= E820_NR_ENTRIES)
- return -EBUSY;
- entry = &e820_table.entry[index++];
+ if (type != E820_RAM) {
+ /* old FW_CFG_E820_TABLE entry -- reservations only */
+ if (index >= E820_NR_ENTRIES) {
+ return -EBUSY;
+ }
+ entry = &e820_reserve.entry[index++];
+
+ entry->address = cpu_to_le64(address);
+ entry->length = cpu_to_le64(length);
+ entry->type = cpu_to_le32(type);
+
+ e820_reserve.count = cpu_to_le32(index);
+ }
- entry->address = cpu_to_le64(address);
- entry->length = cpu_to_le64(length);
- entry->type = cpu_to_le32(type);
+ /* new "etc/e820" file -- include ram too */
+ e820_table = g_realloc(e820_table,
+ sizeof(struct e820_entry) * (e820_entries+1));
+ e820_table[e820_entries].address = cpu_to_le64(address);
+ e820_table[e820_entries].length = cpu_to_le64(length);
+ e820_table[e820_entries].type = cpu_to_le32(type);
+ e820_entries++;
- e820_table.count = cpu_to_le32(index);
- return index;
+ return e820_entries;
}
/* Calculates the limit to CPU APIC ID values
fw_cfg_add_bytes(fw_cfg, FW_CFG_SMBIOS_ENTRIES,
smbios_table, smbios_len);
fw_cfg_add_bytes(fw_cfg, FW_CFG_E820_TABLE,
- &e820_table, sizeof(e820_table));
+ &e820_reserve, sizeof(e820_reserve));
+ fw_cfg_add_file(fw_cfg, "etc/e820", e820_table,
+ sizeof(struct e820_entry) * e820_entries);
fw_cfg_add_bytes(fw_cfg, FW_CFG_HPET, &hpet_cfg, sizeof(hpet_cfg));
/* allocate memory for the NUMA channel: one (64bit) word for the number
MIN(ARRAY_SIZE(header), kernel_size)) {
fprintf(stderr, "qemu: could not load kernel '%s': %s\n",
kernel_filename, strerror(errno));
+
+#ifdef CONFIG_MARU
+ char *error_msg = NULL;
+
+ error_msg = maru_convert_path(error_msg, kernel_filename);
+ maru_register_exit_msg(MARU_EXIT_KERNEL_FILE_EXCEPTION, error_msg);
+ if (error_msg) {
+ g_free(error_msg);
+ }
+#endif
exit(1);
}
cpu = pc_new_cpu(cpu_model, x86_cpu_apic_id_from_index(i),
icc_bridge, &error);
if (error) {
- fprintf(stderr, "%s\n", error_get_pretty(error));
+ error_report("%s", error_get_pretty(error));
error_free(error);
exit(1);
}
PcGuestInfoState,
machine_done);
pc_fw_cfg_guest_info(&guest_info_state->info);
+ acpi_setup(&guest_info_state->info);
}
PcGuestInfo *pc_guest_info_init(ram_addr_t below_4g_mem_size,
{
PcGuestInfoState *guest_info_state = g_malloc0(sizeof *guest_info_state);
PcGuestInfo *guest_info = &guest_info_state->info;
+ int i, j;
+
+ guest_info->ram_size = below_4g_mem_size + above_4g_mem_size;
+ guest_info->apic_id_limit = pc_apic_id_limit(max_cpus);
+ guest_info->apic_xrupt_override = kvm_allows_irq0_override();
+ guest_info->numa_nodes = nb_numa_nodes;
+ guest_info->node_mem = g_memdup(node_mem, guest_info->numa_nodes *
+ sizeof *guest_info->node_mem);
+ guest_info->node_cpu = g_malloc0(guest_info->apic_id_limit *
+ sizeof *guest_info->node_cpu);
+
+ for (i = 0; i < max_cpus; i++) {
+ unsigned int apic_id = x86_cpu_apic_id_from_index(i);
+ assert(apic_id < guest_info->apic_id_limit);
+ for (j = 0; j < nb_numa_nodes; j++) {
+ if (test_bit(i, node_cpumask[j])) {
+ guest_info->node_cpu[apic_id] = j;
+ break;
+ }
+ }
+ }
guest_info_state->machine_done.notify = pc_guest_info_machine_done;
qemu_add_machine_init_done_notifier(&guest_info_state->machine_done);
opts = qemu_opts_parse(qemu_find_opts("acpi"), arg, 0);
g_assert(opts != NULL);
- acpi_table_add(opts, &err);
+ acpi_table_add_builtin(opts, &err);
if (err) {
- fprintf(stderr, "WARNING: failed to load %s: %s\n", filename,
- error_get_pretty(err));
+ error_report("WARNING: failed to load %s: %s", filename,
+ error_get_pretty(err));
error_free(err);
}
g_free(arg);
memory_region_init_alias(ram_below_4g, NULL, "ram-below-4g", ram,
0, below_4g_mem_size);
memory_region_add_subregion(system_memory, 0, ram_below_4g);
+ e820_add_entry(0, below_4g_mem_size, E820_RAM);
if (above_4g_mem_size > 0) {
ram_above_4g = g_malloc(sizeof(*ram_above_4g));
memory_region_init_alias(ram_above_4g, NULL, "ram-above-4g", ram,
below_4g_mem_size, above_4g_mem_size);
memory_region_add_subregion(system_memory, 0x100000000ULL,
ram_above_4g);
+ e820_add_entry(0x100000000ULL, above_4g_mem_size, E820_RAM);
}
#include <glib.h>
#include "hw/hw.h"
+ #include "hw/loader.h"
#include "hw/i386/pc.h"
#include "hw/i386/apic.h"
#include "hw/pci/pci.h"
#define MAX_IDE_BUS 2
++#ifdef CONFIG_MARU
++void pc_init_pci(QEMUMachineInitArgs *args);
++
++extern MemoryRegion *global_ram_memory;
++extern void *preallocated_ptr;
++#endif
++
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 bool has_pvpanic;
- static bool has_pci_info = true;
+ static bool has_pci_info;
+ static bool has_acpi_build = true;
/* PC hardware initialisation */
- static void pc_init1(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,
+ static void pc_init1(QEMUMachineInitArgs *args,
int pci_enabled,
int kvmclock_enabled)
{
+ MemoryRegion *system_memory = get_system_memory();
+ MemoryRegion *system_io = get_system_io();
int i;
ram_addr_t below_4g_mem_size, above_4g_mem_size;
PCIBus *pci_bus;
object_property_add_child(qdev_get_machine(), "icc-bridge",
OBJECT(icc_bridge), NULL);
- pc_cpus_init(cpu_model, icc_bridge);
+ pc_cpus_init(args->cpu_model, icc_bridge);
if (kvm_enabled() && kvmclock_enabled) {
kvmclock_create();
}
- if (ram_size >= QEMU_BELOW_4G_RAM_END ) {
- above_4g_mem_size = ram_size - QEMU_BELOW_4G_RAM_END;
- below_4g_mem_size = QEMU_BELOW_4G_RAM_END;
+ if (args->ram_size >= 0xe0000000) {
+ above_4g_mem_size = args->ram_size - 0xe0000000;
+ below_4g_mem_size = 0xe0000000;
} else {
above_4g_mem_size = 0;
- below_4g_mem_size = ram_size;
+ below_4g_mem_size = args->ram_size;
}
if (pci_enabled) {
}
guest_info = pc_guest_info_init(below_4g_mem_size, above_4g_mem_size);
+
+ guest_info->has_acpi_build = has_acpi_build;
+
guest_info->has_pci_info = has_pci_info;
guest_info->isapc_ram_fw = !pci_enabled;
++#ifdef CONFIG_MARU
++ // for ramdump...
++ global_ram_memory = ram_memory;
++#endif
++
/* allocate ram and load rom/bios */
if (!xen_enabled()) {
++#ifdef CONFIG_MARU
++ // W/A for allocate larger continuous heap.
++ // see vl.c
++ if(preallocated_ptr != NULL) {
++ g_free(preallocated_ptr);
++ }
++#endif
fw_cfg = pc_memory_init(system_memory,
- kernel_filename, kernel_cmdline, initrd_filename,
- args->kernel_filename, args->kernel_cmdline,
- args->initrd_filename,
-- below_4g_mem_size, above_4g_mem_size,
-- rom_memory, &ram_memory, guest_info);
++ args->kernel_filename, args->kernel_cmdline,
++ args->initrd_filename,
++ below_4g_mem_size, above_4g_mem_size,
++ rom_memory, &ram_memory, guest_info);
}
gsi_state = g_malloc0(sizeof(*gsi_state));
if (kvm_irqchip_in_kernel()) {
kvm_pc_setup_irq_routing(pci_enabled);
gsi = qemu_allocate_irqs(kvm_pc_gsi_handler, gsi_state,
-- GSI_NUM_PINS);
++ 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,
+ system_memory, system_io, args->ram_size,
below_4g_mem_size,
0x100000000ULL - below_4g_mem_size,
above_4g_mem_size,
}
}
- pc_cmos_init(below_4g_mem_size, above_4g_mem_size, boot_device,
+ pc_cmos_init(below_4g_mem_size, above_4g_mem_size, args->boot_order,
floppy, idebus[0], idebus[1], rtc_state);
if (pci_enabled && usb_enabled(false)) {
if (pci_enabled) {
pc_pci_device_init(pci_bus);
}
-
- if (has_pvpanic) {
- pvpanic_init(isa_bus);
- }
}
++#ifdef CONFIG_MARU
++void pc_init_pci(QEMUMachineInitArgs *args)
++#else
static void pc_init_pci(QEMUMachineInitArgs *args)
++#endif
{
- ram_addr_t ram_size = args->ram_size;
- const char *cpu_model = args->cpu_model;
- const char *kernel_filename = args->kernel_filename;
- const char *kernel_cmdline = args->kernel_cmdline;
- const char *initrd_filename = args->initrd_filename;
- const char *boot_device = args->boot_device;
- pc_init1(get_system_memory(),
- get_system_io(),
- ram_size, boot_device,
- kernel_filename, kernel_cmdline,
- initrd_filename, cpu_model, 1, 1);
+ pc_init1(args, 1, 1);
}
- static void pc_init_pci_1_6(QEMUMachineInitArgs *args)
+ static void pc_compat_1_6(QEMUMachineInitArgs *args)
{
has_pci_info = false;
- pc_init_pci(args);
+ rom_file_in_ram = false;
+ has_acpi_build = false;
}
- static void pc_init_pci_1_5(QEMUMachineInitArgs *args)
+ static void pc_compat_1_5(QEMUMachineInitArgs *args)
{
- has_pvpanic = true;
- pc_init_pci_1_6(args);
+ pc_compat_1_6(args);
}
- static void pc_init_pci_1_4(QEMUMachineInitArgs *args)
+ static void pc_compat_1_4(QEMUMachineInitArgs *args)
{
+ pc_compat_1_5(args);
x86_cpu_compat_set_features("n270", FEAT_1_ECX, 0, CPUID_EXT_MOVBE);
x86_cpu_compat_set_features("Westmere", FEAT_1_ECX, 0, CPUID_EXT_PCLMULQDQ);
- has_pci_info = false;
- pc_init_pci(args);
}
- static void pc_init_pci_1_3(QEMUMachineInitArgs *args)
+ static void pc_compat_1_3(QEMUMachineInitArgs *args)
{
+ pc_compat_1_4(args);
enable_compat_apic_id_mode();
- pc_init_pci_1_4(args);
}
- /* PC machine init function for pc-1.1 to pc-1.2 */
- static void pc_init_pci_1_2(QEMUMachineInitArgs *args)
+ /* PC compat function for pc-0.14 to pc-1.2 */
+ static void pc_compat_1_2(QEMUMachineInitArgs *args)
{
+ pc_compat_1_3(args);
disable_kvm_pv_eoi();
- pc_init_pci_1_3(args);
}
- /* PC machine init function for pc-0.14 to pc-1.0 */
- static void pc_init_pci_1_0(QEMUMachineInitArgs *args)
+ static void pc_init_pci_1_6(QEMUMachineInitArgs *args)
+ {
+ pc_compat_1_6(args);
+ pc_init_pci(args);
+ }
+
+ static void pc_init_pci_1_5(QEMUMachineInitArgs *args)
+ {
+ pc_compat_1_5(args);
+ pc_init_pci(args);
+ }
+
+ static void pc_init_pci_1_4(QEMUMachineInitArgs *args)
+ {
+ pc_compat_1_4(args);
+ pc_init_pci(args);
+ }
+
+ static void pc_init_pci_1_3(QEMUMachineInitArgs *args)
{
- pc_init_pci_1_2(args);
+ pc_compat_1_3(args);
+ pc_init_pci(args);
+ }
+
+ /* PC machine init function for pc-0.14 to pc-1.2 */
+ static void pc_init_pci_1_2(QEMUMachineInitArgs *args)
+ {
+ pc_compat_1_2(args);
+ pc_init_pci(args);
}
/* PC init function for pc-0.10 to pc-0.13, and reused by xenfv */
static void pc_init_pci_no_kvmclock(QEMUMachineInitArgs *args)
{
- ram_addr_t ram_size = args->ram_size;
- const char *cpu_model = args->cpu_model;
- const char *kernel_filename = args->kernel_filename;
- const char *kernel_cmdline = args->kernel_cmdline;
- const char *initrd_filename = args->initrd_filename;
- const char *boot_device = args->boot_device;
has_pci_info = false;
+ has_acpi_build = false;
disable_kvm_pv_eoi();
enable_compat_apic_id_mode();
- pc_init1(get_system_memory(),
- get_system_io(),
- ram_size, boot_device,
- kernel_filename, kernel_cmdline,
- initrd_filename, cpu_model, 1, 0);
+ pc_init1(args, 1, 0);
}
static void pc_init_isa(QEMUMachineInitArgs *args)
{
- ram_addr_t ram_size = args->ram_size;
- const char *cpu_model = args->cpu_model;
- const char *kernel_filename = args->kernel_filename;
- const char *kernel_cmdline = args->kernel_cmdline;
- const char *initrd_filename = args->initrd_filename;
- const char *boot_device = args->boot_device;
has_pci_info = false;
- if (cpu_model == NULL)
- cpu_model = "486";
+ has_acpi_build = false;
+ if (!args->cpu_model) {
+ args->cpu_model = "486";
+ }
disable_kvm_pv_eoi();
enable_compat_apic_id_mode();
- pc_init1(get_system_memory(),
- get_system_io(),
- ram_size, boot_device,
- kernel_filename, kernel_cmdline,
- initrd_filename, cpu_model, 0, 1);
+ pc_init1(args, 0, 1);
}
#ifdef CONFIG_XEN
}
#endif
+ #define PC_I440FX_MACHINE_OPTIONS \
+ PC_DEFAULT_MACHINE_OPTIONS, \
+ .desc = "Standard PC (i440FX + PIIX, 1996)", \
+ .hot_add_cpu = pc_hot_add_cpu
+
+ #define PC_I440FX_1_7_MACHINE_OPTIONS PC_I440FX_MACHINE_OPTIONS
+ static QEMUMachine pc_i440fx_machine_v1_7 = {
+ PC_I440FX_1_7_MACHINE_OPTIONS,
+ .name = "pc-i440fx-1.7",
+ .alias = "pc",
+ .init = pc_init_pci,
+ .is_default = 1,
+ };
+
+ #define PC_I440FX_1_6_MACHINE_OPTIONS PC_I440FX_MACHINE_OPTIONS
+
static QEMUMachine pc_i440fx_machine_v1_6 = {
+ PC_I440FX_1_6_MACHINE_OPTIONS,
.name = "pc-i440fx-1.6",
- .alias = "pc",
- .desc = "Standard PC (i440FX + PIIX, 1996)",
.init = pc_init_pci_1_6,
- .hot_add_cpu = pc_hot_add_cpu,
- .max_cpus = 255,
- .is_default = 1,
- DEFAULT_MACHINE_OPTIONS,
+ .compat_props = (GlobalProperty[]) {
+ PC_COMPAT_1_6,
+ { /* end of list */ }
+ },
};
static QEMUMachine pc_i440fx_machine_v1_5 = {
+ PC_I440FX_1_6_MACHINE_OPTIONS,
.name = "pc-i440fx-1.5",
- .desc = "Standard PC (i440FX + PIIX, 1996)",
.init = pc_init_pci_1_5,
- .hot_add_cpu = pc_hot_add_cpu,
- .max_cpus = 255,
.compat_props = (GlobalProperty[]) {
PC_COMPAT_1_5,
{ /* end of list */ }
},
- DEFAULT_MACHINE_OPTIONS,
};
+ #define PC_I440FX_1_4_MACHINE_OPTIONS \
+ PC_I440FX_1_6_MACHINE_OPTIONS, \
+ .hot_add_cpu = NULL
+
static QEMUMachine pc_i440fx_machine_v1_4 = {
+ PC_I440FX_1_4_MACHINE_OPTIONS,
.name = "pc-i440fx-1.4",
- .desc = "Standard PC (i440FX + PIIX, 1996)",
.init = pc_init_pci_1_4,
- .max_cpus = 255,
.compat_props = (GlobalProperty[]) {
PC_COMPAT_1_4,
{ /* end of list */ }
},
- DEFAULT_MACHINE_OPTIONS,
};
#define PC_COMPAT_1_3 \
}
static QEMUMachine pc_machine_v1_3 = {
+ PC_I440FX_1_4_MACHINE_OPTIONS,
.name = "pc-1.3",
- .desc = "Standard PC",
.init = pc_init_pci_1_3,
- .max_cpus = 255,
.compat_props = (GlobalProperty[]) {
PC_COMPAT_1_3,
{ /* end of list */ }
},
- DEFAULT_MACHINE_OPTIONS,
};
#define PC_COMPAT_1_2 \
.value = "off",\
}
+ #define PC_I440FX_1_2_MACHINE_OPTIONS \
+ PC_I440FX_1_4_MACHINE_OPTIONS, \
+ .init = pc_init_pci_1_2
+
static QEMUMachine pc_machine_v1_2 = {
+ PC_I440FX_1_2_MACHINE_OPTIONS,
.name = "pc-1.2",
- .desc = "Standard PC",
- .init = pc_init_pci_1_2,
- .max_cpus = 255,
.compat_props = (GlobalProperty[]) {
PC_COMPAT_1_2,
{ /* end of list */ }
},
- DEFAULT_MACHINE_OPTIONS,
};
#define PC_COMPAT_1_1 \
}
static QEMUMachine pc_machine_v1_1 = {
+ PC_I440FX_1_2_MACHINE_OPTIONS,
.name = "pc-1.1",
- .desc = "Standard PC",
- .init = pc_init_pci_1_2,
- .max_cpus = 255,
.compat_props = (GlobalProperty[]) {
PC_COMPAT_1_1,
{ /* end of list */ }
},
- DEFAULT_MACHINE_OPTIONS,
};
#define PC_COMPAT_1_0 \
}
static QEMUMachine pc_machine_v1_0 = {
+ PC_I440FX_1_2_MACHINE_OPTIONS,
.name = "pc-1.0",
- .desc = "Standard PC",
- .init = pc_init_pci_1_0,
- .max_cpus = 255,
.compat_props = (GlobalProperty[]) {
PC_COMPAT_1_0,
{ /* end of list */ }
},
.hw_version = "1.0",
- DEFAULT_MACHINE_OPTIONS,
};
#define PC_COMPAT_0_15 \
PC_COMPAT_1_0
static QEMUMachine pc_machine_v0_15 = {
+ PC_I440FX_1_2_MACHINE_OPTIONS,
.name = "pc-0.15",
- .desc = "Standard PC",
- .init = pc_init_pci_1_0,
- .max_cpus = 255,
.compat_props = (GlobalProperty[]) {
PC_COMPAT_0_15,
{ /* end of list */ }
},
.hw_version = "0.15",
- DEFAULT_MACHINE_OPTIONS,
};
#define PC_COMPAT_0_14 \
}
static QEMUMachine pc_machine_v0_14 = {
+ PC_I440FX_1_2_MACHINE_OPTIONS,
.name = "pc-0.14",
- .desc = "Standard PC",
- .init = pc_init_pci_1_0,
- .max_cpus = 255,
.compat_props = (GlobalProperty[]) {
PC_COMPAT_0_14,
{
{ /* end of list */ }
},
.hw_version = "0.14",
- DEFAULT_MACHINE_OPTIONS,
};
#define PC_COMPAT_0_13 \
.value = stringify(1),\
}
+ #define PC_I440FX_0_13_MACHINE_OPTIONS \
+ PC_I440FX_1_2_MACHINE_OPTIONS, \
+ .init = pc_init_pci_no_kvmclock
+
static QEMUMachine pc_machine_v0_13 = {
+ PC_I440FX_0_13_MACHINE_OPTIONS,
.name = "pc-0.13",
- .desc = "Standard PC",
- .init = pc_init_pci_no_kvmclock,
- .max_cpus = 255,
.compat_props = (GlobalProperty[]) {
PC_COMPAT_0_13,
{
{ /* end of list */ }
},
.hw_version = "0.13",
- DEFAULT_MACHINE_OPTIONS,
};
#define PC_COMPAT_0_12 \
}
static QEMUMachine pc_machine_v0_12 = {
+ PC_I440FX_0_13_MACHINE_OPTIONS,
.name = "pc-0.12",
- .desc = "Standard PC",
- .init = pc_init_pci_no_kvmclock,
- .max_cpus = 255,
.compat_props = (GlobalProperty[]) {
PC_COMPAT_0_12,
{
{ /* end of list */ }
},
.hw_version = "0.12",
- DEFAULT_MACHINE_OPTIONS,
};
#define PC_COMPAT_0_11 \
}
static QEMUMachine pc_machine_v0_11 = {
+ PC_I440FX_0_13_MACHINE_OPTIONS,
.name = "pc-0.11",
- .desc = "Standard PC, qemu 0.11",
- .init = pc_init_pci_no_kvmclock,
- .max_cpus = 255,
.compat_props = (GlobalProperty[]) {
PC_COMPAT_0_11,
{
{ /* end of list */ }
},
.hw_version = "0.11",
- DEFAULT_MACHINE_OPTIONS,
};
static QEMUMachine pc_machine_v0_10 = {
+ PC_I440FX_0_13_MACHINE_OPTIONS,
.name = "pc-0.10",
- .desc = "Standard PC, qemu 0.10",
- .init = pc_init_pci_no_kvmclock,
- .max_cpus = 255,
.compat_props = (GlobalProperty[]) {
PC_COMPAT_0_11,
{
{ /* end of list */ }
},
.hw_version = "0.10",
- DEFAULT_MACHINE_OPTIONS,
};
static QEMUMachine isapc_machine = {
+ PC_COMMON_MACHINE_OPTIONS,
.name = "isapc",
.desc = "ISA-only PC",
.init = pc_init_isa,
.compat_props = (GlobalProperty[]) {
{ /* end of list */ }
},
- DEFAULT_MACHINE_OPTIONS,
};
#ifdef CONFIG_XEN
static QEMUMachine xenfv_machine = {
+ PC_COMMON_MACHINE_OPTIONS,
.name = "xenfv",
.desc = "Xen Fully-virtualized PC",
.init = pc_xen_hvm_init,
.max_cpus = HVM_MAX_VCPUS,
.default_machine_opts = "accel=xen",
- DEFAULT_MACHINE_OPTIONS,
+ .hot_add_cpu = pc_hot_add_cpu,
};
#endif
static void pc_machine_init(void)
{
+ qemu_register_machine(&pc_i440fx_machine_v1_7);
qemu_register_machine(&pc_i440fx_machine_v1_6);
qemu_register_machine(&pc_i440fx_machine_v1_5);
qemu_register_machine(&pc_i440fx_machine_v1_4);
#include "hw/block/flash.h"
#include "sysemu/kvm.h"
+#ifdef CONFIG_MARU
+#include "../../tizen/src/maru_err_table.h"
+#endif
+
#define BIOS_FILENAME "bios.bin"
typedef struct PcSysFwDevice {
flash_size = memory_region_size(flash_mem);
/* map the last 128KB of the BIOS in ISA space */
- isa_bios_size = flash_size;
- if (isa_bios_size > (128 * 1024)) {
- isa_bios_size = 128 * 1024;
- }
+ isa_bios_size = MIN(flash_size, 128 * 1024);
isa_bios = g_malloc(sizeof(*isa_bios));
memory_region_init_ram(isa_bios, NULL, "isa-bios", isa_bios_size);
vmstate_register_ram_global(isa_bios);
if (ret != 0) {
bios_error:
fprintf(stderr, "qemu: could not load PC BIOS '%s'\n", bios_name);
+#ifdef CONFIG_MARU
+ maru_register_exit_msg(MARU_EXIT_BIOS_FILE_EXCEPTION, bios_name);
+#endif
exit(1);
}
if (filename) {
s->wait_for_sipi = 1;
if (s->timer) {
- qemu_del_timer(s->timer);
+ timer_del(s->timer);
}
s->timer_expiry = -1;
}
mmio_registered = true;
}
+#ifndef CONFIG_MARU
/* Note: We need at least 1M to map the VAPIC option ROM */
if (!vapic && s->vapic_control & VAPIC_ENABLE_MASK &&
ram_size >= 1024 * 1024) {
vapic = sysbus_create_simple("kvmvapic", -1, NULL);
}
+#endif
s->vapic = vapic;
if (apic_report_tpr_access && info->enable_tpr_reporting) {
info->enable_tpr_reporting(s, true);
}
dev = pci_create(bus, devfn, "virtio-blk-pci");
if (qdev_prop_set_drive(&dev->qdev, "drive", dinfo->bdrv) < 0) {
- qdev_free(&dev->qdev);
+ object_unparent(OBJECT(dev));
dev = NULL;
break;
}
return dev;
}
+#ifdef CONFIG_MARU
+static PCIDevice *qemu_pci_hot_add_keyboard(Monitor *mon,
+ const char *devaddr,
+ const char *opts)
+{
+ PCIDevice *dev;
+ PCIBus *root = pci_find_primary_bus();
+ PCIBus *bus;
+ int devfn;
+
+ if (!root) {
+ monitor_printf(mon, "no primary PCI bus (if there are multiple"
+ " PCI roots, you must use device_add instead)");
+ return NULL;
+ }
+
+ bus = pci_get_bus_devfn(&devfn, root, devaddr);
+ if (!bus) {
+ monitor_printf(mon, "Invalid PCI device address %s\n", devaddr);
+ return NULL;
+ }
+
+ if (!((BusState*)bus)->allow_hotplug) {
+ monitor_printf(mon, "PCI bus doesn't support hotplug\n");
+ return NULL;
+ }
+
+ dev = pci_create(bus, devfn, "virtio-keyboard-pci");
+ if (qdev_init(&dev->qdev) < 0) {
+ dev = NULL;
+ }
+
+ return dev;
+}
+#endif /* CONFIG_MARU */
+
+#ifdef CONFIG_MARU
+void pci_device_hot_add(Monitor *mon, const QDict *qdict)
+{
+ do_pci_device_hot_add(mon, qdict);
+}
+
+PCIDevice *do_pci_device_hot_add(Monitor *mon, const QDict *qdict)
+#else
void pci_device_hot_add(Monitor *mon, const QDict *qdict)
+#endif
{
PCIDevice *dev = NULL;
const char *pci_addr = qdict_get_str(qdict, "pci_addr");
dev = qemu_pci_hot_add_nic(mon, pci_addr, opts);
} else if (strcmp(type, "storage") == 0) {
dev = qemu_pci_hot_add_storage(mon, pci_addr, opts);
+#ifdef CONFIG_MARU
+ } else if (strcmp(type, "keyboard") == 0) {
+ dev = qemu_pci_hot_add_keyboard(mon, pci_addr, opts);
+#endif
} else {
monitor_printf(mon, "invalid type: %s\n", type);
}
PCI_FUNC(dev->devfn));
} else
monitor_printf(mon, "failed to add %s\n", opts);
+#ifdef CONFIG_MARU
+ return dev;
+#endif
}
static int pci_device_hot_remove(Monitor *mon, const char *pci_addr)
static char *pcibus_get_dev_path(DeviceState *dev);
static char *pcibus_get_fw_dev_path(DeviceState *dev);
static int pcibus_reset(BusState *qbus);
+ static void pci_bus_finalize(Object *obj);
static Property pci_props[] = {
DEFINE_PROP_PCI_DEVFN("addr", PCIDevice, devfn, -1),
.name = TYPE_PCI_BUS,
.parent = TYPE_BUS,
.instance_size = sizeof(PCIBus),
+ .instance_finalize = pci_bus_finalize,
.class_init = pci_bus_class_init,
};
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 void pci_irq_handler(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);
{
int i;
for (i = 0; i < PCI_NUM_PINS; ++i) {
- qemu_set_irq(dev->irq[i], 0);
+ pci_irq_handler(dev, i, 0);
}
}
return !bus->parent_dev;
}
- void pci_bus_new_inplace(PCIBus *bus, DeviceState *parent,
+ void pci_bus_new_inplace(PCIBus *bus, size_t bus_size, DeviceState *parent,
const char *name,
MemoryRegion *address_space_mem,
MemoryRegion *address_space_io,
uint8_t devfn_min, const char *typename)
{
- qbus_create_inplace(bus, typename, parent, name);
+ qbus_create_inplace(bus, bus_size, typename, parent, name);
pci_bus_init(bus, parent, name, address_space_mem,
address_space_io, devfn_min);
}
return s->parent_dev->config[PCI_SECONDARY_BUS];
}
+ static void pci_bus_finalize(Object *obj)
+ {
+ PCIBus *bus = PCI_BUS(obj);
+ vmstate_unregister(NULL, &vmstate_pcibus, bus);
+ }
+
static int get_pci_config_device(QEMUFile *f, void *pv, size_t size)
{
PCIDevice *s = container_of(pv, PCIDevice, config);
}
pci_dev->bus = bus;
- if (bus->iommu_fn) {
- dma_as = bus->iommu_fn(bus, bus->iommu_opaque, devfn);
- } else {
- /* FIXME: inherit memory region from bus creator */
- dma_as = &address_space_memory;
- }
+ dma_as = pci_device_iommu_address_space(pci_dev);
memory_region_init_alias(&pci_dev->bus_master_enable_region,
OBJECT(pci_dev), "bus master",
pci_dev->config_read = config_read;
pci_dev->config_write = config_write;
bus->devices[devfn] = pci_dev;
- pci_dev->irq = qemu_allocate_irqs(pci_set_irq, pci_dev, PCI_NUM_PINS);
pci_dev->version_id = 2; /* Current pci device vmstate version */
return pci_dev;
}
static void do_pci_unregister_device(PCIDevice *pci_dev)
{
- qemu_free_irqs(pci_dev->irq);
pci_dev->bus->devices[pci_dev->devfn] = NULL;
pci_config_free(pci_dev);
}
new_addr = pci_get_long(d->config + bar) & ~(size - 1);
last_addr = new_addr + size - 1;
- /* NOTE: we have only 64K ioports on PC */
- if (last_addr <= new_addr || new_addr == 0 || last_addr > UINT16_MAX) {
+ /* Check if 32 bit BAR wraps around explicitly.
+ * TODO: make priorities correct and remove this work around.
+ */
+ if (last_addr <= new_addr || new_addr == 0 || last_addr >= UINT32_MAX) {
return PCI_BAR_UNMAPPED;
}
return new_addr;
/* generic PCI irq support */
/* 0 <= irq_num <= 3. level must be 0 or 1 */
- static void pci_set_irq(void *opaque, int irq_num, int level)
+ static void pci_irq_handler(void *opaque, int irq_num, int level)
{
PCIDevice *pci_dev = opaque;
int change;
pci_change_irq_level(pci_dev, irq_num, change);
}
+ static inline int pci_intx(PCIDevice *pci_dev)
+ {
+ return pci_get_byte(pci_dev->config + PCI_INTERRUPT_PIN) - 1;
+ }
+
+ qemu_irq pci_allocate_irq(PCIDevice *pci_dev)
+ {
+ int intx = pci_intx(pci_dev);
+
+ return qemu_allocate_irq(pci_irq_handler, pci_dev, intx);
+ }
+
+ void pci_set_irq(PCIDevice *pci_dev, int level)
+ {
+ int intx = pci_intx(pci_dev);
+ pci_irq_handler(pci_dev, intx, level);
+ }
+
/* Special hooks used by device assignment */
void pci_bus_set_route_irq_fn(PCIBus *bus, pci_route_irq_fn route_intx_to_irq)
{
info->function = PCI_FUNC(dev->devfn);
class = pci_get_word(dev->config + PCI_CLASS_DEVICE);
- info->class_info.class = class;
+ info->class_info.q_class = class;
desc = get_class_desc(class);
if (desc->desc) {
info->class_info.has_desc = true;
return pci_create_simple(bus, -1, "VGA");
case VGA_VMWARE:
return pci_create_simple(bus, -1, "vmware-svga");
+#ifdef CONFIG_MARU
+ case VGA_MARU:
+ return pci_create_simple(bus, -1, "MARU_VGA");
+#endif
case VGA_NONE:
default: /* Other non-PCI types. Checking for unsupported types is already
done in vl.c. */
k->props = pci_props;
}
+ AddressSpace *pci_device_iommu_address_space(PCIDevice *dev)
+ {
+ PCIBus *bus = PCI_BUS(dev->bus);
+
+ if (bus->iommu_fn) {
+ return bus->iommu_fn(bus, bus->iommu_opaque, dev->devfn);
+ }
+
+ if (bus->parent_dev) {
+ /** We are ignoring the bus master DMA bit of the bridge
+ * as it would complicate things such as VFIO for no good reason */
+ return pci_device_iommu_address_space(bus->parent_dev);
+ }
+
+ return &address_space_memory;
+ }
+
void pci_setup_iommu(PCIBus *bus, PCIIOMMUFunc fn, void *opaque)
{
bus->iommu_fn = fn;
bus->iommu_opaque = opaque;
}
+ static void pci_dev_get_w64(PCIBus *b, PCIDevice *dev, void *opaque)
+ {
+ Range *range = opaque;
+ PCIDeviceClass *pc = PCI_DEVICE_GET_CLASS(dev);
+ uint16_t cmd = pci_get_word(dev->config + PCI_COMMAND);
+ int i;
+
+ if (!(cmd & PCI_COMMAND_MEMORY)) {
+ return;
+ }
+
+ if (pc->is_bridge) {
+ pcibus_t base = pci_bridge_get_base(dev, PCI_BASE_ADDRESS_MEM_PREFETCH);
+ pcibus_t limit = pci_bridge_get_limit(dev, PCI_BASE_ADDRESS_MEM_PREFETCH);
+
+ base = MAX(base, 0x1ULL << 32);
+
+ if (limit >= base) {
+ Range pref_range;
+ pref_range.begin = base;
+ pref_range.end = limit + 1;
+ range_extend(range, &pref_range);
+ }
+ }
+ for (i = 0; i < PCI_NUM_REGIONS; ++i) {
+ PCIIORegion *r = &dev->io_regions[i];
+ Range region_range;
+
+ if (!r->size ||
+ (r->type & PCI_BASE_ADDRESS_SPACE_IO) ||
+ !(r->type & PCI_BASE_ADDRESS_MEM_TYPE_64)) {
+ continue;
+ }
+ region_range.begin = pci_bar_address(dev, i, r->type, r->size);
+ region_range.end = region_range.begin + r->size;
+
+ if (region_range.begin == PCI_BAR_UNMAPPED) {
+ continue;
+ }
+
+ region_range.begin = MAX(region_range.begin, 0x1ULL << 32);
+
+ if (region_range.end - 1 >= region_range.begin) {
+ range_extend(range, ®ion_range);
+ }
+ }
+ }
+
+ void pci_bus_get_w64_range(PCIBus *bus, Range *range)
+ {
+ range->begin = range->end = 0;
+ pci_for_each_device_under_bus(bus, pci_dev_get_w64, range);
+ }
+
static const TypeInfo pci_device_type_info = {
.name = TYPE_PCI_DEVICE,
.parent = TYPE_DEVICE,
#include "sysemu/sysemu.h"
#include "sysemu/blockdev.h"
+#ifdef CONFIG_MARU
+#include "../tizen/src/mloop_event.h"
+#endif
+
//#define DEBUG_MSD
#ifdef DEBUG_MSD
}
}
+#ifdef CONFIG_MARU
+static void usb_msd_handle_destroy(USBDevice *dev)
+{
+ mloop_evcmd_set_usbdisk(NULL);
+}
+#endif
+
static void usb_msd_password_cb(void *opaque, int err)
{
MSDState *s = opaque;
usb_desc_create_serial(dev);
usb_desc_init(dev);
- scsi_bus_new(&s->bus, &s->dev.qdev, &usb_msd_scsi_info_storage, NULL);
+ scsi_bus_new(&s->bus, sizeof(s->bus), DEVICE(dev),
+ &usb_msd_scsi_info_storage, NULL);
scsi_dev = scsi_bus_legacy_add_drive(&s->bus, bs, 0, !!s->removable,
s->conf.bootindex, dev->serial,
&err);
usb_desc_create_serial(dev);
usb_desc_init(dev);
- scsi_bus_new(&s->bus, &s->dev.qdev, &usb_msd_scsi_info_bot, NULL);
+ scsi_bus_new(&s->bus, sizeof(s->bus), DEVICE(dev),
+ &usb_msd_scsi_info_bot, NULL);
s->bus.qbus.allow_hotplug = 0;
usb_msd_handle_reset(dev);
QemuOpts *opts;
DriveInfo *dinfo;
USBDevice *dev;
+#ifndef CONFIG_MARU
const char *p1;
char fmt[32];
+#endif
/* parse -usbdevice disk: syntax into drive opts */
snprintf(id, sizeof(id), "usb%d", nr++);
opts = qemu_opts_create(qemu_find_opts("drive"), id, 0, NULL);
-
+#ifndef CONFIG_MARU
p1 = strchr(filename, ':');
if (p1++) {
const char *p2;
}
filename = p1;
}
+#endif
if (!*filename) {
printf("block device specification needed\n");
return NULL;
return NULL;
}
if (qdev_prop_set_drive(&dev->qdev, "drive", dinfo->bdrv) < 0) {
- qdev_free(&dev->qdev);
+ object_unparent(OBJECT(dev));
return NULL;
}
if (qdev_init(&dev->qdev) < 0)
return NULL;
+#ifdef CONFIG_MARU
+ mloop_evcmd_set_usbdisk(dev);
+#endif
+
return dev;
}
uc->handle_reset = usb_msd_handle_reset;
uc->handle_control = usb_msd_handle_control;
uc->handle_data = usb_msd_handle_data;
+#ifdef CONFIG_MARU
+ uc->handle_destroy = usb_msd_handle_destroy;
+#endif
set_bit(DEVICE_CATEGORY_STORAGE, dc->categories);
dc->fw_name = "storage";
dc->vmsd = &vmstate_usb_msd;
--- /dev/null
- qemu_irq_lower(s->dev.pci_dev.irq[0]);
+/*
+ * vigs
+ *
+ * Copyright (c) 2000 - 2013 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Contact:
+ * Stanislav Vorobiov <s.vorobiov@samsung.com>
+ * Jinhyung Jo <jinhyung.jo@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 "vigs_device.h"
+#include "vigs_log.h"
+#include "vigs_server.h"
+#include "vigs_backend.h"
+#include "vigs_regs.h"
+#include "hw/hw.h"
+#include "ui/console.h"
+
+#define PCI_VENDOR_ID_VIGS 0x19B2
+#define PCI_DEVICE_ID_VIGS 0x1011
+
+#define VIGS_IO_SIZE 0x1000
+
+typedef struct VIGSState
+{
+ VIGSDevice dev;
+
+ void *display;
+
+ MemoryRegion vram_bar;
+ uint32_t vram_size;
+
+ MemoryRegion ram_bar;
+ uint32_t ram_size;
+
+ MemoryRegion io_bar;
+
+ struct vigs_server *server;
+
+ /*
+ * Our console.
+ */
+ QemuConsole *con;
+
+ uint32_t reg_int;
+} VIGSState;
+
+#define TYPE_VIGS_DEVICE "vigs"
+
+extern const char *vigs_backend;
+
+static void vigs_update_irq(VIGSState *s)
+{
+ if ((s->reg_int & VIGS_REG_INT_VBLANK_ENABLE) == 0) {
- qemu_irq_raise(s->dev.pci_dev.irq[0]);
++ pci_set_irq(&s->dev.pci_dev, 0);
+ return;
+ }
+
+ if (s->reg_int & VIGS_REG_INT_VBLANK_PENDING) {
- qemu_irq_lower(s->dev.pci_dev.irq[0]);
++ pci_set_irq(&s->dev.pci_dev, 1);
+ } else {
++ pci_set_irq(&s->dev.pci_dev, 0);
+ }
+}
+
+static void vigs_hw_update(void *opaque)
+{
+ VIGSState *s = opaque;
+ DisplaySurface *ds = qemu_console_surface(s->con);
+
+ if (!surface_data(ds)) {
+ return;
+ }
+
+ vigs_server_update_display(s->server);
+
+ dpy_gfx_update(s->con, 0, 0, surface_width(ds), surface_height(ds));
+
+ if (s->reg_int & VIGS_REG_INT_VBLANK_ENABLE) {
+ s->reg_int |= VIGS_REG_INT_VBLANK_PENDING;
+ vigs_update_irq(s);
+ }
+}
+
+static void vigs_hw_invalidate(void *opaque)
+{
+}
+
+static void vigs_dpy_resize(void *user_data,
+ uint32_t width,
+ uint32_t height)
+{
+ VIGSState *s = user_data;
+ DisplaySurface *ds = qemu_console_surface(s->con);
+
+ if ((width != surface_width(ds)) ||
+ (height != surface_height(ds)))
+ {
+ qemu_console_resize(s->con, width, height);
+ }
+}
+
+static uint32_t vigs_dpy_get_stride(void *user_data)
+{
+ VIGSState *s = user_data;
+ DisplaySurface *ds = qemu_console_surface(s->con);
+
+ return surface_stride(ds);
+}
+
+static uint32_t vigs_dpy_get_bpp(void *user_data)
+{
+ VIGSState *s = user_data;
+ DisplaySurface *ds = qemu_console_surface(s->con);
+
+ return surface_bytes_per_pixel(ds);
+}
+
+static uint8_t *vigs_dpy_get_data(void *user_data)
+{
+ VIGSState *s = user_data;
+ DisplaySurface *ds = qemu_console_surface(s->con);
+
+ return surface_data(ds);
+}
+
+static uint64_t vigs_io_read(void *opaque, hwaddr offset,
+ unsigned size)
+{
+ VIGSState *s = opaque;
+
+ switch (offset) {
+ case VIGS_REG_INT:
+ return s->reg_int;
+ default:
+ VIGS_LOG_CRITICAL("Bad register 0x%X read", (uint32_t)offset);
+ break;
+ }
+
+ return 0;
+}
+
+static void vigs_io_write(void *opaque, hwaddr offset,
+ uint64_t value, unsigned size)
+{
+ VIGSState *s = opaque;
+
+ switch (offset) {
+ case VIGS_REG_EXEC:
+ vigs_server_dispatch(s->server, value);
+ break;
+ case VIGS_REG_INT:
+ if (((s->reg_int & VIGS_REG_INT_VBLANK_PENDING) == 0) &&
+ (value & VIGS_REG_INT_VBLANK_PENDING)) {
+ VIGS_LOG_CRITICAL("Attempt to set VBLANK_PENDING");
+ value &= ~VIGS_REG_INT_VBLANK_PENDING;
+ }
+
+ if (((s->reg_int & VIGS_REG_INT_VBLANK_ENABLE) == 0) &&
+ (value & VIGS_REG_INT_VBLANK_ENABLE)) {
+ VIGS_LOG_DEBUG("VBLANK On");
+ } else if (((value & VIGS_REG_INT_VBLANK_ENABLE) == 0) &&
+ (s->reg_int & VIGS_REG_INT_VBLANK_ENABLE)) {
+ VIGS_LOG_DEBUG("VBLANK Off");
+ }
+
+ s->reg_int = value & VIGS_REG_INT_MASK;
+ if ((value & VIGS_REG_INT_VBLANK_ENABLE) == 0) {
+ s->reg_int &= ~VIGS_REG_INT_VBLANK_PENDING;
+ }
+ vigs_update_irq(s);
+ break;
+ default:
+ VIGS_LOG_CRITICAL("Bad register 0x%X write", (uint32_t)offset);
+ break;
+ }
+}
+
+static struct GraphicHwOps vigs_hw_ops =
+{
+ .invalidate = vigs_hw_invalidate,
+ .gfx_update = vigs_hw_update
+};
+
+static const MemoryRegionOps vigs_io_ops =
+{
+ .read = vigs_io_read,
+ .write = vigs_io_write,
+ .endianness = DEVICE_NATIVE_ENDIAN,
+};
+
+static struct vigs_display_ops vigs_dpy_ops =
+{
+ .resize = vigs_dpy_resize,
+ .get_stride = vigs_dpy_get_stride,
+ .get_bpp = vigs_dpy_get_bpp,
+ .get_data = vigs_dpy_get_data,
+};
+
+static int vigs_device_init(PCIDevice *dev)
+{
+ VIGSState *s = DO_UPCAST(VIGSState, dev.pci_dev, dev);
+ struct vigs_backend *backend = NULL;
+
+ vigs_log_init();
+
+ if (s->vram_size < 16 * 1024 * 1024) {
+ VIGS_LOG_WARN("\"vram_size\" is too small, defaulting to 16mb");
+ s->vram_size = 16 * 1024 * 1024;
+ }
+
+ if (s->ram_size < 1 * 1024 * 1024) {
+ VIGS_LOG_WARN("\"ram_size\" is too small, defaulting to 1mb");
+ s->ram_size = 1 * 1024 * 1024;
+ }
+
+ pci_config_set_interrupt_pin(dev->config, 1);
+
+ memory_region_init_ram(&s->vram_bar, OBJECT(s),
+ TYPE_VIGS_DEVICE ".vram",
+ s->vram_size);
+
+ memory_region_init_ram(&s->ram_bar, OBJECT(s),
+ TYPE_VIGS_DEVICE ".ram",
+ s->ram_size);
+
+ memory_region_init_io(&s->io_bar, OBJECT(s),
+ &vigs_io_ops,
+ s,
+ TYPE_VIGS_DEVICE ".io",
+ VIGS_IO_SIZE);
+
+ pci_register_bar(&s->dev.pci_dev, 0, PCI_BASE_ADDRESS_SPACE_MEMORY, &s->vram_bar);
+ pci_register_bar(&s->dev.pci_dev, 1, PCI_BASE_ADDRESS_SPACE_MEMORY, &s->ram_bar);
+ pci_register_bar(&s->dev.pci_dev, 2, PCI_BASE_ADDRESS_SPACE_MEMORY, &s->io_bar);
+
+ if (!strcmp(vigs_backend, "gl")) {
+ backend = vigs_gl_backend_create(s->display);
+ } else if (!strcmp(vigs_backend, "sw")) {
+ backend = vigs_sw_backend_create();
+ }
+
+ if (!backend) {
+ goto fail;
+ }
+
+ s->con = graphic_console_init(DEVICE(dev), &vigs_hw_ops, s);
+
+ if (!s->con) {
+ goto fail;
+ }
+
+ s->server = vigs_server_create(memory_region_get_ram_ptr(&s->vram_bar),
+ memory_region_get_ram_ptr(&s->ram_bar),
+ &vigs_dpy_ops,
+ s,
+ backend);
+
+ if (!s->server) {
+ goto fail;
+ }
+
+ s->dev.wsi = &s->server->wsi;
+
+ VIGS_LOG_INFO("VIGS initialized");
+
+ VIGS_LOG_DEBUG("vram_size = %u", s->vram_size);
+ VIGS_LOG_DEBUG("ram_size = %u", s->ram_size);
+
+ return 0;
+
+fail:
+ if (backend) {
+ backend->destroy(backend);
+ }
+
+ memory_region_destroy(&s->io_bar);
+ memory_region_destroy(&s->ram_bar);
+ memory_region_destroy(&s->vram_bar);
+
+ vigs_log_cleanup();
+
+ return -1;
+}
+
+static void vigs_device_reset(DeviceState *d)
+{
+ VIGSState *s = container_of(d, VIGSState, dev.pci_dev.qdev);
+
+ vigs_server_reset(s->server);
+
+ s->reg_int = 0;
+
+ VIGS_LOG_INFO("VIGS reset");
+}
+
+static void vigs_device_exit(PCIDevice *dev)
+{
+ VIGSState *s = DO_UPCAST(VIGSState, dev.pci_dev, dev);
+
+ vigs_server_destroy(s->server);
+
+ memory_region_destroy(&s->io_bar);
+ memory_region_destroy(&s->ram_bar);
+ memory_region_destroy(&s->vram_bar);
+
+ VIGS_LOG_INFO("VIGS deinitialized");
+
+ vigs_log_cleanup();
+}
+
+static Property vigs_properties[] = {
+ {
+ .name = "display",
+ .info = &qdev_prop_ptr,
+ .offset = offsetof(VIGSState, display),
+ },
+ DEFINE_PROP_UINT32("vram_size", VIGSState, vram_size,
+ 32 * 1024 * 1024),
+ DEFINE_PROP_UINT32("ram_size", VIGSState, ram_size,
+ 1 * 1024 * 1024),
+ DEFINE_PROP_END_OF_LIST(),
+};
+
+static void vigs_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
+
+ k->init = vigs_device_init;
+ k->exit = vigs_device_exit;
+ k->vendor_id = PCI_VENDOR_ID_VIGS;
+ k->device_id = PCI_DEVICE_ID_VIGS;
+ k->class_id = PCI_CLASS_DISPLAY_VGA;
+ dc->reset = vigs_device_reset;
+ dc->props = vigs_properties;
+ dc->desc = "VIGS device";
+}
+
+static TypeInfo vigs_device_info =
+{
+ .name = TYPE_VIGS_DEVICE,
+ .parent = TYPE_PCI_DEVICE,
+ .instance_size = sizeof(VIGSState),
+ .class_init = vigs_class_init,
+};
+
+static void vigs_register_types(void)
+{
+ type_register_static(&vigs_device_info);
+}
+
+type_init(vigs_register_types)
/* HACK for virtio to determine if it's running a big endian guest */
bool virtio_is_big_endian(void);
- static void virtio_pci_bus_new(VirtioBusState *bus, VirtIOPCIProxy *dev);
+ static void virtio_pci_bus_new(VirtioBusState *bus, size_t bus_size,
+ VirtIOPCIProxy *dev);
/* virtio device */
/* DeviceState to VirtIOPCIProxy. For use off data-path. TODO: use QOM. */
if (msix_enabled(&proxy->pci_dev))
msix_notify(&proxy->pci_dev, vector);
else
- qemu_set_irq(proxy->pci_dev.irq[0], proxy->vdev->isr & 1);
+ pci_set_irq(&proxy->pci_dev, proxy->vdev->isr & 1);
}
static void virtio_pci_save_config(DeviceState *d, QEMUFile *f)
/* reading from the ISR also clears it. */
ret = vdev->isr;
vdev->isr = 0;
- qemu_set_irq(proxy->pci_dev.irq[0], 0);
+ pci_irq_deassert(&proxy->pci_dev);
break;
case VIRTIO_MSI_CONFIG_VECTOR:
ret = vdev->config_vector;
VirtQueue *vq = virtio_get_queue(proxy->vdev, queue_no);
EventNotifier *n = virtio_queue_get_guest_notifier(vq);
int ret;
- ret = kvm_irqchip_add_irqfd_notifier(kvm_state, n, irqfd->virq);
+ ret = kvm_irqchip_add_irqfd_notifier(kvm_state, n, NULL, irqfd->virq);
return ret;
}
/* If guest supports masking, keep irqfd but mask it.
* Otherwise, clean it up now.
- */
+ */
if (k->guest_notifier_mask) {
k->guest_notifier_mask(proxy->vdev, queue_no, true);
} else {
static void virtio_9p_pci_instance_init(Object *obj)
{
V9fsPCIState *dev = VIRTIO_9P_PCI(obj);
- object_initialize(OBJECT(&dev->vdev), TYPE_VIRTIO_9P);
+ object_initialize(&dev->vdev, sizeof(dev->vdev), TYPE_VIRTIO_9P);
object_property_add_child(obj, "virtio-backend", OBJECT(&dev->vdev), NULL);
}
{
VirtIOPCIProxy *dev = VIRTIO_PCI(pci_dev);
VirtioPCIClass *k = VIRTIO_PCI_GET_CLASS(pci_dev);
- virtio_pci_bus_new(&dev->bus, dev);
+ virtio_pci_bus_new(&dev->bus, sizeof(dev->bus), dev);
if (k->init != NULL) {
return k->init(dev);
}
static void virtio_blk_pci_instance_init(Object *obj)
{
VirtIOBlkPCI *dev = VIRTIO_BLK_PCI(obj);
- object_initialize(OBJECT(&dev->vdev), TYPE_VIRTIO_BLK);
+ object_initialize(&dev->vdev, sizeof(dev->vdev), TYPE_VIRTIO_BLK);
object_property_add_child(obj, "virtio-backend", OBJECT(&dev->vdev), NULL);
}
static void virtio_scsi_pci_instance_init(Object *obj)
{
VirtIOSCSIPCI *dev = VIRTIO_SCSI_PCI(obj);
- object_initialize(OBJECT(&dev->vdev), TYPE_VIRTIO_SCSI);
+ object_initialize(&dev->vdev, sizeof(dev->vdev), TYPE_VIRTIO_SCSI);
object_property_add_child(obj, "virtio-backend", OBJECT(&dev->vdev), NULL);
}
static void vhost_scsi_pci_instance_init(Object *obj)
{
VHostSCSIPCI *dev = VHOST_SCSI_PCI(obj);
- object_initialize(OBJECT(&dev->vdev), TYPE_VHOST_SCSI);
+ object_initialize(&dev->vdev, sizeof(dev->vdev), TYPE_VHOST_SCSI);
object_property_add_child(obj, "virtio-backend", OBJECT(&dev->vdev), NULL);
}
static void virtio_balloon_pci_instance_init(Object *obj)
{
VirtIOBalloonPCI *dev = VIRTIO_BALLOON_PCI(obj);
- object_initialize(OBJECT(&dev->vdev), TYPE_VIRTIO_BALLOON);
+ object_initialize(&dev->vdev, sizeof(dev->vdev), TYPE_VIRTIO_BALLOON);
object_property_add_child(obj, "virtio-backend", OBJECT(&dev->vdev), NULL);
object_property_add(obj, "guest-stats", "guest statistics",
static void virtio_serial_pci_instance_init(Object *obj)
{
VirtIOSerialPCI *dev = VIRTIO_SERIAL_PCI(obj);
- object_initialize(OBJECT(&dev->vdev), TYPE_VIRTIO_SERIAL);
+ object_initialize(&dev->vdev, sizeof(dev->vdev), TYPE_VIRTIO_SERIAL);
object_property_add_child(obj, "virtio-backend", OBJECT(&dev->vdev), NULL);
}
static void virtio_net_pci_instance_init(Object *obj)
{
VirtIONetPCI *dev = VIRTIO_NET_PCI(obj);
- object_initialize(OBJECT(&dev->vdev), TYPE_VIRTIO_NET);
+ object_initialize(&dev->vdev, sizeof(dev->vdev), TYPE_VIRTIO_NET);
object_property_add_child(obj, "virtio-backend", OBJECT(&dev->vdev), NULL);
}
static void virtio_rng_initfn(Object *obj)
{
VirtIORngPCI *dev = VIRTIO_RNG_PCI(obj);
- object_initialize(OBJECT(&dev->vdev), TYPE_VIRTIO_RNG);
+ object_initialize(&dev->vdev, sizeof(dev->vdev), TYPE_VIRTIO_RNG);
object_property_add_child(obj, "virtio-backend", OBJECT(&dev->vdev), NULL);
object_property_add_link(obj, "rng", TYPE_RNG_BACKEND,
(Object **)&dev->vdev.conf.rng, NULL);
.class_init = virtio_rng_pci_class_init,
};
- object_initialize(OBJECT(&dev->vdev), TYPE_VIRTIO_GL);
+#ifdef CONFIG_MARU
+/* virtio-gl-pci */
+
+static int virtio_gl_pci_init(VirtIOPCIProxy *vpci_dev)
+{
+ VirtIOGLPCI *dev = VIRTIO_GL_PCI(vpci_dev);
+ DeviceState *vdev = DEVICE(&dev->vdev);
+
+ qdev_set_parent_bus(vdev, BUS(&vpci_dev->bus));
+ if (qdev_init(vdev) < 0) {
+ return -1;
+ }
+
+ return 0;
+}
+
+static void virtio_gl_pci_class_init(ObjectClass *klass, void *data)
+{
+ VirtioPCIClass *k = VIRTIO_PCI_CLASS(klass);
+ PCIDeviceClass *pcidev_k = PCI_DEVICE_CLASS(klass);
+
+ k->init = virtio_gl_pci_init;
+ pcidev_k->vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET;
+ pcidev_k->device_id = PCI_DEVICE_ID_VIRTIO_GL;
+ pcidev_k->revision = VIRTIO_PCI_ABI_VERSION;
+ pcidev_k->class_id = PCI_CLASS_OTHERS;
+}
+
+static void virtio_gl_pci_instance_init(Object *obj)
+{
+ VirtIOGLPCI *dev = VIRTIO_GL_PCI(obj);
- object_initialize(OBJECT(&dev->vdev), TYPE_VIRTIO_TOUCHSCREEN);
++ object_initialize(&dev->vdev, sizeof(dev->vdev), TYPE_VIRTIO_GL);
+ object_property_add_child(obj, "virtio-backend", OBJECT(&dev->vdev), NULL);
+}
+
+static TypeInfo virtio_gl_pci_info = {
+ .name = TYPE_VIRTIO_GL_PCI,
+ .parent = TYPE_VIRTIO_PCI,
+ .instance_size = sizeof(VirtIOGLPCI),
+ .instance_init = virtio_gl_pci_instance_init,
+ .class_init = virtio_gl_pci_class_init,
+};
+
+/* virtio-touchscreen-pci */
+
+static int virtio_touchscreen_pci_init(VirtIOPCIProxy *vpci_dev)
+{
+ VirtIOTouchscreenPCI *dev = VIRTIO_TOUCHSCREEN_PCI(vpci_dev);
+ DeviceState *vdev = DEVICE(&dev->vdev);
+
+ qdev_set_parent_bus(vdev, BUS(&vpci_dev->bus));
+ if (qdev_init(vdev) < 0) {
+ return -1;
+ }
+ return 0;
+}
+
+static void virtio_touchscreen_pci_class_init(ObjectClass *klass, void *data)
+{
+// DeviceClass *dc = DEVICE_CLASS(klass);
+ VirtioPCIClass *k = VIRTIO_PCI_CLASS(klass);
+ PCIDeviceClass *pcidev_k = PCI_DEVICE_CLASS(klass);
+
+ k->init = virtio_touchscreen_pci_init;
+ pcidev_k->vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET;
+ pcidev_k->device_id = PCI_DEVICE_ID_VIRTIO_TOUCHSCREEN;
+ pcidev_k->revision = VIRTIO_PCI_ABI_VERSION;
+ pcidev_k->class_id = PCI_CLASS_OTHERS;
+}
+
+static void virtio_touchscreen_pci_instance_init(Object *obj)
+{
+ VirtIOTouchscreenPCI *dev = VIRTIO_TOUCHSCREEN_PCI(obj);
- object_initialize(OBJECT(&dev->vdev), TYPE_VIRTIO_KEYBOARD);
++ object_initialize(&dev->vdev, sizeof(dev->vdev), TYPE_VIRTIO_TOUCHSCREEN);
+ object_property_add_child(obj, "virtio-backend", OBJECT(&dev->vdev), NULL);
+}
+
+static TypeInfo virtio_touchscreen_pci_info = {
+ .name = TYPE_VIRTIO_TOUCHSCREEN_PCI,
+ .parent = TYPE_VIRTIO_PCI,
+ .instance_size = sizeof(VirtIOTouchscreenPCI),
+ .instance_init = virtio_touchscreen_pci_instance_init,
+ .class_init = virtio_touchscreen_pci_class_init,
+};
+
+/* virtio-keyboard-pci */
+
+static int virtio_keyboard_pci_init(VirtIOPCIProxy *vpci_dev)
+{
+ VirtIOKeyboardPCI *dev = VIRTIO_KEYBOARD_PCI(vpci_dev);
+ DeviceState *vdev = DEVICE(&dev->vdev);
+
+ qdev_set_parent_bus(vdev, BUS(&vpci_dev->bus));
+ if (qdev_init(vdev) < 0) {
+ return -1;
+ }
+ return 0;
+}
+
+static void virtio_keyboard_pci_class_init(ObjectClass *klass, void *data)
+{
+// DeviceClass *dc = DEVICE_CLASS(klass);
+ VirtioPCIClass *k = VIRTIO_PCI_CLASS(klass);
+ PCIDeviceClass *pcidev_k = PCI_DEVICE_CLASS(klass);
+
+ k->init = virtio_keyboard_pci_init;
+ pcidev_k->vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET;
+ pcidev_k->device_id = PCI_DEVICE_ID_VIRTIO_KEYBOARD;
+ pcidev_k->revision = VIRTIO_PCI_ABI_VERSION;
+ pcidev_k->class_id = PCI_CLASS_OTHERS;
+}
+
+static void virtio_keyboard_pci_instance_init(Object *obj)
+{
+ VirtIOKeyboardPCI *dev = VIRTIO_KEYBOARD_PCI(obj);
- object_initialize(OBJECT(&dev->vdev), TYPE_VIRTIO_ESM);
++ object_initialize(&dev->vdev, sizeof(dev->vdev), TYPE_VIRTIO_KEYBOARD);
+ object_property_add_child(obj, "virtio-backend", OBJECT(&dev->vdev), NULL);
+}
+
+static TypeInfo virtio_keyboard_pci_info = {
+ .name = TYPE_VIRTIO_KEYBOARD_PCI,
+ .parent = TYPE_VIRTIO_PCI,
+ .instance_size = sizeof(VirtIOKeyboardPCI),
+ .instance_init = virtio_keyboard_pci_instance_init,
+ .class_init = virtio_keyboard_pci_class_init,
+};
+
+/* virtio-esm-pci */
+
+static int virtio_esm_pci_init(VirtIOPCIProxy *vpci_dev)
+{
+ VirtIOESMPCI *dev = VIRTIO_ESM_PCI(vpci_dev);
+ DeviceState *vdev = DEVICE(&dev->vdev);
+
+ qdev_set_parent_bus(vdev, BUS(&vpci_dev->bus));
+ if (qdev_init(vdev) < 0) {
+ return -1;
+ }
+ return 0;
+}
+
+static void virtio_esm_pci_class_init(ObjectClass *klass, void *data)
+{
+// DeviceClass *dc = DEVICE_CLASS(klass);
+ VirtioPCIClass *k = VIRTIO_PCI_CLASS(klass);
+ PCIDeviceClass *pcidev_k = PCI_DEVICE_CLASS(klass);
+
+ k->init = virtio_esm_pci_init;
+ pcidev_k->vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET;
+ pcidev_k->device_id = PCI_DEVICE_ID_VIRTIO_ESM;
+ pcidev_k->revision = VIRTIO_PCI_ABI_VERSION;
+ pcidev_k->class_id = PCI_CLASS_OTHERS;
+}
+
+static void virtio_esm_pci_instance_init(Object *obj)
+{
+ VirtIOESMPCI *dev = VIRTIO_ESM_PCI(obj);
- object_initialize(OBJECT(&dev->vdev), TYPE_VIRTIO_HWKEY);
++ object_initialize(&dev->vdev, sizeof(dev->vdev), TYPE_VIRTIO_ESM);
+ object_property_add_child(obj, "virtio-backend", OBJECT(&dev->vdev), NULL);
+}
+
+static TypeInfo virtio_esm_pci_info = {
+ .name = TYPE_VIRTIO_ESM_PCI,
+ .parent = TYPE_VIRTIO_PCI,
+ .instance_size = sizeof(VirtIOESMPCI),
+ .instance_init = virtio_esm_pci_instance_init,
+ .class_init = virtio_esm_pci_class_init,
+};
+
+/* virtio-hwkey-pci */
+
+static int virtio_hwkey_pci_init(VirtIOPCIProxy *vpci_dev)
+{
+ VirtIOHWKeyPCI *dev = VIRTIO_HWKEY_PCI(vpci_dev);
+ DeviceState *vdev = DEVICE(&dev->vdev);
+
+ qdev_set_parent_bus(vdev, BUS(&vpci_dev->bus));
+ if (qdev_init(vdev) < 0) {
+ return -1;
+ }
+ return 0;
+}
+
+static void virtio_hwkey_pci_class_init(ObjectClass *klass, void *data)
+{
+// DeviceClass *dc = DEVICE_CLASS(klass);
+ VirtioPCIClass *k = VIRTIO_PCI_CLASS(klass);
+ PCIDeviceClass *pcidev_k = PCI_DEVICE_CLASS(klass);
+
+ k->init = virtio_hwkey_pci_init;
+ pcidev_k->vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET;
+ pcidev_k->device_id = PCI_DEVICE_ID_VIRTIO_HWKEY;
+ pcidev_k->revision = VIRTIO_PCI_ABI_VERSION;
+ pcidev_k->class_id = PCI_CLASS_OTHERS;
+}
+
+static void virtio_hwkey_pci_instance_init(Object *obj)
+{
+ VirtIOHWKeyPCI *dev = VIRTIO_HWKEY_PCI(obj);
- object_initialize(OBJECT(&dev->vdev), TYPE_VIRTIO_EVDI);
++ object_initialize(&dev->vdev, sizeof(dev->vdev), TYPE_VIRTIO_HWKEY);
+ object_property_add_child(obj, "virtio-backend", OBJECT(&dev->vdev), NULL);
+}
+
+static TypeInfo virtio_hwkey_pci_info = {
+ .name = TYPE_VIRTIO_HWKEY_PCI,
+ .parent = TYPE_VIRTIO_PCI,
+ .instance_size = sizeof(VirtIOHWKeyPCI),
+ .instance_init = virtio_hwkey_pci_instance_init,
+ .class_init = virtio_hwkey_pci_class_init,
+};
+
+/* virtio-evdi-pci */
+
+static int virtio_evdi_pci_init(VirtIOPCIProxy *vpci_dev)
+{
+ VirtIOEVDIPCI *dev = VIRTIO_EVDI_PCI(vpci_dev);
+ DeviceState *vdev = DEVICE(&dev->vdev);
+
+ qdev_set_parent_bus(vdev, BUS(&vpci_dev->bus));
+ if (qdev_init(vdev) < 0) {
+ return -1;
+ }
+ return 0;
+}
+
+static void virtio_evdi_pci_class_init(ObjectClass *klass, void *data)
+{
+// DeviceClass *dc = DEVICE_CLASS(klass);
+ VirtioPCIClass *k = VIRTIO_PCI_CLASS(klass);
+ PCIDeviceClass *pcidev_k = PCI_DEVICE_CLASS(klass);
+
+ k->init = virtio_evdi_pci_init;
+ pcidev_k->vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET;
+ pcidev_k->device_id = PCI_DEVICE_ID_VIRTIO_EVDI;
+ pcidev_k->revision = VIRTIO_PCI_ABI_VERSION;
+ pcidev_k->class_id = PCI_CLASS_OTHERS;
+}
+
+static void virtio_evdi_pci_instance_init(Object *obj)
+{
+ VirtIOEVDIPCI *dev = VIRTIO_EVDI_PCI(obj);
- object_initialize(OBJECT(&dev->vdev), TYPE_VIRTIO_SENSOR);
++ object_initialize(&dev->vdev, sizeof(dev->vdev), TYPE_VIRTIO_EVDI);
+ object_property_add_child(obj, "virtio-backend", OBJECT(&dev->vdev), NULL);
+}
+
+static TypeInfo virtio_evdi_pci_info = {
+ .name = TYPE_VIRTIO_EVDI_PCI,
+ .parent = TYPE_VIRTIO_PCI,
+ .instance_size = sizeof(VirtIOEVDIPCI),
+ .instance_init = virtio_evdi_pci_instance_init,
+ .class_init = virtio_evdi_pci_class_init,
+};
+
+/* virtio-sensor-pci */
+
+static int virtio_sensor_pci_init(VirtIOPCIProxy *vpci_dev)
+{
+ VirtIOSENSORPCI *dev = VIRTIO_SENSOR_PCI(vpci_dev);
+ DeviceState *vdev = DEVICE(&dev->vdev);
+
+ qdev_set_parent_bus(vdev, BUS(&vpci_dev->bus));
+ if (qdev_init(vdev) < 0) {
+ return -1;
+ }
+ return 0;
+}
+
+static void virtio_sensor_pci_class_init(ObjectClass *klass, void *data)
+{
+ VirtioPCIClass *k = VIRTIO_PCI_CLASS(klass);
+ PCIDeviceClass *pcidev_k = PCI_DEVICE_CLASS(klass);
+
+ k->init = virtio_sensor_pci_init;
+ pcidev_k->vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET;
+ pcidev_k->device_id = PCI_DEVICE_ID_VIRTIO_SENSOR;
+ pcidev_k->revision = VIRTIO_PCI_ABI_VERSION;
+ pcidev_k->class_id = PCI_CLASS_OTHERS;
+}
+
+static void virtio_sensor_pci_instance_init(Object *obj)
+{
+ VirtIOSENSORPCI *dev = VIRTIO_SENSOR_PCI(obj);
- object_initialize(OBJECT(&dev->vdev), TYPE_VIRTIO_NFC);
++ object_initialize(&dev->vdev, sizeof(dev->vdev), TYPE_VIRTIO_SENSOR);
+ object_property_add_child(obj, "virtio-backend", OBJECT(&dev->vdev), NULL);
+}
+
+static TypeInfo virtio_sensor_pci_info = {
+ .name = TYPE_VIRTIO_SENSOR_PCI,
+ .parent = TYPE_VIRTIO_PCI,
+ .instance_size = sizeof(VirtIOSENSORPCI),
+ .instance_init = virtio_sensor_pci_instance_init,
+ .class_init = virtio_sensor_pci_class_init,
+};
+
+/* virtio NFC */
+
+static int virtio_nfc_pci_init(VirtIOPCIProxy *vpci_dev)
+{
+ VirtIONFCPCI *dev = VIRTIO_NFC_PCI(vpci_dev);
+ DeviceState *vdev = DEVICE(&dev->vdev);
+
+ qdev_set_parent_bus(vdev, BUS(&vpci_dev->bus));
+ if (qdev_init(vdev) < 0) {
+ return -1;
+ }
+ return 0;
+}
+
+static void virtio_nfc_pci_class_init(ObjectClass *klass, void *data)
+{
+ VirtioPCIClass *k = VIRTIO_PCI_CLASS(klass);
+ PCIDeviceClass *pcidev_k = PCI_DEVICE_CLASS(klass);
+
+ k->init = virtio_nfc_pci_init;
+ pcidev_k->vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET;
+ pcidev_k->device_id = PCI_DEVICE_ID_VIRTIO_NFC;
+ pcidev_k->revision = VIRTIO_PCI_ABI_VERSION;
+ pcidev_k->class_id = PCI_CLASS_OTHERS;
+}
+
+static void virtio_nfc_pci_instance_init(Object *obj)
+{
+ VirtIONFCPCI *dev = VIRTIO_NFC_PCI(obj);
++ object_initialize(&dev->vdev, sizeof(dev->vdev), TYPE_VIRTIO_NFC);
+ object_property_add_child(obj, "virtio-backend", OBJECT(&dev->vdev), NULL);
+}
+
+static TypeInfo virtio_nfc_pci_info = {
+ .name = TYPE_VIRTIO_NFC_PCI,
+ .parent = TYPE_VIRTIO_PCI,
+ .instance_size = sizeof(VirtIONFCPCI),
+ .instance_init = virtio_nfc_pci_instance_init,
+ .class_init = virtio_nfc_pci_class_init,
+};
+
+
+#endif
+
/* virtio-pci-bus */
- static void virtio_pci_bus_new(VirtioBusState *bus, VirtIOPCIProxy *dev)
+ static void virtio_pci_bus_new(VirtioBusState *bus, size_t bus_size,
+ VirtIOPCIProxy *dev)
{
DeviceState *qdev = DEVICE(dev);
BusState *qbus;
char virtio_bus_name[] = "virtio-bus";
- qbus_create_inplace((BusState *)bus, TYPE_VIRTIO_PCI_BUS, qdev,
+ qbus_create_inplace(bus, bus_size, TYPE_VIRTIO_PCI_BUS, qdev,
virtio_bus_name);
qbus = BUS(bus);
qbus->allow_hotplug = 1;
#ifdef CONFIG_VHOST_SCSI
type_register_static(&vhost_scsi_pci_info);
#endif
+#ifdef CONFIG_MARU
+ type_register_static(&virtio_evdi_pci_info);
+ type_register_static(&virtio_esm_pci_info);
+ type_register_static(&virtio_hwkey_pci_info);
+ type_register_static(&virtio_keyboard_pci_info);
+ type_register_static(&virtio_touchscreen_pci_info);
+ type_register_static(&virtio_gl_pci_info);
+ type_register_static(&virtio_sensor_pci_info);
+ type_register_static(&virtio_nfc_pci_info);
+#endif
}
type_init(virtio_pci_register_types)
sigjmp_buf jmp_env; \
int exception_index; \
\
+ /* for hax */ \
+ int hax_vcpu_dirty; \
+ struct hax_vcpu_state *hax_vcpu; \
+ \
/* user data */ \
void *opaque; \
- \
- const char *cpu_model_str;
#endif
#include "hw/i386/ioapic.h"
#include "qemu/range.h"
+ #include "qemu/bitmap.h"
+ #include "sysemu/sysemu.h"
+ #include "hw/pci/pci.h"
/* PC-style peripherals (also used by other machines). */
Range w64;
} PcPciInfo;
+ #define ACPI_PM_PROP_S3_DISABLED "disable_s3"
+ #define ACPI_PM_PROP_S4_DISABLED "disable_s4"
+ #define ACPI_PM_PROP_S4_VAL "s4_val"
+ #define ACPI_PM_PROP_SCI_INT "sci_int"
+ #define ACPI_PM_PROP_ACPI_ENABLE_CMD "acpi_enable_cmd"
+ #define ACPI_PM_PROP_ACPI_DISABLE_CMD "acpi_disable_cmd"
+ #define ACPI_PM_PROP_PM_IO_BASE "pm_io_base"
+ #define ACPI_PM_PROP_GPE0_BLK "gpe0_blk"
+ #define ACPI_PM_PROP_GPE0_BLK_LEN "gpe0_blk_len"
+
struct PcGuestInfo {
bool has_pci_info;
bool isapc_ram_fw;
+ hwaddr ram_size;
+ unsigned apic_id_limit;
+ bool apic_xrupt_override;
+ uint64_t numa_nodes;
+ uint64_t *node_mem;
+ uint64_t *node_cpu;
FWCfgState *fw_cfg;
+ bool has_acpi_build;
};
/* parallel.c */
void pc_register_ferr_irq(qemu_irq irq);
void pc_acpi_smi_interrupt(void *opaque, int irq, int level);
+#define QEMU_BELOW_4G_RAM_END 0xe0000000
+#define QEMU_BELOW_4G_MMIO_LENGTH ((1ULL << 32) - QEMU_BELOW_4G_RAM_END)
+
void pc_cpus_init(const char *cpu_model, DeviceState *icc_bridge);
void pc_hot_add_cpu(const int64_t id, Error **errp);
void pc_acpi_init(const char *default_dsdt);
MemoryRegion *pci_memory,
MemoryRegion *ram_memory);
+ PCIBus *find_i440fx(void);
/* piix4.c */
extern PCIDevice *piix4_dev;
int piix4_init(PCIBus *bus, ISABus **isa_bus, int devfn);
bool isapc_ram_fw);
/* pvpanic.c */
- void pvpanic_init(ISABus *bus);
+ uint16_t pvpanic_port(void);
/* e820 types */
#define E820_RAM 1
int e820_add_entry(uint64_t, uint64_t, uint32_t);
+ #define PC_COMPAT_1_6 \
+ {\
+ .driver = "e1000",\
+ .property = "mitigation",\
+ .value = "off",\
+ },{\
+ .driver = "qemu64-" TYPE_X86_CPU,\
+ .property = "model",\
+ .value = stringify(2),\
+ },{\
+ .driver = "qemu32-" TYPE_X86_CPU,\
+ .property = "model",\
+ .value = stringify(3),\
+ },{\
+ .driver = "i440FX-pcihost",\
+ .property = "short_root_bus",\
+ .value = stringify(1),\
+ },{\
+ .driver = "q35-pcihost",\
+ .property = "short_root_bus",\
+ .value = stringify(1),\
+ }
+
#define PC_COMPAT_1_5 \
+ PC_COMPAT_1_6, \
{\
.driver = "Conroe-" TYPE_X86_CPU,\
.property = "model",\
.driver = TYPE_X86_CPU,\
.property = "pmu",\
.value = "on",\
+ },{\
+ .driver = "i440FX-pcihost",\
+ .property = "short_root_bus",\
+ .value = stringify(0),\
+ },{\
+ .driver = "q35-pcihost",\
+ .property = "short_root_bus",\
+ .value = stringify(0),\
}
#define PC_COMPAT_1_4 \
.value = stringify(0),\
}
+ #define PC_COMMON_MACHINE_OPTIONS \
+ .default_boot_order = "cad"
+
+ #define PC_DEFAULT_MACHINE_OPTIONS \
+ PC_COMMON_MACHINE_OPTIONS, \
+ .hot_add_cpu = pc_hot_add_cpu, \
+ .max_cpus = 255
+
#endif
int64_t strtosz_suffix_unit(const char *nptr, char **end,
const char default_suffix, int64_t unit);
+ /* used to print char* safely */
+ #define STR_OR_NULL(str) ((str) ? (str) : "null")
+
/* path.c */
void init_paths(const char *prefix);
const char *path(const char *pathname);
*/
int parse_debug_env(const char *name, int max, int initial);
+#if defined(CONFIG_MARU) && defined(CONFIG_WIN32)
+#include "../tizen/src/maru_common.h"
+
+int is_wow64(void);
+bool get_java_path(char **java_path);
+#endif
+
#endif
void select_soundhw(const char *optarg);
void do_acpitable_option(const QemuOpts *opts);
- void do_smbios_option(const char *optarg);
+ void do_smbios_option(QemuOpts *opts);
void cpudef_init(void);
void audio_init(void);
int tcg_available(void);
int kvm_available(void);
int xen_available(void);
+int hax_available(void);
CpuDefinitionInfoList *arch_query_cpu_definitions(Error **errp);
extern bool kvm_irqfds_allowed;
extern bool kvm_msi_via_irqfd_allowed;
extern bool kvm_gsi_routing_allowed;
+ extern bool kvm_gsi_direct_mapping;
extern bool kvm_readonly_mem_allowed;
#if defined CONFIG_KVM || !defined NEED_CPU_H
#define kvm_gsi_routing_enabled() (kvm_gsi_routing_allowed)
/**
+ * kvm_gsi_direct_mapping:
+ *
+ * Returns: true if GSI direct mapping is enabled.
+ */
+ #define kvm_gsi_direct_mapping() (kvm_gsi_direct_mapping)
+
+ /**
* kvm_readonly_mem_enabled:
*
* Returns: true if KVM readonly memory is enabled (ie the kernel
#define kvm_irqfds_enabled() (false)
#define kvm_msi_via_irqfd_enabled() (false)
#define kvm_gsi_routing_allowed() (false)
+ #define kvm_gsi_direct_mapping() (false)
#define kvm_readonly_mem_enabled() (false)
#endif
#ifdef NEED_CPU_H
- #if !defined(CONFIG_USER_ONLY)
- void *kvm_ram_alloc(ram_addr_t size);
- void *kvm_arch_ram_alloc(ram_addr_t size);
- #endif
-
void kvm_setup_guest_memory(void *start, size_t size);
void kvm_flush_coalesced_mmio_buffer(void);
uint32_t kvm_arch_get_supported_cpuid(KVMState *env, uint32_t function,
uint32_t index, int reg);
- void kvm_cpu_synchronize_state(CPUState *cpu);
-
- #ifdef CONFIG_HAX
- void hax_cpu_synchronize_state(CPUState *cpu);
- #endif
-
- /* generic hooks - to be moved/refactored once there are more users */
-
- static inline void cpu_synchronize_state(CPUState *cpu)
- {
- if (kvm_enabled()) {
- kvm_cpu_synchronize_state(cpu);
- }
- #ifdef CONFIG_HAX
- hax_cpu_synchronize_state(cpu);
- #endif
- }
-
#if !defined(CONFIG_USER_ONLY)
int kvm_physical_memory_addr_from_host(KVMState *s, void *ram_addr,
hwaddr *phys_addr);
#endif /* NEED_CPU_H */
+ void kvm_cpu_synchronize_state(CPUState *cpu);
void kvm_cpu_synchronize_post_reset(CPUState *cpu);
void kvm_cpu_synchronize_post_init(CPUState *cpu);
+#ifdef CONFIG_HAX
+void hax_cpu_synchronize_post_reset(CPUArchState *env);
+void hax_cpu_synchronize_post_init(CPUArchState *env);
+#endif
+ /* generic hooks - to be moved/refactored once there are more users */
+
+ static inline void cpu_synchronize_state(CPUState *cpu)
+ {
+ if (kvm_enabled()) {
+ kvm_cpu_synchronize_state(cpu);
+ }
+ }
+
static inline void cpu_synchronize_post_reset(CPUState *cpu)
{
if (kvm_enabled()) {
kvm_cpu_synchronize_post_reset(cpu);
}
+#ifdef CONFIG_HAX
+ CPUArchState *env = cpu->env_ptr;
+ hax_cpu_synchronize_post_reset(env);
+#endif
}
static inline void cpu_synchronize_post_init(CPUState *cpu)
if (kvm_enabled()) {
kvm_cpu_synchronize_post_init(cpu);
}
+#ifdef CONFIG_HAX
+ CPUArchState *env = cpu->env_ptr;
+ hax_cpu_synchronize_post_init(env);
+#endif
}
int kvm_irqchip_add_msi_route(KVMState *s, MSIMessage msg);
int kvm_irqchip_update_msi_route(KVMState *s, int virq, MSIMessage msg);
void kvm_irqchip_release_virq(KVMState *s, int virq);
- int kvm_irqchip_add_irqfd_notifier(KVMState *s, EventNotifier *n, int virq);
+ int kvm_irqchip_add_irqfd_notifier(KVMState *s, EventNotifier *n,
+ EventNotifier *rn, int virq);
int kvm_irqchip_remove_irqfd_notifier(KVMState *s, EventNotifier *n, int virq);
void kvm_pc_gsi_handler(void *opaque, int n, int level);
void kvm_pc_setup_irq_routing(bool pci_enabled);
extern const char *qemu_name;
extern uint8_t qemu_uuid[];
+ extern bool qemu_uuid_set;
int qemu_uuid_parse(const char *str, uint8_t *uuid);
+
#define UUID_FMT "%02hhx%02hhx%02hhx%02hhx-%02hhx%02hhx-%02hhx%02hhx-%02hhx%02hhx-%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx"
+ #define UUID_NONE "00000000-0000-0000-0000-000000000000"
bool runstate_check(RunState state);
void runstate_set(RunState new_state);
DT_SDL,
DT_GTK,
DT_NOGRAPHIC,
+#ifdef CONFIG_MARU
+ DT_MARU,
+#endif
DT_NONE,
} DisplayType;
typedef enum {
VGA_NONE, VGA_STD, VGA_CIRRUS, VGA_VMWARE, VGA_XENFB, VGA_QXL,
+#ifdef CONFIG_MARU
+ VGA_MARU,
+#endif
} VGAInterfaceType;
extern int vga_interface_type;
#define xenfb_enabled (vga_interface_type == VGA_XENFB)
+#ifdef CONFIG_MARU
+#define maru_vga_enabled (vga_interface_type == VGA_MARU)
+#endif
extern int graphic_width;
extern int graphic_height;
extern uint8_t *boot_splash_filedata;
extern size_t boot_splash_filedata_size;
extern uint8_t qemu_extra_params_fw[2];
- extern QEMUClock *rtc_clock;
+ extern QEMUClockType rtc_clock;
#define MAX_NODES 64
#define MAX_CPUMASK_BITS 255
extern unsigned int nb_prom_envs;
/* pci-hotplug */
+#ifdef CONFIG_MARU
+PCIDevice *do_pci_device_hot_add(Monitor *mon, const QDict *qdict);
+#endif
void pci_device_hot_add(Monitor *mon, const QDict *qdict);
+
int pci_drive_hot_add(Monitor *mon, const QDict *qdict, DriveInfo *dinfo);
void do_pci_device_hot_remove(Monitor *mon, const QDict *qdict);
bool usb_enabled(bool default_usb);
+ extern QemuOptsList qemu_legacy_drive_opts;
+ extern QemuOptsList qemu_common_drive_opts;
extern QemuOptsList qemu_drive_opts;
extern QemuOptsList qemu_chardev_opts;
extern QemuOptsList qemu_device_opts;
#include "qemu/main-loop.h"
#include "block/aio.h"
+#include "sysemu/hax.h"
+
#ifndef _WIN32
#include "qemu/compatfd.h"
return qemu_aio_context;
}
+#ifdef CONFIG_HAX
+static void qemu_notify_hax_event(void)
+{
+ CPUArchState *env = NULL;
+
+ if (hax_enabled()) {
+ for (env = first_cpu; env != NULL; env = env->next_cpu) {
+ hax_raise_event(env);
+ }
+ }
+}
+#endif
+
void qemu_notify_event(void)
{
if (!qemu_aio_context) {
return;
}
+#ifdef CONFIG_HAX
+ qemu_notify_hax_event();
+#endif
aio_notify(qemu_aio_context);
}
GSource *src;
init_clocks();
- if (init_timer_alarm() < 0) {
- fprintf(stderr, "could not initialize alarm timer\n");
- exit(1);
- }
ret = qemu_signal_init();
if (ret) {
static int glib_pollfds_idx;
static int glib_n_poll_fds;
- static void glib_pollfds_fill(uint32_t *cur_timeout)
+ static void glib_pollfds_fill(int64_t *cur_timeout)
{
GMainContext *context = g_main_context_default();
int timeout = 0;
+ int64_t timeout_ns;
int n;
g_main_context_prepare(context, &max_priority);
glib_n_poll_fds);
} while (n != glib_n_poll_fds);
- if (timeout >= 0 && timeout < *cur_timeout) {
- *cur_timeout = timeout;
+ if (timeout < 0) {
+ timeout_ns = -1;
+ } else {
+ timeout_ns = (int64_t)timeout * (int64_t)SCALE_MS;
}
+
+ *cur_timeout = qemu_soonest_timeout(timeout_ns, *cur_timeout);
}
static void glib_pollfds_poll(void)
#define MAX_MAIN_LOOP_SPIN (1000)
- static int os_host_main_loop_wait(uint32_t timeout)
+ static int os_host_main_loop_wait(int64_t timeout)
{
int ret;
static int spin_counter;
* print a message to the screen. If we run into this condition, create
* a fake timeout in order to give the VCPU threads a chance to run.
*/
- if (spin_counter > MAX_MAIN_LOOP_SPIN) {
+ if (!timeout && (spin_counter > MAX_MAIN_LOOP_SPIN)) {
static bool notified;
if (!notified) {
notified = true;
}
- timeout = 1;
+ timeout = SCALE_MS;
}
- if (timeout > 0) {
+ if (timeout) {
spin_counter = 0;
qemu_mutex_unlock_iothread();
} else {
spin_counter++;
}
- ret = g_poll((GPollFD *)gpollfds->data, gpollfds->len, timeout);
+ ret = qemu_poll_ns((GPollFD *)gpollfds->data, gpollfds->len, timeout);
- if (timeout > 0) {
+ if (timeout) {
qemu_mutex_lock_iothread();
}
}
}
- static int os_host_main_loop_wait(uint32_t timeout)
+ static int os_host_main_loop_wait(int64_t timeout)
{
GMainContext *context = g_main_context_default();
GPollFD poll_fds[1024 * 2]; /* this is probably overkill */
PollingEntry *pe;
WaitObjects *w = &wait_objects;
gint poll_timeout;
+ int64_t poll_timeout_ns;
static struct timeval tv0;
fd_set rfds, wfds, xfds;
int nfds;
poll_fds[n_poll_fds + i].events = G_IO_IN;
}
- if (poll_timeout < 0 || timeout < poll_timeout) {
- poll_timeout = timeout;
+ if (poll_timeout < 0) {
+ poll_timeout_ns = -1;
+ } else {
+ poll_timeout_ns = (int64_t)poll_timeout * (int64_t)SCALE_MS;
}
+ poll_timeout_ns = qemu_soonest_timeout(poll_timeout_ns, timeout);
+
qemu_mutex_unlock_iothread();
- g_poll_ret = g_poll(poll_fds, n_poll_fds + w->num, poll_timeout);
+ g_poll_ret = qemu_poll_ns(poll_fds, n_poll_fds + w->num, poll_timeout_ns);
+
qemu_mutex_lock_iothread();
if (g_poll_ret > 0) {
for (i = 0; i < w->num; i++) {
{
int ret;
uint32_t timeout = UINT32_MAX;
+ int64_t timeout_ns;
if (nonblocking) {
timeout = 0;
g_array_set_size(gpollfds, 0); /* reset for new iteration */
/* XXX: separate device handlers from system ones */
#ifdef CONFIG_SLIRP
- slirp_update_timeout(&timeout);
- slirp_pollfds_fill(gpollfds);
+ slirp_pollfds_fill(gpollfds, &timeout);
#endif
qemu_iohandler_fill(gpollfds);
- ret = os_host_main_loop_wait(timeout);
+
+ if (timeout == UINT32_MAX) {
+ timeout_ns = -1;
+ } else {
+ timeout_ns = (uint64_t)timeout * (int64_t)(SCALE_MS);
+ }
+
+ timeout_ns = qemu_soonest_timeout(timeout_ns,
+ timerlistgroup_deadline_ns(
+ &main_loop_tlg));
+
+ ret = os_host_main_loop_wait(timeout_ns);
qemu_iohandler_poll(gpollfds, ret);
#ifdef CONFIG_SLIRP
slirp_pollfds_poll(gpollfds, (ret < 0));
#endif
- qemu_run_all_timers();
+ qemu_clock_run_all_timers();
return ret;
}
void qemu_aio_set_fd_handler(int fd,
IOHandler *io_read,
IOHandler *io_write,
- AioFlushHandler *io_flush,
void *opaque)
{
- aio_set_fd_handler(qemu_aio_context, fd, io_read, io_write, io_flush,
- opaque);
+ aio_set_fd_handler(qemu_aio_context, fd, io_read, io_write, opaque);
}
#endif
void qemu_aio_set_event_notifier(EventNotifier *notifier,
- EventNotifierHandler *io_read,
- AioFlushEventNotifierHandler *io_flush)
+ EventNotifierHandler *io_read)
{
- aio_set_event_notifier(qemu_aio_context, notifier, io_read, io_flush);
+ aio_set_event_notifier(qemu_aio_context, notifier, io_read);
}
'vm-clock-sec': 'int', 'vm-clock-nsec': 'int' } }
##
+ # @ImageInfoSpecificQCow2:
+ #
+ # @compat: compatibility level
+ #
+ # @lazy-refcounts: #optional on or off; only valid for compat >= 1.1
+ #
+ # Since: 1.7
+ ##
+ { 'type': 'ImageInfoSpecificQCow2',
+ 'data': {
+ 'compat': 'str',
+ '*lazy-refcounts': 'bool'
+ } }
+
+ ##
+ # @ImageInfoSpecificVmdk:
+ #
+ # @create-type: The create type of VMDK image
+ #
+ # @cid: Content id of image
+ #
+ # @parent-cid: Parent VMDK image's cid
+ #
+ # @extents: List of extent files
+ #
+ # Since: 1.7
+ ##
+ { 'type': 'ImageInfoSpecificVmdk',
+ 'data': {
+ 'create-type': 'str',
+ 'cid': 'int',
+ 'parent-cid': 'int',
+ 'extents': ['ImageInfo']
+ } }
+
+ ##
+ # @ImageInfoSpecific:
+ #
+ # A discriminated record of image format specific information structures.
+ #
+ # Since: 1.7
+ ##
+
+ { 'union': 'ImageInfoSpecific',
+ 'data': {
+ 'qcow2': 'ImageInfoSpecificQCow2',
+ 'vmdk': 'ImageInfoSpecificVmdk'
+ } }
+
+ ##
# @ImageInfo:
#
# Information about a QEMU image file
#
# @encrypted: #optional true if the image is encrypted
#
+ # @compressed: #optional true if the image is compressed (Since 1.7)
+ #
# @backing-filename: #optional name of the backing file
#
# @full-backing-filename: #optional full path of the backing file
#
# @backing-image: #optional info of the backing image (since 1.6)
#
+ # @format-specific: #optional structure supplying additional format-specific
+ # information (since 1.7)
+ #
# Since: 1.3
#
##
{ 'type': 'ImageInfo',
'data': {'filename': 'str', 'format': 'str', '*dirty-flag': 'bool',
'*actual-size': 'int', 'virtual-size': 'int',
- '*cluster-size': 'int', '*encrypted': 'bool',
+ '*cluster-size': 'int', '*encrypted': 'bool', '*compressed': 'bool',
'*backing-filename': 'str', '*full-backing-filename': 'str',
'*backing-filename-format': 'str', '*snapshots': ['SnapshotInfo'],
- '*backing-image': 'ImageInfo' } }
+ '*backing-image': 'ImageInfo',
+ '*format-specific': 'ImageInfoSpecific' } }
##
# @ImageCheck:
#
# @image: the info of image used (since: 1.6)
#
+ # @bps_max: #optional total max in bytes (Since 1.7)
+ #
+ # @bps_rd_max: #optional read max in bytes (Since 1.7)
+ #
+ # @bps_wr_max: #optional write max in bytes (Since 1.7)
+ #
+ # @iops_max: #optional total I/O operations max (Since 1.7)
+ #
+ # @iops_rd_max: #optional read I/O operations max (Since 1.7)
+ #
+ # @iops_wr_max: #optional write I/O operations max (Since 1.7)
+ #
+ # @iops_size: #optional an I/O size in bytes (Since 1.7)
+ #
# Since: 0.14.0
#
# Notes: This interface is only found in @BlockInfo.
'encrypted': 'bool', 'encryption_key_missing': 'bool',
'bps': 'int', 'bps_rd': 'int', 'bps_wr': 'int',
'iops': 'int', 'iops_rd': 'int', 'iops_wr': 'int',
- 'image': 'ImageInfo' } }
+ 'image': 'ImageInfo',
+ '*bps_max': 'int', '*bps_rd_max': 'int',
+ '*bps_wr_max': 'int', '*iops_max': 'int',
+ '*iops_rd_max': 'int', '*iops_wr_max': 'int',
+ '*iops_size': 'int' } }
##
# @BlockDeviceIoStatus:
{ 'enum': 'BlockDeviceIoStatus', 'data': [ 'ok', 'failed', 'nospace' ] }
##
+ # @BlockDeviceMapEntry:
+ #
+ # Entry in the metadata map of the device (returned by "qemu-img map")
+ #
+ # @start: Offset in the image of the first byte described by this entry
+ # (in bytes)
+ #
+ # @length: Length of the range described by this entry (in bytes)
+ #
+ # @depth: Number of layers (0 = top image, 1 = top image's backing file, etc.)
+ # before reaching one for which the range is allocated. The value is
+ # in the range 0 to the depth of the image chain - 1.
+ #
+ # @zero: the sectors in this range read as zeros
+ #
+ # @data: reading the image will actually read data from a file (in particular,
+ # if @offset is present this means that the sectors are not simply
+ # preallocated, but contain actual data in raw format)
+ #
+ # @offset: if present, the image file stores the data for this range in
+ # raw format at the given offset.
+ #
+ # Since 1.7
+ ##
+ { 'type': 'BlockDeviceMapEntry',
+ 'data': { 'start': 'int', 'length': 'int', 'depth': 'int', 'zero': 'bool',
+ 'data': 'bool', '*offset': 'int' } }
+
+ ##
# @BlockDirtyInfo:
#
# Block dirty bitmap information.
'data': ['top', 'full', 'none'] }
##
+ # @BlockJobType:
+ #
+ # Type of a block job.
+ #
+ # @commit: block commit job type, see "block-commit"
+ #
+ # @stream: block stream job type, see "block-stream"
+ #
+ # @mirror: drive mirror job type, see "drive-mirror"
+ #
+ # @backup: drive backup job type, see "drive-backup"
+ #
+ # Since: 1.7
+ ##
+ { 'enum': 'BlockJobType',
+ 'data': ['commit', 'stream', 'mirror', 'backup'] }
+
+ ##
# @BlockJobInfo:
#
# Information about a long-running block device operation.
# @existing: QEMU should look for an existing image file.
#
# @absolute-paths: QEMU should create a new image with absolute paths
- # for the backing file.
+ # for the backing file. If there is no backing file available, the new
+ # image will not be backed either.
#
# Since: 1.1
##
'*mode': 'NewImageMode' } }
##
+ # @BlockdevSnapshotInternal
+ #
+ # @device: the name of the device to generate the snapshot from
+ #
+ # @name: the name of the internal snapshot to be created
+ #
+ # Notes: In transaction, if @name is empty, or any snapshot matching @name
+ # exists, the operation will fail. Only some image formats support it,
+ # for example, qcow2, rbd, and sheepdog.
+ #
+ # Since: 1.7
+ ##
+ { 'type': 'BlockdevSnapshotInternal',
+ 'data': { 'device': 'str', 'name': 'str' } }
+
+ ##
# @DriveBackup
#
# @device: the name of the device which should be copied.
'data': {
'blockdev-snapshot-sync': 'BlockdevSnapshot',
'drive-backup': 'DriveBackup',
- 'abort': 'Abort'
+ 'abort': 'Abort',
+ 'blockdev-snapshot-internal-sync': 'BlockdevSnapshotInternal'
} }
##
'data': 'BlockdevSnapshot' }
##
+ # @blockdev-snapshot-internal-sync
+ #
+ # Synchronously take an internal snapshot of a block device, when the format
+ # of the image used supports it.
+ #
+ # For the arguments, see the documentation of BlockdevSnapshotInternal.
+ #
+ # Returns: nothing on success
+ # If @device is not a valid block device, DeviceNotFound
+ # If any snapshot matching @name exists, or @name is empty,
+ # GenericError
+ # If the format of the image used does not support it,
+ # BlockFormatFeatureNotSupported
+ #
+ # Since 1.7
+ ##
+ { 'command': 'blockdev-snapshot-internal-sync',
+ 'data': 'BlockdevSnapshotInternal' }
+
+ ##
+ # @blockdev-snapshot-delete-internal-sync
+ #
+ # Synchronously delete an internal snapshot of a block device, when the format
+ # of the image used support it. The snapshot is identified by name or id or
+ # both. One of the name or id is required. Return SnapshotInfo for the
+ # successfully deleted snapshot.
+ #
+ # @device: the name of the device to delete the snapshot from
+ #
+ # @id: optional the snapshot's ID to be deleted
+ #
+ # @name: optional the snapshot's name to be deleted
+ #
+ # Returns: SnapshotInfo on success
+ # If @device is not a valid block device, DeviceNotFound
+ # If snapshot not found, GenericError
+ # If the format of the image used does not support it,
+ # BlockFormatFeatureNotSupported
+ # If @id and @name are both not specified, GenericError
+ #
+ # Since 1.7
+ ##
+ { 'command': 'blockdev-snapshot-delete-internal-sync',
+ 'data': { 'device': 'str', '*id': 'str', '*name': 'str'},
+ 'returns': 'SnapshotInfo' }
+
+ ##
# @human-monitor-command:
#
# Execute a command on the human monitor and return the output.
#
# Since: 0.14.0
#
- # Notes: This command only exists as a stop-gap. It's use is highly
+ # Notes: This command only exists as a stop-gap. Its use is highly
# discouraged. The semantics of this command are not guaranteed.
#
# Known limitations:
#
# @iops_wr: write I/O operations per second
#
+ # @bps_max: #optional total max in bytes (Since 1.7)
+ #
+ # @bps_rd_max: #optional read max in bytes (Since 1.7)
+ #
+ # @bps_wr_max: #optional write max in bytes (Since 1.7)
+ #
+ # @iops_max: #optional total I/O operations max (Since 1.7)
+ #
+ # @iops_rd_max: #optional read I/O operations max (Since 1.7)
+ #
+ # @iops_wr_max: #optional write I/O operations max (Since 1.7)
+ #
+ # @iops_size: #optional an I/O size in bytes (Since 1.7)
+ #
# Returns: Nothing on success
# If @device is not a valid block device, DeviceNotFound
#
##
{ 'command': 'block_set_io_throttle',
'data': { 'device': 'str', 'bps': 'int', 'bps_rd': 'int', 'bps_wr': 'int',
- 'iops': 'int', 'iops_rd': 'int', 'iops_wr': 'int' } }
+ 'iops': 'int', 'iops_rd': 'int', 'iops_wr': 'int',
+ '*bps_max': 'int', '*bps_rd_max': 'int',
+ '*bps_wr_max': 'int', '*iops_max': 'int',
+ '*iops_rd_max': 'int', '*iops_wr_max': 'int',
+ '*iops_size': 'int' } }
##
# @block-stream:
##
{ 'command': 'query-target', 'returns': 'TargetInfo' }
+## Eric 2013.3.7 ##
+
+##
+# @AccelInfo:
+#
+# Information describing the acceleration sensor value
+#
+# @Xaxis: x axis value of the acceleration sensor
+# @Yaxis: y axis value of the acceleration sensor
+# @Zaxis: z axis value of the acceleration sensor
+#
+# Since: 1.2.0
+##
+{ 'type': 'AccelInfo',
+ 'data': { 'Xaxis': 'int', 'Yaxis': 'int', 'Zaxis' : 'int'} }
+
##
# @QKeyCode:
#
##
{ 'command': 'query-rx-filter', 'data': { '*name': 'str' },
'returns': ['RxFilterInfo'] }
+
+
+ ##
+ # @BlockdevDiscardOptions
+ #
+ # Determines how to handle discard requests.
+ #
+ # @ignore: Ignore the request
+ # @unmap: Forward as an unmap request
+ #
+ # Since: 1.7
+ ##
+ { 'enum': 'BlockdevDiscardOptions',
+ 'data': [ 'ignore', 'unmap' ] }
+
+ ##
+ # @BlockdevAioOptions
+ #
+ # Selects the AIO backend to handle I/O requests
+ #
+ # @threads: Use qemu's thread pool
+ # @native: Use native AIO backend (only Linux and Windows)
+ #
+ # Since: 1.7
+ ##
+ { 'enum': 'BlockdevAioOptions',
+ 'data': [ 'threads', 'native' ] }
+
+ ##
+ # @BlockdevCacheOptions
+ #
+ # Includes cache-related options for block devices
+ #
+ # @writeback: #optional enables writeback mode for any caches (default: true)
+ # @direct: #optional enables use of O_DIRECT (bypass the host page cache;
+ # default: false)
+ # @no-flush: #optional ignore any flush requests for the device (default:
+ # false)
+ #
+ # Since: 1.7
+ ##
+ { 'type': 'BlockdevCacheOptions',
+ 'data': { '*writeback': 'bool',
+ '*direct': 'bool',
+ '*no-flush': 'bool' } }
+
+ ##
+ # @BlockdevOptionsBase
+ #
+ # Options that are available for all block devices, independent of the block
+ # driver.
+ #
+ # @driver: block driver name
+ # @id: #optional id by which the new block device can be referred to.
+ # This is a required option on the top level of blockdev-add, and
+ # currently not allowed on any other level.
+ # @discard: #optional discard-related options (default: ignore)
+ # @cache: #optional cache-related options
+ # @aio: #optional AIO backend (default: threads)
+ # @rerror: #optional how to handle read errors on the device
+ # (default: report)
+ # @werror: #optional how to handle write errors on the device
+ # (default: enospc)
+ # @read-only: #optional whether the block device should be read-only
+ # (default: false)
+ #
+ # Since: 1.7
+ ##
+ { 'type': 'BlockdevOptionsBase',
+ 'data': { 'driver': 'str',
+ '*id': 'str',
+ '*discard': 'BlockdevDiscardOptions',
+ '*cache': 'BlockdevCacheOptions',
+ '*aio': 'BlockdevAioOptions',
+ '*rerror': 'BlockdevOnError',
+ '*werror': 'BlockdevOnError',
+ '*read-only': 'bool' } }
+
+ ##
+ # @BlockdevOptionsFile
+ #
+ # Driver specific block device options for the file backend and similar
+ # protocols.
+ #
+ # @filename: path to the image file
+ #
+ # Since: 1.7
+ ##
+ { 'type': 'BlockdevOptionsFile',
+ 'data': { 'filename': 'str' } }
+
+ ##
+ # @BlockdevOptionsVVFAT
+ #
+ # Driver specific block device options for the vvfat protocol.
+ #
+ # @dir: directory to be exported as FAT image
+ # @fat-type: #optional FAT type: 12, 16 or 32
+ # @floppy: #optional whether to export a floppy image (true) or
+ # partitioned hard disk (false; default)
+ # @rw: #optional whether to allow write operations (default: false)
+ #
+ # Since: 1.7
+ ##
+ { 'type': 'BlockdevOptionsVVFAT',
+ 'data': { 'dir': 'str', '*fat-type': 'int', '*floppy': 'bool',
+ '*rw': 'bool' } }
+
+ ##
+ # @BlockdevOptionsGenericFormat
+ #
+ # Driver specific block device options for image format that have no option
+ # besides their data source.
+ #
+ # @file: reference to or definition of the data source block device
+ #
+ # Since: 1.7
+ ##
+ { 'type': 'BlockdevOptionsGenericFormat',
+ 'data': { 'file': 'BlockdevRef' } }
+
+ ##
+ # @BlockdevOptionsGenericCOWFormat
+ #
+ # Driver specific block device options for image format that have no option
+ # besides their data source and an optional backing file.
+ #
+ # @backing: #optional reference to or definition of the backing file block
+ # device (if missing, taken from the image file content). It is
+ # allowed to pass an empty string here in order to disable the
+ # default backing file.
+ #
+ # Since: 1.7
+ ##
+ { 'type': 'BlockdevOptionsGenericCOWFormat',
+ 'base': 'BlockdevOptionsGenericFormat',
+ 'data': { '*backing': 'BlockdevRef' } }
+
+ ##
+ # @BlockdevOptionsQcow2
+ #
+ # Driver specific block device options for qcow2.
+ #
+ # @lazy-refcounts: #optional whether to enable the lazy refcounts
+ # feature (default is taken from the image file)
+ #
+ # @pass-discard-request: #optional whether discard requests to the qcow2
+ # device should be forwarded to the data source
+ #
+ # @pass-discard-snapshot: #optional whether discard requests for the data source
+ # should be issued when a snapshot operation (e.g.
+ # deleting a snapshot) frees clusters in the qcow2 file
+ #
+ # @pass-discard-other: #optional whether discard requests for the data source
+ # should be issued on other occasions where a cluster
+ # gets freed
+ #
+ # Since: 1.7
+ ##
+ { 'type': 'BlockdevOptionsQcow2',
+ 'base': 'BlockdevOptionsGenericCOWFormat',
+ 'data': { '*lazy-refcounts': 'bool',
+ '*pass-discard-request': 'bool',
+ '*pass-discard-snapshot': 'bool',
+ '*pass-discard-other': 'bool' } }
+
+ ##
+ # @BlockdevOptions
+ #
+ # Options for creating a block device.
+ #
+ # Since: 1.7
+ ##
+ { 'union': 'BlockdevOptions',
+ 'base': 'BlockdevOptionsBase',
+ 'discriminator': 'driver',
+ 'data': {
+ 'file': 'BlockdevOptionsFile',
+ 'http': 'BlockdevOptionsFile',
+ 'https': 'BlockdevOptionsFile',
+ 'ftp': 'BlockdevOptionsFile',
+ 'ftps': 'BlockdevOptionsFile',
+ 'tftp': 'BlockdevOptionsFile',
+ # TODO gluster: Wait for structured options
+ # TODO iscsi: Wait for structured options
+ # TODO nbd: Should take InetSocketAddress for 'host'?
+ # TODO rbd: Wait for structured options
+ # TODO sheepdog: Wait for structured options
+ # TODO ssh: Should take InetSocketAddress for 'host'?
+ 'vvfat': 'BlockdevOptionsVVFAT',
+
+ # TODO blkdebug: Wait for structured options
+ # TODO blkverify: Wait for structured options
+
+ 'bochs': 'BlockdevOptionsGenericFormat',
+ 'cloop': 'BlockdevOptionsGenericFormat',
+ 'cow': 'BlockdevOptionsGenericCOWFormat',
+ 'dmg': 'BlockdevOptionsGenericFormat',
+ 'parallels': 'BlockdevOptionsGenericFormat',
+ 'qcow': 'BlockdevOptionsGenericCOWFormat',
+ 'qcow2': 'BlockdevOptionsQcow2',
+ 'qed': 'BlockdevOptionsGenericCOWFormat',
+ 'raw': 'BlockdevOptionsGenericFormat',
+ 'vdi': 'BlockdevOptionsGenericFormat',
+ 'vhdx': 'BlockdevOptionsGenericFormat',
+ 'vmdk': 'BlockdevOptionsGenericCOWFormat',
+ 'vpc': 'BlockdevOptionsGenericFormat'
+ } }
+
+ ##
+ # @BlockdevRef
+ #
+ # Reference to a block device.
+ #
+ # @definition: defines a new block device inline
+ # @reference: references the ID of an existing block device. An
+ # empty string means that no block device should be
+ # referenced.
+ #
+ # Since: 1.7
+ ##
+ { 'union': 'BlockdevRef',
+ 'discriminator': {},
+ 'data': { 'definition': 'BlockdevOptions',
+ 'reference': 'str' } }
+
+ ##
+ # @blockdev-add:
+ #
+ # Creates a new block device.
+ #
+ # @options: block device options for the new device
+ #
+ # Since: 1.7
+ ##
+ { 'command': 'blockdev-add', 'data': { 'options': 'BlockdevOptions' } }
va_end(ap);
}
+ static void remove_fd_in_watch(CharDriverState *chr);
+
void qemu_chr_add_handlers(CharDriverState *s,
IOCanReadHandler *fd_can_read,
IOReadHandler *fd_read,
if (!opaque && !fd_can_read && !fd_read && !fd_event) {
fe_open = 0;
+ remove_fd_in_watch(s);
} else {
fe_open = 1;
}
int64_t ti;
int secs;
- ti = qemu_get_clock_ms(rt_clock);
+ ti = qemu_clock_get_ms(QEMU_CLOCK_REALTIME);
if (d->timestamps_start == -1)
d->timestamps_start = ti;
ti -= d->timestamps_start;
g_source_destroy(&iwp->parent);
}
+ static void remove_fd_in_watch(CharDriverState *chr)
+ {
+ if (chr->fd_in_tag) {
+ io_remove_watch_poll(chr->fd_in_tag);
+ chr->fd_in_tag = 0;
+ }
+ }
+
#ifndef _WIN32
static GIOChannel *io_channel_from_fd(int fd)
{
typedef struct FDCharDriver {
CharDriverState *chr;
GIOChannel *fd_in, *fd_out;
- guint fd_in_tag;
int max_size;
QTAILQ_ENTRY(FDCharDriver) node;
} FDCharDriver;
status = g_io_channel_read_chars(chan, (gchar *)buf,
len, &bytes_read, NULL);
if (status == G_IO_STATUS_EOF) {
- if (s->fd_in_tag) {
- io_remove_watch_poll(s->fd_in_tag);
- s->fd_in_tag = 0;
- }
+ remove_fd_in_watch(chr);
qemu_chr_be_event(chr, CHR_EVENT_CLOSED);
return FALSE;
}
{
FDCharDriver *s = chr->opaque;
- if (s->fd_in_tag) {
- io_remove_watch_poll(s->fd_in_tag);
- s->fd_in_tag = 0;
- }
-
+ remove_fd_in_watch(chr);
if (s->fd_in) {
- s->fd_in_tag = io_add_watch_poll(s->fd_in, fd_chr_read_poll, fd_chr_read, chr);
+ chr->fd_in_tag = io_add_watch_poll(s->fd_in, fd_chr_read_poll,
+ fd_chr_read, chr);
}
}
{
FDCharDriver *s = chr->opaque;
- if (s->fd_in_tag) {
- io_remove_watch_poll(s->fd_in_tag);
- s->fd_in_tag = 0;
- }
-
+ remove_fd_in_watch(chr);
if (s->fd_in) {
g_io_channel_unref(s->fd_in);
}
typedef struct {
GIOChannel *fd;
- guint fd_tag;
int connected;
int read_bytes;
guint timer_tag;
PtyCharDriver *s = chr->opaque;
if (!connected) {
- if (s->fd_tag) {
- io_remove_watch_poll(s->fd_tag);
- s->fd_tag = 0;
- }
+ remove_fd_in_watch(chr);
s->connected = 0;
/* (re-)connect poll interval for idle guests: once per second.
* We check more frequently in case the guests sends data to
if (!s->connected) {
s->connected = 1;
qemu_chr_be_generic_open(chr);
- s->fd_tag = io_add_watch_poll(s->fd, pty_chr_read_poll, pty_chr_read, chr);
+ chr->fd_in_tag = io_add_watch_poll(s->fd, pty_chr_read_poll,
+ pty_chr_read, chr);
}
}
}
PtyCharDriver *s = chr->opaque;
int fd;
- if (s->fd_tag) {
- io_remove_watch_poll(s->fd_tag);
- s->fd_tag = 0;
- }
+ remove_fd_in_watch(chr);
fd = g_io_channel_unix_get_fd(s->fd);
g_io_channel_unref(s->fd);
close(fd);
COMSTAT comstat;
DWORD size;
DWORD err;
+#ifdef CONFIG_MARU
+ int open_flags, ret;
+#endif
s->hsend = CreateEvent(NULL, TRUE, FALSE, NULL);
if (!s->hsend) {
fprintf(stderr, "Failed CreateEvent\n");
goto fail;
}
-
- s->hcom = CreateFile(filename, GENERIC_READ|GENERIC_WRITE, 0, NULL,
+#ifndef CONFIG_MARU
+ s->hcom = CreateFile(filename,
+ GENERIC_READ|GENERIC_WRITE, 0, NULL,
OPEN_EXISTING, FILE_FLAG_OVERLAPPED, 0);
+#else
+ open_flags = O_BINARY | O_RDWR;
+ // TODO : FILE_FLAG_OVERLAPPED
+
+ ret = qemu_open(filename, open_flags, 0644);
+ if (ret < 0) {
+ fprintf(stderr, "win_chr_init failed(%d)\n", ret);
+ goto fail;
+ }
+ s->hcom = (HANDLE)_get_osfhandle(ret);
+#endif
if (s->hcom == INVALID_HANDLE_VALUE) {
fprintf(stderr, "Failed CreateFile (%lu)\n", GetLastError());
s->hcom = NULL;
typedef struct {
int fd;
GIOChannel *chan;
- guint tag;
uint8_t buf[READ_BUF_LEN];
int bufcnt;
int bufptr;
s->bufcnt = bytes_read;
s->bufptr = s->bufcnt;
if (status != G_IO_STATUS_NORMAL) {
- if (s->tag) {
- io_remove_watch_poll(s->tag);
- s->tag = 0;
- }
+ remove_fd_in_watch(chr);
return FALSE;
}
{
NetCharDriver *s = chr->opaque;
- if (s->tag) {
- io_remove_watch_poll(s->tag);
- s->tag = 0;
- }
-
+ remove_fd_in_watch(chr);
if (s->chan) {
- s->tag = io_add_watch_poll(s->chan, udp_chr_read_poll, udp_chr_read, chr);
+ chr->fd_in_tag = io_add_watch_poll(s->chan, udp_chr_read_poll,
+ udp_chr_read, chr);
}
}
static void udp_chr_close(CharDriverState *chr)
{
NetCharDriver *s = chr->opaque;
- if (s->tag) {
- io_remove_watch_poll(s->tag);
- s->tag = 0;
- }
+
+ remove_fd_in_watch(chr);
if (s->chan) {
g_io_channel_unref(s->chan);
closesocket(s->fd);
typedef struct {
GIOChannel *chan, *listen_chan;
- guint tag, listen_tag;
+ guint listen_tag;
int fd, listen_fd;
int connected;
int max_size;
if (s->listen_chan) {
s->listen_tag = g_io_add_watch(s->listen_chan, G_IO_IN, tcp_chr_accept, chr);
}
- if (s->tag) {
- io_remove_watch_poll(s->tag);
- s->tag = 0;
- }
+ remove_fd_in_watch(chr);
g_io_channel_unref(s->chan);
s->chan = NULL;
closesocket(s->fd);
s->connected = 1;
if (s->chan) {
- s->tag = io_add_watch_poll(s->chan, tcp_chr_read_poll, tcp_chr_read, chr);
+ chr->fd_in_tag = io_add_watch_poll(s->chan, tcp_chr_read_poll,
+ tcp_chr_read, chr);
}
qemu_chr_be_generic_open(chr);
}
{
TCPCharDriver *s = chr->opaque;
if (s->fd >= 0) {
- if (s->tag) {
- io_remove_watch_poll(s->tag);
- s->tag = 0;
- }
+ remove_fd_in_watch(chr);
if (s->chan) {
g_io_channel_unref(s->chan);
}
if (strstart(filename, "vc", &p)) {
qemu_opt_set(opts, "backend", "vc");
if (*p == ':') {
- if (sscanf(p+1, "%8[0-9]x%8[0-9]", width, height) == 2) {
+ if (sscanf(p+1, "%7[0-9]x%7[0-9]", width, height) == 2) {
/* pixels */
qemu_opt_set(opts, "width", width);
qemu_opt_set(opts, "height", height);
- } else if (sscanf(p+1, "%8[0-9]Cx%8[0-9]C", width, height) == 2) {
+ } else if (sscanf(p+1, "%7[0-9]Cx%7[0-9]C", width, height) == 2) {
/* chars */
qemu_opt_set(opts, "cols", width);
qemu_opt_set(opts, "rows", height);
backend->kind = CHARDEV_BACKEND_KIND_MUX;
backend->mux->chardev = g_strdup(bid);
ret = qmp_chardev_add(id, backend, errp);
- assert(!error_is_set(errp));
+ if (error_is_set(errp)) {
+ chr = qemu_chr_find(bid);
+ qemu_chr_delete(chr);
+ chr = NULL;
+ goto qapi_out;
+ }
}
chr = qemu_chr_find(id);
chr = qemu_chr_new_from_opts(opts, init, &err);
if (error_is_set(&err)) {
- fprintf(stderr, "%s\n", error_get_pretty(err));
+ error_report("%s", error_get_pretty(err));
error_free(err);
}
if (chr && qemu_opt_get_bool(opts, "mux", 0)) {
static CharDriverState *qmp_chardev_open_file(ChardevFile *file, Error **errp)
{
HANDLE out;
+#ifdef CONFIG_MARU
+ int open_flags, ret;
+#endif
if (file->has_in) {
error_setg(errp, "input file not supported");
return NULL;
}
+#ifndef CONFIG_MARU
out = CreateFile(file->out, GENERIC_WRITE, FILE_SHARE_READ, NULL,
OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
+#else
+ open_flags = O_BINARY | O_RDWR | O_CREAT | O_TRUNC;
+ ret = qemu_open(file->out, open_flags, 0644);
+ if (ret < 0) {
+ error_setg(errp, "qemu_chr_open_win_file_out failed(%d)", ret);
+ return NULL;
+ }
+ out = (HANDLE)_get_osfhandle(ret);
+#endif
if (out == INVALID_HANDLE_VALUE) {
error_setg(errp, "open %s failed", file->out);
return NULL;
}
+
return qemu_chr_open_win_file(out);
}
" [,cache=writethrough|writeback|none|directsync|unsafe][,format=f]\n"
" [,serial=s][,addr=A][,id=name][,aio=threads|native]\n"
" [,readonly=on|off][,copy-on-read=on|off]\n"
- " [[,bps=b]|[[,bps_rd=r][,bps_wr=w]]][[,iops=i]|[[,iops_rd=r][,iops_wr=w]]\n"
+ " [[,bps=b]|[[,bps_rd=r][,bps_wr=w]]]\n"
+ " [[,iops=i]|[[,iops_rd=r][,iops_wr=w]]]\n"
+ " [[,bps_max=bm]|[[,bps_rd_max=rm][,bps_wr_max=wm]]]\n"
+ " [[,iops_max=im]|[[,iops_rd_max=irm][,iops_wr_max=iwm]]]\n"
+ " [[,iops_size=is]]\n"
" use 'file' as a drive image\n", QEMU_ARCH_ALL)
STEXI
@item -drive @var{option}[,@var{option}[,@var{option}[,...]]]
If running QEMU as an unprivileged user, use the network helper
@var{helper} to configure the TAP interface. The default network
- helper executable is @file{/usr/local/libexec/qemu-bridge-helper}.
+ helper executable is @file{/path/to/qemu-bridge-helper}.
@option{fd}=@var{h} can be used to specify the handle of an already
opened host TAP interface.
#launch a QEMU instance with the default network helper to
#connect a TAP device to bridge br0
qemu-system-i386 linux.img \
- -net nic -net tap,"helper=/usr/local/libexec/qemu-bridge-helper"
+ -net nic -net tap,"helper=/path/to/qemu-bridge-helper"
@end example
@item -netdev bridge,id=@var{id}[,br=@var{bridge}][,helper=@var{helper}]
Use the network helper @var{helper} to configure the TAP interface and
attach it to the bridge. The default network helper executable is
- @file{/usr/local/libexec/qemu-bridge-helper} and the default bridge
+ @file{/path/to/qemu-bridge-helper} and the default bridge
device is @file{br0}.
Examples:
if KVM support is enabled when compiling.
ETEXI
+DEF("enable-gl", 0, QEMU_OPTION_enable_gl, \
+ "-enable-gl enable OpenGL passthrough support\n", QEMU_ARCH_ALL)
+STEXI
+@item -enable-gl
+@findex -enable-gl
+Enable OpenGL passthrough support. This option requires the support of a
+special libGL installed on the guest OS.
+ETEXI
+
+DEF("enable-yagl", 0, QEMU_OPTION_enable_yagl, \
+ "-enable-yagl enable OpenGLES passthrough support\n", QEMU_ARCH_ALL)
+STEXI
+@item -enable-yagl
+@findex -enable-yagl
+Enable EGL and OpenGLES passthrough support. This option requires special
+libEGL, libGLES_CM and libGLESv2 to be installed on the guest OS. Corresponding
+EGL and openGLES calls on target system are translated to host openGL calls.
+ETEXI
+
+DEF("yagl-backend", HAS_ARG, QEMU_OPTION_yagl_backend,
+ "-yagl-backend offscreen|vigs Select YaGL backend, default is offscreen\n", QEMU_ARCH_ALL)
+STEXI
+@item -yagl-backend @var{backend}
+@findex -yagl-backend
+Use @var{backend} as YaGL backend.
+ETEXI
+
+DEF("enable-vigs", 0, QEMU_OPTION_enable_vigs, \
+ "-enable-vigs enable VIGS support\n", QEMU_ARCH_ALL)
+STEXI
+@item -enable-vigs
+@findex -enable-vigs
+Enables VIGS support.
+ETEXI
+
+DEF("vigs-backend", HAS_ARG, QEMU_OPTION_vigs_backend,
+ "-vigs-backend gl Select VIGS backend, default is gl\n", QEMU_ARCH_ALL)
+STEXI
+@item -vigs-backend @var{backend}
+@findex -vigs-backend
+Use @var{backend} as VIGS backend.
+ETEXI
+
+DEF("enable-hax", 0, QEMU_OPTION_enable_hax, \
+ "-enable-hax enable HAX virtualization support\n", QEMU_ARCH_I386)
+STEXI
+@item -enable-hax
+@findex -enable-hax
+Enable HAX (Hardware-based Acceleration eXecution) support. When HAX support detected, emulator will enable it by default. This option will disable the default action
+HAX is only supported in MAC and Windows platform and is not conflict with KVM.
+ETEXI
+
DEF("xen-domid", HAS_ARG, QEMU_OPTION_xen_domid,
"-xen-domid id specify xen guest domain id\n", QEMU_ARCH_ALL)
DEF("xen-create", 0, QEMU_OPTION_xen_create,
@end table
ETEXI
+DEF("max-touch-point", HAS_ARG, QEMU_OPTION_max_touch_point, \
+ "-max-touch-point [count]\n"
+ " define maximum number of touch point\n",
+ QEMU_ARCH_ALL)
+STEXI
+@item -max-touch-point @var{max_count}
+@findex -max-touch-point
+Use @var{max_count} as Integer
+ETEXI
+
+DEF("disable-skin", 0, QEMU_OPTION_disable_skin, \
+ "-disable-skin\n"
+ " do not start with java skin process\n",
+ QEMU_ARCH_ALL)
+STEXI
+@item -disable-skin
+@findex -disable-skin
+ETEXI
+
+DEF("enable-suspend", 0, QEMU_OPTION_enable_suspend, "", QEMU_ARCH_ALL)
+STEXI
+@item -enable-suspend
+@findex -enable-suspend
+Enable suspend power state. Default is disable.
+ETEXI
+
HXCOMM Internal use
DEF("qtest", HAS_ARG, QEMU_OPTION_qtest, "", QEMU_ARCH_ALL)
DEF("qtest-log", HAS_ARG, QEMU_OPTION_qtest_log, "", QEMU_ARCH_ALL)
void *class_data;
void (*instance_init)(Object *obj);
+ void (*instance_post_init)(Object *obj);
void (*instance_finalize)(Object *obj);
bool abstract;
ti->class_data = info->class_data;
ti->instance_init = info->instance_init;
+ ti->instance_post_init = info->instance_post_init;
ti->instance_finalize = info->instance_finalize;
ti->abstract = info->abstract;
}
}
- void object_initialize_with_type(void *data, TypeImpl *type)
+ static void object_post_init_with_type(Object *obj, TypeImpl *ti)
+ {
+ if (ti->instance_post_init) {
+ ti->instance_post_init(obj);
+ }
+
+ if (type_has_parent(ti)) {
+ object_post_init_with_type(obj, type_get_parent(ti));
+ }
+ }
+
+ void object_initialize_with_type(void *data, size_t size, TypeImpl *type)
{
Object *obj = data;
g_assert(type->instance_size >= sizeof(Object));
g_assert(type->abstract == false);
+ g_assert(size >= type->instance_size);
memset(obj, 0, type->instance_size);
obj->class = type->class;
object_ref(obj);
QTAILQ_INIT(&obj->properties);
object_init_with_type(obj, type);
+ object_post_init_with_type(obj, type);
}
- void object_initialize(void *data, const char *typename)
+ void object_initialize(void *data, size_t size, const char *typename)
{
TypeImpl *type = type_get_by_name(typename);
- object_initialize_with_type(data, type);
+ object_initialize_with_type(data, size, type);
}
static inline bool object_property_is_child(ObjectProperty *prop)
type_initialize(type);
obj = g_malloc(type->instance_size);
- object_initialize_with_type(obj, type);
+ object_initialize_with_type(obj, type->instance_size, type);
obj->free = g_free;
return obj;
void object_unref(Object *obj)
{
+// WA for avoid QOM bug related with qbus_create_inplace()... see hw/qdev.c
+ if(obj->ref == 0) { // Object already finalized...
+ return;
+ }
+//
g_assert(obj->ref > 0);
/* parent always holds a reference to its children */
void object_property_set_link(Object *obj, Object *value,
const char *name, Error **errp)
{
- object_property_set_str(obj, object_get_canonical_path(value),
- name, errp);
+ gchar *path = object_get_canonical_path(value);
+ object_property_set_str(obj, path, name, errp);
+ g_free(path);
}
Object *object_property_get_link(Object *obj, const char *name,
return g_strdup(object_get_typename(obj));
}
+ static void property_get_uint8_ptr(Object *obj, Visitor *v,
+ void *opaque, const char *name,
+ Error **errp)
+ {
+ uint8_t value = *(uint8_t *)opaque;
+ visit_type_uint8(v, &value, name, errp);
+ }
+
+ static void property_get_uint16_ptr(Object *obj, Visitor *v,
+ void *opaque, const char *name,
+ Error **errp)
+ {
+ uint16_t value = *(uint16_t *)opaque;
+ visit_type_uint16(v, &value, name, errp);
+ }
+
+ static void property_get_uint32_ptr(Object *obj, Visitor *v,
+ void *opaque, const char *name,
+ Error **errp)
+ {
+ uint32_t value = *(uint32_t *)opaque;
+ visit_type_uint32(v, &value, name, errp);
+ }
+
+ static void property_get_uint64_ptr(Object *obj, Visitor *v,
+ void *opaque, const char *name,
+ Error **errp)
+ {
+ uint64_t value = *(uint64_t *)opaque;
+ visit_type_uint64(v, &value, name, errp);
+ }
+
+ void object_property_add_uint8_ptr(Object *obj, const char *name,
+ const uint8_t *v, Error **errp)
+ {
+ object_property_add(obj, name, "uint8", property_get_uint8_ptr,
+ NULL, NULL, (void *)v, errp);
+ }
+
+ void object_property_add_uint16_ptr(Object *obj, const char *name,
+ const uint16_t *v, Error **errp)
+ {
+ object_property_add(obj, name, "uint16", property_get_uint16_ptr,
+ NULL, NULL, (void *)v, errp);
+ }
+
+ void object_property_add_uint32_ptr(Object *obj, const char *name,
+ const uint32_t *v, Error **errp)
+ {
+ object_property_add(obj, name, "uint32", property_get_uint32_ptr,
+ NULL, NULL, (void *)v, errp);
+ }
+
+ void object_property_add_uint64_ptr(Object *obj, const char *name,
+ const uint64_t *v, Error **errp)
+ {
+ object_property_add(obj, name, "uint64", property_get_uint64_ptr,
+ NULL, NULL, (void *)v, errp);
+ }
+
static void object_instance_init(Object *obj)
{
object_property_add_str(obj, "type", qdev_get_type, NULL, NULL);
#include "helper.h"
#define GEN_HELPER 1
#include "helper.h"
+#include "sysemu/hax.h"
#define PREFIX_REPZ 0x01
#define PREFIX_REPNZ 0x02
int scale;
int opreg;
int mod, rm, code, override, must_add_seg;
+ TCGv sum;
override = s->override;
must_add_seg = s->addseg;
rm = modrm & 7;
if (s->aflag) {
-
havesib = 0;
base = rm;
- index = 0;
+ index = -1;
scale = 0;
if (base == 4) {
code = cpu_ldub_code(env, s->pc++);
scale = (code >> 6) & 3;
index = ((code >> 3) & 7) | REX_X(s);
+ if (index == 4) {
+ index = -1; /* no index */
+ }
base = (code & 7);
}
base |= REX_B(s);
break;
}
- if (base >= 0) {
- /* for correct popl handling with esp */
- if (base == 4 && s->popl_esp_hack)
- disp += s->popl_esp_hack;
- #ifdef TARGET_X86_64
- if (s->aflag == 2) {
- gen_op_movq_A0_reg(base);
- if (disp != 0) {
- gen_op_addq_A0_im(disp);
- }
- } else
- #endif
- {
- gen_op_movl_A0_reg(base);
- if (disp != 0)
- gen_op_addl_A0_im(disp);
+ /* For correct popl handling with esp. */
+ if (base == R_ESP && s->popl_esp_hack) {
+ disp += s->popl_esp_hack;
+ }
+
+ /* Compute the address, with a minimum number of TCG ops. */
+ TCGV_UNUSED(sum);
+ if (index >= 0) {
+ if (scale == 0) {
+ sum = cpu_regs[index];
+ } else {
+ tcg_gen_shli_tl(cpu_A0, cpu_regs[index], scale);
+ sum = cpu_A0;
}
- } else {
- #ifdef TARGET_X86_64
- if (s->aflag == 2) {
- gen_op_movq_A0_im(disp);
- } else
- #endif
- {
- gen_op_movl_A0_im(disp);
+ if (base >= 0) {
+ tcg_gen_add_tl(cpu_A0, sum, cpu_regs[base]);
+ sum = cpu_A0;
}
+ } else if (base >= 0) {
+ sum = cpu_regs[base];
}
- /* index == 4 means no index */
- if (havesib && (index != 4)) {
- #ifdef TARGET_X86_64
- if (s->aflag == 2) {
- gen_op_addq_A0_reg_sN(scale, index);
- } else
- #endif
- {
- gen_op_addl_A0_reg_sN(scale, index);
- }
+ if (TCGV_IS_UNUSED(sum)) {
+ tcg_gen_movi_tl(cpu_A0, disp);
+ } else {
+ tcg_gen_addi_tl(cpu_A0, sum, disp);
}
+
if (must_add_seg) {
if (override < 0) {
- if (base == R_EBP || base == R_ESP)
+ if (base == R_EBP || base == R_ESP) {
override = R_SS;
- else
+ } else {
override = R_DS;
+ }
}
- #ifdef TARGET_X86_64
- if (s->aflag == 2) {
- gen_op_addq_A0_seg(override);
- } else
- #endif
- {
- gen_op_addl_A0_seg(s, override);
+
+ tcg_gen_ld_tl(cpu_tmp0, cpu_env,
+ offsetof(CPUX86State, segs[override].base));
+ if (CODE64(s)) {
+ if (s->aflag != 2) {
+ tcg_gen_ext32u_tl(cpu_A0, cpu_A0);
+ }
+ tcg_gen_add_tl(cpu_A0, cpu_A0, cpu_tmp0);
+ goto done;
}
+
+ tcg_gen_add_tl(cpu_A0, cpu_A0, cpu_tmp0);
+ }
+
+ if (s->aflag != 2) {
+ tcg_gen_ext32u_tl(cpu_A0, cpu_A0);
}
} else {
switch (mod) {
}
}
+ done:
opreg = OR_A0;
disp = 0;
*reg_ptr = opreg;
/* jump to same page: we can use a direct jump */
tcg_gen_goto_tb(tb_num);
gen_jmp_im(eip);
- tcg_gen_exit_tb((tcg_target_long)tb + tb_num);
+ tcg_gen_exit_tb((uintptr_t)tb + tb_num);
} else {
/* jump to another page: currently not optimized */
gen_jmp_im(eip);
}
break;
case 0x1d: /* fucomi */
+ if (!(s->cpuid_features & CPUID_CMOV)) {
+ goto illegal_op;
+ }
gen_update_cc_op(s);
gen_helper_fmov_FT0_STN(cpu_env, tcg_const_i32(opreg));
gen_helper_fucomi_ST0_FT0(cpu_env);
set_cc_op(s, CC_OP_EFLAGS);
break;
case 0x1e: /* fcomi */
+ if (!(s->cpuid_features & CPUID_CMOV)) {
+ goto illegal_op;
+ }
gen_update_cc_op(s);
gen_helper_fmov_FT0_STN(cpu_env, tcg_const_i32(opreg));
gen_helper_fcomi_ST0_FT0(cpu_env);
}
break;
case 0x3d: /* fucomip */
+ if (!(s->cpuid_features & CPUID_CMOV)) {
+ goto illegal_op;
+ }
gen_update_cc_op(s);
gen_helper_fmov_FT0_STN(cpu_env, tcg_const_i32(opreg));
gen_helper_fucomi_ST0_FT0(cpu_env);
set_cc_op(s, CC_OP_EFLAGS);
break;
case 0x3e: /* fcomip */
+ if (!(s->cpuid_features & CPUID_CMOV)) {
+ goto illegal_op;
+ }
gen_update_cc_op(s);
gen_helper_fmov_FT0_STN(cpu_env, tcg_const_i32(opreg));
gen_helper_fcomi_ST0_FT0(cpu_env);
(JCC_BE << 1),
(JCC_P << 1),
};
+
+ if (!(s->cpuid_features & CPUID_CMOV)) {
+ goto illegal_op;
+ }
op1 = fcmov_cc[op & 3] | (((op >> 3) & 1) ^ 1);
l1 = gen_new_label();
gen_jcc1_noeob(s, op1, l1);
gen_ldst_modrm(env, s, modrm, OT_BYTE, OR_TMP0, 1);
break;
case 0x140 ... 0x14f: /* cmov Gv, Ev */
+ if (!(s->cpuid_features & CPUID_CMOV)) {
+ goto illegal_op;
+ }
ot = dflag + OT_WORD;
modrm = cpu_ldub_code(env, s->pc++);
reg = ((modrm >> 3) & 7) | rex_r;
goto do_xchg_reg_eax;
}
if (prefixes & PREFIX_REPZ) {
- gen_svm_check_intercept(s, pc_start, SVM_EXIT_PAUSE);
+ gen_update_cc_op(s);
+ gen_jmp_im(pc_start - s->cs_base);
+ gen_helper_pause(cpu_env, tcg_const_i32(s->pc - pc_start));
+ s->is_jmp = DISAS_TB_JUMP;
}
break;
case 0x9b: /* fwait */
cpu_regs[R_EDI] = tcg_global_mem_new_i32(TCG_AREG0,
offsetof(CPUX86State, regs[R_EDI]), "edi");
#endif
-
- /* register helpers */
- #define GEN_HELPER 2
- #include "helper.h"
}
/* generate intermediate code in gen_opc_buf and gen_opparam_buf for
pc_ptr = disas_insn(env, dc, pc_ptr);
num_insns++;
+#ifdef CONFIG_HAX
+ if (hax_enabled() && hax_stop_translate(env))
+ {
+ gen_jmp_im(pc_ptr - dc->cs_base);
+ gen_eob(dc);
+ break;
+ }
+#endif
/* stop translation if indicated */
if (dc->is_jmp)
break;
* THE SOFTWARE.
*/
+ #include "tcg-be-ldst.h"
+
#ifndef NDEBUG
static const char * const tcg_target_reg_names[TCG_TARGET_NB_REGS] = {
#if TCG_TARGET_REG_BITS == 64
# define have_cmov 1
#elif defined(CONFIG_CPUID_H)
#include <cpuid.h>
+#ifndef bit_CMOV
+#define bit_CMOV (1 << 15)
+#endif
static bool have_cmov;
#else
# define have_cmov 0
static uint8_t *tb_ret_addr;
static void patch_reloc(uint8_t *code_ptr, int type,
- tcg_target_long value, tcg_target_long addend)
+ intptr_t value, intptr_t addend)
{
value += addend;
switch(type) {
/* qemu_ld/st address constraint */
case 'L':
ct->ct |= TCG_CT_REG;
- #if TCG_TARGET_REG_BITS == 64
+ if (TCG_TARGET_REG_BITS == 64) {
tcg_regset_set32(ct->u.regs, 0, 0xffff);
- #else
+ } else {
tcg_regset_set32(ct->u.regs, 0, 0xff);
- #endif
+ }
tcg_regset_reset_reg(ct->u.regs, TCG_REG_L0);
tcg_regset_reset_reg(ct->u.regs, TCG_REG_L1);
break;
that will follow the instruction. */
static void tcg_out_modrm_sib_offset(TCGContext *s, int opc, int r, int rm,
- int index, int shift,
- tcg_target_long offset)
+ int index, int shift, intptr_t offset)
{
int mod, len;
if (TCG_TARGET_REG_BITS == 64) {
/* Try for a rip-relative addressing mode. This has replaced
the 32-bit-mode absolute addressing encoding. */
- tcg_target_long pc = (tcg_target_long)s->code_ptr + 5 + ~rm;
- tcg_target_long disp = offset - pc;
+ intptr_t pc = (intptr_t)s->code_ptr + 5 + ~rm;
+ intptr_t disp = offset - pc;
if (disp == (int32_t)disp) {
tcg_out_opc(s, opc, r, 0, 0);
tcg_out8(s, (LOWREGMASK(r) << 3) | 5);
/* A simplification of the above with no index or shift. */
static inline void tcg_out_modrm_offset(TCGContext *s, int opc, int r,
- int rm, tcg_target_long offset)
+ int rm, intptr_t offset)
{
tcg_out_modrm_sib_offset(s, opc, r, rm, -1, 0, offset);
}
static void tcg_out_movi(TCGContext *s, TCGType type,
TCGReg ret, tcg_target_long arg)
{
+ tcg_target_long diff;
+
if (arg == 0) {
tgen_arithr(s, ARITH_XOR, ret, ret);
return;
- } else if (arg == (uint32_t)arg || type == TCG_TYPE_I32) {
+ }
+ if (arg == (uint32_t)arg || type == TCG_TYPE_I32) {
tcg_out_opc(s, OPC_MOVL_Iv + LOWREGMASK(ret), 0, ret, 0);
tcg_out32(s, arg);
- } else if (arg == (int32_t)arg) {
+ return;
+ }
+ if (arg == (int32_t)arg) {
tcg_out_modrm(s, OPC_MOVL_EvIz + P_REXW, 0, ret);
tcg_out32(s, arg);
- } else {
- tcg_out_opc(s, OPC_MOVL_Iv + P_REXW + LOWREGMASK(ret), 0, ret, 0);
- tcg_out32(s, arg);
- tcg_out32(s, arg >> 31 >> 1);
+ return;
+ }
+
+ /* Try a 7 byte pc-relative lea before the 10 byte movq. */
+ diff = arg - ((uintptr_t)s->code_ptr + 7);
+ if (diff == (int32_t)diff) {
+ tcg_out_opc(s, OPC_LEA | P_REXW, ret, 0, 0);
+ tcg_out8(s, (LOWREGMASK(ret) << 3) | 5);
+ tcg_out32(s, diff);
+ return;
}
+
+ tcg_out_opc(s, OPC_MOVL_Iv + P_REXW + LOWREGMASK(ret), 0, ret, 0);
+ tcg_out64(s, arg);
}
static inline void tcg_out_pushi(TCGContext *s, tcg_target_long val)
}
static inline void tcg_out_ld(TCGContext *s, TCGType type, TCGReg ret,
- TCGReg arg1, tcg_target_long arg2)
+ TCGReg arg1, intptr_t arg2)
{
int opc = OPC_MOVL_GvEv + (type == TCG_TYPE_I64 ? P_REXW : 0);
tcg_out_modrm_offset(s, opc, ret, arg1, arg2);
}
static inline void tcg_out_st(TCGContext *s, TCGType type, TCGReg arg,
- TCGReg arg1, tcg_target_long arg2)
+ TCGReg arg1, intptr_t arg2)
{
int opc = OPC_MOVL_EvGv + (type == TCG_TYPE_I64 ? P_REXW : 0);
tcg_out_modrm_offset(s, opc, arg, arg1, arg2);
}
+ static inline void tcg_out_sti(TCGContext *s, TCGType type, TCGReg base,
+ tcg_target_long ofs, tcg_target_long val)
+ {
+ int opc = OPC_MOVL_EvIz + (type == TCG_TYPE_I64 ? P_REXW : 0);
+ tcg_out_modrm_offset(s, opc, 0, base, ofs);
+ tcg_out32(s, val);
+ }
+
static void tcg_out_shifti(TCGContext *s, int subopc, int reg, int count)
{
/* Propagate an opcode prefix, such as P_DATA16. */
TCGLabel *l = &s->labels[label_index];
if (l->has_value) {
- val = l->u.value - (tcg_target_long)s->code_ptr;
+ val = l->u.value - (intptr_t)s->code_ptr;
val1 = val - 2;
if ((int8_t)val1 == val1) {
if (opc == -1) {
}
#endif
- static void tcg_out_branch(TCGContext *s, int call, tcg_target_long dest)
+ static void tcg_out_branch(TCGContext *s, int call, uintptr_t dest)
{
- tcg_target_long disp = dest - (tcg_target_long)s->code_ptr - 5;
+ intptr_t disp = dest - (intptr_t)s->code_ptr - 5;
if (disp == (int32_t)disp) {
tcg_out_opc(s, call ? OPC_CALL_Jz : OPC_JMP_long, 0, 0, 0);
}
}
- static inline void tcg_out_calli(TCGContext *s, tcg_target_long dest)
+ static inline void tcg_out_calli(TCGContext *s, uintptr_t dest)
{
tcg_out_branch(s, 1, dest);
}
- static void tcg_out_jmp(TCGContext *s, tcg_target_long dest)
+ static void tcg_out_jmp(TCGContext *s, uintptr_t dest)
{
tcg_out_branch(s, 0, dest);
}
#if defined(CONFIG_SOFTMMU)
-
- #include "exec/softmmu_defs.h"
-
- /* helper signature: helper_ld_mmu(CPUState *env, target_ulong addr,
- int mmu_idx) */
- static const void *qemu_ld_helpers[4] = {
- helper_ldb_mmu,
- helper_ldw_mmu,
- helper_ldl_mmu,
- helper_ldq_mmu,
+ /* helper signature: helper_ret_ld_mmu(CPUState *env, target_ulong addr,
+ * int mmu_idx, uintptr_t ra)
+ */
+ static const void * const qemu_ld_helpers[16] = {
+ [MO_UB] = helper_ret_ldub_mmu,
+ [MO_LEUW] = helper_le_lduw_mmu,
+ [MO_LEUL] = helper_le_ldul_mmu,
+ [MO_LEQ] = helper_le_ldq_mmu,
+ [MO_BEUW] = helper_be_lduw_mmu,
+ [MO_BEUL] = helper_be_ldul_mmu,
+ [MO_BEQ] = helper_be_ldq_mmu,
};
- /* helper signature: helper_st_mmu(CPUState *env, target_ulong addr,
- uintxx_t val, int mmu_idx) */
- static const void *qemu_st_helpers[4] = {
- helper_stb_mmu,
- helper_stw_mmu,
- helper_stl_mmu,
- helper_stq_mmu,
+ /* helper signature: helper_ret_st_mmu(CPUState *env, target_ulong addr,
+ * uintxx_t val, int mmu_idx, uintptr_t ra)
+ */
+ static const void * const qemu_st_helpers[16] = {
+ [MO_UB] = helper_ret_stb_mmu,
+ [MO_LEUW] = helper_le_stw_mmu,
+ [MO_LEUL] = helper_le_stl_mmu,
+ [MO_LEQ] = helper_le_stq_mmu,
+ [MO_BEUW] = helper_be_stw_mmu,
+ [MO_BEUL] = helper_be_stl_mmu,
+ [MO_BEQ] = helper_be_stq_mmu,
};
- static void add_qemu_ldst_label(TCGContext *s,
- int is_ld,
- int opc,
- int data_reg,
- int data_reg2,
- int addrlo_reg,
- int addrhi_reg,
- int mem_index,
- uint8_t *raddr,
- uint8_t **label_ptr);
-
/* Perform the TLB load and compare.
Inputs:
- ADDRLO_IDX contains the index into ARGS of the low part of the
- address; the high part of the address is at ADDR_LOW_IDX+1.
+ ADDRLO and ADDRHI contain the low and high part of the address.
MEM_INDEX and S_BITS are the memory context and log2 size of the load.
First argument register is clobbered. */
- static inline void tcg_out_tlb_load(TCGContext *s, int addrlo_idx,
- int mem_index, int s_bits,
- const TCGArg *args,
+ static inline void tcg_out_tlb_load(TCGContext *s, TCGReg addrlo, TCGReg addrhi,
+ int mem_index, TCGMemOp s_bits,
uint8_t **label_ptr, int which)
{
- const int addrlo = args[addrlo_idx];
- const int r0 = TCG_REG_L0;
- const int r1 = TCG_REG_L1;
- TCGType type = TCG_TYPE_I32;
- int rexw = 0;
+ const TCGReg r0 = TCG_REG_L0;
+ const TCGReg r1 = TCG_REG_L1;
+ TCGType ttype = TCG_TYPE_I32;
+ TCGType htype = TCG_TYPE_I32;
+ int trexw = 0, hrexw = 0;
- if (TCG_TARGET_REG_BITS == 64 && TARGET_LONG_BITS == 64) {
- type = TCG_TYPE_I64;
- rexw = P_REXW;
+ if (TCG_TARGET_REG_BITS == 64) {
+ if (TARGET_LONG_BITS == 64) {
+ ttype = TCG_TYPE_I64;
+ trexw = P_REXW;
+ }
+ if (TCG_TYPE_PTR == TCG_TYPE_I64) {
+ htype = TCG_TYPE_I64;
+ hrexw = P_REXW;
+ }
}
- tcg_out_mov(s, type, r0, addrlo);
- tcg_out_mov(s, type, r1, addrlo);
+ tcg_out_mov(s, htype, r0, addrlo);
+ tcg_out_mov(s, ttype, r1, addrlo);
- tcg_out_shifti(s, SHIFT_SHR + rexw, r0,
+ tcg_out_shifti(s, SHIFT_SHR + hrexw, r0,
TARGET_PAGE_BITS - CPU_TLB_ENTRY_BITS);
- tgen_arithi(s, ARITH_AND + rexw, r1,
+ tgen_arithi(s, ARITH_AND + trexw, r1,
TARGET_PAGE_MASK | ((1 << s_bits) - 1), 0);
- tgen_arithi(s, ARITH_AND + rexw, r0,
+ tgen_arithi(s, ARITH_AND + hrexw, r0,
(CPU_TLB_SIZE - 1) << CPU_TLB_ENTRY_BITS, 0);
- tcg_out_modrm_sib_offset(s, OPC_LEA + P_REXW, r0, TCG_AREG0, r0, 0,
+ tcg_out_modrm_sib_offset(s, OPC_LEA + hrexw, r0, TCG_AREG0, r0, 0,
offsetof(CPUArchState, tlb_table[mem_index][0])
+ which);
/* cmp 0(r0), r1 */
- tcg_out_modrm_offset(s, OPC_CMP_GvEv + rexw, r1, r0, 0);
+ tcg_out_modrm_offset(s, OPC_CMP_GvEv + trexw, r1, r0, 0);
- tcg_out_mov(s, type, r1, addrlo);
+ /* Prepare for both the fast path add of the tlb addend, and the slow
+ path function argument setup. There are two cases worth note:
+ For 32-bit guest and x86_64 host, MOVL zero-extends the guest address
+ before the fastpath ADDQ below. For 64-bit guest and x32 host, MOVQ
+ copies the entire guest address for the slow path, while truncation
+ for the 32-bit host happens with the fastpath ADDL below. */
+ tcg_out_mov(s, ttype, r1, addrlo);
/* jne slow_path */
tcg_out_opc(s, OPC_JCC_long + JCC_JNE, 0, 0, 0);
if (TARGET_LONG_BITS > TCG_TARGET_REG_BITS) {
/* cmp 4(r0), addrhi */
- tcg_out_modrm_offset(s, OPC_CMP_GvEv, args[addrlo_idx+1], r0, 4);
+ tcg_out_modrm_offset(s, OPC_CMP_GvEv, addrhi, r0, 4);
/* jne slow_path */
tcg_out_opc(s, OPC_JCC_long + JCC_JNE, 0, 0, 0);
/* TLB Hit. */
/* add addend(r0), r1 */
- tcg_out_modrm_offset(s, OPC_ADD_GvEv + P_REXW, r1, r0,
+ tcg_out_modrm_offset(s, OPC_ADD_GvEv + hrexw, r1, r0,
offsetof(CPUTLBEntry, addend) - which);
}
+
+ /*
+ * Record the context of a call to the out of line helper code for the slow path
+ * for a load or store, so that we can later generate the correct helper code
+ */
+ static void add_qemu_ldst_label(TCGContext *s, int is_ld, TCGMemOp opc,
+ TCGReg datalo, TCGReg datahi,
+ TCGReg addrlo, TCGReg addrhi,
+ int mem_index, uint8_t *raddr,
+ uint8_t **label_ptr)
+ {
+ TCGLabelQemuLdst *label = new_ldst_label(s);
+
+ label->is_ld = is_ld;
+ label->opc = opc;
+ label->datalo_reg = datalo;
+ label->datahi_reg = datahi;
+ label->addrlo_reg = addrlo;
+ label->addrhi_reg = addrhi;
+ label->mem_index = mem_index;
+ label->raddr = raddr;
+ label->label_ptr[0] = label_ptr[0];
+ if (TARGET_LONG_BITS > TCG_TARGET_REG_BITS) {
+ label->label_ptr[1] = label_ptr[1];
+ }
+ }
+
+ /*
+ * Generate code for the slow path for a load at the end of block
+ */
+ static void tcg_out_qemu_ld_slow_path(TCGContext *s, TCGLabelQemuLdst *l)
+ {
+ TCGMemOp opc = l->opc;
+ TCGReg data_reg;
+ uint8_t **label_ptr = &l->label_ptr[0];
+
+ /* resolve label address */
+ *(uint32_t *)label_ptr[0] = (uint32_t)(s->code_ptr - label_ptr[0] - 4);
+ if (TARGET_LONG_BITS > TCG_TARGET_REG_BITS) {
+ *(uint32_t *)label_ptr[1] = (uint32_t)(s->code_ptr - label_ptr[1] - 4);
+ }
+
+ if (TCG_TARGET_REG_BITS == 32) {
+ int ofs = 0;
+
+ tcg_out_st(s, TCG_TYPE_PTR, TCG_AREG0, TCG_REG_ESP, ofs);
+ ofs += 4;
+
+ tcg_out_st(s, TCG_TYPE_I32, l->addrlo_reg, TCG_REG_ESP, ofs);
+ ofs += 4;
+
+ if (TARGET_LONG_BITS == 64) {
+ tcg_out_st(s, TCG_TYPE_I32, l->addrhi_reg, TCG_REG_ESP, ofs);
+ ofs += 4;
+ }
+
+ tcg_out_sti(s, TCG_TYPE_I32, TCG_REG_ESP, ofs, l->mem_index);
+ ofs += 4;
+
+ tcg_out_sti(s, TCG_TYPE_I32, TCG_REG_ESP, ofs, (uintptr_t)l->raddr);
+ } else {
+ tcg_out_mov(s, TCG_TYPE_PTR, tcg_target_call_iarg_regs[0], TCG_AREG0);
+ /* The second argument is already loaded with addrlo. */
+ tcg_out_movi(s, TCG_TYPE_I32, tcg_target_call_iarg_regs[2],
+ l->mem_index);
+ tcg_out_movi(s, TCG_TYPE_PTR, tcg_target_call_iarg_regs[3],
+ (uintptr_t)l->raddr);
+ }
+
+ tcg_out_calli(s, (uintptr_t)qemu_ld_helpers[opc & ~MO_SIGN]);
+
+ data_reg = l->datalo_reg;
+ switch (opc & MO_SSIZE) {
+ case MO_SB:
+ tcg_out_ext8s(s, data_reg, TCG_REG_EAX, P_REXW);
+ break;
+ case MO_SW:
+ tcg_out_ext16s(s, data_reg, TCG_REG_EAX, P_REXW);
+ break;
+ #if TCG_TARGET_REG_BITS == 64
+ case MO_SL:
+ tcg_out_ext32s(s, data_reg, TCG_REG_EAX);
+ break;
+ #endif
+ case MO_UB:
+ case MO_UW:
+ /* Note that the helpers have zero-extended to tcg_target_long. */
+ case MO_UL:
+ tcg_out_mov(s, TCG_TYPE_I32, data_reg, TCG_REG_EAX);
+ break;
+ case MO_Q:
+ if (TCG_TARGET_REG_BITS == 64) {
+ tcg_out_mov(s, TCG_TYPE_I64, data_reg, TCG_REG_RAX);
+ } else if (data_reg == TCG_REG_EDX) {
+ /* xchg %edx, %eax */
+ tcg_out_opc(s, OPC_XCHG_ax_r32 + TCG_REG_EDX, 0, 0, 0);
+ tcg_out_mov(s, TCG_TYPE_I32, l->datahi_reg, TCG_REG_EAX);
+ } else {
+ tcg_out_mov(s, TCG_TYPE_I32, data_reg, TCG_REG_EAX);
+ tcg_out_mov(s, TCG_TYPE_I32, l->datahi_reg, TCG_REG_EDX);
+ }
+ break;
+ default:
+ tcg_abort();
+ }
+
+ /* Jump to the code corresponding to next IR of qemu_st */
+ tcg_out_jmp(s, (uintptr_t)l->raddr);
+ }
+
+ /*
+ * Generate code for the slow path for a store at the end of block
+ */
+ static void tcg_out_qemu_st_slow_path(TCGContext *s, TCGLabelQemuLdst *l)
+ {
+ TCGMemOp opc = l->opc;
+ TCGMemOp s_bits = opc & MO_SIZE;
+ uint8_t **label_ptr = &l->label_ptr[0];
+ TCGReg retaddr;
+
+ /* resolve label address */
+ *(uint32_t *)label_ptr[0] = (uint32_t)(s->code_ptr - label_ptr[0] - 4);
+ if (TARGET_LONG_BITS > TCG_TARGET_REG_BITS) {
+ *(uint32_t *)label_ptr[1] = (uint32_t)(s->code_ptr - label_ptr[1] - 4);
+ }
+
+ if (TCG_TARGET_REG_BITS == 32) {
+ int ofs = 0;
+
+ tcg_out_st(s, TCG_TYPE_PTR, TCG_AREG0, TCG_REG_ESP, ofs);
+ ofs += 4;
+
+ tcg_out_st(s, TCG_TYPE_I32, l->addrlo_reg, TCG_REG_ESP, ofs);
+ ofs += 4;
+
+ if (TARGET_LONG_BITS == 64) {
+ tcg_out_st(s, TCG_TYPE_I32, l->addrhi_reg, TCG_REG_ESP, ofs);
+ ofs += 4;
+ }
+
+ tcg_out_st(s, TCG_TYPE_I32, l->datalo_reg, TCG_REG_ESP, ofs);
+ ofs += 4;
+
+ if (s_bits == MO_64) {
+ tcg_out_st(s, TCG_TYPE_I32, l->datahi_reg, TCG_REG_ESP, ofs);
+ ofs += 4;
+ }
+
+ tcg_out_sti(s, TCG_TYPE_I32, TCG_REG_ESP, ofs, l->mem_index);
+ ofs += 4;
+
+ retaddr = TCG_REG_EAX;
+ tcg_out_movi(s, TCG_TYPE_I32, retaddr, (uintptr_t)l->raddr);
+ tcg_out_st(s, TCG_TYPE_I32, retaddr, TCG_REG_ESP, ofs);
+ } else {
+ tcg_out_mov(s, TCG_TYPE_PTR, tcg_target_call_iarg_regs[0], TCG_AREG0);
+ /* The second argument is already loaded with addrlo. */
+ tcg_out_mov(s, (s_bits == MO_64 ? TCG_TYPE_I64 : TCG_TYPE_I32),
+ tcg_target_call_iarg_regs[2], l->datalo_reg);
+ tcg_out_movi(s, TCG_TYPE_I32, tcg_target_call_iarg_regs[3],
+ l->mem_index);
+
+ if (ARRAY_SIZE(tcg_target_call_iarg_regs) > 4) {
+ retaddr = tcg_target_call_iarg_regs[4];
+ tcg_out_movi(s, TCG_TYPE_PTR, retaddr, (uintptr_t)l->raddr);
+ } else {
+ retaddr = TCG_REG_RAX;
+ tcg_out_movi(s, TCG_TYPE_PTR, retaddr, (uintptr_t)l->raddr);
+ tcg_out_st(s, TCG_TYPE_PTR, retaddr, TCG_REG_ESP, 0);
+ }
+ }
+
+ /* "Tail call" to the helper, with the return address back inline. */
+ tcg_out_push(s, retaddr);
+ tcg_out_jmp(s, (uintptr_t)qemu_st_helpers[opc]);
+ }
#elif defined(__x86_64__) && defined(__linux__)
# include <asm/prctl.h>
# include <sys/prctl.h>
static inline void setup_guest_base_seg(void) { }
#endif /* SOFTMMU */
- static void tcg_out_qemu_ld_direct(TCGContext *s, int datalo, int datahi,
- int base, tcg_target_long ofs, int seg,
- int sizeop)
+ static void tcg_out_qemu_ld_direct(TCGContext *s, TCGReg datalo, TCGReg datahi,
+ TCGReg base, intptr_t ofs, int seg,
+ TCGMemOp memop)
{
- #ifdef TARGET_WORDS_BIGENDIAN
- const int bswap = 1;
- #else
- const int bswap = 0;
- #endif
- switch (sizeop) {
- case 0:
+ const TCGMemOp bswap = memop & MO_BSWAP;
+
+ switch (memop & MO_SSIZE) {
+ case MO_UB:
tcg_out_modrm_offset(s, OPC_MOVZBL + seg, datalo, base, ofs);
break;
- case 0 | 4:
+ case MO_SB:
tcg_out_modrm_offset(s, OPC_MOVSBL + P_REXW + seg, datalo, base, ofs);
break;
- case 1:
+ case MO_UW:
tcg_out_modrm_offset(s, OPC_MOVZWL + seg, datalo, base, ofs);
if (bswap) {
tcg_out_rolw_8(s, datalo);
}
break;
- case 1 | 4:
+ case MO_SW:
if (bswap) {
tcg_out_modrm_offset(s, OPC_MOVZWL + seg, datalo, base, ofs);
tcg_out_rolw_8(s, datalo);
datalo, base, ofs);
}
break;
- case 2:
+ case MO_UL:
tcg_out_modrm_offset(s, OPC_MOVL_GvEv + seg, datalo, base, ofs);
if (bswap) {
tcg_out_bswap32(s, datalo);
}
break;
#if TCG_TARGET_REG_BITS == 64
- case 2 | 4:
+ case MO_SL:
if (bswap) {
tcg_out_modrm_offset(s, OPC_MOVL_GvEv + seg, datalo, base, ofs);
tcg_out_bswap32(s, datalo);
}
break;
#endif
- case 3:
+ case MO_Q:
if (TCG_TARGET_REG_BITS == 64) {
tcg_out_modrm_offset(s, OPC_MOVL_GvEv + P_REXW + seg,
datalo, base, ofs);
/* XXX: qemu_ld and qemu_st could be modified to clobber only EDX and
EAX. It will be useful once fixed registers globals are less
common. */
- static void tcg_out_qemu_ld(TCGContext *s, const TCGArg *args,
- int opc)
+ static void tcg_out_qemu_ld(TCGContext *s, const TCGArg *args, bool is64)
{
- int data_reg, data_reg2 = 0;
- int addrlo_idx;
+ TCGReg datalo, datahi, addrlo;
+ TCGReg addrhi __attribute__((unused));
+ TCGMemOp opc;
#if defined(CONFIG_SOFTMMU)
- int mem_index, s_bits;
+ int mem_index;
+ TCGMemOp s_bits;
uint8_t *label_ptr[2];
#endif
- data_reg = args[0];
- addrlo_idx = 1;
- if (TCG_TARGET_REG_BITS == 32 && opc == 3) {
- data_reg2 = args[1];
- addrlo_idx = 2;
- }
+ datalo = *args++;
+ datahi = (TCG_TARGET_REG_BITS == 32 && is64 ? *args++ : 0);
+ addrlo = *args++;
+ addrhi = (TARGET_LONG_BITS > TCG_TARGET_REG_BITS ? *args++ : 0);
+ opc = *args++;
#if defined(CONFIG_SOFTMMU)
- mem_index = args[addrlo_idx + 1 + (TARGET_LONG_BITS > TCG_TARGET_REG_BITS)];
- s_bits = opc & 3;
+ mem_index = *args++;
+ s_bits = opc & MO_SIZE;
- tcg_out_tlb_load(s, addrlo_idx, mem_index, s_bits, args,
+ tcg_out_tlb_load(s, addrlo, addrhi, mem_index, s_bits,
label_ptr, offsetof(CPUTLBEntry, addr_read));
/* TLB Hit. */
- tcg_out_qemu_ld_direct(s, data_reg, data_reg2, TCG_REG_L1, 0, 0, opc);
+ tcg_out_qemu_ld_direct(s, datalo, datahi, TCG_REG_L1, 0, 0, opc);
/* Record the current context of a load into ldst label */
- add_qemu_ldst_label(s,
- 1,
- opc,
- data_reg,
- data_reg2,
- args[addrlo_idx],
- args[addrlo_idx + 1],
- mem_index,
- s->code_ptr,
- label_ptr);
+ add_qemu_ldst_label(s, 1, opc, datalo, datahi, addrlo, addrhi,
+ mem_index, s->code_ptr, label_ptr);
#else
{
int32_t offset = GUEST_BASE;
- int base = args[addrlo_idx];
+ TCGReg base = addrlo;
int seg = 0;
/* ??? We assume all operations have left us with register contents
offset = 0;
}
- tcg_out_qemu_ld_direct(s, data_reg, data_reg2, base, offset, seg, opc);
+ tcg_out_qemu_ld_direct(s, datalo, datahi, base, offset, seg, opc);
}
#endif
}
- static void tcg_out_qemu_st_direct(TCGContext *s, int datalo, int datahi,
- int base, tcg_target_long ofs, int seg,
- int sizeop)
+ static void tcg_out_qemu_st_direct(TCGContext *s, TCGReg datalo, TCGReg datahi,
+ TCGReg base, intptr_t ofs, int seg,
+ TCGMemOp memop)
{
- #ifdef TARGET_WORDS_BIGENDIAN
- const int bswap = 1;
- #else
- const int bswap = 0;
- #endif
+ const TCGMemOp bswap = memop & MO_BSWAP;
+
/* ??? Ideally we wouldn't need a scratch register. For user-only,
we could perform the bswap twice to restore the original value
instead of moving to the scratch. But as it is, the L constraint
means that TCG_REG_L0 is definitely free here. */
- const int scratch = TCG_REG_L0;
+ const TCGReg scratch = TCG_REG_L0;
- switch (sizeop) {
- case 0:
+ switch (memop & MO_SIZE) {
+ case MO_8:
+ /* In 32-bit mode, 8-byte stores can only happen from [abcd]x.
+ Use the scratch register if necessary. */
+ if (TCG_TARGET_REG_BITS == 32 && datalo >= 4) {
+ tcg_out_mov(s, TCG_TYPE_I32, scratch, datalo);
+ datalo = scratch;
+ }
tcg_out_modrm_offset(s, OPC_MOVB_EvGv + P_REXB_R + seg,
datalo, base, ofs);
break;
- case 1:
+ case MO_16:
if (bswap) {
tcg_out_mov(s, TCG_TYPE_I32, scratch, datalo);
tcg_out_rolw_8(s, scratch);
tcg_out_modrm_offset(s, OPC_MOVL_EvGv + P_DATA16 + seg,
datalo, base, ofs);
break;
- case 2:
+ case MO_32:
if (bswap) {
tcg_out_mov(s, TCG_TYPE_I32, scratch, datalo);
tcg_out_bswap32(s, scratch);
}
tcg_out_modrm_offset(s, OPC_MOVL_EvGv + seg, datalo, base, ofs);
break;
- case 3:
+ case MO_64:
if (TCG_TARGET_REG_BITS == 64) {
if (bswap) {
tcg_out_mov(s, TCG_TYPE_I64, scratch, datalo);
}
}
- static void tcg_out_qemu_st(TCGContext *s, const TCGArg *args,
- int opc)
+ static void tcg_out_qemu_st(TCGContext *s, const TCGArg *args, bool is64)
{
- int data_reg, data_reg2 = 0;
- int addrlo_idx;
+ TCGReg datalo, datahi, addrlo;
+ TCGReg addrhi __attribute__((unused));
+ TCGMemOp opc;
#if defined(CONFIG_SOFTMMU)
- int mem_index, s_bits;
+ int mem_index;
+ TCGMemOp s_bits;
uint8_t *label_ptr[2];
#endif
- data_reg = args[0];
- addrlo_idx = 1;
- if (TCG_TARGET_REG_BITS == 32 && opc == 3) {
- data_reg2 = args[1];
- addrlo_idx = 2;
- }
+ datalo = *args++;
+ datahi = (TCG_TARGET_REG_BITS == 32 && is64 ? *args++ : 0);
+ addrlo = *args++;
+ addrhi = (TARGET_LONG_BITS > TCG_TARGET_REG_BITS ? *args++ : 0);
+ opc = *args++;
#if defined(CONFIG_SOFTMMU)
- mem_index = args[addrlo_idx + 1 + (TARGET_LONG_BITS > TCG_TARGET_REG_BITS)];
- s_bits = opc;
+ mem_index = *args++;
+ s_bits = opc & MO_SIZE;
- tcg_out_tlb_load(s, addrlo_idx, mem_index, s_bits, args,
+ tcg_out_tlb_load(s, addrlo, addrhi, mem_index, s_bits,
label_ptr, offsetof(CPUTLBEntry, addr_write));
/* TLB Hit. */
- tcg_out_qemu_st_direct(s, data_reg, data_reg2, TCG_REG_L1, 0, 0, opc);
+ tcg_out_qemu_st_direct(s, datalo, datahi, TCG_REG_L1, 0, 0, opc);
/* Record the current context of a store into ldst label */
- add_qemu_ldst_label(s,
- 0,
- opc,
- data_reg,
- data_reg2,
- args[addrlo_idx],
- args[addrlo_idx + 1],
- mem_index,
- s->code_ptr,
- label_ptr);
+ add_qemu_ldst_label(s, 0, opc, datalo, datahi, addrlo, addrhi,
+ mem_index, s->code_ptr, label_ptr);
#else
{
int32_t offset = GUEST_BASE;
- int base = args[addrlo_idx];
+ TCGReg base = addrlo;
int seg = 0;
/* ??? We assume all operations have left us with register contents
offset = 0;
}
- tcg_out_qemu_st_direct(s, data_reg, data_reg2, base, offset, seg, opc);
+ tcg_out_qemu_st_direct(s, datalo, datahi, base, offset, seg, opc);
}
#endif
}
- #if defined(CONFIG_SOFTMMU)
- /*
- * Record the context of a call to the out of line helper code for the slow path
- * for a load or store, so that we can later generate the correct helper code
- */
- static void add_qemu_ldst_label(TCGContext *s,
- int is_ld,
- int opc,
- int data_reg,
- int data_reg2,
- int addrlo_reg,
- int addrhi_reg,
- int mem_index,
- uint8_t *raddr,
- uint8_t **label_ptr)
- {
- int idx;
- TCGLabelQemuLdst *label;
-
- if (s->nb_qemu_ldst_labels >= TCG_MAX_QEMU_LDST) {
- tcg_abort();
- }
-
- idx = s->nb_qemu_ldst_labels++;
- label = (TCGLabelQemuLdst *)&s->qemu_ldst_labels[idx];
- label->is_ld = is_ld;
- label->opc = opc;
- label->datalo_reg = data_reg;
- label->datahi_reg = data_reg2;
- label->addrlo_reg = addrlo_reg;
- label->addrhi_reg = addrhi_reg;
- label->mem_index = mem_index;
- label->raddr = raddr;
- label->label_ptr[0] = label_ptr[0];
- if (TARGET_LONG_BITS > TCG_TARGET_REG_BITS) {
- label->label_ptr[1] = label_ptr[1];
- }
- }
-
- /*
- * Generate code for the slow path for a load at the end of block
- */
- static void tcg_out_qemu_ld_slow_path(TCGContext *s, TCGLabelQemuLdst *label)
- {
- int s_bits;
- int opc = label->opc;
- int mem_index = label->mem_index;
- #if TCG_TARGET_REG_BITS == 32
- int stack_adjust;
- int addrlo_reg = label->addrlo_reg;
- int addrhi_reg = label->addrhi_reg;
- #endif
- int data_reg = label->datalo_reg;
- int data_reg2 = label->datahi_reg;
- uint8_t *raddr = label->raddr;
- uint8_t **label_ptr = &label->label_ptr[0];
-
- s_bits = opc & 3;
-
- /* resolve label address */
- *(uint32_t *)label_ptr[0] = (uint32_t)(s->code_ptr - label_ptr[0] - 4);
- if (TARGET_LONG_BITS > TCG_TARGET_REG_BITS) {
- *(uint32_t *)label_ptr[1] = (uint32_t)(s->code_ptr - label_ptr[1] - 4);
- }
-
- #if TCG_TARGET_REG_BITS == 32
- tcg_out_pushi(s, mem_index);
- stack_adjust = 4;
- if (TARGET_LONG_BITS == 64) {
- tcg_out_push(s, addrhi_reg);
- stack_adjust += 4;
- }
- tcg_out_push(s, addrlo_reg);
- stack_adjust += 4;
- tcg_out_push(s, TCG_AREG0);
- stack_adjust += 4;
- #else
- tcg_out_mov(s, TCG_TYPE_I64, tcg_target_call_iarg_regs[0], TCG_AREG0);
- /* The second argument is already loaded with addrlo. */
- tcg_out_movi(s, TCG_TYPE_I32, tcg_target_call_iarg_regs[2], mem_index);
- #endif
-
- /* Code generation of qemu_ld/st's slow path calling MMU helper
-
- PRE_PROC ...
- call MMU helper
- jmp POST_PROC (2b) : short forward jump <- GETRA()
- jmp next_code (5b) : dummy long backward jump which is never executed
- POST_PROC ... : do post-processing <- GETRA() + 7
- jmp next_code : jump to the code corresponding to next IR of qemu_ld/st
- */
-
- tcg_out_calli(s, (tcg_target_long)qemu_ld_helpers[s_bits]);
-
- /* Jump to post-processing code */
- tcg_out8(s, OPC_JMP_short);
- tcg_out8(s, 5);
- /* Dummy backward jump having information of fast path'pc for MMU helpers */
- tcg_out8(s, OPC_JMP_long);
- *(int32_t *)s->code_ptr = (int32_t)(raddr - s->code_ptr - 4);
- s->code_ptr += 4;
-
- #if TCG_TARGET_REG_BITS == 32
- if (stack_adjust == (TCG_TARGET_REG_BITS / 8)) {
- /* Pop and discard. This is 2 bytes smaller than the add. */
- tcg_out_pop(s, TCG_REG_ECX);
- } else if (stack_adjust != 0) {
- tcg_out_addi(s, TCG_REG_CALL_STACK, stack_adjust);
- }
- #endif
-
- switch(opc) {
- case 0 | 4:
- tcg_out_ext8s(s, data_reg, TCG_REG_EAX, P_REXW);
- break;
- case 1 | 4:
- tcg_out_ext16s(s, data_reg, TCG_REG_EAX, P_REXW);
- break;
- case 0:
- tcg_out_ext8u(s, data_reg, TCG_REG_EAX);
- break;
- case 1:
- tcg_out_ext16u(s, data_reg, TCG_REG_EAX);
- break;
- case 2:
- tcg_out_mov(s, TCG_TYPE_I32, data_reg, TCG_REG_EAX);
- break;
- #if TCG_TARGET_REG_BITS == 64
- case 2 | 4:
- tcg_out_ext32s(s, data_reg, TCG_REG_EAX);
- break;
- #endif
- case 3:
- if (TCG_TARGET_REG_BITS == 64) {
- tcg_out_mov(s, TCG_TYPE_I64, data_reg, TCG_REG_RAX);
- } else if (data_reg == TCG_REG_EDX) {
- /* xchg %edx, %eax */
- tcg_out_opc(s, OPC_XCHG_ax_r32 + TCG_REG_EDX, 0, 0, 0);
- tcg_out_mov(s, TCG_TYPE_I32, data_reg2, TCG_REG_EAX);
- } else {
- tcg_out_mov(s, TCG_TYPE_I32, data_reg, TCG_REG_EAX);
- tcg_out_mov(s, TCG_TYPE_I32, data_reg2, TCG_REG_EDX);
- }
- break;
- default:
- tcg_abort();
- }
-
- /* Jump to the code corresponding to next IR of qemu_st */
- tcg_out_jmp(s, (tcg_target_long)raddr);
- }
-
- /*
- * Generate code for the slow path for a store at the end of block
- */
- static void tcg_out_qemu_st_slow_path(TCGContext *s, TCGLabelQemuLdst *label)
- {
- int s_bits;
- int stack_adjust;
- int opc = label->opc;
- int mem_index = label->mem_index;
- int data_reg = label->datalo_reg;
- #if TCG_TARGET_REG_BITS == 32
- int data_reg2 = label->datahi_reg;
- int addrlo_reg = label->addrlo_reg;
- int addrhi_reg = label->addrhi_reg;
- #endif
- uint8_t *raddr = label->raddr;
- uint8_t **label_ptr = &label->label_ptr[0];
-
- s_bits = opc & 3;
-
- /* resolve label address */
- *(uint32_t *)label_ptr[0] = (uint32_t)(s->code_ptr - label_ptr[0] - 4);
- if (TARGET_LONG_BITS > TCG_TARGET_REG_BITS) {
- *(uint32_t *)label_ptr[1] = (uint32_t)(s->code_ptr - label_ptr[1] - 4);
- }
-
- #if TCG_TARGET_REG_BITS == 32
- tcg_out_pushi(s, mem_index);
- stack_adjust = 4;
- if (opc == 3) {
- tcg_out_push(s, data_reg2);
- stack_adjust += 4;
- }
- tcg_out_push(s, data_reg);
- stack_adjust += 4;
- if (TARGET_LONG_BITS == 64) {
- tcg_out_push(s, addrhi_reg);
- stack_adjust += 4;
- }
- tcg_out_push(s, addrlo_reg);
- stack_adjust += 4;
- tcg_out_push(s, TCG_AREG0);
- stack_adjust += 4;
- #else
- tcg_out_mov(s, TCG_TYPE_I64, tcg_target_call_iarg_regs[0], TCG_AREG0);
- /* The second argument is already loaded with addrlo. */
- tcg_out_mov(s, (opc == 3 ? TCG_TYPE_I64 : TCG_TYPE_I32),
- tcg_target_call_iarg_regs[2], data_reg);
- tcg_out_movi(s, TCG_TYPE_I32, tcg_target_call_iarg_regs[3], mem_index);
- stack_adjust = 0;
- #endif
-
- /* Code generation of qemu_ld/st's slow path calling MMU helper
-
- PRE_PROC ...
- call MMU helper
- jmp POST_PROC (2b) : short forward jump <- GETRA()
- jmp next_code (5b) : dummy long backward jump which is never executed
- POST_PROC ... : do post-processing <- GETRA() + 7
- jmp next_code : jump to the code corresponding to next IR of qemu_ld/st
- */
-
- tcg_out_calli(s, (tcg_target_long)qemu_st_helpers[s_bits]);
-
- /* Jump to post-processing code */
- tcg_out8(s, OPC_JMP_short);
- tcg_out8(s, 5);
- /* Dummy backward jump having information of fast path'pc for MMU helpers */
- tcg_out8(s, OPC_JMP_long);
- *(int32_t *)s->code_ptr = (int32_t)(raddr - s->code_ptr - 4);
- s->code_ptr += 4;
-
- if (stack_adjust == (TCG_TARGET_REG_BITS / 8)) {
- /* Pop and discard. This is 2 bytes smaller than the add. */
- tcg_out_pop(s, TCG_REG_ECX);
- } else if (stack_adjust != 0) {
- tcg_out_addi(s, TCG_REG_CALL_STACK, stack_adjust);
- }
-
- /* Jump to the code corresponding to next IR of qemu_st */
- tcg_out_jmp(s, (tcg_target_long)raddr);
- }
-
- /*
- * Generate TB finalization at the end of block
- */
- void tcg_out_tb_finalize(TCGContext *s)
- {
- int i;
- TCGLabelQemuLdst *label;
-
- /* qemu_ld/st slow paths */
- for (i = 0; i < s->nb_qemu_ldst_labels; i++) {
- label = (TCGLabelQemuLdst *)&s->qemu_ldst_labels[i];
- if (label->is_ld) {
- tcg_out_qemu_ld_slow_path(s, label);
- } else {
- tcg_out_qemu_st_slow_path(s, label);
- }
- }
- }
- #endif /* CONFIG_SOFTMMU */
-
static inline void tcg_out_op(TCGContext *s, TCGOpcode opc,
const TCGArg *args, const int *const_args)
{
switch(opc) {
case INDEX_op_exit_tb:
tcg_out_movi(s, TCG_TYPE_PTR, TCG_REG_EAX, args[0]);
- tcg_out_jmp(s, (tcg_target_long) tb_ret_addr);
+ tcg_out_jmp(s, (uintptr_t)tb_ret_addr);
break;
case INDEX_op_goto_tb:
if (s->tb_jmp_offset) {
} else {
/* indirect jump method */
tcg_out_modrm_offset(s, OPC_GRP5, EXT5_JMPN_Ev, -1,
- (tcg_target_long)(s->tb_next + args[0]));
+ (intptr_t)(s->tb_next + args[0]));
}
s->tb_next_offset[args[0]] = s->code_ptr - s->code_buf;
break;
tcg_out_ext16u(s, args[0], args[1]);
break;
- case INDEX_op_qemu_ld8u:
+ case INDEX_op_qemu_ld_i32:
tcg_out_qemu_ld(s, args, 0);
break;
- case INDEX_op_qemu_ld8s:
- tcg_out_qemu_ld(s, args, 0 | 4);
- break;
- case INDEX_op_qemu_ld16u:
+ case INDEX_op_qemu_ld_i64:
tcg_out_qemu_ld(s, args, 1);
break;
- case INDEX_op_qemu_ld16s:
- tcg_out_qemu_ld(s, args, 1 | 4);
- break;
- #if TCG_TARGET_REG_BITS == 64
- case INDEX_op_qemu_ld32u:
- #endif
- case INDEX_op_qemu_ld32:
- tcg_out_qemu_ld(s, args, 2);
- break;
- case INDEX_op_qemu_ld64:
- tcg_out_qemu_ld(s, args, 3);
- break;
-
- case INDEX_op_qemu_st8:
+ case INDEX_op_qemu_st_i32:
tcg_out_qemu_st(s, args, 0);
break;
- case INDEX_op_qemu_st16:
+ case INDEX_op_qemu_st_i64:
tcg_out_qemu_st(s, args, 1);
break;
- case INDEX_op_qemu_st32:
- tcg_out_qemu_st(s, args, 2);
- break;
- case INDEX_op_qemu_st64:
- tcg_out_qemu_st(s, args, 3);
- break;
OP_32_64(mulu2):
tcg_out_modrm(s, OPC_GRP3_Ev + rexw, EXT3_MUL, args[3]);
tcg_out_st(s, TCG_TYPE_I64, args[0], args[1], args[2]);
}
break;
- case INDEX_op_qemu_ld32s:
- tcg_out_qemu_ld(s, args, 2 | 4);
- break;
case INDEX_op_brcond_i64:
tcg_out_brcond64(s, args[2], args[0], args[1], const_args[1],
#endif
#if TCG_TARGET_REG_BITS == 64
- { INDEX_op_qemu_ld8u, { "r", "L" } },
- { INDEX_op_qemu_ld8s, { "r", "L" } },
- { INDEX_op_qemu_ld16u, { "r", "L" } },
- { INDEX_op_qemu_ld16s, { "r", "L" } },
- { INDEX_op_qemu_ld32, { "r", "L" } },
- { INDEX_op_qemu_ld32u, { "r", "L" } },
- { INDEX_op_qemu_ld32s, { "r", "L" } },
- { INDEX_op_qemu_ld64, { "r", "L" } },
-
- { INDEX_op_qemu_st8, { "L", "L" } },
- { INDEX_op_qemu_st16, { "L", "L" } },
- { INDEX_op_qemu_st32, { "L", "L" } },
- { INDEX_op_qemu_st64, { "L", "L" } },
+ { INDEX_op_qemu_ld_i32, { "r", "L" } },
+ { INDEX_op_qemu_st_i32, { "L", "L" } },
+ { INDEX_op_qemu_ld_i64, { "r", "L" } },
+ { INDEX_op_qemu_st_i64, { "L", "L" } },
#elif TARGET_LONG_BITS <= TCG_TARGET_REG_BITS
- { INDEX_op_qemu_ld8u, { "r", "L" } },
- { INDEX_op_qemu_ld8s, { "r", "L" } },
- { INDEX_op_qemu_ld16u, { "r", "L" } },
- { INDEX_op_qemu_ld16s, { "r", "L" } },
- { INDEX_op_qemu_ld32, { "r", "L" } },
- { INDEX_op_qemu_ld64, { "r", "r", "L" } },
-
- { INDEX_op_qemu_st8, { "cb", "L" } },
- { INDEX_op_qemu_st16, { "L", "L" } },
- { INDEX_op_qemu_st32, { "L", "L" } },
- { INDEX_op_qemu_st64, { "L", "L", "L" } },
+ { INDEX_op_qemu_ld_i32, { "r", "L" } },
+ { INDEX_op_qemu_st_i32, { "L", "L" } },
+ { INDEX_op_qemu_ld_i64, { "r", "r", "L" } },
+ { INDEX_op_qemu_st_i64, { "L", "L", "L" } },
#else
- { INDEX_op_qemu_ld8u, { "r", "L", "L" } },
- { INDEX_op_qemu_ld8s, { "r", "L", "L" } },
- { INDEX_op_qemu_ld16u, { "r", "L", "L" } },
- { INDEX_op_qemu_ld16s, { "r", "L", "L" } },
- { INDEX_op_qemu_ld32, { "r", "L", "L" } },
- { INDEX_op_qemu_ld64, { "r", "r", "L", "L" } },
-
- { INDEX_op_qemu_st8, { "cb", "L", "L" } },
- { INDEX_op_qemu_st16, { "L", "L", "L" } },
- { INDEX_op_qemu_st32, { "L", "L", "L" } },
- { INDEX_op_qemu_st64, { "L", "L", "L", "L" } },
+ { INDEX_op_qemu_ld_i32, { "r", "L", "L" } },
+ { INDEX_op_qemu_st_i32, { "L", "L", "L" } },
+ { INDEX_op_qemu_ld_i64, { "r", "r", "L", "L" } },
+ { INDEX_op_qemu_st_i64, { "L", "L", "L", "L" } },
#endif
{ -1 },
};
#if defined(ELF_HOST_MACHINE)
void tcg_register_jit(void *buf, size_t buf_size)
{
- debug_frame.fde.func_start = (tcg_target_long) buf;
+ debug_frame.fde.func_start = (uintptr_t)buf;
debug_frame.fde.func_len = buf_size;
tcg_register_jit_int(buf, buf_size, &debug_frame, sizeof(debug_frame));
#include "tcg-op.h"
- #if TCG_TARGET_REG_BITS == 64
- # define ELF_CLASS ELFCLASS64
- #else
+ #if UINTPTR_MAX == UINT32_MAX
# define ELF_CLASS ELFCLASS32
+ #else
+ # define ELF_CLASS ELFCLASS64
#endif
#ifdef HOST_WORDS_BIGENDIAN
# define ELF_DATA ELFDATA2MSB
/* Forward declarations for functions declared in tcg-target.c and used here. */
static void tcg_target_init(TCGContext *s);
static void tcg_target_qemu_prologue(TCGContext *s);
- static void patch_reloc(uint8_t *code_ptr, int type,
- tcg_target_long value, tcg_target_long addend);
+ static void patch_reloc(uint8_t *code_ptr, int type,
+ intptr_t value, intptr_t addend);
/* The CIE and FDE header definitions will be common to all hosts. */
typedef struct {
typedef struct QEMU_PACKED {
uint32_t len __attribute__((aligned((sizeof(void *)))));
uint32_t cie_offset;
- tcg_target_long func_start;
- tcg_target_long func_len;
+ uintptr_t func_start;
+ uintptr_t func_len;
} DebugFrameFDEHeader;
static void tcg_register_jit_int(void *buf, size_t size,
/* Forward declarations for functions declared and used in tcg-target.c. */
static int target_parse_constraint(TCGArgConstraint *ct, const char **pct_str);
static void tcg_out_ld(TCGContext *s, TCGType type, TCGReg ret, TCGReg arg1,
- tcg_target_long arg2);
+ intptr_t arg2);
static void tcg_out_mov(TCGContext *s, TCGType type, TCGReg ret, TCGReg arg);
static void tcg_out_movi(TCGContext *s, TCGType type,
TCGReg ret, tcg_target_long arg);
static void tcg_out_op(TCGContext *s, TCGOpcode opc, const TCGArg *args,
const int *const_args);
static void tcg_out_st(TCGContext *s, TCGType type, TCGReg arg, TCGReg arg1,
- tcg_target_long arg2);
+ intptr_t arg2);
static int tcg_target_const_match(tcg_target_long val,
const TCGArgConstraint *arg_ct);
+ static void tcg_out_tb_init(TCGContext *s);
+ static void tcg_out_tb_finalize(TCGContext *s);
+
TCGOpDef tcg_op_defs[] = {
#define DEF(s, oargs, iargs, cargs, flags) { #s, oargs, iargs, cargs, iargs + oargs + cargs, flags },
static inline void tcg_out16(TCGContext *s, uint16_t v)
{
- *(uint16_t *)s->code_ptr = v;
- s->code_ptr += 2;
+ uint8_t *p = s->code_ptr;
+ *(uint16_t *)p = v;
+ s->code_ptr = p + 2;
}
static inline void tcg_out32(TCGContext *s, uint32_t v)
{
- *(uint32_t *)s->code_ptr = v;
- s->code_ptr += 4;
+ uint8_t *p = s->code_ptr;
+ *(uint32_t *)p = v;
+ s->code_ptr = p + 4;
+ }
+
+ static inline void tcg_out64(TCGContext *s, uint64_t v)
+ {
+ uint8_t *p = s->code_ptr;
+ *(uint64_t *)p = v;
+ s->code_ptr = p + 8;
}
/* label relocation processing */
static void tcg_out_reloc(TCGContext *s, uint8_t *code_ptr, int type,
- int label_index, long addend)
+ int label_index, intptr_t addend)
{
TCGLabel *l;
TCGRelocation *r;
l = &s->labels[label_index];
if (l->has_value) {
/* FIXME: This may break relocations on RISC targets that
- modify instruction fields in place. The caller may not have
+ modify instruction fields in place. The caller may not have
written the initial value. */
patch_reloc(code_ptr, type, l->u.value, addend);
} else {
{
TCGLabel *l;
TCGRelocation *r;
- tcg_target_long value = (tcg_target_long)ptr;
+ intptr_t value = (intptr_t)ptr;
l = &s->labels[label_index];
- if (l->has_value)
+ if (l->has_value) {
tcg_abort();
+ }
r = l->u.first_reloc;
while (r != NULL) {
patch_reloc(r->ptr, r->type, value, r->addend);
{
TCGPool *p;
int pool_size;
-
+
if (size > TCG_POOL_CHUNK_SIZE) {
/* big malloc: insert a new pool (XXX: could optimize) */
p = g_malloc(sizeof(TCGPool) + size);
p = g_malloc(sizeof(TCGPool) + pool_size);
p->size = pool_size;
p->next = NULL;
- if (s->pool_current)
+ if (s->pool_current)
s->pool_current->next = p;
else
s->pool_first = p;
s->pool_current = NULL;
}
+ #include "helper.h"
+
+ typedef struct TCGHelperInfo {
+ void *func;
+ const char *name;
+ } TCGHelperInfo;
+
+ static const TCGHelperInfo all_helpers[] = {
+ #define GEN_HELPER 2
+ #include "helper.h"
+
+ /* Include tcg-runtime.c functions. */
+ { tcg_helper_div_i32, "div_i32" },
+ { tcg_helper_rem_i32, "rem_i32" },
+ { tcg_helper_divu_i32, "divu_i32" },
+ { tcg_helper_remu_i32, "remu_i32" },
+
+ { tcg_helper_shl_i64, "shl_i64" },
+ { tcg_helper_shr_i64, "shr_i64" },
+ { tcg_helper_sar_i64, "sar_i64" },
+ { tcg_helper_div_i64, "div_i64" },
+ { tcg_helper_rem_i64, "rem_i64" },
+ { tcg_helper_divu_i64, "divu_i64" },
+ { tcg_helper_remu_i64, "remu_i64" },
+ { tcg_helper_mulsh_i64, "mulsh_i64" },
+ { tcg_helper_muluh_i64, "muluh_i64" },
+ };
+
void tcg_context_init(TCGContext *s)
{
- int op, total_args, n;
+ int op, total_args, n, i;
TCGOpDef *def;
TCGArgConstraint *args_ct;
int *sorted_args;
+ GHashTable *helper_table;
memset(s, 0, sizeof(*s));
s->nb_globals = 0;
-
+
/* Count total number of arguments and allocate the corresponding
space */
total_args = 0;
args_ct += n;
}
+ /* Register helpers. */
+ /* Use g_direct_hash/equal for direct pointer comparisons on func. */
+ s->helpers = helper_table = g_hash_table_new(NULL, NULL);
+
+ for (i = 0; i < ARRAY_SIZE(all_helpers); ++i) {
+ g_hash_table_insert(helper_table, (gpointer)all_helpers[i].func,
+ (gpointer)all_helpers[i].name);
+ }
+
tcg_target_init(s);
}
s->code_buf = s->code_gen_prologue;
s->code_ptr = s->code_buf;
tcg_target_qemu_prologue(s);
- flush_icache_range((tcg_target_ulong)s->code_buf,
- (tcg_target_ulong)s->code_ptr);
+ flush_icache_range((uintptr_t)s->code_buf, (uintptr_t)s->code_ptr);
#ifdef DEBUG_DISAS
if (qemu_loglevel_mask(CPU_LOG_TB_OUT_ASM)) {
#endif
}
- void tcg_set_frame(TCGContext *s, int reg,
- tcg_target_long start, tcg_target_long size)
+ void tcg_set_frame(TCGContext *s, int reg, intptr_t start, intptr_t size)
{
s->frame_start = start;
s->frame_end = start + size;
s->gen_opc_ptr = s->gen_opc_buf;
s->gen_opparam_ptr = s->gen_opparam_buf;
- #if defined(CONFIG_QEMU_LDST_OPTIMIZATION) && defined(CONFIG_SOFTMMU)
- /* Initialize qemu_ld/st labels to assist code generation at the end of TB
- for TLB miss cases at the end of TB */
- s->qemu_ldst_labels = tcg_malloc(sizeof(TCGLabelQemuLdst) *
- TCG_MAX_QEMU_LDST);
- s->nb_qemu_ldst_labels = 0;
- #endif
+ s->be = tcg_malloc(sizeof(TCGBackendData));
}
static inline void tcg_temp_alloc(TCGContext *s, int n)
}
static inline int tcg_global_mem_new_internal(TCGType type, int reg,
- tcg_target_long offset,
+ intptr_t offset,
const char *name)
{
TCGContext *s = &tcg_ctx;
return idx;
}
- TCGv_i32 tcg_global_mem_new_i32(int reg, tcg_target_long offset,
- const char *name)
+ TCGv_i32 tcg_global_mem_new_i32(int reg, intptr_t offset, const char *name)
{
- int idx;
-
- idx = tcg_global_mem_new_internal(TCG_TYPE_I32, reg, offset, name);
+ int idx = tcg_global_mem_new_internal(TCG_TYPE_I32, reg, offset, name);
return MAKE_TCGV_I32(idx);
}
- TCGv_i64 tcg_global_mem_new_i64(int reg, tcg_target_long offset,
- const char *name)
+ TCGv_i64 tcg_global_mem_new_i64(int reg, intptr_t offset, const char *name)
{
- int idx;
-
- idx = tcg_global_mem_new_internal(TCG_TYPE_I64, reg, offset, name);
+ int idx = tcg_global_mem_new_internal(TCG_TYPE_I64, reg, offset, name);
return MAKE_TCGV_I64(idx);
}
}
#endif
- void tcg_register_helper(void *func, const char *name)
- {
- TCGContext *s = &tcg_ctx;
- int n;
- if ((s->nb_helpers + 1) > s->allocated_helpers) {
- n = s->allocated_helpers;
- if (n == 0) {
- n = 4;
- } else {
- n *= 2;
- }
- s->helpers = realloc(s->helpers, n * sizeof(TCGHelperInfo));
- s->allocated_helpers = n;
- }
- s->helpers[s->nb_helpers].func = (tcg_target_ulong)func;
- s->helpers[s->nb_helpers].name = name;
- s->nb_helpers++;
- }
-
/* Note: we convert the 64 bit args to 32 bit and do some alignment
and endian swap. Maybe it would be better to do the alignment
and endian swap in tcg_reg_alloc_call(). */
}
#endif
+ static inline TCGMemOp tcg_canonicalize_memop(TCGMemOp op, bool is64, bool st)
+ {
+ switch (op & MO_SIZE) {
+ case MO_8:
+ op &= ~MO_BSWAP;
+ break;
+ case MO_16:
+ break;
+ case MO_32:
+ if (!is64) {
+ op &= ~MO_SIGN;
+ }
+ break;
+ case MO_64:
+ if (!is64) {
+ tcg_abort();
+ }
+ break;
+ }
+ if (st) {
+ op &= ~MO_SIGN;
+ }
+ return op;
+ }
+
+ static const TCGOpcode old_ld_opc[8] = {
+ [MO_UB] = INDEX_op_qemu_ld8u,
+ [MO_SB] = INDEX_op_qemu_ld8s,
+ [MO_UW] = INDEX_op_qemu_ld16u,
+ [MO_SW] = INDEX_op_qemu_ld16s,
+ #if TCG_TARGET_REG_BITS == 32
+ [MO_UL] = INDEX_op_qemu_ld32,
+ [MO_SL] = INDEX_op_qemu_ld32,
+ #else
+ [MO_UL] = INDEX_op_qemu_ld32u,
+ [MO_SL] = INDEX_op_qemu_ld32s,
+ #endif
+ [MO_Q] = INDEX_op_qemu_ld64,
+ };
+
+ static const TCGOpcode old_st_opc[4] = {
+ [MO_UB] = INDEX_op_qemu_st8,
+ [MO_UW] = INDEX_op_qemu_st16,
+ [MO_UL] = INDEX_op_qemu_st32,
+ [MO_Q] = INDEX_op_qemu_st64,
+ };
+
+ void tcg_gen_qemu_ld_i32(TCGv_i32 val, TCGv addr, TCGArg idx, TCGMemOp memop)
+ {
+ memop = tcg_canonicalize_memop(memop, 0, 0);
+
+ if (TCG_TARGET_HAS_new_ldst) {
+ *tcg_ctx.gen_opc_ptr++ = INDEX_op_qemu_ld_i32;
+ tcg_add_param_i32(val);
+ tcg_add_param_tl(addr);
+ *tcg_ctx.gen_opparam_ptr++ = memop;
+ *tcg_ctx.gen_opparam_ptr++ = idx;
+ return;
+ }
+
+ /* The old opcodes only support target-endian memory operations. */
+ assert((memop & MO_BSWAP) == MO_TE || (memop & MO_SIZE) == MO_8);
+ assert(old_ld_opc[memop & MO_SSIZE] != 0);
+
+ if (TCG_TARGET_REG_BITS == 32) {
+ *tcg_ctx.gen_opc_ptr++ = old_ld_opc[memop & MO_SSIZE];
+ tcg_add_param_i32(val);
+ tcg_add_param_tl(addr);
+ *tcg_ctx.gen_opparam_ptr++ = idx;
+ } else {
+ TCGv_i64 val64 = tcg_temp_new_i64();
+
+ *tcg_ctx.gen_opc_ptr++ = old_ld_opc[memop & MO_SSIZE];
+ tcg_add_param_i64(val64);
+ tcg_add_param_tl(addr);
+ *tcg_ctx.gen_opparam_ptr++ = idx;
+
+ tcg_gen_trunc_i64_i32(val, val64);
+ tcg_temp_free_i64(val64);
+ }
+ }
+
+ void tcg_gen_qemu_st_i32(TCGv_i32 val, TCGv addr, TCGArg idx, TCGMemOp memop)
+ {
+ memop = tcg_canonicalize_memop(memop, 0, 1);
+
+ if (TCG_TARGET_HAS_new_ldst) {
+ *tcg_ctx.gen_opc_ptr++ = INDEX_op_qemu_st_i32;
+ tcg_add_param_i32(val);
+ tcg_add_param_tl(addr);
+ *tcg_ctx.gen_opparam_ptr++ = memop;
+ *tcg_ctx.gen_opparam_ptr++ = idx;
+ return;
+ }
+
+ /* The old opcodes only support target-endian memory operations. */
+ assert((memop & MO_BSWAP) == MO_TE || (memop & MO_SIZE) == MO_8);
+ assert(old_st_opc[memop & MO_SIZE] != 0);
+
+ if (TCG_TARGET_REG_BITS == 32) {
+ *tcg_ctx.gen_opc_ptr++ = old_st_opc[memop & MO_SIZE];
+ tcg_add_param_i32(val);
+ tcg_add_param_tl(addr);
+ *tcg_ctx.gen_opparam_ptr++ = idx;
+ } else {
+ TCGv_i64 val64 = tcg_temp_new_i64();
+
+ tcg_gen_extu_i32_i64(val64, val);
+
+ *tcg_ctx.gen_opc_ptr++ = old_st_opc[memop & MO_SIZE];
+ tcg_add_param_i64(val64);
+ tcg_add_param_tl(addr);
+ *tcg_ctx.gen_opparam_ptr++ = idx;
+
+ tcg_temp_free_i64(val64);
+ }
+ }
+
+ void tcg_gen_qemu_ld_i64(TCGv_i64 val, TCGv addr, TCGArg idx, TCGMemOp memop)
+ {
+ memop = tcg_canonicalize_memop(memop, 1, 0);
+
+ #if TCG_TARGET_REG_BITS == 32
+ if ((memop & MO_SIZE) < MO_64) {
+ tcg_gen_qemu_ld_i32(TCGV_LOW(val), addr, idx, memop);
+ if (memop & MO_SIGN) {
+ tcg_gen_sari_i32(TCGV_HIGH(val), TCGV_LOW(val), 31);
+ } else {
+ tcg_gen_movi_i32(TCGV_HIGH(val), 0);
+ }
+ return;
+ }
+ #endif
+
+ if (TCG_TARGET_HAS_new_ldst) {
+ *tcg_ctx.gen_opc_ptr++ = INDEX_op_qemu_ld_i64;
+ tcg_add_param_i64(val);
+ tcg_add_param_tl(addr);
+ *tcg_ctx.gen_opparam_ptr++ = memop;
+ *tcg_ctx.gen_opparam_ptr++ = idx;
+ return;
+ }
+
+ /* The old opcodes only support target-endian memory operations. */
+ assert((memop & MO_BSWAP) == MO_TE || (memop & MO_SIZE) == MO_8);
+ assert(old_ld_opc[memop & MO_SSIZE] != 0);
+
+ *tcg_ctx.gen_opc_ptr++ = old_ld_opc[memop & MO_SSIZE];
+ tcg_add_param_i64(val);
+ tcg_add_param_tl(addr);
+ *tcg_ctx.gen_opparam_ptr++ = idx;
+ }
+
+ void tcg_gen_qemu_st_i64(TCGv_i64 val, TCGv addr, TCGArg idx, TCGMemOp memop)
+ {
+ memop = tcg_canonicalize_memop(memop, 1, 1);
+
+ #if TCG_TARGET_REG_BITS == 32
+ if ((memop & MO_SIZE) < MO_64) {
+ tcg_gen_qemu_st_i32(TCGV_LOW(val), addr, idx, memop);
+ return;
+ }
+ #endif
+
+ if (TCG_TARGET_HAS_new_ldst) {
+ *tcg_ctx.gen_opc_ptr++ = INDEX_op_qemu_st_i64;
+ tcg_add_param_i64(val);
+ tcg_add_param_tl(addr);
+ *tcg_ctx.gen_opparam_ptr++ = memop;
+ *tcg_ctx.gen_opparam_ptr++ = idx;
+ return;
+ }
+
+ /* The old opcodes only support target-endian memory operations. */
+ assert((memop & MO_BSWAP) == MO_TE || (memop & MO_SIZE) == MO_8);
+ assert(old_st_opc[memop & MO_SIZE] != 0);
+
+ *tcg_ctx.gen_opc_ptr++ = old_st_opc[memop & MO_SIZE];
+ tcg_add_param_i64(val);
+ tcg_add_param_tl(addr);
+ *tcg_ctx.gen_opparam_ptr++ = idx;
+ }
static void tcg_reg_alloc_start(TCGContext *s)
{
return tcg_get_arg_str_idx(s, buf, buf_size, GET_TCGV_I64(arg));
}
- static int helper_cmp(const void *p1, const void *p2)
- {
- const TCGHelperInfo *th1 = p1;
- const TCGHelperInfo *th2 = p2;
- if (th1->func < th2->func)
- return -1;
- else if (th1->func == th2->func)
- return 0;
- else
- return 1;
- }
-
- /* find helper definition (Note: A hash table would be better) */
- static TCGHelperInfo *tcg_find_helper(TCGContext *s, tcg_target_ulong val)
+ /* Find helper name. */
+ static inline const char *tcg_find_helper(TCGContext *s, uintptr_t val)
{
- int m, m_min, m_max;
- TCGHelperInfo *th;
- tcg_target_ulong v;
-
- if (unlikely(!s->helpers_sorted)) {
- qsort(s->helpers, s->nb_helpers, sizeof(TCGHelperInfo),
- helper_cmp);
- s->helpers_sorted = 1;
+ const char *ret = NULL;
+ if (s->helpers) {
+ ret = g_hash_table_lookup(s->helpers, (gpointer)val);
}
-
- /* binary search */
- m_min = 0;
- m_max = s->nb_helpers - 1;
- while (m_min <= m_max) {
- m = (m_min + m_max) >> 1;
- th = &s->helpers[m];
- v = th->func;
- if (v == val)
- return th;
- else if (val < v) {
- m_max = m - 1;
- } else {
- m_min = m + 1;
- }
- }
- return NULL;
+ return ret;
}
static const char * const cond_name[] =
[TCG_COND_GTU] = "gtu"
};
+ static const char * const ldst_name[] =
+ {
+ [MO_UB] = "ub",
+ [MO_SB] = "sb",
+ [MO_LEUW] = "leuw",
+ [MO_LESW] = "lesw",
+ [MO_LEUL] = "leul",
+ [MO_LESL] = "lesl",
+ [MO_LEQ] = "leq",
+ [MO_BEUW] = "beuw",
+ [MO_BESW] = "besw",
+ [MO_BEUL] = "beul",
+ [MO_BESL] = "besl",
+ [MO_BEQ] = "beq",
+ };
+
void tcg_dump_ops(TCGContext *s)
{
const uint16_t *opc_ptr;
}
} else if (c == INDEX_op_movi_i32 || c == INDEX_op_movi_i64) {
tcg_target_ulong val;
- TCGHelperInfo *th;
+ const char *name;
nb_oargs = def->nb_oargs;
nb_iargs = def->nb_iargs;
qemu_log(" %s %s,$", def->name,
tcg_get_arg_str_idx(s, buf, sizeof(buf), args[0]));
val = args[1];
- th = tcg_find_helper(s, val);
- if (th) {
- qemu_log("%s", th->name);
+ name = tcg_find_helper(s, val);
+ if (name) {
+ qemu_log("%s", name);
} else {
if (c == INDEX_op_movi_i32) {
qemu_log("0x%x", (uint32_t)val);
}
i = 1;
break;
+ case INDEX_op_qemu_ld_i32:
+ case INDEX_op_qemu_st_i32:
+ case INDEX_op_qemu_ld_i64:
+ case INDEX_op_qemu_st_i64:
+ if (args[k] < ARRAY_SIZE(ldst_name) && ldst_name[args[k]]) {
+ qemu_log(",%s", ldst_name[args[k++]]);
+ } else {
+ qemu_log(",$0x%" TCG_PRIlx, args[k++]);
+ }
+ i = 1;
+ break;
default:
i = 0;
break;
static void tcg_liveness_analysis(TCGContext *s)
{
int i, op_index, nb_args, nb_iargs, nb_oargs, arg, nb_ops;
- TCGOpcode op, op_new;
+ TCGOpcode op, op_new, op_new2;
TCGArg *args;
const TCGOpDef *def;
uint8_t *dead_temps, *mem_temps;
uint16_t dead_args;
uint8_t sync_args;
+ bool have_op_new2;
s->gen_opc_ptr++; /* skip end */
goto do_not_remove;
case INDEX_op_mulu2_i32:
+ op_new = INDEX_op_mul_i32;
+ op_new2 = INDEX_op_muluh_i32;
+ have_op_new2 = TCG_TARGET_HAS_muluh_i32;
+ goto do_mul2;
case INDEX_op_muls2_i32:
op_new = INDEX_op_mul_i32;
+ op_new2 = INDEX_op_mulsh_i32;
+ have_op_new2 = TCG_TARGET_HAS_mulsh_i32;
goto do_mul2;
case INDEX_op_mulu2_i64:
+ op_new = INDEX_op_mul_i64;
+ op_new2 = INDEX_op_muluh_i64;
+ have_op_new2 = TCG_TARGET_HAS_muluh_i64;
+ goto do_mul2;
case INDEX_op_muls2_i64:
op_new = INDEX_op_mul_i64;
+ op_new2 = INDEX_op_mulsh_i64;
+ have_op_new2 = TCG_TARGET_HAS_mulsh_i64;
+ goto do_mul2;
do_mul2:
args -= 4;
nb_iargs = 2;
nb_oargs = 2;
- /* Likewise, test for the high part of the operation dead. */
if (dead_temps[args[1]] && !mem_temps[args[1]]) {
if (dead_temps[args[0]] && !mem_temps[args[0]]) {
+ /* Both parts of the operation are dead. */
goto do_remove;
}
+ /* The high part of the operation is dead; generate the low. */
s->gen_opc_buf[op_index] = op = op_new;
args[1] = args[2];
args[2] = args[3];
- assert(s->gen_opc_buf[op_index + 1] == INDEX_op_nop);
- tcg_set_nop(s, s->gen_opc_buf + op_index + 1, args + 3, 1);
- /* Fall through and mark the single-word operation live. */
- nb_oargs = 1;
+ } else if (have_op_new2 && dead_temps[args[0]]
+ && !mem_temps[args[0]]) {
+ /* The low part of the operation is dead; generate the high. */
+ s->gen_opc_buf[op_index] = op = op_new2;
+ args[0] = args[1];
+ args[1] = args[2];
+ args[2] = args[3];
+ } else {
+ goto do_not_remove;
}
+ assert(s->gen_opc_buf[op_index + 1] == INDEX_op_nop);
+ tcg_set_nop(s, s->gen_opc_buf + op_index + 1, args + 3, 1);
+ /* Mark the single-word operation live. */
+ nb_oargs = 1;
goto do_not_remove;
default:
ts->mem_offset = s->current_frame_offset;
ts->mem_reg = s->frame_reg;
ts->mem_allocated = 1;
- s->current_frame_offset += (tcg_target_long)sizeof(tcg_target_long);
+ s->current_frame_offset += sizeof(tcg_target_long);
}
/* sync register 'reg' by saving it to the corresponding temporary */
int nb_iargs, nb_oargs, flags, nb_regs, i, reg, nb_params;
TCGArg arg, func_arg;
TCGTemp *ts;
- tcg_target_long stack_offset, call_stack_size, func_addr;
+ intptr_t stack_offset;
+ size_t call_stack_size;
+ uintptr_t func_addr;
int const_func_arg, allocate_args;
TCGRegSet allocated_regs;
const TCGArgConstraint *arg_ct;
s->code_buf = gen_code_buf;
s->code_ptr = gen_code_buf;
+ tcg_out_tb_init(s);
+
args = s->gen_opparam_buf;
op_index = 0;
#endif
}
the_end:
- #if defined(CONFIG_QEMU_LDST_OPTIMIZATION) && defined(CONFIG_SOFTMMU)
/* Generate TB finalization at the end of block */
tcg_out_tb_finalize(s);
- #endif
return -1;
}
tcg_gen_code_common(s, gen_code_buf, -1);
/* flush instruction cache */
- flush_icache_range((tcg_target_ulong)gen_code_buf,
- (tcg_target_ulong)s->code_ptr);
+ flush_icache_range((uintptr_t)gen_code_buf, (uintptr_t)s->code_ptr);
return s->code_ptr - gen_code_buf;
}
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
+
+ #ifndef TCG_H
+ #define TCG_H
+
#include "qemu-common.h"
- /* Target word size (must be identical to pointer size). */
- #if UINTPTR_MAX == UINT32_MAX
- # define TCG_TARGET_REG_BITS 32
- #elif UINTPTR_MAX == UINT64_MAX
- # define TCG_TARGET_REG_BITS 64
- #else
- # error Unknown pointer size for tcg target
+ #include "tcg-target.h"
+
+ /* Default target word size to pointer size. */
+ #ifndef TCG_TARGET_REG_BITS
+ # if UINTPTR_MAX == UINT32_MAX
+ # define TCG_TARGET_REG_BITS 32
+ # elif UINTPTR_MAX == UINT64_MAX
+ # define TCG_TARGET_REG_BITS 64
+ # else
+ # error Unknown pointer size for tcg target
+ # endif
#endif
#if TCG_TARGET_REG_BITS == 32
#error unsupported
#endif
- #include "tcg-target.h"
#include "tcg-runtime.h"
#if TCG_TARGET_NB_REGS <= 32
#define TCG_TARGET_HAS_sub2_i64 0
#define TCG_TARGET_HAS_mulu2_i64 0
#define TCG_TARGET_HAS_muls2_i64 0
+ #define TCG_TARGET_HAS_muluh_i64 0
+ #define TCG_TARGET_HAS_mulsh_i64 0
/* Turn some undef macros into true macros. */
#define TCG_TARGET_HAS_add2_i32 1
#define TCG_TARGET_HAS_sub2_i32 1
struct TCGRelocation *next;
int type;
uint8_t *ptr;
- tcg_target_long addend;
- } TCGRelocation;
+ intptr_t addend;
+ } TCGRelocation;
typedef struct TCGLabel {
int has_value;
union {
- tcg_target_ulong value;
+ uintptr_t value;
TCGRelocation *first_reloc;
} u;
} TCGLabel;
TCG_TYPE_REG = TCG_TYPE_I64,
#endif
- /* An alias for the size of the native pointer. We don't currently
- support any hosts with 64-bit registers and 32-bit pointers. */
- TCG_TYPE_PTR = TCG_TYPE_REG,
+ /* An alias for the size of the native pointer. */
+ #if UINTPTR_MAX == UINT32_MAX
+ TCG_TYPE_PTR = TCG_TYPE_I32,
+ #else
+ TCG_TYPE_PTR = TCG_TYPE_I64,
+ #endif
/* An alias for the size of the target "long", aka register. */
#if TARGET_LONG_BITS == 64
#endif
} TCGType;
+ /* Constants for qemu_ld and qemu_st for the Memory Operation field. */
+ typedef enum TCGMemOp {
+ MO_8 = 0,
+ MO_16 = 1,
+ MO_32 = 2,
+ MO_64 = 3,
+ MO_SIZE = 3, /* Mask for the above. */
+
+ MO_SIGN = 4, /* Sign-extended, otherwise zero-extended. */
+
+ MO_BSWAP = 8, /* Host reverse endian. */
+ #ifdef HOST_WORDS_BIGENDIAN
+ MO_LE = MO_BSWAP,
+ MO_BE = 0,
+ #else
+ MO_LE = 0,
+ MO_BE = MO_BSWAP,
+ #endif
+ #ifdef TARGET_WORDS_BIGENDIAN
+ MO_TE = MO_BE,
+ #else
+ MO_TE = MO_LE,
+ #endif
+
+ /* Combinations of the above, for ease of use. */
+ MO_UB = MO_8,
+ MO_UW = MO_16,
+ MO_UL = MO_32,
+ MO_SB = MO_SIGN | MO_8,
+ MO_SW = MO_SIGN | MO_16,
+ MO_SL = MO_SIGN | MO_32,
+ MO_Q = MO_64,
+
+ MO_LEUW = MO_LE | MO_UW,
+ MO_LEUL = MO_LE | MO_UL,
+ MO_LESW = MO_LE | MO_SW,
+ MO_LESL = MO_LE | MO_SL,
+ MO_LEQ = MO_LE | MO_Q,
+
+ MO_BEUW = MO_BE | MO_UW,
+ MO_BEUL = MO_BE | MO_UL,
+ MO_BESW = MO_BE | MO_SW,
+ MO_BESL = MO_BE | MO_SL,
+ MO_BEQ = MO_BE | MO_Q,
+
+ MO_TEUW = MO_TE | MO_UW,
+ MO_TEUL = MO_TE | MO_UL,
+ MO_TESW = MO_TE | MO_SW,
+ MO_TESL = MO_TE | MO_SL,
+ MO_TEQ = MO_TE | MO_Q,
+
+ MO_SSIZE = MO_SIZE | MO_SIGN,
+ } TCGMemOp;
+
typedef tcg_target_ulong TCGArg;
/* Define a type and accessor macros for variables. Using a struct is
are aliases for target_ulong and host pointer sized values respectively.
*/
- #if defined(CONFIG_QEMU_LDST_OPTIMIZATION) && defined(CONFIG_SOFTMMU)
- /* Macros/structures for qemu_ld/st IR code optimization:
- TCG_MAX_HELPER_LABELS is defined as same as OPC_BUF_SIZE in exec-all.h. */
- #define TCG_MAX_QEMU_LDST 640
-
- typedef struct TCGLabelQemuLdst {
- int is_ld:1; /* qemu_ld: 1, qemu_st: 0 */
- int opc:4;
- int addrlo_reg; /* reg index for low word of guest virtual addr */
- int addrhi_reg; /* reg index for high word of guest virtual addr */
- int datalo_reg; /* reg index for low word to be loaded or stored */
- int datahi_reg; /* reg index for high word to be loaded or stored */
- int mem_index; /* soft MMU memory index */
- uint8_t *raddr; /* gen code addr of the next IR of qemu_ld/st IR */
- uint8_t *label_ptr[2]; /* label pointers to be updated */
- } TCGLabelQemuLdst;
- #endif
-
#ifdef CONFIG_DEBUG_TCG
#define DEBUG_TCGV 1
#endif
int reg;
tcg_target_long val;
int mem_reg;
- tcg_target_long mem_offset;
+ intptr_t mem_offset;
unsigned int fixed_reg:1;
unsigned int mem_coherent:1;
unsigned int mem_allocated:1;
const char *name;
} TCGTemp;
- typedef struct TCGHelperInfo {
- tcg_target_ulong func;
- const char *name;
- } TCGHelperInfo;
-
typedef struct TCGContext TCGContext;
struct TCGContext {
int nb_globals;
int nb_temps;
/* index of free temps, -1 if none */
- int first_free_temp[TCG_TYPE_COUNT * 2];
+ int first_free_temp[TCG_TYPE_COUNT * 2];
/* goto_tb support */
uint8_t *code_buf;
into account fixed registers */
int reg_to_temp[TCG_TARGET_NB_REGS];
TCGRegSet reserved_regs;
- tcg_target_long current_frame_offset;
- tcg_target_long frame_start;
- tcg_target_long frame_end;
+ intptr_t current_frame_offset;
+ intptr_t frame_start;
+ intptr_t frame_end;
int frame_reg;
uint8_t *code_ptr;
TCGTemp temps[TCG_MAX_TEMPS]; /* globals first, temps after */
- TCGHelperInfo *helpers;
- int nb_helpers;
- int allocated_helpers;
- int helpers_sorted;
+ GHashTable *helpers;
#ifdef CONFIG_PROFILER
/* profiling info */
TBContext tb_ctx;
- #if defined(CONFIG_QEMU_LDST_OPTIMIZATION) && defined(CONFIG_SOFTMMU)
- /* labels info for qemu_ld/st IRs
- The labels help to generate TLB miss case codes at the end of TB */
- TCGLabelQemuLdst *qemu_ldst_labels;
- int nb_qemu_ldst_labels;
- #endif
+ /* The TCGBackendData structure is private to tcg-target.c. */
+ struct TCGBackendData *be;
};
extern TCGContext tcg_ctx;
int tcg_gen_code(TCGContext *s, uint8_t *gen_code_buf);
int tcg_gen_code_search_pc(TCGContext *s, uint8_t *gen_code_buf, long offset);
- void tcg_set_frame(TCGContext *s, int reg,
- tcg_target_long start, tcg_target_long size);
+ void tcg_set_frame(TCGContext *s, int reg, intptr_t start, intptr_t size);
TCGv_i32 tcg_global_reg_new_i32(int reg, const char *name);
- TCGv_i32 tcg_global_mem_new_i32(int reg, tcg_target_long offset,
- const char *name);
+ TCGv_i32 tcg_global_mem_new_i32(int reg, intptr_t offset, const char *name);
TCGv_i32 tcg_temp_new_internal_i32(int temp_local);
static inline TCGv_i32 tcg_temp_new_i32(void)
{
char *tcg_get_arg_str_i32(TCGContext *s, char *buf, int buf_size, TCGv_i32 arg);
TCGv_i64 tcg_global_reg_new_i64(int reg, const char *name);
- TCGv_i64 tcg_global_mem_new_i64(int reg, tcg_target_long offset,
- const char *name);
+ TCGv_i64 tcg_global_mem_new_i64(int reg, intptr_t offset, const char *name);
TCGv_i64 tcg_temp_new_internal_i64(int temp_local);
static inline TCGv_i64 tcg_temp_new_i64(void)
{
void tcg_add_target_add_op_defs(const TCGTargetOpDef *tdefs);
- #if TCG_TARGET_REG_BITS == 32
+ #if UINTPTR_MAX == UINT32_MAX
#define TCGV_NAT_TO_PTR(n) MAKE_TCGV_PTR(GET_TCGV_I32(n))
#define TCGV_PTR_TO_NAT(n) MAKE_TCGV_I32(GET_TCGV_PTR(n))
- #define tcg_const_ptr(V) TCGV_NAT_TO_PTR(tcg_const_i32((tcg_target_long)(V)))
+ #define tcg_const_ptr(V) TCGV_NAT_TO_PTR(tcg_const_i32((intptr_t)(V)))
#define tcg_global_reg_new_ptr(R, N) \
TCGV_NAT_TO_PTR(tcg_global_reg_new_i32((R), (N)))
#define tcg_global_mem_new_ptr(R, O, N) \
#define TCGV_NAT_TO_PTR(n) MAKE_TCGV_PTR(GET_TCGV_I64(n))
#define TCGV_PTR_TO_NAT(n) MAKE_TCGV_I64(GET_TCGV_PTR(n))
- #define tcg_const_ptr(V) TCGV_NAT_TO_PTR(tcg_const_i64((tcg_target_long)(V)))
+ #define tcg_const_ptr(V) TCGV_NAT_TO_PTR(tcg_const_i64((intptr_t)(V)))
#define tcg_global_reg_new_ptr(R, N) \
TCGV_NAT_TO_PTR(tcg_global_reg_new_i64((R), (N)))
#define tcg_global_mem_new_ptr(R, O, N) \
TCGOpDef *tcg_op_def);
/* only used for debugging purposes */
- void tcg_register_helper(void *func, const char *name);
- const char *tcg_helper_get_name(TCGContext *s, void *func);
void tcg_dump_ops(TCGContext *s);
void dump_ops(const uint16_t *opc_buf, const TCGArg *opparam_buf);
#if !defined(tcg_qemu_tb_exec)
# define tcg_qemu_tb_exec(env, tb_ptr) \
- ((tcg_target_ulong (*)(void *, void *))tcg_ctx.code_gen_prologue)(env, \
- tb_ptr)
+ ((uintptr_t (*)(void *, void *))tcg_ctx.code_gen_prologue)(env, tb_ptr)
#endif
void tcg_register_jit(void *buf, size_t buf_size);
- #if defined(CONFIG_QEMU_LDST_OPTIMIZATION) && defined(CONFIG_SOFTMMU)
- /* Generate TB finalization at the end of block */
- void tcg_out_tb_finalize(TCGContext *s);
+ /*
+ * Memory helpers that will be used by TCG generated code.
+ */
+ #ifdef CONFIG_SOFTMMU
+ /* Value zero-extended to tcg register size. */
+ tcg_target_ulong helper_ret_ldub_mmu(CPUArchState *env, target_ulong addr,
+ int mmu_idx, uintptr_t retaddr);
+ tcg_target_ulong helper_le_lduw_mmu(CPUArchState *env, target_ulong addr,
+ int mmu_idx, uintptr_t retaddr);
+ tcg_target_ulong helper_le_ldul_mmu(CPUArchState *env, target_ulong addr,
+ int mmu_idx, uintptr_t retaddr);
+ uint64_t helper_le_ldq_mmu(CPUArchState *env, target_ulong addr,
+ int mmu_idx, uintptr_t retaddr);
+ tcg_target_ulong helper_be_lduw_mmu(CPUArchState *env, target_ulong addr,
+ int mmu_idx, uintptr_t retaddr);
+ tcg_target_ulong helper_be_ldul_mmu(CPUArchState *env, target_ulong addr,
+ int mmu_idx, uintptr_t retaddr);
+ uint64_t helper_be_ldq_mmu(CPUArchState *env, target_ulong addr,
+ int mmu_idx, uintptr_t retaddr);
+
+ /* Value sign-extended to tcg register size. */
+ tcg_target_ulong helper_ret_ldsb_mmu(CPUArchState *env, target_ulong addr,
+ int mmu_idx, uintptr_t retaddr);
+ tcg_target_ulong helper_le_ldsw_mmu(CPUArchState *env, target_ulong addr,
+ int mmu_idx, uintptr_t retaddr);
+ tcg_target_ulong helper_le_ldsl_mmu(CPUArchState *env, target_ulong addr,
+ int mmu_idx, uintptr_t retaddr);
+ tcg_target_ulong helper_be_ldsw_mmu(CPUArchState *env, target_ulong addr,
+ int mmu_idx, uintptr_t retaddr);
+ tcg_target_ulong helper_be_ldsl_mmu(CPUArchState *env, target_ulong addr,
+ int mmu_idx, uintptr_t retaddr);
+
+ void helper_ret_stb_mmu(CPUArchState *env, target_ulong addr, uint8_t val,
+ int mmu_idx, uintptr_t retaddr);
+ void helper_le_stw_mmu(CPUArchState *env, target_ulong addr, uint16_t val,
+ int mmu_idx, uintptr_t retaddr);
+ void helper_le_stl_mmu(CPUArchState *env, target_ulong addr, uint32_t val,
+ int mmu_idx, uintptr_t retaddr);
+ void helper_le_stq_mmu(CPUArchState *env, target_ulong addr, uint64_t val,
+ int mmu_idx, uintptr_t retaddr);
+ void helper_be_stw_mmu(CPUArchState *env, target_ulong addr, uint16_t val,
+ int mmu_idx, uintptr_t retaddr);
+ void helper_be_stl_mmu(CPUArchState *env, target_ulong addr, uint32_t val,
+ int mmu_idx, uintptr_t retaddr);
+ void helper_be_stq_mmu(CPUArchState *env, target_ulong addr, uint64_t val,
+ int mmu_idx, uintptr_t retaddr);
+
+ /* Temporary aliases until backends are converted. */
+ #ifdef TARGET_WORDS_BIGENDIAN
+ # define helper_ret_ldsw_mmu helper_be_ldsw_mmu
+ # define helper_ret_lduw_mmu helper_be_lduw_mmu
+ # define helper_ret_ldsl_mmu helper_be_ldsl_mmu
+ # define helper_ret_ldul_mmu helper_be_ldul_mmu
+ # define helper_ret_ldq_mmu helper_be_ldq_mmu
+ # define helper_ret_stw_mmu helper_be_stw_mmu
+ # define helper_ret_stl_mmu helper_be_stl_mmu
+ # define helper_ret_stq_mmu helper_be_stq_mmu
+ #else
+ # define helper_ret_ldsw_mmu helper_le_ldsw_mmu
+ # define helper_ret_lduw_mmu helper_le_lduw_mmu
+ # define helper_ret_ldsl_mmu helper_le_ldsl_mmu
+ # define helper_ret_ldul_mmu helper_le_ldul_mmu
+ # define helper_ret_ldq_mmu helper_le_ldq_mmu
+ # define helper_ret_stw_mmu helper_le_stw_mmu
+ # define helper_ret_stl_mmu helper_le_stl_mmu
+ # define helper_ret_stq_mmu helper_le_stq_mmu
#endif
+
+ uint8_t helper_ldb_mmu(CPUArchState *env, target_ulong addr, int mmu_idx);
+ uint16_t helper_ldw_mmu(CPUArchState *env, target_ulong addr, int mmu_idx);
+ uint32_t helper_ldl_mmu(CPUArchState *env, target_ulong addr, int mmu_idx);
+ uint64_t helper_ldq_mmu(CPUArchState *env, target_ulong addr, int mmu_idx);
+
+ void helper_stb_mmu(CPUArchState *env, target_ulong addr,
+ uint8_t val, int mmu_idx);
+ void helper_stw_mmu(CPUArchState *env, target_ulong addr,
+ uint16_t val, int mmu_idx);
+ void helper_stl_mmu(CPUArchState *env, target_ulong addr,
+ uint32_t val, int mmu_idx);
+ void helper_stq_mmu(CPUArchState *env, target_ulong addr,
+ uint64_t val, int mmu_idx);
+ #endif /* CONFIG_SOFTMMU */
+
+ #endif /* TCG_H */
--- /dev/null
- qemu_del_timer(cs->alive_timer);
+/*
+ * Emulator Control Server
+ *
+ * Copyright (c) 2013 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Contact:
+ * Jinhyung choi <jinhyung2.choi@samsung.com>
+ * MunKyu Im <munkyu.im@samsung.com>
+ * Daiyoung Kim <daiyoung777.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 <stdbool.h>
+#include <pthread.h>
+#include <stdlib.h>
+
+#include "hw/qdev.h"
+#include "net/net.h"
+#include "ui/console.h"
+
+#include "qemu-common.h"
+#include "qemu/queue.h"
+#include "qemu/sockets.h"
+#include "qemu/option.h"
+#include "qemu/timer.h"
+#include "qemu/main-loop.h"
+#include "sysemu/char.h"
+#include "config.h"
+#include "qapi/qmp/qint.h"
+
+#include "sdb.h"
+#include "ecs.h"
+#include "guest_server.h"
+#include "emul_state.h"
+
+#include "genmsg/ecs.pb-c.h"
+
+#define DEBUG
+
+#ifndef min
+#define min(a,b) ((a)<(b)?(a):(b))
+#endif
+
+static QTAILQ_HEAD(ECS_ClientHead, ECS_Client)
+clients = QTAILQ_HEAD_INITIALIZER(clients);
+
+static ECS_State *current_ecs;
+
+static void* keepalive_buf;
+static int payloadsize;
+
+static int port;
+static int port_setting = -1;
+
+static int log_fd = -1;
+static int g_client_id = 1;
+
+static pthread_mutex_t mutex_clilist = PTHREAD_MUTEX_INITIALIZER;
+
+static int suspend_state = 1;
+
+void ecs_set_suspend_state(int state)
+{
+ suspend_state = state;
+}
+
+int ecs_get_suspend_state(void)
+{
+ return suspend_state;
+}
+
+static char* get_emulator_ecs_log_path(void)
+{
+ gchar *emulator_ecs_log_path = NULL;
+ gchar *tizen_sdk_data = NULL;
+#ifndef CONFIG_WIN32
+ char emulator_ecs[] = "/emulator/vms/ecs.log";
+#else
+ char emulator_ecs[] = "\\emulator\\vms\\ecs.log";
+#endif
+
+ tizen_sdk_data = get_tizen_sdk_data_path();
+ if (!tizen_sdk_data) {
+ LOG("failed to get tizen-sdk-data path.\n");
+ return NULL;
+ }
+
+ emulator_ecs_log_path =
+ g_malloc(strlen(tizen_sdk_data) + sizeof(emulator_ecs) + 1);
+ if (!emulator_ecs_log_path) {
+ LOG("failed to allocate memory.\n");
+ return NULL;
+ }
+
+ g_snprintf(emulator_ecs_log_path, strlen(tizen_sdk_data) + sizeof(emulator_ecs),
+ "%s%s", tizen_sdk_data, emulator_ecs);
+
+ g_free(tizen_sdk_data);
+
+ LOG("ecs log path: %s\n", emulator_ecs_log_path);
+ return emulator_ecs_log_path;
+}
+
+static char* get_emulator_ecs_prop_path(void)
+{
+ int path_len = 0;
+ gchar *ecs_property_path = NULL;
+ gchar *tizen_sdk_data = NULL;
+#ifndef CONFIG_WIN32
+ char emulator_vms[] = "/emulator/vms/";
+ char ecs_prop[] = "/.ecs.properties";
+#else
+ char emulator_vms[] = "\\emulator\\vms\\";
+ char ecs_prop[] = "\\.ecs.properties";
+#endif
+ char* emul_name = get_emul_vm_name();
+
+ tizen_sdk_data = get_tizen_sdk_data_path();
+ if (!tizen_sdk_data) {
+ LOG("failed to get tizen-sdk-data path.\n");
+ return NULL;
+ }
+
+ path_len = strlen(tizen_sdk_data) + sizeof(emulator_vms) + sizeof(ecs_prop) + strlen(emul_name);
+ ecs_property_path = g_malloc(path_len + 1);
+ g_snprintf(ecs_property_path, path_len, "%s%s%s%s", tizen_sdk_data, emulator_vms, emul_name, ecs_prop);
+
+ g_free(tizen_sdk_data);
+ LOG("ecs property path: %s", ecs_property_path);
+
+ return ecs_property_path;
+}
+
+static inline void start_logging(void) {
+ char* path = get_emulator_ecs_log_path();
+ if (!path)
+ return;
+
+#ifdef _WIN32
+ FILE* fnul;
+ FILE* flog;
+
+ fnul = fopen("NUL", "rt");
+ if (fnul != NULL)
+ stdin[0] = fnul[0];
+
+ flog = fopen(path, "wt+");
+ if (flog == NULL)
+ flog = fnul;
+
+ setvbuf(flog, NULL, _IONBF, 0);
+
+ stdout[0] = flog[0];
+ stderr[0] = flog[0];
+#else
+ log_fd = open("/dev/null", O_RDONLY);
+ dup2(log_fd, 0);
+
+ log_fd = creat(path, 0640);
+ if (log_fd < 0) {
+ log_fd = open("/dev/null", O_WRONLY);
+ }
+ dup2(log_fd, 1);
+ dup2(log_fd, 2);
+#endif
+}
+
+static inline void stop_logging(void) {
+ int ret = -1;
+ if (log_fd >= 0) {
+ ret = close(log_fd);
+ if (ret != 0) {
+ LOG("failed to close log fd.");
+ }
+ }
+}
+
+int ecs_write(int fd, const uint8_t *buf, int len) {
+ LOG("write buflen : %d, buf : %s", len, (char*)buf);
+ if (fd < 0) {
+ return -1;
+ }
+
+ return send_all(fd, buf, len);
+}
+
+void ecs_client_close(ECS_Client* clii) {
+ if (clii == NULL)
+ return;
+
+ pthread_mutex_lock(&mutex_clilist);
+
+ if (clii->client_fd > 0) {
+ LOG("ecs client closed with fd: %d", clii->client_fd);
+ closesocket(clii->client_fd);
+#ifndef CONFIG_LINUX
+ FD_CLR(clii->client_fd, &clii->cs->reads);
+#endif
+ clii->client_fd = -1;
+ }
+
+ QTAILQ_REMOVE(&clients, clii, next);
+
+ g_free(clii);
+ clii = NULL;
+
+ pthread_mutex_unlock(&mutex_clilist);
+}
+
+bool send_to_all_client(const char* data, const int len) {
+ LOG("data len: %d, data: %s", len, data);
+ pthread_mutex_lock(&mutex_clilist);
+
+ ECS_Client *clii;
+
+ QTAILQ_FOREACH(clii, &clients, next)
+ {
+ send_to_client(clii->client_fd, data, len);
+ }
+ pthread_mutex_unlock(&mutex_clilist);
+
+ return true;
+}
+
+void send_to_single_client(ECS_Client *clii, const char* data, const int len)
+{
+ pthread_mutex_lock(&mutex_clilist);
+ send_to_client(clii->client_fd, data, len);
+ pthread_mutex_unlock(&mutex_clilist);
+}
+
+void send_to_client(int fd, const char* data, const int len)
+{
+ ecs_write(fd, (const uint8_t*) data, len);
+}
+
+void read_val_short(const char* data, unsigned short* ret_val) {
+ memcpy(ret_val, data, sizeof(unsigned short));
+}
+
+void read_val_char(const char* data, unsigned char* ret_val) {
+ memcpy(ret_val, data, sizeof(unsigned char));
+}
+
+void read_val_str(const char* data, char* ret_val, int len) {
+ memcpy(ret_val, data, len);
+}
+
+bool ntf_to_control(const char* data, const int len) {
+ return true;
+}
+
+bool ntf_to_monitor(const char* data, const int len) {
+ return true;
+}
+
+void print_binary(const char* data, const int len) {
+ int i;
+ printf("[DATA: ");
+ for(i = 0; i < len; i++) {
+ if(i == len - 1) {
+ printf("%02x]\n", data[i]);
+ } else {
+ printf("%02x,", data[i]);
+ }
+ }
+}
+
+void ecs_make_header(QDict* obj, type_length length, type_group group,
+ type_action action) {
+ qdict_put(obj, "length", qint_from_int((int64_t )length));
+ qdict_put(obj, "group", qint_from_int((int64_t )group));
+ qdict_put(obj, "action", qint_from_int((int64_t )action));
+}
+
+static Monitor *monitor_create(void) {
+ Monitor *mon;
+
+ mon = g_malloc0(sizeof(*mon));
+ if (NULL == mon) {
+ LOG("monitor allocation failed.");
+ return NULL;
+ }
+
+ return mon;
+}
+
+static void ecs_close(ECS_State *cs) {
+ ECS_Client *clii;
+ LOG("### Good bye! ECS ###");
+
+ if (cs == NULL)
+ return;
+
+ if (0 <= cs->listen_fd) {
+ LOG("close listen_fd: %d", cs->listen_fd);
+ closesocket(cs->listen_fd);
+ cs->listen_fd = -1;
+ }
+
+ if (cs->mon != NULL) {
+ g_free(cs->mon);
+ cs->mon = NULL;
+ }
+
+ if (keepalive_buf) {
+ g_free(keepalive_buf);
+ }
+
+ if (cs->alive_timer != NULL) {
- qemu_mod_timer(current_ecs->alive_timer,
- qemu_get_clock_ns(vm_clock) + get_ticks_per_sec() * TIMER_ALIVE_S);
++ timer_del(cs->alive_timer);
+ cs->alive_timer = NULL;
+ }
+
+ QTAILQ_FOREACH(clii, &clients, next)
+ {
+ ecs_client_close(clii);
+ }
+
+ g_free(cs);
+ cs = NULL;
+ current_ecs = NULL;
+
+ stop_logging();
+}
+
+#ifndef _WIN32
+static ssize_t ecs_recv(int fd, char *buf, size_t len) {
+ struct msghdr msg = { NULL, };
+ struct iovec iov[1];
+ union {
+ struct cmsghdr cmsg;
+ char control[CMSG_SPACE(sizeof(int))];
+ } msg_control;
+ int flags = 0;
+
+ iov[0].iov_base = buf;
+ iov[0].iov_len = len;
+
+ msg.msg_iov = iov;
+ msg.msg_iovlen = 1;
+ msg.msg_control = &msg_control;
+ msg.msg_controllen = sizeof(msg_control);
+
+#ifdef MSG_CMSG_CLOEXEC
+ flags |= MSG_CMSG_CLOEXEC;
+#endif
+ return recvmsg(fd, &msg, flags);
+}
+
+#else
+static ssize_t ecs_recv(int fd, char *buf, size_t len)
+{
+ return qemu_recv(fd, buf, len, 0);
+}
+#endif
+
+
+static void reset_sbuf(sbuf* sbuf)
+{
+ memset(sbuf->_buf, 0, 4096);
+ sbuf->_use = 0;
+ sbuf->_netlen = 0;
+}
+
+static void ecs_read(ECS_Client *cli) {
+
+ int read = 0;
+ int to_read_bytes = 0;
+
+#ifndef __WIN32
+ if (ioctl(cli->client_fd, FIONREAD, &to_read_bytes) < 0)
+ {
+ LOG("ioctl failed");
+ return;
+ }
+#else
+ unsigned long to_read_bytes_long = 0;
+ if (ioctlsocket(cli->client_fd, FIONREAD, &to_read_bytes_long) < 0)
+ {
+ LOG("ioctl failed");
+ return;
+ }
+ to_read_bytes = (int)to_read_bytes_long;
+#endif
+
+ if (to_read_bytes == 0) {
+ LOG("ioctl FIONREAD: 0");
+ goto fail;
+ }
+
+ if (cli->sbuf._netlen == 0)
+ {
+ if (to_read_bytes < 4)
+ {
+ //LOG("insufficient data size to read");
+ return;
+ }
+
+ long payloadsize = 0;
+ read = ecs_recv(cli->client_fd, (char*) &payloadsize, 4);
+
+ if (read < 4)
+ {
+ LOG("insufficient header size");
+ goto fail;
+ }
+
+ payloadsize = ntohl(payloadsize);
+
+ cli->sbuf._netlen = payloadsize;
+
+ LOG("payload size: %ld\n", payloadsize);
+
+ to_read_bytes -= 4;
+ }
+
+ if (to_read_bytes == 0)
+ return;
+
+
+ to_read_bytes = min(to_read_bytes, cli->sbuf._netlen - cli->sbuf._use);
+
+ read = ecs_recv(cli->client_fd, (char*)(cli->sbuf._buf + cli->sbuf._use), to_read_bytes);
+ if (read == 0)
+ goto fail;
+
+
+ cli->sbuf._use += read;
+
+
+ if (cli->sbuf._netlen == cli->sbuf._use)
+ {
+ handle_protobuf_msg(cli, (char*)cli->sbuf._buf, cli->sbuf._use);
+ reset_sbuf(&cli->sbuf);
+ }
+
+ return;
+fail:
+ ecs_client_close(cli);
+}
+
+#ifdef CONFIG_LINUX
+static void epoll_cli_add(ECS_State *cs, int fd) {
+ struct epoll_event events;
+
+ /* event control set for read event */
+ events.events = EPOLLIN;
+ events.data.fd = fd;
+
+ if (epoll_ctl(cs->epoll_fd, EPOLL_CTL_ADD, fd, &events) < 0) {
+ LOG("Epoll control fails.in epoll_cli_add.");
+ }
+}
+#endif
+
+static ECS_Client *ecs_find_client(int fd) {
+ ECS_Client *clii;
+
+ QTAILQ_FOREACH(clii, &clients, next)
+ {
+ if (clii->client_fd == fd)
+ return clii;
+ }
+ return NULL;
+}
+
+ECS_Client *find_client(unsigned char id, unsigned char type) {
+ ECS_Client *clii;
+
+ QTAILQ_FOREACH(clii, &clients, next)
+ {
+ if (clii->client_id == id && clii->client_type == type)
+ return clii;
+ }
+ return NULL;
+}
+
+static int ecs_add_client(ECS_State *cs, int fd) {
+
+ ECS_Client *clii = g_malloc0(sizeof(ECS_Client));
+ if (NULL == clii) {
+ LOG("ECS_Client allocation failed.");
+ return -1;
+ }
+
+ reset_sbuf(&clii->sbuf);
+
+ qemu_set_nonblock(fd);
+
+ clii->client_fd = fd;
+ clii->cs = cs;
+ clii->client_type = TYPE_NONE;
+
+ ecs_json_message_parser_init(&clii->parser, handle_qmp_command, clii);
+
+#ifdef CONFIG_LINUX
+ epoll_cli_add(cs, fd);
+#else
+ FD_SET(fd, &cs->reads);
+#endif
+
+ pthread_mutex_lock(&mutex_clilist);
+
+ QTAILQ_INSERT_TAIL(&clients, clii, next);
+
+ LOG("Add an ecs client. fd: %d", fd);
+
+ pthread_mutex_unlock(&mutex_clilist);
+
+// send_ecs_version_check(clii);
+
+ return 0;
+}
+
+static void ecs_accept(ECS_State *cs) {
+ struct sockaddr_in saddr;
+#ifndef _WIN32
+ struct sockaddr_un uaddr;
+#endif
+ struct sockaddr *addr;
+ socklen_t len;
+ int fd;
+
+ for (;;) {
+#ifndef _WIN32
+ if (cs->is_unix) {
+ len = sizeof(uaddr);
+ addr = (struct sockaddr *) &uaddr;
+ } else
+#endif
+ {
+ len = sizeof(saddr);
+ addr = (struct sockaddr *) &saddr;
+ }
+ fd = qemu_accept(cs->listen_fd, addr, &len);
+ if (0 > fd && EINTR != errno) {
+ return;
+ } else if (0 <= fd) {
+ break;
+ }
+ }
+ if (0 > ecs_add_client(cs, fd)) {
+ LOG("failed to add client.");
+ }
+}
+
+#ifdef CONFIG_LINUX
+static void epoll_init(ECS_State *cs) {
+ struct epoll_event events;
+
+ cs->epoll_fd = epoll_create(MAX_EVENTS);
+ if (cs->epoll_fd < 0) {
+ closesocket(cs->listen_fd);
+ }
+
+ events.events = EPOLLIN;
+ events.data.fd = cs->listen_fd;
+
+ if (epoll_ctl(cs->epoll_fd, EPOLL_CTL_ADD, cs->listen_fd, &events) < 0) {
+ close(cs->listen_fd);
+ close(cs->epoll_fd);
+ }
+}
+#endif
+
+static void send_keep_alive_msg(ECS_Client *clii) {
+ send_to_single_client(clii, keepalive_buf, payloadsize);
+}
+
+static void make_keep_alive_msg(void) {
+ int len_pack = 0;
+ char msg [5] = {'s','e','l','f'};
+
+ ECS__Master master = ECS__MASTER__INIT;
+ ECS__KeepAliveReq req = ECS__KEEP_ALIVE_REQ__INIT;
+
+ req.time_str = (char*) g_malloc(5);
+
+ strncpy(req.time_str, msg, 4);
+
+ master.type = ECS__MASTER__TYPE__KEEPALIVE_REQ;
+ master.keepalive_req = &req;
+
+ len_pack = ecs__master__get_packed_size(&master);
+ payloadsize = len_pack + 4;
+
+ keepalive_buf = g_malloc(len_pack + 4);
+ if (!keepalive_buf) {
+ LOG("keep alive message creation is failed.");
+ return;
+ }
+
+ ecs__master__pack(&master, keepalive_buf + 4);
+
+ len_pack = htonl(len_pack);
+ memcpy(keepalive_buf, &len_pack, 4);
+}
+
+static void alive_checker(void *opaque) {
+
+ ECS_Client *clii;
+
+ if (NULL != current_ecs && !current_ecs->ecs_running) {
+ return;
+ }
+
+ QTAILQ_FOREACH(clii, &clients, next)
+ {
+ if (1 == clii->keep_alive) {
+ LOG("get client fd %d - keep alive fail", clii->client_fd);
+ ecs_client_close(clii);
+ continue;
+ }
+ LOG("set client fd %d - keep alive 1", clii->client_fd);
+ clii->keep_alive = 1;
+ send_keep_alive_msg(clii);
+ }
+
+ if (current_ecs == NULL) {
+ LOG("alive checking is failed because current ecs is null.");
+ return;
+ }
+
- cs->alive_timer = qemu_new_timer_ns(vm_clock, alive_checker, cs);
++ timer_mod(current_ecs->alive_timer,
++ qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + get_ticks_per_sec() * TIMER_ALIVE_S);
+
+}
+
+static int socket_initialize(ECS_State *cs, QemuOpts *opts) {
+ int fd = -1;
+ Error *local_err = NULL;
+
+ fd = inet_listen_opts(opts, 0, &local_err);
+ if (0 > fd || error_is_set(&local_err)) {
+ qerror_report_err(local_err);
+ error_free(local_err);
+ return -1;
+ }
+
+ LOG("Listen fd is %d", fd);
+
+ qemu_set_nonblock(fd);
+
+ cs->listen_fd = fd;
+
+#ifdef CONFIG_LINUX
+ epoll_init(cs);
+#else
+ FD_ZERO(&cs->reads);
+ FD_SET(fd, &cs->reads);
+#endif
+
+ make_keep_alive_msg();
+
- qemu_mod_timer(cs->alive_timer,
- qemu_get_clock_ns(vm_clock) + get_ticks_per_sec() * TIMER_ALIVE_S);
++ cs->alive_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, alive_checker, cs);
+
++ timer_mod(cs->alive_timer,
++ qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + get_ticks_per_sec() * TIMER_ALIVE_S);
+
+ return 0;
+}
+
+#ifdef CONFIG_LINUX
+static int ecs_loop(ECS_State *cs) {
+ int i, nfds;
+
+ nfds = epoll_wait(cs->epoll_fd, cs->events, MAX_EVENTS, 100);
+ if (0 == nfds) {
+ return 0;
+ }
+
+ if (0 > nfds) {
+ if (errno == EINTR)
+ return 0;
+ perror("epoll wait error");
+ return -1;
+ }
+
+ for (i = 0; i < nfds; i++) {
+ if (cs->events[i].data.fd == cs->listen_fd) {
+ ecs_accept(cs);
+ continue;
+ }
+ ecs_read(ecs_find_client(cs->events[i].data.fd));
+ }
+
+ return 0;
+}
+#elif defined(CONFIG_WIN32)
+static int ecs_loop(ECS_State *cs)
+{
+ int index = 0;
+ TIMEVAL timeout;
+ fd_set temps = cs->reads;
+
+ timeout.tv_sec = 5;
+ timeout.tv_usec = 0;
+
+ if (select(0, &temps, 0, 0, &timeout) < 0) {
+ LOG("select error.");
+ return -1;
+ }
+
+ for (index = 0; index < cs->reads.fd_count; index++) {
+ if (FD_ISSET(cs->reads.fd_array[index], &temps)) {
+ if (cs->reads.fd_array[index] == cs->listen_fd) {
+ ecs_accept(cs);
+ continue;
+ }
+
+ ecs_read(ecs_find_client(cs->reads.fd_array[index]));
+ }
+ }
+
+ return 0;
+}
+#elif defined(CONFIG_DARWIN)
+static int ecs_loop(ECS_State *cs)
+{
+ int index = 0;
+ int res = 0;
+ struct timeval timeout;
+ fd_set temps = cs->reads;
+
+ timeout.tv_sec = 5;
+ timeout.tv_usec = 0;
+
+ if ((res = select(MAX_FD_NUM + 1, &temps, NULL, NULL, &timeout)) < 0) {
+ LOG("select failed..");
+ return -1;
+ }
+
+ for (index = 0; index < MAX_FD_NUM; index ++) {
+ if (FD_ISSET(index, &temps)) {
+ if (index == cs->listen_fd) {
+ ecs_accept(cs);
+ continue;
+ }
+
+ ecs_read(ecs_find_client(index));
+ }
+ }
+
+ return 0;
+}
+
+#endif
+
+int get_ecs_port(void) {
+ if (port_setting < 0) {
+ LOG("ecs port is not determined yet.");
+ return 0;
+ }
+ LOG("requests ecs port, and port is %d", port);
+ return port;
+}
+
+static int set_ecs_port(int port) {
+ FILE* fprop;
+ char* path = get_emulator_ecs_prop_path();
+ if (!path)
+ return -1;
+
+ fprop = fopen(path, "wt+");
+ if (fprop == NULL) {
+ return -1;
+ }
+
+ fprintf(fprop, "%d", port);
+ fclose(fprop);
+
+ g_free(path);
+
+ return 0;
+}
+
+static int setting_ecs_port(ECS_State *cs) {
+ struct sockaddr server_addr;
+ socklen_t server_len;
+
+ server_len = sizeof(server_addr);
+ memset(&server_addr, 0, sizeof(server_addr));
+ if (getsockname(cs->listen_fd, (struct sockaddr *) &server_addr, &server_len) < 0) {
+ return -1;
+ }
+
+ port = ntohs( ((struct sockaddr_in *) &server_addr)->sin_port );
+ LOG("listen port is %d", port);
+
+ return set_ecs_port(port);
+}
+
+static void* ecs_initialize(void* args) {
+ int ret = 1;
+ ECS_State *cs = NULL;
+ QemuOpts *opts = NULL;
+ Error *local_err = NULL;
+ Monitor* mon = NULL;
+ char host_port[16];
+
+ start_logging();
+ LOG("ecs starts initializing.");
+
+ opts = qemu_opts_create(qemu_find_opts(ECS_OPTS_NAME), ECS_OPTS_NAME, 1, &local_err);
+ if (error_is_set(&local_err)) {
+ qerror_report_err(local_err);
+ error_free(local_err);
+ return NULL;
+ }
+
+ qemu_opt_set(opts, "host", HOST_LISTEN_ADDR);
+
+ cs = g_malloc0(sizeof(ECS_State));
+ if (NULL == cs) {
+ LOG("ECS_State allocation failed.");
+ return NULL;
+ }
+
+ sprintf(host_port, "%d", port);
+ qemu_opt_set(opts, "port", host_port);
+ ret = socket_initialize(cs, opts);
+ if (ret < 0) {
+ LOG("Socket initialization is failed.");
+ ecs_close(cs);
+ return NULL;
+ }
+
+ if (setting_ecs_port(cs) < 0) {
+ LOG("Failed to get random port.");
+ ecs_close(cs);
+ return NULL;
+ }
+
+ port_setting = 1;
+
+ mon = monitor_create();
+ if (NULL == mon) {
+ LOG("monitor initialization failed.");
+ ecs_close(cs);
+ return NULL;
+ }
+
+ cs->mon = mon;
+ current_ecs = cs;
+ cs->ecs_running = 1;
+
+ LOG("ecs_loop entered.");
+ while (cs->ecs_running) {
+ ret = ecs_loop(cs);
+ if (0 > ret) {
+ ecs_close(cs);
+ break;
+ }
+ }
+ LOG("ecs_loop exited.");
+
+ return NULL;
+}
+
+int stop_ecs(void) {
+ LOG("ecs is closing.");
+ if (NULL != current_ecs) {
+ current_ecs->ecs_running = 0;
+ ecs_close(current_ecs);
+ }
+
+ pthread_mutex_destroy(&mutex_clilist);
+
+ return 0;
+}
+
+int start_ecs(void) {
+ pthread_t thread_id;
+
+ if (0 != pthread_create(&thread_id, NULL, ecs_initialize, NULL)) {
+ LOG("pthread creation failed.");
+ return -1;
+ }
+ return 0;
+}
+
+bool handle_protobuf_msg(ECS_Client* cli, char* data, int len)
+{
+ ECS__Master* master = ecs__master__unpack(NULL, (size_t)len, (const uint8_t*)data);
+ if (!master)
+ return false;
+
+ if (master->type == ECS__MASTER__TYPE__INJECTOR_REQ)
+ {
+ ECS__InjectorReq* msg = master->injector_req;
+ if (!msg)
+ goto fail;
+ msgproc_injector_req(cli, msg);
+ }
+ else if (master->type == ECS__MASTER__TYPE__MONITOR_REQ)
+ {
+ ECS__MonitorReq* msg = master->monitor_req;
+ if (!msg)
+ goto fail;
+ msgproc_monitor_req(cli, msg);
+ }
+ else if (master->type == ECS__MASTER__TYPE__DEVICE_REQ)
+ {
+ cli->client_type = TYPE_ECP;
+ ECS__DeviceReq* msg = master->device_req;
+ if (!msg)
+ goto fail;
+ msgproc_device_req(cli, msg);
+ }
+ else if (master->type == ECS__MASTER__TYPE__NFC_REQ)
+ {
+ ECS__NfcReq* msg = master->nfc_req;
+ if (!msg)
+ goto fail;
+
+ pthread_mutex_lock(&mutex_clilist);
+ if(cli->client_type == TYPE_NONE) {
+ if (!strncmp(msg->category, MSG_TYPE_NFC, 3)) {
+ QTAILQ_REMOVE(&clients, cli, next);
+ cli->client_type = TYPE_ECP;
+ if(g_client_id > 255) {
+ g_client_id = 1;
+ }
+ cli->client_id = g_client_id++;
+
+ QTAILQ_INSERT_TAIL(&clients, cli, next);
+ }
+ else if (!strncmp(msg->category, MSG_TYPE_SIMUL_NFC, 9)) {
+ QTAILQ_REMOVE(&clients, cli, next);
+ cli->client_type = TYPE_SIMUL_NFC;
+ if(g_client_id > 255) {
+ g_client_id = 1;
+ }
+ cli->client_id = g_client_id++;
+ QTAILQ_INSERT_TAIL(&clients, cli, next);
+ }
+ else {
+ LOG("unsupported category is found: %s", msg->category);
+ goto fail;
+ }
+ }
+ pthread_mutex_unlock(&mutex_clilist);
+
+ msgproc_nfc_req(cli, msg);
+ }
+#if 0
+ else if (master->type == ECS__MASTER__TYPE__CHECKVERSION_REQ)
+ {
+ ECS__CheckVersionReq* msg = master->checkversion_req;
+ if (!msg)
+ goto fail;
+ msgproc_checkversion_req(cli, msg);
+ }
+#endif
+ else if (master->type == ECS__MASTER__TYPE__KEEPALIVE_ANS)
+ {
+ ECS__KeepAliveAns* msg = master->keepalive_ans;
+ if (!msg)
+ goto fail;
+ msgproc_keepalive_ans(cli, msg);
+ }
+ else if (master->type == ECS__MASTER__TYPE__TETHERING_REQ)
+ {
+ ECS__TetheringReq* msg = master->tethering_req;
+ if (!msg)
+ goto fail;
+ msgproc_tethering_req(cli, msg);
+ }
+
+ ecs__master__free_unpacked(master, NULL);
+ return true;
+fail:
+ LOG("invalid message type");
+ ecs__master__free_unpacked(master, NULL);
+ return false;
+}
--- /dev/null
- static bool has_pvpanic = true;
+/*
+ * TIZEN base board
+ *
+ * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Contact:
+ * YeongKyoon Lee <yeongkyoon.lee@samsung.com>
+ * SeokYeon Hwang <syeon.hwang@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>
+ * DongKyun Yun
+ * DoHyung Hong
+ * Hyunjun Son
+ *
+ * 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/hw.h"
+#include "hw/i386/pc.h"
+#include "hw/i386/apic.h"
+#include "hw/pci/pci.h"
+#include "hw/pci/pci_ids.h"
+#include "hw/usb.h"
+#include "net/net.h"
+#include "hw/boards.h"
+#include "hw/ide.h"
+#include "sysemu/kvm.h"
+#include "hw/kvm/clock.h"
+#include "sysemu/sysemu.h"
+#include "hw/sysbus.h"
+#include "hw/cpu/icc_bus.h"
+#include "sysemu/arch_init.h"
+#include "sysemu/blockdev.h"
+#include "hw/i2c/smbus.h"
+#include "hw/xen/xen.h"
+#include "exec/memory.h"
+#include "exec/address-spaces.h"
+#include "hw/acpi/acpi.h"
+#include "cpu.h"
+#ifdef CONFIG_XEN
+# include <xen/hvm/hvm_info_table.h>
+#endif
+
+#include "maru_common.h"
+#include "guest_debug.h"
+#include "maru_pm.h"
+#include "maru_brightness.h"
+#include "maru_overlay.h"
+#if defined(__linux__)
+#include <X11/Xlib.h>
+#endif
+#include "vigs/vigs_device.h"
+extern int enable_yagl;
+extern const char *yagl_backend;
+extern int enable_vigs;
+extern const char *vigs_backend;
+extern int enable_spice;
+
+#define MAX_IDE_BUS 2
+
+int codec_init(PCIBus *bus);
+int maru_brill_codec_pci_device_init(PCIBus *bus);
+
+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 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)
+static bool has_pci_info = true;
+
+MemoryRegion *global_ram_memory;
+
+MemoryRegion *get_ram_memory(void)
+{
+ return global_ram_memory;
+}
+
- 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;
- DeviceState *icc_bridge;
- void *fw_cfg = NULL;
- PcGuestInfo *guest_info;
++/* maru specialized device init */
++static void maru_device_init(void)
+{
- #if defined(__linux__)
++ PCIBus *pci_bus = (PCIBus *) object_resolve_path_type("", TYPE_PCI_BUS, NULL);
+
- if (xen_enabled() && xen_hvm_init(&ram_memory) != 0) {
- fprintf(stderr, "xen hardware virtual machine initialisation failed\n");
- exit(1);
- }
-
- icc_bridge = qdev_create(NULL, TYPE_ICC_BRIDGE);
- object_property_add_child(qdev_get_machine(), "icc-bridge",
- OBJECT(icc_bridge), NULL);
-
- pc_cpus_init(cpu_model, icc_bridge);
- pc_acpi_init("acpi-dsdt.aml");
-
- if (kvmclock_enabled) {
- kvmclock_create();
- }
-
- if (ram_size >= QEMU_BELOW_4G_RAM_END ) {
- above_4g_mem_size = ram_size - QEMU_BELOW_4G_RAM_END;
- below_4g_mem_size = QEMU_BELOW_4G_RAM_END;
- } 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, NULL, "pci", INT64_MAX);
- rom_memory = pci_memory;
- } else {
- pci_memory = NULL;
- rom_memory = system_memory;
- }
-
- guest_info = pc_guest_info_init(below_4g_mem_size, above_4g_mem_size);
- guest_info->has_pci_info = has_pci_info;
- guest_info->isapc_ram_fw = !pci_enabled;
-
- /* allocate ram and load rom/bios */
- if (!xen_enabled()) {
- // W/A for allocate larger continuous heap.
- // see vl.c
- if(preallocated_ptr != NULL) {
- g_free(preallocated_ptr);
- }
- //
- fw_cfg = pc_memory_init(system_memory,
- kernel_filename, kernel_cmdline, initrd_filename,
- below_4g_mem_size, above_4g_mem_size,
- rom_memory, &ram_memory, guest_info);
- }
-
- // for ramdump...
- global_ram_memory = ram_memory;
-
- gsi_state = g_malloc0(sizeof(*gsi_state));
- if (kvm_irqchip_in_kernel()) {
- kvm_pc_setup_irq_routing(pci_enabled);
- gsi = qemu_allocate_irqs(kvm_pc_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,
- above_4g_mem_size,
- 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(gsi_state, "i440fx");
- }
- qdev_init_nofail(icc_bridge);
-
- 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());
-
- pc_nic_init(isa_bus, pci_bus);
-
- 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(DEVICE(dev), "ide.0");
- }
- }
-
- 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(false)) {
- 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. */
- smbus = piix4_pm_init(pci_bus, piix3_devfn + 3, 0xb100,
- gsi[9], *smi_irq,
- kvm_enabled(), fw_cfg);
- smbus_eeprom_init(smbus, 8, NULL, 0);
- }
-
- if (pci_enabled) {
- pc_pci_device_init(pci_bus);
- }
-
- if (has_pvpanic) {
- pvpanic_init(isa_bus);
- }
-
- /* maru specialized device init */
- if (pci_enabled) {
- // codec_init(pci_bus);
- pci_maru_overlay_init(pci_bus);
- pci_maru_brightness_init(pci_bus);
- maru_brill_codec_pci_device_init(pci_bus);
- }
++#if defined(CONFIG_LINUX)
+ Display *display = XOpenDisplay(0);
+ if (!display && !enable_spice) {
+ fprintf(stderr, "Cannot open X display\n");
+ exit(1);
+ }
+#else
+ void *display = NULL;
+#endif
+ struct winsys_interface *vigs_wsi = NULL;
+
- has_pci_info = false;
++ pci_maru_overlay_init(pci_bus);
++ pci_maru_brightness_init(pci_bus);
++ maru_brill_codec_pci_device_init(pci_bus);
+
+ if (enable_vigs) {
+ PCIDevice *pci_dev = pci_create(pci_bus, -1, "vigs");
+ qdev_prop_set_ptr(&pci_dev->qdev, "display", display);
+ qdev_init_nofail(&pci_dev->qdev);
+ vigs_wsi = DO_UPCAST(VIGSDevice, pci_dev, pci_dev)->wsi;
+ }
+
+ if (enable_yagl) {
+ PCIDevice *pci_dev = pci_create(pci_bus, -1, "yagl");
+ qdev_prop_set_ptr(&pci_dev->qdev, "display", display);
+ if (vigs_wsi &&
+ (strcmp(yagl_backend, "vigs") == 0) &&
+ (strcmp(vigs_backend, "gl") == 0)) {
+ qdev_prop_set_ptr(&pci_dev->qdev, "winsys_gl_interface", vigs_wsi);
+ }
+ qdev_init_nofail(&pci_dev->qdev);
+ }
+}
+
++extern void pc_init_pci(QEMUMachineInitArgs *args);
+static void maru_x86_board_init(QEMUMachineInitArgs *args)
+{
- ram_addr_t ram_size = args->ram_size;
- const char *cpu_model = args->cpu_model;
- const char *kernel_filename = args->kernel_filename;
- const char *kernel_cmdline = args->kernel_cmdline;
- const char *initrd_filename = args->initrd_filename;
- const char *boot_device = args->boot_device;
- maru_x86_machine_init(get_system_memory(),
- get_system_io(),
- ram_size, boot_device,
- kernel_filename, kernel_cmdline,
- initrd_filename, cpu_model, 1, 1);
++ pc_init_pci(args);
+
- .max_cpus = 255,
- DEFAULT_MACHINE_OPTIONS,
++ has_pci_info = false;
++ maru_device_init();
+}
+
+static QEMUMachine maru_x86_machine = {
++ PC_DEFAULT_MACHINE_OPTIONS,
+ .name = "maru-x86-machine",
+ .alias = "maru-x86-machine",
+ .desc = "Maru Board (x86)",
+ .init = maru_x86_board_init,
+ .hot_add_cpu = pc_hot_add_cpu,
+};
+
+static void maru_machine_init(void)
+{
+ qemu_register_machine(&maru_x86_machine);
+}
+
+machine_init(maru_machine_init);
--- /dev/null
- qemu_irq_raise(s->dev.irq[0]);
+/*
+ * Virtual Codec Device
+ *
+ * Copyright (c) 2013 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Contact:
+ * Kitae Kim <kt920.kim@samsung.com>
+ * SeokYeon Hwang <syeon.hwang@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_brill_codec.h"
+
+/* define debug channel */
+MULTI_DEBUG_CHANNEL(qemu, brillcodec);
+
+// device
+#define CODEC_DEVICE_NAME "brilcodec"
+#define CODEC_VERSION 1
+
+// device memory
+#define CODEC_META_DATA_SIZE (256)
+
+#define CODEC_MEM_SIZE (32 * 1024 * 1024)
+#define CODEC_REG_SIZE (256)
+
+// libav
+#define GEN_MASK(x) ((1 << (x)) - 1)
+#define ROUND_UP_X(v, x) (((v) + GEN_MASK(x)) & ~GEN_MASK(x))
+#define ROUND_UP_2(x) ROUND_UP_X(x, 1)
+#define ROUND_UP_4(x) ROUND_UP_X(x, 2)
+#define ROUND_UP_8(x) ROUND_UP_X(x, 3)
+#define DIV_ROUND_UP_X(v, x) (((v) + GEN_MASK(x)) >> (x))
+
+#define DEFAULT_VIDEO_GOP_SIZE 15
+
+
+// define a queue to manage ioparam, context data
+typedef struct DeviceMemEntry {
+ uint8_t *buf;
+ uint32_t buf_size;
+ uint32_t ctx_id;
+
+ QTAILQ_ENTRY(DeviceMemEntry) node;
+} DeviceMemEntry;
+
+typedef struct CodecDataStg {
+ CodecParam *param_buf;
+ DeviceMemEntry *data_buf;
+
+ QTAILQ_ENTRY(CodecDataStg) node;
+} CodecDataStg;
+
+// define two queue to store input and output buffers.
+static QTAILQ_HEAD(codec_wq, DeviceMemEntry) codec_wq =
+ QTAILQ_HEAD_INITIALIZER(codec_wq);
+
+static QTAILQ_HEAD(codec_rq, CodecDataStg) codec_rq =
+ QTAILQ_HEAD_INITIALIZER(codec_rq);
+
+static DeviceMemEntry *entry[CODEC_CONTEXT_MAX];
+
+// pixel info
+typedef struct PixFmtInfo {
+ uint8_t x_chroma_shift;
+ uint8_t y_chroma_shift;
+} PixFmtInfo;
+
+static PixFmtInfo pix_fmt_info[PIX_FMT_NB];
+
+// thread
+// static int idle_thread_cnt = 0;
+#define DEFAULT_WORKER_THREAD_CNT 8
+
+static void *maru_brill_codec_threads(void *opaque);
+
+// static void maru_brill_codec_reset_parser_info(MaruBrillCodecState *s, int32_t ctx_index);
+static int maru_brill_codec_query_list(MaruBrillCodecState *s);
+static void maru_brill_codec_release_context(MaruBrillCodecState *s, int32_t value);
+
+// codec functions
+static bool codec_init(MaruBrillCodecState *, int, void *);
+static bool codec_deinit(MaruBrillCodecState *, int, void *);
+static bool codec_decode_video(MaruBrillCodecState *, int, void *);
+static bool codec_encode_video(MaruBrillCodecState *, int, void *);
+static bool codec_decode_audio(MaruBrillCodecState *, int, void *);
+static bool codec_encode_audio(MaruBrillCodecState *, int, void *);
+static bool codec_picture_copy(MaruBrillCodecState *, int, void *);
+static bool codec_flush_buffers(MaruBrillCodecState *, int, void *);
+
+typedef bool (*CodecFuncEntry)(MaruBrillCodecState *, int, void *);
+static CodecFuncEntry codec_func_handler[] = {
+ codec_init,
+ codec_decode_video,
+ codec_encode_video,
+ codec_decode_audio,
+ codec_encode_audio,
+ codec_picture_copy,
+ codec_deinit,
+ codec_flush_buffers,
+};
+
+static AVCodecParserContext *maru_brill_codec_parser_init(AVCodecContext *avctx);
+#if 0
+static int maru_brill_codec_parser_parse (AVCodecParserContext *pctx, AVCodecContext *avctx,
+ uint8_t *inbuf, int inbuf_size,
+ int64_t pts, int64_t dts, int64_t pos);
+#endif
+
+static void maru_brill_codec_pop_writequeue(MaruBrillCodecState *s, uint32_t ctx_idx);
+static void maru_brill_codec_push_readqueue(MaruBrillCodecState *s, CodecParam *ioparam);
+static void maru_brill_codec_push_writequeue(MaruBrillCodecState *s, void* buf,
+ uint32_t buf_size, int ctx_id);
+
+static void *maru_brill_codec_store_inbuf(uint8_t *mem_base_offset, CodecParam *ioparam);
+
+static void maru_brill_codec_reset(DeviceState *s);
+
+static void maru_brill_codec_get_cpu_cores(MaruBrillCodecState *s)
+{
+ s->worker_thread_cnt = get_number_of_processors();
+ if (s->worker_thread_cnt < DEFAULT_WORKER_THREAD_CNT) {
+ s->worker_thread_cnt = DEFAULT_WORKER_THREAD_CNT;
+ }
+
+ TRACE("number of threads: %d\n", s->worker_thread_cnt);
+}
+
+static void maru_brill_codec_threads_create(MaruBrillCodecState *s)
+{
+ int index;
+ QemuThread *pthread = NULL;
+
+ TRACE("enter: %s\n", __func__);
+
+ pthread = g_malloc(sizeof(QemuThread) * s->worker_thread_cnt);
+ if (!pthread) {
+ ERR("failed to allocate threadpool memory.\n");
+ return;
+ }
+
+ qemu_cond_init(&s->threadpool.cond);
+ qemu_mutex_init(&s->threadpool.mutex);
+
+ s->is_thread_running = true;
+ s->idle_thread_cnt = 0;
+
+ for (index = 0; index < s->worker_thread_cnt; index++) {
+ qemu_thread_create(&pthread[index],
+ maru_brill_codec_threads, (void *)s, QEMU_THREAD_JOINABLE);
+ }
+
+ s->threadpool.threads = pthread;
+
+ TRACE("leave: %s\n", __func__);
+}
+
+static void maru_brill_codec_thread_exit(MaruBrillCodecState *s)
+{
+ int index;
+
+ TRACE("enter: %s\n", __func__);
+
+ /* stop to run dedicated threads. */
+ s->is_thread_running = false;
+
+ for (index = 0; index < s->worker_thread_cnt; index++) {
+ qemu_thread_join(&s->threadpool.threads[index]);
+ }
+
+ TRACE("destroy mutex and conditional.\n");
+ qemu_mutex_destroy(&s->threadpool.mutex);
+ qemu_cond_destroy(&s->threadpool.cond);
+
+ if (s->threadpool.threads) {
+ g_free(s->threadpool.threads);
+ s->threadpool.threads = NULL;
+ }
+
+ TRACE("leave: %s\n", __func__);
+}
+
+static void maru_brill_codec_wakeup_threads(MaruBrillCodecState *s, int api_index)
+{
+ CodecParam *ioparam = NULL;
+
+ ioparam = g_malloc0(sizeof(CodecParam));
+ if (!ioparam) {
+ ERR("failed to allocate ioparam\n");
+ return;
+ }
+
+ memcpy(ioparam, &s->ioparam, sizeof(CodecParam));
+
+ TRACE("wakeup thread. ctx_id: %u, api_id: %u, mem_offset: 0x%x\n",
+ ioparam->ctx_index, ioparam->api_index, ioparam->mem_offset);
+
+ maru_brill_codec_push_readqueue(s, ioparam);
+
+ qemu_mutex_lock(&s->context_mutex);
+ // W/A for threads starvation.
+ while (s->idle_thread_cnt == 0) {
+ qemu_mutex_unlock(&s->context_mutex);
+ TRACE("Worker threads are exhausted\n");
+ usleep(2000); // wait 2ms.
+ qemu_mutex_lock(&s->context_mutex);
+ }
+ qemu_cond_signal(&s->threadpool.cond);
+ qemu_mutex_unlock(&s->context_mutex);
+
+ TRACE("after sending conditional signal\n");
+}
+
+static void *maru_brill_codec_threads(void *opaque)
+{
+ MaruBrillCodecState *s = (MaruBrillCodecState *)opaque;
+
+ TRACE("enter: %s\n", __func__);
+
+ while (s->is_thread_running) {
+ int ctx_id, api_id;
+ CodecDataStg *elem = NULL;
+ DeviceMemEntry *indata_buf = NULL;
+
+ qemu_mutex_lock(&s->context_mutex);
+ ++(s->idle_thread_cnt); // protected under mutex.
+ qemu_cond_wait(&s->threadpool.cond, &s->context_mutex);
+ --(s->idle_thread_cnt); // protected under mutex.
+ qemu_mutex_unlock(&s->context_mutex);
+
+ qemu_mutex_lock(&s->ioparam_queue_mutex);
+ elem = QTAILQ_FIRST(&codec_rq);
+ if (elem) {
+ QTAILQ_REMOVE(&codec_rq, elem, node);
+ qemu_mutex_unlock(&s->ioparam_queue_mutex);
+ } else {
+ qemu_mutex_unlock(&s->ioparam_queue_mutex);
+ continue;
+ }
+
+ if (!elem->param_buf) {
+ continue;
+ }
+
+ api_id = elem->param_buf->api_index;
+ ctx_id = elem->param_buf->ctx_index;
+ indata_buf = elem->data_buf;
+
+ TRACE("api_id: %d ctx_id: %d\n", api_id, ctx_id);
+
+ if (!codec_func_handler[api_id](s, ctx_id, indata_buf)) {
+ ERR("codec_func failure.\n");
+ continue;
+ }
+
+ TRACE("release a buffer of CodecParam\n");
+ g_free(elem->param_buf);
+
+ if (elem->data_buf) {
+
+ if (elem->data_buf->buf) {
+ TRACE("release inbuf\n");
+ g_free(elem->data_buf->buf);
+ }
+
+ TRACE("release a buffer indata_buf\n");
+ g_free(elem->data_buf);
+ }
+
+ TRACE("release an element of CodecDataStg\n");
+ g_free(elem);
+
+ if (api_id == CODEC_DEINIT) {
+ TRACE("deinit doesn't need to raise interrupt.\n");
+ } else {
+ TRACE("switch context to raise interrupt.\n");
+ qemu_bh_schedule(s->codec_bh);
+ }
+ }
+
+ maru_brill_codec_thread_exit(s);
+
+ TRACE("leave: %s\n", __func__);
+ return NULL;
+}
+
+// queue
+static void maru_brill_codec_push_readqueue(MaruBrillCodecState *s,
+ CodecParam *ioparam)
+{
+ CodecDataStg *elem = NULL;
+ DeviceMemEntry *data_buf = NULL;
+
+ elem = g_malloc0(sizeof(CodecDataStg));
+ if (!elem) {
+ ERR("failed to allocate ioparam_queue. %d\n", sizeof(CodecDataStg));
+ return;
+ }
+
+ elem->param_buf = ioparam;
+
+ switch(ioparam->api_index) {
+ case CODEC_DECODE_VIDEO ... CODEC_ENCODE_AUDIO:
+ data_buf = maru_brill_codec_store_inbuf((uint8_t *)s->vaddr, ioparam);
+ break;
+ default:
+ TRACE("no buffer from guest\n");
+ break;
+ }
+
+ elem->data_buf = data_buf;
+
+ qemu_mutex_lock(&s->ioparam_queue_mutex);
+ QTAILQ_INSERT_TAIL(&codec_rq, elem, node);
+ qemu_mutex_unlock(&s->ioparam_queue_mutex);
+}
+
+static void *maru_brill_codec_store_inbuf(uint8_t *mem_base_offset,
+ CodecParam *ioparam)
+{
+ DeviceMemEntry *elem = NULL;
+ int readbuf_size, size = 0;
+ uint8_t *readbuf = NULL;
+ uint8_t *device_mem = mem_base_offset + ioparam->mem_offset;
+
+ elem = g_malloc0(sizeof(DeviceMemEntry));
+ if (!elem) {
+ ERR("failed to allocate readqueue node. size: %d\n",
+ sizeof(DeviceMemEntry));
+ return NULL;
+ }
+
+ memcpy(&readbuf_size, device_mem, sizeof(readbuf_size));
+ size = sizeof(readbuf_size);
+
+ TRACE("readbuf size: %d\n", readbuf_size);
+ if (readbuf_size <= 0) {
+ TRACE("inbuf size is zero. api_id: %d, ctx_id: %d, mem_offset: %x\n",
+ readbuf_size, ioparam->api_index, ioparam->ctx_index, ioparam->mem_offset);
+ } else {
+ readbuf = g_malloc0(readbuf_size);
+ if (!readbuf) {
+ ERR("failed to allocate a read buffer. size: %d\n", readbuf_size);
+ } else {
+ TRACE("copy input buffer from guest. ctx_id: %d, mem_offset: %x\n",
+ ioparam->ctx_index, ioparam->mem_offset);
+ memcpy(readbuf, device_mem + size, readbuf_size);
+ }
+ }
+ memset(device_mem, 0x00, sizeof(readbuf_size));
+
+ elem->buf = readbuf;
+ elem->buf_size = readbuf_size;
+ elem->ctx_id = ioparam->ctx_index;
+
+ return elem;
+}
+
+static void maru_brill_codec_push_writequeue(MaruBrillCodecState *s, void* buf,
+ uint32_t buf_size, int ctx_id)
+{
+ DeviceMemEntry *elem = NULL;
+ elem = g_malloc0(sizeof(DeviceMemEntry));
+
+ elem->buf = buf;
+ elem->buf_size = buf_size;
+ elem->ctx_id = ctx_id;
+
+ qemu_mutex_lock(&s->context_queue_mutex);
+ QTAILQ_INSERT_TAIL(&codec_wq, elem, node);
+ qemu_mutex_unlock(&s->context_queue_mutex);
+}
+
+static void maru_brill_codec_pop_writequeue(MaruBrillCodecState *s, uint32_t ctx_idx)
+{
+ DeviceMemEntry *elem = NULL;
+ uint32_t mem_offset = 0;
+
+ TRACE("enter: %s\n", __func__);
+
+ if (ctx_idx < 1 || ctx_idx > (CODEC_CONTEXT_MAX - 1)) {
+ ERR("invalid buffer index. %d\n", ctx_idx);
+ return;
+ }
+
+ TRACE("pop_writeqeue. context index: %d\n", ctx_idx);
+ elem = entry[ctx_idx];
+ if (elem) {
+ mem_offset = s->ioparam.mem_offset;
+
+ // check corrupted mem_offset
+ if (mem_offset < CODEC_MEM_SIZE) {
+ if (elem->buf) {
+ TRACE("write data %d to guest. mem_offset: 0x%x\n",
+ elem->buf_size, mem_offset);
+ memcpy(s->vaddr + mem_offset, elem->buf, elem->buf_size);
+
+ TRACE("release output buffer: %p\n", elem->buf);
+ g_free(elem->buf);
+ }
+ } else {
+ TRACE("mem_offset is corrupted!!\n");
+ }
+
+ TRACE("pop_writequeue. release elem: %p\n", elem);
+ g_free(elem);
+
+ entry[ctx_idx] = NULL;
+ } else {
+ TRACE("there is no buffer to copy data to guest\n");
+ }
+
+ TRACE("leave: %s\n", __func__);
+}
+
+static void serialize_video_data(const struct video_data *video,
+ AVCodecContext *avctx)
+{
+ if (video->width) {
+ avctx->width = video->width;
+ }
+ if (video->height) {
+ avctx->height = video->height;
+ }
+ if (video->fps_n) {
+ avctx->time_base.num = video->fps_n;
+ }
+ if (video->fps_d) {
+ avctx->time_base.den = video->fps_d;
+ }
+ if (video->pix_fmt > PIX_FMT_NONE) {
+ avctx->pix_fmt = video->pix_fmt;
+ }
+ if (video->par_n) {
+ avctx->sample_aspect_ratio.num = video->par_n;
+ }
+ if (video->par_d) {
+ avctx->sample_aspect_ratio.den = video->par_d;
+ }
+ if (video->bpp) {
+ avctx->bits_per_coded_sample = video->bpp;
+ }
+ if (video->ticks_per_frame) {
+ avctx->ticks_per_frame = video->ticks_per_frame;
+ }
+}
+
+static void deserialize_video_data (const AVCodecContext *avctx,
+ struct video_data *video)
+{
+ memset(video, 0x00, sizeof(struct video_data));
+
+ video->width = avctx->width;
+ video->height = avctx->height;
+ video->fps_n = avctx->time_base.num;
+ video->fps_d = avctx->time_base.den;
+ video->pix_fmt = avctx->pix_fmt;
+ video->par_n = avctx->sample_aspect_ratio.num;
+ video->par_d = avctx->sample_aspect_ratio.den;
+ video->bpp = avctx->bits_per_coded_sample;
+ video->ticks_per_frame = avctx->ticks_per_frame;
+}
+
+static void serialize_audio_data (const struct audio_data *audio,
+ AVCodecContext *avctx)
+{
+ if (audio->channels) {
+ avctx->channels = audio->channels;
+ }
+ if (audio->sample_rate) {
+ avctx->sample_rate = audio->sample_rate;
+ }
+ if (audio->block_align) {
+ avctx->block_align = audio->block_align;
+ }
+
+ if (audio->sample_fmt > AV_SAMPLE_FMT_NONE) {
+ avctx->sample_fmt = audio->sample_fmt;
+ }
+}
+
+#if 0
+static void maru_brill_codec_reset_parser_info(MaruBrillCodecState *s, int32_t ctx_index)
+{
+ s->context[ctx_index].parser_buf = NULL;
+ s->context[ctx_index].parser_use = false;
+}
+#endif
+
+static void maru_brill_codec_release_context(MaruBrillCodecState *s, int32_t context_id)
+{
+ DeviceMemEntry *wq_elem = NULL, *wnext = NULL;
+ CodecDataStg *rq_elem = NULL, *rnext = NULL;
+
+ TRACE("enter: %s\n", __func__);
+
+ TRACE("release %d of context\n", context_id);
+ codec_deinit(s, context_id, NULL);
+ s->context[context_id].occupied = false;
+
+ // TODO: check if foreach statment needs lock or not.
+ QTAILQ_FOREACH_SAFE(rq_elem, &codec_rq, node, rnext) {
+ if (rq_elem && rq_elem->data_buf &&
+ (rq_elem->data_buf->ctx_id == context_id)) {
+
+ TRACE("remove unused node from codec_rq. ctx_id: %d\n", context_id);
+ qemu_mutex_lock(&s->context_queue_mutex);
+ QTAILQ_REMOVE(&codec_rq, rq_elem, node);
+ qemu_mutex_unlock(&s->context_queue_mutex);
+ if (rq_elem && rq_elem->data_buf) {
+ TRACE("release rq_buffer: %p\n", rq_elem->data_buf);
+ g_free(rq_elem->data_buf);
+ }
+
+ TRACE("release rq_elem: %p\n", rq_elem);
+ g_free(rq_elem);
+ } else {
+ TRACE("no elem of %d context in the codec_rq.\n", context_id);
+ }
+ }
+
+ QTAILQ_FOREACH_SAFE(wq_elem, &codec_wq, node, wnext) {
+ if (wq_elem && wq_elem->ctx_id == context_id) {
+ TRACE("remove unused node from codec_wq. ctx_id: %d\n", context_id);
+ qemu_mutex_lock(&s->context_queue_mutex);
+ QTAILQ_REMOVE(&codec_wq, wq_elem, node);
+ qemu_mutex_unlock(&s->context_queue_mutex);
+
+ if (wq_elem && wq_elem->buf) {
+ TRACE("release wq_buffer: %p\n", wq_elem->buf);
+ g_free(wq_elem->buf);
+ wq_elem->buf = NULL;
+ }
+
+ TRACE("release wq_elem: %p\n", wq_elem);
+ g_free(wq_elem);
+ } else {
+ TRACE("no elem of %d context in the codec_wq.\n", context_id);
+ }
+ }
+
+ TRACE("leave: %s\n", __func__);
+}
+
+
+// initialize each pixel format.
+static void maru_brill_codec_pixfmt_info_init(void)
+{
+ /* YUV formats */
+ pix_fmt_info[PIX_FMT_YUV420P].x_chroma_shift = 1;
+ pix_fmt_info[PIX_FMT_YUV420P].y_chroma_shift = 1;
+
+ pix_fmt_info[PIX_FMT_YUV422P].x_chroma_shift = 1;
+ pix_fmt_info[PIX_FMT_YUV422P].y_chroma_shift = 0;
+
+ pix_fmt_info[PIX_FMT_YUV444P].x_chroma_shift = 0;
+ pix_fmt_info[PIX_FMT_YUV444P].y_chroma_shift = 0;
+
+ pix_fmt_info[PIX_FMT_YUYV422].x_chroma_shift = 1;
+ pix_fmt_info[PIX_FMT_YUYV422].y_chroma_shift = 0;
+
+ pix_fmt_info[PIX_FMT_YUV410P].x_chroma_shift = 2;
+ pix_fmt_info[PIX_FMT_YUV410P].y_chroma_shift = 2;
+
+ pix_fmt_info[PIX_FMT_YUV411P].x_chroma_shift = 2;
+ pix_fmt_info[PIX_FMT_YUV411P].y_chroma_shift = 0;
+
+ pix_fmt_info[PIX_FMT_YUVJ420P].x_chroma_shift = 1;
+ pix_fmt_info[PIX_FMT_YUVJ420P].y_chroma_shift = 1;
+
+ pix_fmt_info[PIX_FMT_YUVJ422P].x_chroma_shift = 1;
+ pix_fmt_info[PIX_FMT_YUVJ422P].y_chroma_shift = 0;
+
+ pix_fmt_info[PIX_FMT_YUVJ444P].x_chroma_shift = 0;
+ pix_fmt_info[PIX_FMT_YUVJ444P].y_chroma_shift = 0;
+
+ /* RGB formats */
+ pix_fmt_info[PIX_FMT_RGB24].x_chroma_shift = 0;
+ pix_fmt_info[PIX_FMT_RGB24].y_chroma_shift = 0;
+
+ pix_fmt_info[PIX_FMT_BGR24].x_chroma_shift = 0;
+ pix_fmt_info[PIX_FMT_BGR24].y_chroma_shift = 0;
+
+ pix_fmt_info[PIX_FMT_RGB32].x_chroma_shift = 0;
+ pix_fmt_info[PIX_FMT_RGB32].y_chroma_shift = 0;
+
+ pix_fmt_info[PIX_FMT_RGB565].x_chroma_shift = 0;
+ pix_fmt_info[PIX_FMT_RGB565].y_chroma_shift = 0;
+
+ pix_fmt_info[PIX_FMT_RGB555].x_chroma_shift = 0;
+ pix_fmt_info[PIX_FMT_RGB555].y_chroma_shift = 0;
+
+ pix_fmt_info[PIX_FMT_YUVA420P].x_chroma_shift = 1;
+ pix_fmt_info[PIX_FMT_YUVA420P].y_chroma_shift = 1;
+}
+
+static int maru_brill_codec_get_picture_size(AVPicture *picture, uint8_t *ptr,
+ int pix_fmt, int width,
+ int height, bool encode)
+{
+ int size, w2, h2, size2;
+ int stride, stride2;
+ int fsize;
+ PixFmtInfo *pinfo;
+
+ pinfo = &pix_fmt_info[pix_fmt];
+
+ switch (pix_fmt) {
+ case PIX_FMT_YUV420P:
+ case PIX_FMT_YUV422P:
+ case PIX_FMT_YUV444P:
+ case PIX_FMT_YUV410P:
+ case PIX_FMT_YUV411P:
+ case PIX_FMT_YUVJ420P:
+ case PIX_FMT_YUVJ422P:
+ case PIX_FMT_YUVJ444P:
+ stride = ROUND_UP_4(width);
+ h2 = ROUND_UP_X(height, pinfo->y_chroma_shift);
+ size = stride * h2;
+ w2 = DIV_ROUND_UP_X(width, pinfo->x_chroma_shift);
+ stride2 = ROUND_UP_4(w2);
+ h2 = DIV_ROUND_UP_X(height, pinfo->y_chroma_shift);
+ size2 = stride2 * h2;
+ fsize = size + 2 * size2;
+ TRACE("stride: %d, stride2: %d, size: %d, size2: %d, fsize: %d\n",
+ stride, stride2, size, size2, fsize);
+
+ if (!encode && !ptr) {
+ TRACE("allocate a buffer for a decoded picture.\n");
+ ptr = av_mallocz(fsize);
+ if (!ptr) {
+ ERR("[%d] failed to allocate memory.\n", __LINE__);
+ return -1;
+ }
+ }
+ picture->data[0] = ptr;
+ picture->data[1] = picture->data[0] + size;
+ picture->data[2] = picture->data[1] + size2;
+ picture->data[3] = NULL;
+ picture->linesize[0] = stride;
+ picture->linesize[1] = stride2;
+ picture->linesize[2] = stride2;
+ picture->linesize[3] = 0;
+ TRACE("planes %d %d %d\n", 0, size, size + size2);
+ TRACE("strides %d %d %d\n", 0, stride, stride2, stride2);
+ break;
+ case PIX_FMT_YUVA420P:
+ stride = ROUND_UP_4(width);
+ h2 = ROUND_UP_X(height, pinfo->y_chroma_shift);
+ size = stride * h2;
+ w2 = DIV_ROUND_UP_X(width, pinfo->x_chroma_shift);
+ stride2 = ROUND_UP_4(w2);
+ h2 = DIV_ROUND_UP_X(height, pinfo->y_chroma_shift);
+ size2 = stride2 * h2;
+ fsize = 2 * size + 2 * size2;
+ if (!encode && !ptr) {
+ TRACE("allocate a buffer for a decoded picture.\n");
+ ptr = av_mallocz(fsize);
+ if (!ptr) {
+ ERR("[%d] failed to allocate memory.\n", __LINE__);
+ return -1;
+ }
+ }
+ picture->data[0] = ptr;
+ picture->data[1] = picture->data[0] + size;
+ picture->data[2] = picture->data[1] + size2;
+ picture->data[3] = picture->data[2] + size2;
+ picture->linesize[0] = stride;
+ picture->linesize[1] = stride2;
+ picture->linesize[2] = stride2;
+ picture->linesize[3] = stride;
+ TRACE("planes %d %d %d\n", 0, size, size + size2);
+ TRACE("strides %d %d %d\n", 0, stride, stride2, stride2);
+ break;
+ case PIX_FMT_RGB24:
+ case PIX_FMT_BGR24:
+ stride = ROUND_UP_4 (width * 3);
+ fsize = stride * height;
+ TRACE("stride: %d, size: %d\n", stride, fsize);
+
+ if (!encode && !ptr) {
+ TRACE("allocate a buffer for a decoded picture.\n");
+ ptr = av_mallocz(fsize);
+ if (!ptr) {
+ ERR("[%d] failed to allocate memory.\n", __LINE__);
+ return -1;
+ }
+ }
+ picture->data[0] = ptr;
+ picture->data[1] = NULL;
+ picture->data[2] = NULL;
+ picture->data[3] = NULL;
+ picture->linesize[0] = stride;
+ picture->linesize[1] = 0;
+ picture->linesize[2] = 0;
+ picture->linesize[3] = 0;
+ break;
+ case PIX_FMT_RGB32:
+ stride = width * 4;
+ fsize = stride * height;
+ TRACE("stride: %d, size: %d\n", stride, fsize);
+
+ if (!encode && !ptr) {
+ TRACE("allocate a buffer for a decoded picture.\n");
+ ptr = av_mallocz(fsize);
+ if (!ptr) {
+ ERR("[%d] failed to allocate memory.\n", __LINE__);
+ return -1;
+ }
+ }
+ picture->data[0] = ptr;
+ picture->data[1] = NULL;
+ picture->data[2] = NULL;
+ picture->data[3] = NULL;
+ picture->linesize[0] = stride;
+ picture->linesize[1] = 0;
+ picture->linesize[2] = 0;
+ picture->linesize[3] = 0;
+ break;
+ case PIX_FMT_RGB555:
+ case PIX_FMT_RGB565:
+ stride = ROUND_UP_4 (width * 2);
+ fsize = stride * height;
+ TRACE("stride: %d, size: %d\n", stride, fsize);
+
+ if (!encode && !ptr) {
+ TRACE("allocate a buffer for a decoded picture.\n");
+ ptr = av_mallocz(fsize);
+ if (!ptr) {
+ ERR("[%d] failed to allocate memory.\n", __LINE__);
+ return -1;
+ }
+ }
+ picture->data[0] = ptr;
+ picture->data[1] = NULL;
+ picture->data[2] = NULL;
+ picture->data[3] = NULL;
+ picture->linesize[0] = stride;
+ picture->linesize[1] = 0;
+ picture->linesize[2] = 0;
+ picture->linesize[3] = 0;
+ break;
+ case PIX_FMT_PAL8:
+ stride = ROUND_UP_4(width);
+ size = stride * height;
+ fsize = size + 256 * 4;
+ TRACE("stride: %d, size: %d\n", stride, fsize);
+
+ if (!encode && !ptr) {
+ TRACE("allocate a buffer for a decoded picture.\n");
+ ptr = av_mallocz(fsize);
+ if (!ptr) {
+ ERR("[%d] failed to allocate memory.\n", __LINE__);
+ return -1;
+ }
+ }
+ picture->data[0] = ptr;
+ picture->data[1] = ptr + size;
+ picture->data[2] = NULL;
+ picture->data[3] = NULL;
+ picture->linesize[0] = stride;
+ picture->linesize[1] = 4;
+ picture->linesize[2] = 0;
+ picture->linesize[3] = 0;
+ break;
+ default:
+ picture->data[0] = NULL;
+ picture->data[1] = NULL;
+ picture->data[2] = NULL;
+ picture->data[3] = NULL;
+ fsize = -1;
+ ERR("pixel format: %d was wrong.\n", pix_fmt);
+ break;
+ }
+
+ return fsize;
+}
+
+static int maru_brill_codec_query_list (MaruBrillCodecState *s)
+{
+ AVCodec *codec = NULL;
+ uint32_t size = 0, mem_size = 0;
+ uint32_t data_len = 0, length = 0;
+ int32_t codec_type, media_type;
+ int32_t codec_fmts[4], i;
+
+ /* register avcodec */
+ TRACE("register avcodec\n");
+ av_register_all();
+
+ codec = av_codec_next(NULL);
+ if (!codec) {
+ ERR("failed to get codec info.\n");
+ return -1;
+ }
+
+ // a region to store the number of codecs.
+ length = 32 + 64 + 6 * sizeof(int32_t);
+ mem_size = size = sizeof(uint32_t);
+
+ while (codec) {
+ codec_type =
+ codec->decode ? CODEC_TYPE_DECODE : CODEC_TYPE_ENCODE;
+ media_type = codec->type;
+
+ memset(codec_fmts, -1, sizeof(codec_fmts));
+ if (media_type == AVMEDIA_TYPE_VIDEO) {
+ if (codec->pix_fmts) {
+ for (i = 0; codec->pix_fmts[i] != -1; i++) {
+ codec_fmts[i] = codec->pix_fmts[i];
+ }
+ }
+ } else if (media_type == AVMEDIA_TYPE_AUDIO) {
+ if (codec->sample_fmts) {
+ for (i = 0; codec->sample_fmts[i] != -1; i++) {
+ codec_fmts[i] = codec->sample_fmts[i];
+ }
+ }
+ } else {
+ ERR("%s of media type is unknown.\n", codec->name);
+ }
+
+ memset(s->vaddr + mem_size, 0x00, length);
+ mem_size += length;
+
+ data_len += length;
+ memcpy(s->vaddr, &data_len, sizeof(data_len));
+
+ memcpy(s->vaddr + size, &codec_type, sizeof(codec_type));
+ size += sizeof(codec_type);
+ memcpy(s->vaddr + size, &media_type, sizeof(media_type));
+ size += sizeof(media_type);
+ memcpy(s->vaddr + size, codec->name, strlen(codec->name));
+ size += 32;
+ memcpy(s->vaddr + size,
+ codec->long_name, strlen(codec->long_name));
+ size += 64;
+ memcpy(s->vaddr + size, codec_fmts, sizeof(codec_fmts));
+ size += sizeof(codec_fmts);
+
+ codec = av_codec_next(codec);
+ }
+
+ return 0;
+}
+
+static int maru_brill_codec_get_context_index(MaruBrillCodecState *s)
+{
+ int index;
+
+ TRACE("enter: %s\n", __func__);
+
+ for (index = 1; index < CODEC_CONTEXT_MAX; index++) {
+ if (s->context[index].occupied == false) {
+ TRACE("get %d of codec context successfully.\n", index);
+ s->context[index].occupied = true;
+ break;
+ }
+ }
+
+ if (index == CODEC_CONTEXT_MAX) {
+ ERR("failed to get available codec context. ");
+ ERR("try to run codec again.\n");
+ index = -1;
+ }
+
+ TRACE("leave: %s\n", __func__);
+
+ return index;
+}
+
+// allocate avcontext and avframe struct.
+static AVCodecContext *maru_brill_codec_alloc_context(MaruBrillCodecState *s, int index)
+{
+ TRACE("enter: %s\n", __func__);
+
+ TRACE("allocate %d of context and frame.\n", index);
+ s->context[index].avctx = avcodec_alloc_context();
+ s->context[index].frame = avcodec_alloc_frame();
+ s->context[index].opened = false;
+
+ s->context[index].parser_buf = NULL;
+ s->context[index].parser_use = false;
+
+ TRACE("leave: %s\n", __func__);
+
+ return s->context[index].avctx;
+}
+
+static AVCodec *maru_brill_codec_find_avcodec(uint8_t *mem_buf)
+{
+ AVCodec *codec = NULL;
+ int32_t encode, size = 0;
+ char codec_name[32] = {0, };
+
+ memcpy(&encode, mem_buf, sizeof(encode));
+ size = sizeof(encode);
+ memcpy(codec_name, mem_buf + size, sizeof(codec_name));
+ size += sizeof(codec_name);
+
+ TRACE("type: %d, name: %s\n", encode, codec_name);
+
+ if (encode) {
+ codec = avcodec_find_encoder_by_name (codec_name);
+ } else {
+ codec = avcodec_find_decoder_by_name (codec_name);
+ }
+ INFO("%s!! find %s %s\n",
+ codec ? "success" : "failure",
+ codec_name, encode ? "encoder" : "decoder");
+
+ return codec;
+}
+
+static void read_codec_init_data(AVCodecContext *avctx, uint8_t *mem_buf)
+{
+ struct video_data video = { 0, };
+ struct audio_data audio = { 0, };
+ int bitrate = 0, size = 0;
+
+ memcpy(&video, mem_buf + size, sizeof(video));
+ size = sizeof(video);
+ serialize_video_data(&video, avctx);
+
+ memcpy(&audio, mem_buf + size, sizeof(int32_t) * 6);
+ size += sizeof(int32_t) * 6;
+ memcpy(&audio.bits_per_smp_fmt, mem_buf + size, sizeof(int32_t));
+ size += sizeof(int32_t);
+ memcpy(&audio.channel_layout, mem_buf + size, sizeof(int64_t));
+ size += sizeof(int64_t);
+ serialize_audio_data(&audio, avctx);
+
+ memcpy(&bitrate, mem_buf + size, sizeof(bitrate));
+ size += sizeof(bitrate);
+ if (bitrate) {
+ avctx->bit_rate = bitrate;
+ }
+ memcpy(&avctx->codec_tag, mem_buf + size, sizeof(avctx->codec_tag));
+ size += sizeof(avctx->codec_tag);
+ memcpy(&avctx->extradata_size,
+ mem_buf + size, sizeof(avctx->extradata_size));
+ size += sizeof(avctx->extradata_size);
+ if (avctx->extradata_size > 0) {
+ TRACE("extradata size: %d.\n", avctx->extradata_size);
+ avctx->extradata =
+ av_mallocz(ROUND_UP_X(avctx->extradata_size +
+ FF_INPUT_BUFFER_PADDING_SIZE, 4));
+ if (avctx->extradata) {
+ memcpy(avctx->extradata, mem_buf + size, avctx->extradata_size);
+ }
+ } else {
+ TRACE("no extra data.\n");
+ avctx->extradata =
+ av_mallocz(ROUND_UP_X(FF_INPUT_BUFFER_PADDING_SIZE, 4));
+ }
+}
+
+// write the result of codec_init
+static void write_codec_init_data(AVCodecContext *avctx, uint8_t *mem_buf)
+{
+ int size = 0;
+
+ if (avctx->codec->type == AVMEDIA_TYPE_AUDIO) {
+ int osize = 0;
+
+ TRACE("codec_init. audio sample_fmt: %d\n", avctx->sample_fmt);
+
+ memcpy(mem_buf, &avctx->sample_fmt, sizeof(avctx->sample_fmt));
+ size = sizeof(avctx->sample_fmt);
+ memcpy(mem_buf + size,
+ &avctx->frame_size, sizeof(avctx->frame_size));
+ size += sizeof(avctx->frame_size);
+ osize = av_get_bits_per_sample(avctx->codec->id) / 8;
+ memcpy(mem_buf + size, &osize, sizeof(osize));
+ }
+}
+
+// write the result of codec_decode_video
+static void write_codec_decode_video_data(AVCodecContext *avctx, int len,
+ int got_pic_ptr, uint8_t *mem_buf)
+{
+ struct video_data video;
+ int size = 0;
+
+ memcpy(mem_buf, &len, sizeof(len));
+ size = sizeof(len);
+ memcpy(mem_buf + size, &got_pic_ptr, sizeof(got_pic_ptr));
+ size += sizeof(got_pic_ptr);
+ if (avctx) {
+ deserialize_video_data(avctx, &video);
+ memcpy(mem_buf + size, &video, sizeof(struct video_data));
+ }
+}
+
+// write the result of codec_decode_audio
+static void write_codec_decode_audio_data(int sample_rate, int channel,
+ int64_t channel_layout, int len,
+ int frame_size_ptr, uint8_t *mem_buf)
+{
+ int size = 0;
+
+ TRACE("copy decode_audio. len %d, frame_size %d\n", len, frame_size_ptr);
+
+ memcpy(mem_buf, &sample_rate, sizeof(sample_rate));
+ size = sizeof(sample_rate);
+ memcpy(mem_buf + size, &channel, sizeof(channel));
+ size += sizeof(channel);
+ memcpy(mem_buf + size, &channel_layout, sizeof(channel_layout));
+ size += sizeof(channel_layout);
+ memcpy(mem_buf + size, &len, sizeof(len));
+ size += sizeof(len);
+ memcpy(mem_buf + size, &frame_size_ptr, sizeof(frame_size_ptr));
+}
+
+// codec functions
+static bool codec_init(MaruBrillCodecState *s, int ctx_id, void *elem)
+{
+ AVCodecContext *avctx = NULL;
+ AVCodec *codec = NULL;
+ int size = 0, ret = -1;
+ uint8_t *meta_buf = NULL;
+
+ TRACE("enter: %s\n", __func__);
+
+ // assign meta_buf
+ meta_buf = s->vaddr + ((ctx_id - 1) * CODEC_META_DATA_SIZE);
+ meta_buf += 8; // skipped header.
+
+ // allocate AVCodecContext
+ avctx = maru_brill_codec_alloc_context(s, ctx_id);
+ if (!avctx) {
+ ERR("[%d] failed to allocate context.\n", __LINE__);
+ ret = -1;
+ } else {
+ codec = maru_brill_codec_find_avcodec(meta_buf);
+ if (codec) {
+ size = sizeof(int32_t) + 32; // buffer size of codec_name
+ read_codec_init_data(avctx, meta_buf + size);
+
+ ret = avcodec_open(avctx, codec);
+ INFO("avcodec_open done. ctx_id: %d\n", ctx_id);
+
+ s->context[ctx_id].opened = true;
+ s->context[ctx_id].parser_ctx =
+ maru_brill_codec_parser_init(avctx);
+ } else {
+ ERR("failed to find codec. ctx_id: %d\n", ctx_id);
+ }
+ }
+
+ // return the result of avcodec_open
+ memcpy(meta_buf, &ret, sizeof(ret));
+ size = sizeof(ret);
+ if (ret < 0) {
+ ERR("failed to open codec contex.\n");
+ } else {
+ write_codec_init_data(avctx, meta_buf + size);
+ }
+
+ maru_brill_codec_push_writequeue(s, NULL, 0, ctx_id);
+
+ TRACE("leave: %s\n", __func__);
+
+ return true;
+}
+
+static bool codec_deinit(MaruBrillCodecState *s, int ctx_id, void *data_buf)
+{
+ AVCodecContext *avctx = NULL;
+ AVFrame *frame = NULL;
+ AVCodecParserContext *parserctx = NULL;
+
+ TRACE("enter: %s\n", __func__);
+
+ avctx = s->context[ctx_id].avctx;
+ frame = s->context[ctx_id].frame;
+ parserctx = s->context[ctx_id].parser_ctx;
+ if (!avctx || !frame) {
+ TRACE("%d of AVCodecContext or AVFrame is NULL. "
+ " Those resources have been released before.\n", ctx_id);
+ return false;
+ } else {
+ qemu_mutex_lock(&s->threadpool.mutex);
+ if (!s->context[ctx_id].opened) {
+ TRACE("%d of context has already been closed\n", ctx_id);
+ qemu_mutex_unlock(&s->threadpool.mutex);
+ return false;
+ }
+ avcodec_close(avctx);
+ INFO("close avcontext of %d\n", ctx_id);
+ s->context[ctx_id].opened = false;
+ qemu_mutex_unlock(&s->threadpool.mutex);
+
+ if (avctx->extradata) {
+ TRACE("free context extradata\n");
+ av_free(avctx->extradata);
+ s->context[ctx_id].avctx->extradata = NULL;
+ }
+
+ if (avctx->palctrl) {
+ TRACE("free context palctrl \n");
+ av_free(avctx->palctrl);
+ s->context[ctx_id].avctx->palctrl = NULL;
+ }
+
+ if (frame) {
+ TRACE("free frame\n");
+ av_free(frame);
+ s->context[ctx_id].frame = NULL;
+ }
+
+ if (avctx) {
+ TRACE("free codec context\n");
+ av_free(avctx);
+ s->context[ctx_id].avctx = NULL;
+ }
+
+ if (parserctx) {
+ av_parser_close(parserctx);
+ s->context[ctx_id].parser_ctx = NULL;
+ }
+ }
+
+ TRACE("leave: %s\n", __func__);
+
+ return true;
+}
+
+//
+static bool codec_flush_buffers(MaruBrillCodecState *s, int ctx_id, void *data_buf)
+{
+ AVCodecContext *avctx = NULL;
+
+ TRACE("enter: %s\n", __func__);
+
+ avctx = s->context[ctx_id].avctx;
+ if (!avctx) {
+ ERR("%d of AVCodecContext is NULL.\n", ctx_id);
+ return false;
+ } else {
+ avcodec_flush_buffers(avctx);
+ TRACE("flush %d context of buffers.\n", ctx_id);
+ }
+
+ TRACE("leave: %s\n", __func__);
+
+ return true;
+}
+
+static bool codec_decode_video(MaruBrillCodecState *s, int ctx_id, void *data_buf)
+{
+ AVCodecContext *avctx = NULL;
+ AVFrame *picture = NULL;
+ AVPacket avpkt;
+ int got_pic_ptr = 0, len = 0;
+ uint8_t *inbuf = NULL;
+ int inbuf_size, idx, size = 0;
+ int64_t in_offset;
+
+ DeviceMemEntry *elem = NULL;
+ uint8_t *meta_buf = NULL;
+
+ TRACE("enter: %s\n", __func__);
+
+ meta_buf = s->vaddr + ((ctx_id - 1) * CODEC_META_DATA_SIZE);
+ meta_buf += 8; // skipped header.
+
+ memcpy(&inbuf_size, meta_buf, sizeof(inbuf_size));
+ size = sizeof(inbuf_size);
+ memcpy(&idx, meta_buf + size, sizeof(idx));
+ size += sizeof(idx);
+ memcpy(&in_offset, meta_buf + size, sizeof(in_offset));
+ size += sizeof(in_offset);
+ TRACE("decode_video. input buffer size: %d\n", inbuf_size);
+
+ elem = (DeviceMemEntry *)data_buf;
+ if (elem && elem->buf) {
+ inbuf = elem->buf;
+ } else if (elem) {
+ inbuf_size = 0;
+ TRACE("decode_video. no input buffer. ctx_id: %d, %p, %d\n",
+ ctx_id, inbuf, elem->buf_size);
+ } else {
+ ERR("wrong input data\n");
+ return false;
+ }
+
+ av_init_packet(&avpkt);
+ avpkt.data = inbuf;
+ avpkt.size = inbuf_size;
+
+ avctx = s->context[ctx_id].avctx;
+ picture = s->context[ctx_id].frame;
+ if (!avctx || !picture) {
+ ERR("%d of AVCodecContext or AVFrame is NULL.\n", ctx_id);
+ len = -1;
+ } else if (!avctx->codec) {
+ ERR("%d of AVCodec is NULL.\n", ctx_id);
+ len = -1;
+ } else {
+ // in case of skipping frames
+ picture->pict_type = -1;
+
+ len = avcodec_decode_video2(avctx, picture, &got_pic_ptr, &avpkt);
+ if (len < 0) {
+ ERR("failed to decode video. ctx index: %d\n", ctx_id);
+ }
+ }
+
+ TRACE("after decoding video. len: %d, have_data: %d\n",
+ len, got_pic_ptr);
+
+ write_codec_decode_video_data(avctx, len, got_pic_ptr, meta_buf);
+ maru_brill_codec_push_writequeue(s, NULL, 0, ctx_id);
+
+ TRACE("leave: %s\n", __func__);
+
+ return true;
+}
+
+static bool codec_picture_copy (MaruBrillCodecState *s, int ctx_id, void *elem)
+{
+ AVCodecContext *avctx;
+ AVPicture *src;
+ AVPicture dst;
+ uint8_t *out_buffer = NULL, *tempbuf = NULL;
+ int pict_size = 0;
+
+ TRACE("enter: %s\n", __func__);
+
+ TRACE("copy decoded image of %d context.\n", ctx_id);
+
+ avctx = s->context[ctx_id].avctx;
+ src = (AVPicture *)s->context[ctx_id].frame;
+ if (!avctx || !src) {
+ ERR("%d of AVCodecContext or AVFrame is NULL.\n", ctx_id);
+ } else if (!avctx->codec) {
+ ERR("%d of AVCodec is NULL.\n", ctx_id);
+ } else {
+ TRACE("decoded image. pix_fmt: %d width: %d, height: %d\n",
+ avctx->pix_fmt, avctx->width, avctx->height);
+
+ pict_size =
+ maru_brill_codec_get_picture_size(&dst, NULL, avctx->pix_fmt,
+ avctx->width, avctx->height, false);
+ if ((pict_size) < 0) {
+ ERR("picture size: %d\n", pict_size);
+ } else {
+ TRACE("picture size: %d\n", pict_size);
+ av_picture_copy(&dst, src, avctx->pix_fmt,
+ avctx->width, avctx->height);
+
+ tempbuf = g_malloc0(pict_size);
+ if (!tempbuf) {
+ ERR("failed to allocate a picture buffer. size: %d\n", pict_size);
+ } else {
+ out_buffer = dst.data[0];
+ memcpy(tempbuf, out_buffer, pict_size);
+ }
+ av_free(out_buffer);
+ }
+ }
+ maru_brill_codec_push_writequeue(s, tempbuf, pict_size, ctx_id);
+
+ TRACE("leave: %s\n", __func__);
+
+ return true;
+}
+
+static bool codec_decode_audio(MaruBrillCodecState *s, int ctx_id, void *data_buf)
+{
+ AVCodecContext *avctx;
+ AVPacket avpkt;
+ int16_t *samples = NULL;
+ uint8_t *inbuf = NULL;
+ int inbuf_size = 0;
+ int len = 0, frame_size_ptr = 0;
+ uint8_t *meta_buf = NULL;
+ DeviceMemEntry *elem = NULL;
+ uint8_t *tempbuf = NULL;
+
+ TRACE("enter: %s\n", __func__);
+
+ meta_buf = s->vaddr + ((ctx_id - 1) * CODEC_META_DATA_SIZE);
+ meta_buf += 8; // skipped header.
+
+ memcpy(&inbuf_size, meta_buf, sizeof(inbuf_size));
+ TRACE("before decoding audio. inbuf_size: %d\n", inbuf_size);
+
+ elem = (DeviceMemEntry *)data_buf;
+ if (elem && elem->buf) {
+ inbuf = elem->buf;
+ } else if (elem) {
+ inbuf_size = 0;
+ TRACE("decode_audio. no input buffer.\n");
+ } else {
+ ERR("wrong input data\n");
+ return false;
+ }
+
+ av_init_packet(&avpkt);
+ avpkt.data = inbuf;
+ avpkt.size = inbuf_size;
+
+ avctx = s->context[ctx_id].avctx;
+ if (!avctx) {
+ ERR("[%s] %d of AVCodecContext is NULL!\n", __func__, ctx_id);
+ write_codec_decode_audio_data(0, 0, 0, -1, 0, meta_buf);
+ } else if (!avctx->codec) {
+ ERR("%d of AVCodec is NULL.\n", ctx_id);
+ write_codec_decode_audio_data(0, 0, 0, -1, 0, meta_buf);
+ } else {
+ frame_size_ptr = AVCODEC_MAX_AUDIO_FRAME_SIZE;
+ samples = av_mallocz(frame_size_ptr);
+ if (!samples) {
+ ERR("failed to allocate an outbuf of audio.\n");
+ len = -1;
+ } else {
+ len =
+ avcodec_decode_audio3(avctx, samples, &frame_size_ptr, &avpkt);
+
+ TRACE("audio. len %d, channel_layout %lld, frame_size %d\n",
+ len, avctx->channel_layout, frame_size_ptr);
+ }
+
+ write_codec_decode_audio_data(avctx->sample_rate, avctx->channels,
+ avctx->channel_layout, len,
+ frame_size_ptr, meta_buf);
+ }
+
+ if (len < 0) {
+ ERR("failed to decode audio. ctx_id: %d, len: %d\n", ctx_id, len);
+ frame_size_ptr = 0;
+ } else {
+ if (frame_size_ptr > 0) {
+ tempbuf = g_malloc0(frame_size_ptr);
+ if (!tempbuf) {
+ ERR("failed to allocate decoded audio buffer. "
+ "ctx_id: %d, outbuf_size: %d\n", ctx_id, frame_size_ptr);
+ } else {
+ memcpy(tempbuf, samples, frame_size_ptr);
+ }
+ av_free(samples);
+ }
+ }
+
+ maru_brill_codec_push_writequeue(s, tempbuf, frame_size_ptr, ctx_id);
+
+ TRACE("leave: %s\n", __func__);
+
+ return true;
+}
+
+static bool codec_encode_video(MaruBrillCodecState *s, int ctx_id, void *data_buf)
+{
+ AVCodecContext *avctx = NULL;
+ AVFrame *pict = NULL;
+ uint8_t *inbuf = NULL, *outbuf = NULL;
+ int inbuf_size, outbuf_size, len = 0;
+ int ret;
+ int64_t in_timestamp;
+
+ uint8_t *meta_buf = NULL;
+ DeviceMemEntry *elem = NULL;
+ uint8_t *tempbuf = NULL;
+
+ TRACE("enter: %s\n", __func__);
+
+ meta_buf = s->vaddr + ((ctx_id - 1) * CODEC_META_DATA_SIZE);
+ meta_buf += 8; // skipped header.
+
+ memcpy(&inbuf_size, meta_buf, sizeof(inbuf_size));
+ memcpy(&in_timestamp, meta_buf + sizeof(inbuf_size), sizeof(in_timestamp));
+ TRACE("input buffer size: %d\n", inbuf_size);
+
+ elem = (DeviceMemEntry *)data_buf;
+ if (elem && elem->buf) {
+ inbuf = elem->buf;
+ } else if (elem) {
+ TRACE("encode_video. no input buffer.\n");
+ inbuf_size = 0;
+ } else {
+ ERR("wrong input data\n");
+ return false;
+ }
+
+ avctx = s->context[ctx_id].avctx;
+ pict = s->context[ctx_id].frame;
+ if (!avctx || !pict) {
+ ERR("%d of context or frame is NULL\n", ctx_id);
+ len = -1;
+ } else if (!avctx->codec) {
+ ERR("%d of AVCodec is NULL.\n", ctx_id);
+ len = -1;
+ } else {
+ TRACE("pixel format: %d inbuf: %p, picture data: %p\n",
+ avctx->pix_fmt, inbuf, pict->data[0]);
+
+ ret =
+ maru_brill_codec_get_picture_size((AVPicture *)pict, inbuf,
+ avctx->pix_fmt, avctx->width,
+ avctx->height, true);
+ if (ret < 0) {
+ ERR("after avpicture_fill, ret:%d\n", ret);
+ len = -1;
+ } else {
+ if (avctx->time_base.num == 0) {
+ pict->pts = AV_NOPTS_VALUE;
+ } else {
+ AVRational bq =
+ {1, (G_USEC_PER_SEC * G_GINT64_CONSTANT(1000))};
+ pict->pts = av_rescale_q(in_timestamp, bq, avctx->time_base);
+ }
+ TRACE("before encode video, ticks_per_frame:%d, pts:%lld\n",
+ avctx->ticks_per_frame, pict->pts);
+
+ outbuf_size =
+ (avctx->width * avctx->height * 6) + FF_MIN_BUFFER_SIZE;
+ outbuf = g_malloc0(outbuf_size);
+ if (!outbuf) {
+ ERR("failed to allocate a buffer of encoding video.\n");
+ len = -1;
+ } else {
+ len = avcodec_encode_video(avctx, outbuf, outbuf_size, pict);
+
+ TRACE("encode video! len:%d pts:%lld outbuf:%p outbuf size: %d\n",
+ len, pict->pts, outbuf, outbuf_size);
+ }
+ }
+ }
+
+ // write encoded video data
+ memcpy(meta_buf, &len, sizeof(len));
+ if (len < 0) {
+ ERR("failed to encode video. len: %d\n", len);
+ } else {
+ tempbuf = g_malloc0(len);
+ if (!tempbuf) {
+ ERR("failed to allocate an element of writequeue.\n");
+ } else {
+ memcpy(tempbuf, outbuf, len);
+ }
+ }
+
+ if (outbuf) {
+ TRACE("release encoded output buffer. %p\n", outbuf);
+ g_free(outbuf);
+ }
+
+ maru_brill_codec_push_writequeue(s, tempbuf, len, ctx_id);
+
+ TRACE("leave: %s\n", __func__);
+ return true;
+}
+
+static bool codec_encode_audio(MaruBrillCodecState *s, int ctx_id, void *data_buf)
+{
+ AVCodecContext *avctx;
+ uint8_t *inbuf = NULL, *outbuf = NULL;
+ int32_t inbuf_size, max_size;
+ int len = 0;
+ uint8_t *meta_buf = NULL;
+
+ DeviceMemEntry *elem = NULL;
+ uint8_t *tempbuf = NULL;
+
+ TRACE("enter: %s\n", __func__);
+
+ meta_buf = s->vaddr + ((ctx_id - 1) * CODEC_META_DATA_SIZE);
+ meta_buf += 8; // skipped header.
+
+ memcpy(&inbuf_size, meta_buf, sizeof(inbuf_size));
+ memcpy(&max_size, meta_buf + sizeof(inbuf_size), sizeof(max_size));
+ TRACE("encoding audio. in_size: %d, max_size: %d\n", inbuf_size, max_size);
+
+ elem = (DeviceMemEntry *)data_buf;
+ if (elem && elem->buf) {
+ inbuf = elem->buf;
+ } else if (elem) {
+ TRACE("no input buffer to encode audio.\n");
+ inbuf_size = 0;
+ } else {
+ ERR("wrong input data\n");
+ return false;
+ }
+
+ avctx = s->context[ctx_id].avctx;
+ if (!avctx) {
+ ERR("[%s] %d of Context is NULL!\n", __func__, ctx_id);
+ } else if (!avctx->codec) {
+ ERR("%d of AVCodec is NULL.\n", ctx_id);
+ } else {
+ outbuf = g_malloc0(max_size + FF_MIN_BUFFER_SIZE);
+ if (!outbuf) {
+ ERR("failed to allocate a buffer of encoding audio.\n");
+ len = -1;
+ } else {
+ len =
+ avcodec_encode_audio(avctx, outbuf, max_size, (short *)inbuf);
+ TRACE("after encoding audio. len: %d\n", len);
+ }
+ }
+
+ // write encoded audio data
+ memcpy(meta_buf, &len, sizeof(len));
+ if (len < 0) {
+ ERR("failed to encode audio. ctx_id: %d len: %d\n", ctx_id, len);
+ } else {
+ tempbuf = g_malloc0(len);
+ if (!tempbuf) {
+ ERR("encode_audio. failed to allocate temporary buffer.\n");
+ } else {
+ memcpy(tempbuf, outbuf, len);
+ }
+ }
+
+ if (outbuf) {
+ av_free(outbuf);
+ }
+
+ maru_brill_codec_push_writequeue(s, tempbuf, len, ctx_id);
+
+ TRACE("[%s] leave:\n", __func__);
+ return true;
+}
+
+static AVCodecParserContext *maru_brill_codec_parser_init(AVCodecContext *avctx)
+{
+ AVCodecParserContext *parser = NULL;
+
+ if (!avctx) {
+ ERR("context is NULL\n");
+ return NULL;
+ }
+
+ switch (avctx->codec_id) {
+ case CODEC_ID_MPEG4:
+ case CODEC_ID_VC1:
+ TRACE("not using parser.\n");
+ break;
+ case CODEC_ID_H264:
+ if (avctx->extradata_size == 0) {
+ TRACE("H.264 with no extradata, creating parser.\n");
+ parser = av_parser_init (avctx->codec_id);
+ }
+ break;
+ default:
+ parser = av_parser_init (avctx->codec_id);
+ if (parser) {
+ INFO("using parser. %d\n", avctx->codec_id);
+ }
+ break;
+ }
+
+ return parser;
+}
+
+//
+static void maru_brill_codec_bh_callback(void *opaque)
+{
+ MaruBrillCodecState *s = (MaruBrillCodecState *)opaque;
+
+ TRACE("enter: %s\n", __func__);
+
+ qemu_mutex_lock(&s->context_queue_mutex);
+ if (!QTAILQ_EMPTY(&codec_wq)) {
+ qemu_mutex_unlock(&s->context_queue_mutex);
+
+ TRACE("raise irq\n");
- qemu_irq_lower(s->dev.irq[0]);
++ pci_set_irq(&s->dev, 1);
+ s->irq_raised = 1;
+ } else {
+ qemu_mutex_unlock(&s->context_queue_mutex);
+ TRACE("codec_wq is empty!!\n");
+ }
+
+ TRACE("leave: %s\n", __func__);
+}
+
+/*
+ * Codec Device APIs
+ */
+static uint64_t maru_brill_codec_read(void *opaque,
+ hwaddr addr,
+ unsigned size)
+{
+ MaruBrillCodecState *s = (MaruBrillCodecState *)opaque;
+ uint64_t ret = 0;
+
+ switch (addr) {
+ case CODEC_CMD_GET_THREAD_STATE:
+ qemu_mutex_lock(&s->context_queue_mutex);
+ if (s->irq_raised) {
+ ret = CODEC_TASK_END;
++ pci_set_irq(&s->dev, 0);
+ s->irq_raised = 0;
+ }
+ qemu_mutex_unlock(&s->context_queue_mutex);
+
+ TRACE("get thread_state. ret: %d\n", ret);
+ break;
+
+ case CODEC_CMD_GET_CTX_FROM_QUEUE:
+ {
+ DeviceMemEntry *head = NULL;
+
+ qemu_mutex_lock(&s->context_queue_mutex);
+ head = QTAILQ_FIRST(&codec_wq);
+ if (head) {
+ ret = head->ctx_id;
+ QTAILQ_REMOVE(&codec_wq, head, node);
+ entry[ret] = head;
+ TRACE("get a elem from codec_wq. 0x%x\n", head);
+ } else {
+ ret = 0;
+ }
+ qemu_mutex_unlock(&s->context_queue_mutex);
+
+ TRACE("get a head from a writequeue. head: %x\n", ret);
+ }
+ break;
+
+ case CODEC_CMD_GET_VERSION:
+ ret = CODEC_VERSION;
+ TRACE("codec version: %d\n", ret);
+ break;
+
+ case CODEC_CMD_GET_ELEMENT:
+ ret = maru_brill_codec_query_list(s);
+ break;
+
+ case CODEC_CMD_GET_CONTEXT_INDEX:
+ ret = maru_brill_codec_get_context_index(s);
+ TRACE("get context index: %d\n", ret);
+ break;
+
+ default:
+ ERR("no avaiable command for read. %d\n", addr);
+ }
+
+ return ret;
+}
+
+static void maru_brill_codec_write(void *opaque, hwaddr addr,
+ uint64_t value, unsigned size)
+{
+ MaruBrillCodecState *s = (MaruBrillCodecState *)opaque;
+
+ switch (addr) {
+ case CODEC_CMD_API_INDEX:
+ TRACE("set codec_cmd value: %d\n", value);
+ s->ioparam.api_index = value;
+ maru_brill_codec_wakeup_threads(s, value);
+ break;
+
+ case CODEC_CMD_CONTEXT_INDEX:
+ TRACE("set context_index value: %d\n", value);
+ s->ioparam.ctx_index = value;
+ break;
+
+ case CODEC_CMD_DEVICE_MEM_OFFSET:
+ TRACE("set mem_offset value: 0x%x\n", value);
+ s->ioparam.mem_offset = value;
+ break;
+
+ case CODEC_CMD_RELEASE_CONTEXT:
+ maru_brill_codec_release_context(s, (int32_t)value);
+ break;
+
+ case CODEC_CMD_GET_DATA_FROM_QUEUE:
+ maru_brill_codec_pop_writequeue(s, (uint32_t)value);
+ break;
+
+ default:
+ ERR("no available command for write. %d\n", addr);
+ }
+}
+
+static const MemoryRegionOps maru_brill_codec_mmio_ops = {
+ .read = maru_brill_codec_read,
+ .write = maru_brill_codec_write,
+ .valid = {
+ .min_access_size = 4,
+ .max_access_size = 4,
+ .unaligned = false
+ },
+ .endianness = DEVICE_LITTLE_ENDIAN,
+};
+
+static int maru_brill_codec_initfn(PCIDevice *dev)
+{
+ MaruBrillCodecState *s = DO_UPCAST(MaruBrillCodecState, dev, dev);
+ uint8_t *pci_conf = s->dev.config;
+
+ INFO("device initialization.\n");
+ pci_config_set_interrupt_pin(pci_conf, 1);
+
+ memory_region_init_ram(&s->vram, OBJECT(s), "maru_brill_codec.vram", CODEC_MEM_SIZE);
+ s->vaddr = (uint8_t *)memory_region_get_ram_ptr(&s->vram);
+
+ memory_region_init_io(&s->mmio, OBJECT(s), &maru_brill_codec_mmio_ops, s,
+ "maru_brill_codec.mmio", CODEC_REG_SIZE);
+
+ pci_register_bar(&s->dev, 0, PCI_BASE_ADDRESS_MEM_PREFETCH, &s->vram);
+ pci_register_bar(&s->dev, 1, PCI_BASE_ADDRESS_SPACE_MEMORY, &s->mmio);
+
+// maru_brill_codec_reset(&s->dev.qdev);
+
+ qemu_mutex_init(&s->context_mutex);
+ qemu_mutex_init(&s->context_queue_mutex);
+ qemu_mutex_init(&s->ioparam_queue_mutex);
+
+ maru_brill_codec_get_cpu_cores(s);
+ maru_brill_codec_threads_create(s);
+
+ // register a function to qemu bottom-halves to switch context.
+ s->codec_bh = qemu_bh_new(maru_brill_codec_bh_callback, s);
+
+ return 0;
+}
+
+static void maru_brill_codec_exitfn(PCIDevice *dev)
+{
+ MaruBrillCodecState *s = DO_UPCAST(MaruBrillCodecState, dev, dev);
+ INFO("device exit\n");
+
+ qemu_mutex_destroy(&s->context_mutex);
+ qemu_mutex_destroy(&s->context_queue_mutex);
+ qemu_mutex_destroy(&s->ioparam_queue_mutex);
+
+ qemu_bh_delete(s->codec_bh);
+
+ memory_region_destroy(&s->vram);
+ memory_region_destroy(&s->mmio);
+}
+
+static void maru_brill_codec_reset(DeviceState *d)
+{
+ MaruBrillCodecState *s = (MaruBrillCodecState *)d;
+ INFO("device reset\n");
+
+ s->irq_raised = 0;
+
+ memset(&s->context, 0, sizeof(CodecContext) * CODEC_CONTEXT_MAX);
+ memset(&s->ioparam, 0, sizeof(CodecParam));
+
+ maru_brill_codec_pixfmt_info_init();
+}
+
+static void maru_brill_codec_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
+
+ k->init = maru_brill_codec_initfn;
+ k->exit = maru_brill_codec_exitfn;
+ k->vendor_id = PCI_VENDOR_ID_TIZEN;
+ k->device_id = PCI_DEVICE_ID_VIRTUAL_BRILL_CODEC;
+ k->class_id = PCI_CLASS_OTHERS;
+ dc->reset = maru_brill_codec_reset;
+ dc->desc = "Virtual new codec device for Tizen emulator";
+}
+
+static TypeInfo codec_device_info = {
+ .name = CODEC_DEVICE_NAME,
+ .parent = TYPE_PCI_DEVICE,
+ .instance_size = sizeof(MaruBrillCodecState),
+ .class_init = maru_brill_codec_class_init,
+};
+
+static void codec_register_types(void)
+{
+ type_register_static(&codec_device_info);
+}
+
+type_init(codec_register_types)
+
+int maru_brill_codec_pci_device_init(PCIBus *bus)
+{
+ INFO("device create.\n");
+ pci_create_simple(bus, -1, CODEC_DEVICE_NAME);
+ return 0;
+}
--- /dev/null
+/*
+ * Virtual Codec device
+ *
+ * Copyright (c) 2013 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Contact:
+ * Kitae Kim <kt920.kim@samsung.com>
+ * SeokYeon Hwang <syeon.hwang@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 <stdio.h>
+#include <sys/types.h>
+
+#include "hw/hw.h"
+#include "sysemu/kvm.h"
++#include "qemu/main-loop.h"
+#include "hw/pci/pci.h"
+#include "hw/pci/pci_ids.h"
+#include "qemu-common.h"
+#include "qemu/thread.h"
+
+#include "osutil.h"
+#include "tizen/src/debug_ch.h"
+#include "maru_device_ids.h"
+#include "libavformat/avformat.h"
+
+#define CODEC_CONTEXT_MAX 1024
+
+/*
+ * Codec Device Structures
+ */
+typedef struct CodecParam {
+ int32_t api_index;
+ int32_t ctx_index;
+ uint32_t mem_offset;
+} CodecParam;
+
+struct video_data {
+ int32_t width;
+ int32_t height;
+ int32_t fps_n;
+ int32_t fps_d;
+ int32_t par_n;
+ int32_t par_d;
+ int32_t pix_fmt;
+ int32_t bpp;
+ int32_t ticks_per_frame;
+};
+
+struct audio_data {
+ int32_t channels;
+ int32_t sample_rate;
+ int32_t block_align;
+ int32_t depth;
+ int32_t sample_fmt;
+ int32_t frame_size;
+ int32_t bits_per_smp_fmt;
+ int64_t channel_layout;
+};
+
+typedef struct CodecContext {
+ AVCodecContext *avctx;
+ AVFrame *frame;
+ AVCodecParserContext *parser_ctx;
+ uint8_t *parser_buf;
+ uint16_t parser_use;
+ bool occupied;
+ bool opened;
+} CodecContext;
+
+typedef struct CodecThreadPool {
+ QemuThread *threads;
+ QemuMutex mutex;
+ QemuCond cond;
+} CodecThreadPool;
+
+typedef struct MaruBrillCodecState {
+ PCIDevice dev;
+
+ uint8_t *vaddr;
+ MemoryRegion vram;
+ MemoryRegion mmio;
+
+ QEMUBH *codec_bh;
+ QemuMutex context_mutex;
+ QemuMutex context_queue_mutex;
+ QemuMutex ioparam_queue_mutex;
+
+ CodecThreadPool threadpool;
+ bool is_thread_running;
+ uint32_t worker_thread_cnt;
+ uint32_t idle_thread_cnt;
+
+ int irq_raised;
+
+ CodecContext context[CODEC_CONTEXT_MAX];
+ CodecParam ioparam;
+} MaruBrillCodecState;
+
+enum codec_io_cmd {
+ CODEC_CMD_API_INDEX = 0x28,
+ CODEC_CMD_CONTEXT_INDEX = 0x2C,
+ CODEC_CMD_DEVICE_MEM_OFFSET = 0x34,
+ CODEC_CMD_GET_THREAD_STATE = 0x38,
+ CODEC_CMD_GET_CTX_FROM_QUEUE = 0x3C,
+ CODEC_CMD_GET_DATA_FROM_QUEUE = 0x40,
+ CODEC_CMD_RELEASE_CONTEXT = 0x44,
+ CODEC_CMD_GET_VERSION = 0x50,
+ CODEC_CMD_GET_ELEMENT = 0x54,
+ CODEC_CMD_GET_CONTEXT_INDEX = 0x58,
+};
+
+enum codec_api_type {
+ CODEC_INIT = 0,
+ CODEC_DECODE_VIDEO,
+ CODEC_ENCODE_VIDEO,
+ CODEC_DECODE_AUDIO,
+ CODEC_ENCODE_AUDIO,
+ CODEC_PICTURE_COPY,
+ CODEC_DEINIT,
+ CODEC_FLUSH_BUFFERS,
+ };
+
+enum codec_type {
+ CODEC_TYPE_UNKNOWN = -1,
+ CODEC_TYPE_DECODE,
+ CODEC_TYPE_ENCODE,
+};
+
+enum thread_state {
+ CODEC_TASK_START = 0,
+ CODEC_TASK_END = 0x1f,
+};
+
+/*
+ * Codec Device Functions
+ */
+int maru_brill_codec_pci_device_init(PCIBus *bus);
--- /dev/null
- qemu_irq_lower(state->dev.irq[2]);
+/*
+ * Common implementation of MARU Virtual Camera device by PCI bus.
+ *
+ * Copyright (c) 2011 - 2013 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Contact:
+ * JinHyung Jo <jinhyung.jo@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 <stdarg.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <inttypes.h>
+#include <signal.h>
+
+#include "qemu-common.h"
++#include "qemu/main-loop.h"
+#include "exec/cpu-common.h"
+
+#include "maru_camera_common.h"
+#include "maru_device_ids.h"
+#include "tizen/src/debug_ch.h"
+
+MULTI_DEBUG_CHANNEL(tizen, camera_pci);
+
+#define MARU_PCI_CAMERA_DEVICE_NAME "maru_camera_pci"
+
+#define MARUCAM_MEM_SIZE (4 * 1024 * 1024) /* 4MB */
+#define MARUCAM_REG_SIZE (256) /* 64 * 4Byte */
+
+/*
+ * I/O functions
+ */
+static inline uint32_t
+marucam_mmio_read(void *opaque, hwaddr offset)
+{
+ uint32_t ret = 0;
+ MaruCamState *state = (MaruCamState *)opaque;
+
+ switch (offset & 0xFF) {
+ case MARUCAM_CMD_ISR:
+ qemu_mutex_lock(&state->thread_mutex);
+ ret = state->isr;
+ if (ret != 0) {
- qemu_irq_raise(state->dev.irq[2]);
++ pci_set_irq(&state->dev, 0);
+ state->isr = 0;
+ }
+ qemu_mutex_unlock(&state->thread_mutex);
+ break;
+ case MARUCAM_CMD_G_DATA:
+ ret = state->param->stack[state->param->top++];
+ break;
+ case MARUCAM_CMD_OPEN:
+ case MARUCAM_CMD_CLOSE:
+ case MARUCAM_CMD_START_PREVIEW:
+ case MARUCAM_CMD_STOP_PREVIEW:
+ case MARUCAM_CMD_S_PARAM:
+ case MARUCAM_CMD_G_PARAM:
+ case MARUCAM_CMD_ENUM_FMT:
+ case MARUCAM_CMD_TRY_FMT:
+ case MARUCAM_CMD_S_FMT:
+ case MARUCAM_CMD_G_FMT:
+ case MARUCAM_CMD_QCTRL:
+ case MARUCAM_CMD_S_CTRL:
+ case MARUCAM_CMD_G_CTRL:
+ case MARUCAM_CMD_ENUM_FSIZES:
+ case MARUCAM_CMD_ENUM_FINTV:
+ ret = state->param->errCode;
+ state->param->errCode = 0;
+ break;
+ default:
+ ERR("Not supported command: 0x%x\n", offset);
+ ret = EINVAL;
+ break;
+ }
+ return ret;
+}
+
+static inline void
+marucam_mmio_write(void *opaque, hwaddr offset, uint32_t value)
+{
+ MaruCamState *state = (MaruCamState *)opaque;
+
+ switch (offset & 0xFF) {
+ case MARUCAM_CMD_OPEN:
+ marucam_device_open(state);
+ break;
+ case MARUCAM_CMD_CLOSE:
+ marucam_device_close(state);
+ break;
+ case MARUCAM_CMD_START_PREVIEW:
+ marucam_device_start_preview(state);
+ break;
+ case MARUCAM_CMD_STOP_PREVIEW:
+ marucam_device_stop_preview(state);
+ memset(state->vaddr, 0, MARUCAM_MEM_SIZE);
+ break;
+ case MARUCAM_CMD_S_PARAM:
+ marucam_device_s_param(state);
+ break;
+ case MARUCAM_CMD_G_PARAM:
+ marucam_device_g_param(state);
+ break;
+ case MARUCAM_CMD_ENUM_FMT:
+ marucam_device_enum_fmt(state);
+ break;
+ case MARUCAM_CMD_TRY_FMT:
+ marucam_device_try_fmt(state);
+ break;
+ case MARUCAM_CMD_S_FMT:
+ marucam_device_s_fmt(state);
+ break;
+ case MARUCAM_CMD_G_FMT:
+ marucam_device_g_fmt(state);
+ break;
+ case MARUCAM_CMD_QCTRL:
+ marucam_device_qctrl(state);
+ break;
+ case MARUCAM_CMD_S_CTRL:
+ marucam_device_s_ctrl(state);
+ break;
+ case MARUCAM_CMD_G_CTRL:
+ marucam_device_g_ctrl(state);
+ break;
+ case MARUCAM_CMD_ENUM_FSIZES:
+ marucam_device_enum_fsizes(state);
+ break;
+ case MARUCAM_CMD_ENUM_FINTV:
+ marucam_device_enum_fintv(state);
+ break;
+ case MARUCAM_CMD_S_DATA:
+ state->param->stack[state->param->top++] = value;
+ break;
+ case MARUCAM_CMD_DATACLR:
+ memset(state->param, 0, sizeof(MaruCamParam));
+ break;
+ case MARUCAM_CMD_REQFRAME:
+ qemu_mutex_lock(&state->thread_mutex);
+ state->req_frame = value + 1;
+ qemu_mutex_unlock(&state->thread_mutex);
+ break;
+ default:
+ ERR("Not supported command: 0x%x\n", offset);
+ break;
+ }
+}
+
+static const MemoryRegionOps maru_camera_mmio_ops = {
+ .old_mmio = {
+ .read = {
+ marucam_mmio_read,
+ marucam_mmio_read,
+ marucam_mmio_read,
+ },
+ .write = {
+ marucam_mmio_write,
+ marucam_mmio_write,
+ marucam_mmio_write,
+ },
+ },
+ .endianness = DEVICE_LITTLE_ENDIAN,
+};
+
+/*
+ * QEMU bottom half funtion
+ */
+static void marucam_tx_bh(void *opaque)
+{
+ MaruCamState *state = (MaruCamState *)opaque;
+
+ qemu_mutex_lock(&state->thread_mutex);
+ if (state->isr) {
++ pci_set_irq(&state->dev, 1);
+ }
+ qemu_mutex_unlock(&state->thread_mutex);
+}
+
+/*
+ * Initialization function
+ */
+static int marucam_initfn(PCIDevice *dev)
+{
+ MaruCamState *s = DO_UPCAST(MaruCamState, dev, dev);
+ uint8_t *pci_conf = s->dev.config;
+
+ pci_config_set_interrupt_pin(pci_conf, 0x03);
+
+ memory_region_init_ram(&s->vram, OBJECT(s), "marucamera.ram", MARUCAM_MEM_SIZE);
+ s->vaddr = memory_region_get_ram_ptr(&s->vram);
+ memset(s->vaddr, 0, MARUCAM_MEM_SIZE);
+
+ memory_region_init_io(&s->mmio, OBJECT(s),
+ &maru_camera_mmio_ops,
+ s,
+ "maru-camera-mmio",
+ MARUCAM_REG_SIZE);
+
+ pci_register_bar(&s->dev, 0, PCI_BASE_ADDRESS_MEM_PREFETCH, &s->vram);
+ pci_register_bar(&s->dev, 1, PCI_BASE_ADDRESS_SPACE_MEMORY, &s->mmio);
+
+ /* for worker thread */
+ s->param = (MaruCamParam *)g_malloc0(sizeof(MaruCamParam));
+ qemu_cond_init(&s->thread_cond);
+ qemu_mutex_init(&s->thread_mutex);
+
+ marucam_device_init(s);
+
+ s->tx_bh = qemu_bh_new(marucam_tx_bh, s);
+ INFO("[%s] camera device was initialized.\n", __func__);
+
+ return 0;
+}
+
+/*
+ * Termination function
+ */
+static void marucam_exitfn(PCIDevice *pci_dev)
+{
+ MaruCamState *s =
+ OBJECT_CHECK(MaruCamState, pci_dev, MARU_PCI_CAMERA_DEVICE_NAME);
+
+ marucam_device_exit(s);
+ g_free(s->param);
+ qemu_cond_destroy(&s->thread_cond);
+ qemu_mutex_destroy(&s->thread_mutex);
+
+ memory_region_destroy(&s->vram);
+ memory_region_destroy(&s->mmio);
+
+
+ INFO("[%s] camera device was released.\n", __func__);
+}
+
+int maru_camera_pci_init(PCIBus *bus)
+{
+ INFO("[%s] camera device was initialized.\n", __func__);
+ pci_create_simple(bus, -1, MARU_PCI_CAMERA_DEVICE_NAME);
+ return 0;
+}
+
+static void maru_camera_pci_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
+
+ k->no_hotplug = 1;
+ k->init = marucam_initfn;
+ k->exit = marucam_exitfn;
+ k->vendor_id = PCI_VENDOR_ID_TIZEN;
+ k->device_id = PCI_DEVICE_ID_VIRTUAL_CAMERA;
+ k->class_id = PCI_CLASS_OTHERS;
+ dc->desc = "MARU Virtual Camera device for Tizen emulator";
+}
+
+static TypeInfo maru_camera_info = {
+ .name = MARU_PCI_CAMERA_DEVICE_NAME,
+ .parent = TYPE_PCI_DEVICE,
+ .instance_size = sizeof(MaruCamState),
+ .class_init = maru_camera_pci_class_init,
+};
+
+static void maru_camera_pci_register_types(void)
+{
+ type_register_static(&maru_camera_info);
+}
+
+type_init(maru_camera_pci_register_types)
--- /dev/null
- cur_tick = qemu_get_clock_ns(vm_clock);
+/*
+ * Maru vga device
+ * Based on qemu/hw/vga.c
+ *
+ * Copyright (C) 2011 - 2013 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Contact:
+ * JinHyung Jo <jinhyung.jo@samsung.com>
+ * GiWoong Kim <giwoong.kim@samsung.com>
+ * YeongKyoon Lee <yeongkyoon.lee@samsung.com>
+ * HyunJun Son
+ *
+ * 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 "hw/hw.h"
+#include "display/vga.h"
+#include "ui/console.h"
+#include "hw/i386/pc.h"
+#include "hw/pci/pci.h"
+#include "display/vga_int.h"
+#include "ui/pixel_ops.h"
+#include "qemu/timer.h"
+#include "hw/xen/xen.h"
+#include "trace.h"
+
+#include <pthread.h>
+
+#define MARU_VGA
+#include "maru_common.h"
+#include "maru_vga_int.h"
+#include "debug_ch.h"
+
+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
+
+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_dumb_update_retrace_info(VGACommonState *s)
+{
+ (void) s;
+}
+
+static void vga_precise_update_retrace_info(VGACommonState *s)
+{
+ int htotal_chars;
+ int hretr_start_char;
+ int hretr_skew_chars;
+ int hretr_end_char;
+
+ int vtotal_lines;
+ int vretr_start_line;
+ int vretr_end_line;
+
+ int dots;
+#if 0
+ int div2, sldiv2;
+#endif
+ int clocking_mode;
+ int clock_sel;
+ const int clk_hz[] = {25175000, 28322000, 25175000, 25175000};
+ int64_t chars_per_sec;
+ struct vga_precise_retrace *r = &s->retrace_info.precise;
+
+ htotal_chars = s->cr[VGA_CRTC_H_TOTAL] + 5;
+ hretr_start_char = s->cr[VGA_CRTC_H_SYNC_START];
+ hretr_skew_chars = (s->cr[VGA_CRTC_H_SYNC_END] >> 5) & 3;
+ hretr_end_char = s->cr[VGA_CRTC_H_SYNC_END] & 0x1f;
+
+ vtotal_lines = (s->cr[VGA_CRTC_V_TOTAL] |
+ (((s->cr[VGA_CRTC_OVERFLOW] & 1) |
+ ((s->cr[VGA_CRTC_OVERFLOW] >> 4) & 2)) << 8)) + 2;
+ vretr_start_line = s->cr[VGA_CRTC_V_SYNC_START] |
+ ((((s->cr[VGA_CRTC_OVERFLOW] >> 2) & 1) |
+ ((s->cr[VGA_CRTC_OVERFLOW] >> 6) & 2)) << 8);
+ vretr_end_line = s->cr[VGA_CRTC_V_SYNC_END] & 0xf;
+
+ clocking_mode = (s->sr[VGA_SEQ_CLOCK_MODE] >> 3) & 1;
+ clock_sel = (s->msr >> 2) & 3;
+ dots = (s->msr & 1) ? 8 : 9;
+
+ chars_per_sec = clk_hz[clock_sel] / dots;
+
+ htotal_chars <<= clocking_mode;
+
+ r->total_chars = vtotal_lines * htotal_chars;
+ if (r->freq) {
+ r->ticks_per_char = get_ticks_per_sec() / (r->total_chars * r->freq);
+ } else {
+ r->ticks_per_char = get_ticks_per_sec() / chars_per_sec;
+ }
+
+ r->vstart = vretr_start_line;
+ r->vend = r->vstart + vretr_end_line + 1;
+
+ r->hstart = hretr_start_char + hretr_skew_chars;
+ r->hend = r->hstart + hretr_end_char + 1;
+ r->htotal = htotal_chars;
+
+#if 0
+ div2 = (s->cr[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;
+
- int64_t now = qemu_get_clock_ms(vm_clock);
++ cur_tick = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
+
+ 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);
+}
+
+typedef void maru_vga_draw_glyph8_func(uint8_t *d, int linesize,
+ const uint8_t *font_ptr, int h,
+ uint32_t fgcol, uint32_t bgcol);
+typedef void maru_vga_draw_glyph9_func(uint8_t *d, int linesize,
+ const uint8_t *font_ptr, int h,
+ uint32_t fgcol, uint32_t bgcol, int dup9);
+typedef void maru_vga_draw_line_func(VGACommonState *s1, uint8_t *d,
+ const uint8_t *s, int width);
+
+#define DEPTH 8
+#include "maru_vga_template.h"
+
+#define DEPTH 15
+#include "maru_vga_template.h"
+
+#define BGR_FORMAT
+#define DEPTH 15
+#include "maru_vga_template.h"
+
+#define DEPTH 16
+#include "maru_vga_template.h"
+
+#define BGR_FORMAT
+#define DEPTH 16
+#include "maru_vga_template.h"
+
+#define DEPTH 32
+#include "maru_vga_template.h"
+
+#define BGR_FORMAT
+#define DEPTH 32
+#include "maru_vga_template.h"
+
+static unsigned int rgb_to_pixel8_dup(unsigned int r, unsigned int g, unsigned b)
+{
+ unsigned int col;
+ col = rgb_to_pixel8(r, g, b);
+ col |= col << 8;
+ col |= col << 16;
+ return col;
+}
+
+static unsigned int rgb_to_pixel15_dup(unsigned int r, unsigned int g, unsigned b)
+{
+ unsigned int col;
+ col = rgb_to_pixel15(r, g, b);
+ col |= col << 16;
+ return col;
+}
+
+static unsigned int rgb_to_pixel15bgr_dup(unsigned int r, unsigned int g,
+ unsigned int b)
+{
+ unsigned int col;
+ col = rgb_to_pixel15bgr(r, g, b);
+ col |= col << 16;
+ return col;
+}
+
+static unsigned int rgb_to_pixel16_dup(unsigned int r, unsigned int g, unsigned b)
+{
+ unsigned int col;
+ col = rgb_to_pixel16(r, g, b);
+ col |= col << 16;
+ return col;
+}
+
+static unsigned int rgb_to_pixel16bgr_dup(unsigned int r, unsigned int g,
+ unsigned int b)
+{
+ unsigned int col;
+ col = rgb_to_pixel16bgr(r, g, b);
+ col |= col << 16;
+ return col;
+}
+
+static unsigned int rgb_to_pixel32_dup(unsigned int r, unsigned int g, unsigned b)
+{
+ unsigned int col;
+ col = rgb_to_pixel32(r, g, b);
+ return col;
+}
+
+static unsigned int rgb_to_pixel32bgr_dup(unsigned int r, unsigned int g, unsigned b)
+{
+ unsigned int col;
+ col = rgb_to_pixel32bgr(r, g, b);
+ return col;
+}
+
+/* return true if the palette was modified */
+static int update_palette16(VGACommonState *s)
+{
+ int full_update, i;
+ uint32_t v, col, *palette;
+
+ full_update = 0;
+ palette = s->last_palette;
+ for(i = 0; i < 16; i++) {
+ v = s->ar[i];
+ if (s->ar[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;
+
+ 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 {
+ /* compute line_offset in bytes */
+ line_offset = s->cr[VGA_CRTC_OFFSET];
+ line_offset <<= 3;
+
+ /* starting address */
+ start_addr = s->cr[VGA_CRTC_START_LO] |
+ (s->cr[VGA_CRTC_START_HI] << 8);
+
+ /* line compare */
+ 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(DisplaySurface *s)
+{
+ switch (surface_bits_per_pixel(s)) {
+ default:
+ case 8:
+ return 0;
+ case 15:
+ return 1;
+ case 16:
+ return 2;
+ case 32:
+ if (is_surface_bgr(s)) {
+ return 4;
+ } else {
+ return 3;
+ }
+ }
+}
+
+static maru_vga_draw_glyph8_func * const maru_vga_draw_glyph8_table[NB_DEPTHS] = {
+ maru_vga_draw_glyph8_8,
+ maru_vga_draw_glyph8_16,
+ maru_vga_draw_glyph8_16,
+ maru_vga_draw_glyph8_32,
+ maru_vga_draw_glyph8_32,
+ maru_vga_draw_glyph8_16,
+ maru_vga_draw_glyph8_16,
+};
+
+static maru_vga_draw_glyph8_func * const maru_vga_draw_glyph16_table[NB_DEPTHS] = {
+ maru_vga_draw_glyph16_8,
+ maru_vga_draw_glyph16_16,
+ maru_vga_draw_glyph16_16,
+ maru_vga_draw_glyph16_32,
+ maru_vga_draw_glyph16_32,
+ maru_vga_draw_glyph16_16,
+ maru_vga_draw_glyph16_16,
+};
+
+static maru_vga_draw_glyph9_func * const maru_vga_draw_glyph9_table[NB_DEPTHS] = {
+ maru_vga_draw_glyph9_8,
+ maru_vga_draw_glyph9_16,
+ maru_vga_draw_glyph9_16,
+ maru_vga_draw_glyph9_32,
+ maru_vga_draw_glyph9_32,
+ maru_vga_draw_glyph9_16,
+ maru_vga_draw_glyph9_16,
+};
+
+static const uint8_t cursor_glyph[32 * 4] = {
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+};
+
+static void vga_get_text_resolution(VGACommonState *s, int *pwidth, int *pheight,
+ int *pcwidth, int *pcheight)
+{
+ int width, cwidth, height, cheight;
+
+ /* total width & height */
+ cheight = (s->cr[VGA_CRTC_MAX_SCAN] & 0x1f) + 1;
+ cwidth = 8;
+ if (!(s->sr[VGA_SEQ_CLOCK_MODE] & VGA_SR01_CHAR_CLK_8DOTS)) {
+ cwidth = 9;
+ }
+ if (s->sr[VGA_SEQ_CLOCK_MODE] & 0x08) {
+ cwidth = 16; /* NOTE: no 18 pixel wide */
+ }
+ width = (s->cr[VGA_CRTC_H_DISP] + 1);
+ if (s->cr[VGA_CRTC_V_TOTAL] == 100) {
+ /* ugly hack for CGA 160x100x16 - explain me the logic */
+ height = 100;
+ } else {
+ height = s->cr[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)
+{
+ DisplaySurface *surface = qemu_console_surface(s->con);
+ 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;
- s->cursor_blink_time = qemu_get_clock_ms(vm_clock);
++ int64_t now = qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL);
+
+ /* compute font data address (in plane 2) */
+ 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->con, s->last_scr_width, s->last_scr_height);
+ surface = qemu_console_surface(s->con);
+ dpy_text_resize(s->con, width, 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(surface)];
+ full_update |= update_palette16(s);
+ palette = s->last_palette;
+ x_incr = cw * surface_bytes_per_pixel(surface);
+
+ if (full_update) {
+ s->full_update_text = 1;
+ }
+ if (s->full_update_gfx) {
+ s->full_update_gfx = 0;
+ full_update |= 1;
+ }
+
+ cursor_offset = ((s->cr[VGA_CRTC_CURSOR_HI] << 8) |
+ s->cr[VGA_CRTC_CURSOR_LO]) - s->start_addr;
+ if (cursor_offset != s->cursor_offset ||
+ s->cr[VGA_CRTC_CURSOR_START] != s->cursor_start ||
+ s->cr[VGA_CRTC_CURSOR_END] != s->cursor_end) {
+ /* if the cursor position changed, we update the old and new
+ chars */
+ if (s->cursor_offset < CH_ATTR_SIZE)
+ s->last_ch_attr[s->cursor_offset] = -1;
+ if (cursor_offset < CH_ATTR_SIZE)
+ s->last_ch_attr[cursor_offset] = -1;
+ s->cursor_offset = cursor_offset;
+ s->cursor_start = s->cr[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(surface);
+ 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 = surface_data(surface);
+ linesize = surface_stride(surface);
+ ch_attr_ptr = s->last_ch_attr;
+ line = 0;
+ offset = s->start_addr * 4;
+ for(cy = 0; cy < height; cy++) {
+ d1 = dest;
+ src = s->vram_ptr + offset;
+ cx_min = width;
+ cx_max = -1;
+ for(cx = 0; cx < width; cx++) {
+ ch_attr = *(uint16_t *)src;
+ if (full_update || ch_attr != *ch_attr_ptr || src == cursor_ptr) {
+ if (cx < cx_min)
+ cx_min = cx;
+ if (cx > cx_max)
+ cx_max = cx;
+ *ch_attr_ptr = ch_attr;
+#ifdef HOST_WORDS_BIGENDIAN
+ ch = ch_attr >> 8;
+ cattr = ch_attr & 0xff;
+#else
+ ch = ch_attr & 0xff;
+ cattr = ch_attr >> 8;
+#endif
+ font_ptr = font_base[(cattr >> 3) & 1];
+ font_ptr += 32 * 4 * ch;
+ bgcol = palette[cattr >> 4];
+ fgcol = palette[cattr & 0x0f];
+ if (cw != 9) {
+ maru_vga_draw_glyph8(d1, linesize,
+ font_ptr, cheight, fgcol, bgcol);
+ } else {
+ dup9 = 0;
+ if (ch >= 0xb0 && ch <= 0xdf &&
+ (s->ar[VGA_ATC_MODE] & 0x04)) {
+ dup9 = 1;
+ }
+ maru_vga_draw_glyph9(d1, linesize,
+ font_ptr, cheight, fgcol, bgcol, dup9);
+ }
+ if (src == cursor_ptr &&
+ !(s->cr[VGA_CRTC_CURSOR_START] & 0x20) &&
+ s->cursor_visible_phase) {
+ int line_start, line_last, h;
+ /* draw the cursor */
+ 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_gfx_update(s->con, 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;
+
+ if (s->vbe_regs[VBE_DISPI_INDEX_ENABLE] & VBE_DISPI_ENABLED) {
+ ret = s->vbe_regs[VBE_DISPI_INDEX_BPP];
+ } else {
+ ret = 0;
+ }
+ return ret;
+}
+
+static void vga_get_resolution(VGACommonState *s, int *pwidth, int *pheight)
+{
+ int width, height;
+
+ 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 {
+ 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;
+}
+
+/*
+ * graphic modes
+ */
+static void vga_draw_graphic(VGACommonState *s, int full_update)
+{
+ DisplaySurface *surface = qemu_console_surface(s->con);
+ 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;
+#if defined(HOST_WORDS_BIGENDIAN) == defined(TARGET_WORDS_BIGENDIAN)
+ static const bool byteswap = false;
+#else
+ static const bool byteswap = true;
+#endif
+
+ full_update |= update_basic_params(s);
+
+ if (!full_update)
+ vga_sync_dirty_bitmap(s);
+
+ s->get_resolution(s, &width, &height);
+ disp_width = width;
+
+ shift_control = (s->gr[VGA_GFX_MODE] >> 5) & 3;
+ double_scan = (s->cr[VGA_CRTC_MAX_SCAN] >> 7);
+ if (shift_control != 1) {
+ multi_scan = (((s->cr[VGA_CRTC_MAX_SCAN] & 0x1f) + 1) << double_scan)
+ - 1;
+ } else {
+ /* in CGA modes, multi_scan is ignored */
+ /* XXX: is it correct ? */
+ multi_scan = double_scan;
+ }
+ multi_run = multi_scan;
+ if (shift_control != s->shift_control ||
+ double_scan != s->double_scan) {
+ full_update = 1;
+ s->shift_control = shift_control;
+ s->double_scan = double_scan;
+ }
+
+ if (shift_control == 0) {
+ if (s->sr[VGA_SEQ_CLOCK_MODE] & 8) {
+ disp_width <<= 1;
+ }
+ } else if (shift_control == 1) {
+ 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 (depth == 32 || (depth == 16 && !byteswap)) {
+#ifdef MARU_VGA /* create new sufrace by g_new0 in MARU VGA */
+ TRACE("create the display surface\n");
+ surface = qemu_create_displaysurface(disp_width, height);
+#else /* MARU_VGA */
+ surface = qemu_create_displaysurface_from(disp_width,
+ height, depth, s->line_offset,
+ s->vram_ptr + (s->start_addr * 4), byteswap);
+#endif /* MARU_VGA */
+ dpy_gfx_replace_surface(s->con, surface);
+ } else {
+ qemu_console_resize(s->con, disp_width, height);
+ surface = qemu_console_surface(s->con);
+ }
+ 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;
+ } else if (is_buffer_shared(surface) &&
+ (full_update || surface_data(surface) != s->vram_ptr
+ + (s->start_addr * 4))) {
+ DisplaySurface *surface;
+ surface = qemu_create_displaysurface_from(disp_width,
+ height, depth, s->line_offset,
+ s->vram_ptr + (s->start_addr * 4), byteswap);
+ dpy_gfx_replace_surface(s->con, surface);
+ }
+
+ s->rgb_to_pixel =
+ rgb_to_pixel_dup_table[get_depth_index(surface)];
+
+ if (shift_control == 0) {
+ full_update |= update_palette16(s);
+ if (s->sr[VGA_SEQ_CLOCK_MODE] & 8) {
+ v = maru_vga_draw_line4D2;
+ } else {
+ v = maru_vga_draw_line4;
+ }
+ bits = 4;
+ } else if (shift_control == 1) {
+ full_update |= update_palette16(s);
+ if (s->sr[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(surface)];
+
+ if (!is_buffer_shared(surface) && s->cursor_invalidate) {
+ s->cursor_invalidate(s);
+ }
+
+ line_offset = s->line_offset;
+#if 0
+ printf("w=%d h=%d v=%d line_offset=%d cr[0x09]=0x%02x cr[0x17]=0x%02x linecmp=%d sr[0x01]=0x%02x\n",
+ width, height, v, line_offset, s->cr[9], s->cr[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 = surface_data(surface);
+ linesize = surface_stride(surface);
+ y1 = 0;
+ for(y = 0; y < height; y++) {
+ addr = addr1;
+ if (!(s->cr[VGA_CRTC_MODE] & 1)) {
+ int shift;
+ /* CGA compatibility handling */
+ shift = 14 + ((s->cr[VGA_CRTC_MODE] >> 6) & 1);
+ addr = (addr & ~(1 << shift)) | ((y1 & 1) << shift);
+ }
+ if (!(s->cr[VGA_CRTC_MODE] & 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;
+ if (!(is_buffer_shared(surface))) {
+ maru_vga_draw_line(s, d, s->vram_ptr + addr, width);
+ if (s->cursor_draw_line)
+ s->cursor_draw_line(s, d, y);
+ }
+ } else {
+ if (y_start >= 0) {
+ /* flush to display */
+ dpy_gfx_update(s->con, 0, y_start,
+ disp_width, y - y_start);
+ y_start = -1;
+ }
+ }
+ if (!multi_run) {
+ 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_gfx_update(s->con, 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)
+{
+ DisplaySurface *surface = qemu_console_surface(s->con);
+ 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(surface)];
+ if (surface_bits_per_pixel(surface) == 8) {
+ val = s->rgb_to_pixel(0, 0, 0);
+ } else {
+ val = 0;
+ }
+ w = s->last_scr_width * surface_bytes_per_pixel(surface);
+ d = surface_data(surface);
+ for(i = 0; i < s->last_scr_height; i++) {
+ memset(d, val, w);
+ d += surface_stride(surface);
+ }
+ dpy_gfx_update(s->con, 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;
+ DisplaySurface *surface = qemu_console_surface(s->con);
+ int full_update, graphic_mode;
+
+ qemu_flush_coalesced_mmio_buffer();
+
+ if (surface_bits_per_pixel(surface) == 0) {
+ /* nothing to do */
+ } else {
+ full_update = 0;
+ if (!(s->ar_index & 0x20)) {
+ graphic_mode = GMODE_BLANK;
+ } else {
+ 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_clock_get_ms(QEMU_CLOCK_VIRTUAL);
+ 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;
+}
+
+#define TEXTMODE_X(x) ((x) % width)
+#define TEXTMODE_Y(x) ((x) / width)
+#define VMEM2CHTYPE(v) ((v & 0xff0007ff) | \
+ ((v & 0x00000800) << 10) | ((v & 0x00007000) >> 1))
+/* relay text rendering to the display driver
+ * instead of doing a full vga_update_display() */
+static void vga_update_text(void *opaque, console_ch_t *chardata)
+{
+ VGACommonState *s = opaque;
+ int graphic_mode, i, cursor_offset, cursor_visible;
+ int cw, cheight, width, height, size, c_min, c_max;
+ uint32_t *src;
+ console_ch_t *dst, val;
+ char msg_buffer[80];
+ int full_update = 0;
+
+ qemu_flush_coalesced_mmio_buffer();
+
+ if (!(s->ar_index & 0x20)) {
+ graphic_mode = GMODE_BLANK;
+ } else {
+ graphic_mode = s->gr[VGA_GFX_MISC] & VGA_GR06_GRAPHICS_MODE;
+ }
+ if (graphic_mode != s->graphic_mode) {
+ s->graphic_mode = graphic_mode;
+ full_update = 1;
+ }
+ if (s->last_width == -1) {
+ s->last_width = 0;
+ full_update = 1;
+ }
+
+ switch (graphic_mode) {
+ case GMODE_TEXT:
+ /* TODO: update palette */
+ full_update |= update_basic_params(s);
+
+ /* total width & height */
+ cheight = (s->cr[VGA_CRTC_MAX_SCAN] & 0x1f) + 1;
+ cw = 8;
+ if (!(s->sr[VGA_SEQ_CLOCK_MODE] & VGA_SR01_CHAR_CLK_8DOTS)) {
+ cw = 9;
+ }
+ if (s->sr[VGA_SEQ_CLOCK_MODE] & 0x08) {
+ cw = 16; /* NOTE: no 18 pixel wide */
+ }
+ width = (s->cr[VGA_CRTC_H_DISP] + 1);
+ if (s->cr[VGA_CRTC_V_TOTAL] == 100) {
+ /* ugly hack for CGA 160x100x16 - explain me the logic */
+ height = 100;
+ } else {
+ height = s->cr[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;
+ qemu_console_resize(s->con, s->last_scr_width, s->last_scr_height);
+ dpy_text_resize(s->con, width, height);
+ s->last_depth = 0;
+ s->last_width = width;
+ s->last_height = height;
+ s->last_ch = cheight;
+ s->last_cw = cw;
+ full_update = 1;
+ }
+
+ if (full_update) {
+ s->full_update_gfx = 1;
+ }
+ if (s->full_update_text) {
+ s->full_update_text = 0;
+ full_update |= 1;
+ }
+
+ /* Update "hardware" cursor */
+ cursor_offset = ((s->cr[VGA_CRTC_CURSOR_HI] << 8) |
+ s->cr[VGA_CRTC_CURSOR_LO]) - s->start_addr;
+ if (cursor_offset != s->cursor_offset ||
+ s->cr[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_text_cursor(s->con,
+ TEXTMODE_X(cursor_offset),
+ TEXTMODE_Y(cursor_offset));
+ else
+ dpy_text_cursor(s->con, -1, -1);
+ s->cursor_offset = cursor_offset;
+ 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_text_update(s->con, 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_text_update(s->con, 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_text_cursor(s->con, -1, -1);
+ dpy_text_resize(s->con, s->last_width, height);
+
+ 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_text_update(s->con, 0, 0, s->last_width, height);
+}
+
+static const GraphicHwOps vga_ops = {
+ .invalidate = vga_invalidate_display,
+ .gfx_update = vga_update_display,
+ .text_update = vga_update_text,
+};
+
+void maru_vga_common_init(VGACommonState *s, Object *obj)
+{
+ 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;
+
+ s->is_vbe_vmstate = 1;
+ memory_region_init_ram(&s->vram, obj, "maru_vga.vram", s->vram_size);
+ vmstate_register_ram_global(&s->vram);
+ xen_register_framebuffer(&s->vram);
+ s->vram_ptr = memory_region_get_ram_ptr(&s->vram);
+ s->get_bpp = vga_get_bpp;
+ s->get_offsets = vga_get_offsets;
+ s->get_resolution = vga_get_resolution;
+ s->hw_ops = &vga_ops;
+ 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);
+ TRACE("%s\n", __func__);
+}
+
+void maru_vga_common_fini(void)
+{
+ /* do nothing */
+ TRACE("%s\n", __func__);
+}
--- /dev/null
- cpu_to_32wu((uint32_t *)d, (dmask16[(font_data >> 4)] & xorcol) ^ bgcol);
+/*
+ * vga device
+ * Based on qemu/hw/vga_template.h
+ *
+ * Copyright (C) 2011 - 2012 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Contact:
+ * GiWoong Kim <giwoong.kim@samsung.com>
+ * YeongKyoon Lee <yeongkyoon.lee@samsung.com>
+ * Hyunjun Son
+ *
+ * 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
+ *
+ */
+
+#if DEPTH == 8
+#define BPP 1
+#define PIXEL_TYPE uint8_t
+#elif DEPTH == 15 || DEPTH == 16
+#define BPP 2
+#define PIXEL_TYPE uint16_t
+#elif DEPTH == 32
+#define BPP 4
+#define PIXEL_TYPE uint32_t
+#else
+#error unsupport depth
+#endif
+
+#ifdef BGR_FORMAT
+#define PIXEL_NAME glue(DEPTH, bgr)
+#else
+#define PIXEL_NAME DEPTH
+#endif /* BGR_FORMAT */
+
+#if DEPTH != 15 && !defined(BGR_FORMAT)
+
+static inline void glue(maru_vga_draw_glyph_line_, DEPTH)(uint8_t *d,
+ uint32_t font_data,
+ uint32_t xorcol,
+ uint32_t bgcol)
+{
+#if BPP == 1
+ ((uint32_t *)d)[0] = (dmask16[(font_data >> 4)] & xorcol) ^ bgcol;
+ ((uint32_t *)d)[1] = (dmask16[(font_data >> 0) & 0xf] & xorcol) ^ bgcol;
+#elif BPP == 2
+ ((uint32_t *)d)[0] = (dmask4[(font_data >> 6)] & xorcol) ^ bgcol;
+ ((uint32_t *)d)[1] = (dmask4[(font_data >> 4) & 3] & xorcol) ^ bgcol;
+ ((uint32_t *)d)[2] = (dmask4[(font_data >> 2) & 3] & xorcol) ^ bgcol;
+ ((uint32_t *)d)[3] = (dmask4[(font_data >> 0) & 3] & xorcol) ^ bgcol;
+#else
+ ((uint32_t *)d)[0] = (-((font_data >> 7)) & xorcol) ^ bgcol;
+ ((uint32_t *)d)[1] = (-((font_data >> 6) & 1) & xorcol) ^ bgcol;
+ ((uint32_t *)d)[2] = (-((font_data >> 5) & 1) & xorcol) ^ bgcol;
+ ((uint32_t *)d)[3] = (-((font_data >> 4) & 1) & xorcol) ^ bgcol;
+ ((uint32_t *)d)[4] = (-((font_data >> 3) & 1) & xorcol) ^ bgcol;
+ ((uint32_t *)d)[5] = (-((font_data >> 2) & 1) & xorcol) ^ bgcol;
+ ((uint32_t *)d)[6] = (-((font_data >> 1) & 1) & xorcol) ^ bgcol;
+ ((uint32_t *)d)[7] = (-((font_data >> 0) & 1) & xorcol) ^ bgcol;
+#endif
+}
+
+static void glue(maru_vga_draw_glyph8_, DEPTH)(uint8_t *d, int linesize,
+ const uint8_t *font_ptr, int h,
+ uint32_t fgcol, uint32_t bgcol)
+{
+ uint32_t font_data, xorcol;
+
+ xorcol = bgcol ^ fgcol;
+ do {
+ font_data = font_ptr[0];
+ glue(maru_vga_draw_glyph_line_, DEPTH)(d, font_data, xorcol, bgcol);
+ font_ptr += 4;
+ d += linesize;
+ } while (--h);
+}
+
+static void glue(maru_vga_draw_glyph16_, DEPTH)(uint8_t *d, int linesize,
+ const uint8_t *font_ptr, int h,
+ uint32_t fgcol, uint32_t bgcol)
+{
+ uint32_t font_data, xorcol;
+
+ xorcol = bgcol ^ fgcol;
+ do {
+ font_data = font_ptr[0];
+ glue(maru_vga_draw_glyph_line_, DEPTH)(d,
+ expand4to8[font_data >> 4],
+ xorcol, bgcol);
+ glue(maru_vga_draw_glyph_line_, DEPTH)(d + 8 * BPP,
+ expand4to8[font_data & 0x0f],
+ xorcol, bgcol);
+ font_ptr += 4;
+ d += linesize;
+ } while (--h);
+}
+
+static void glue(maru_vga_draw_glyph9_, DEPTH)(uint8_t *d, int linesize,
+ const uint8_t *font_ptr, int h,
+ uint32_t fgcol, uint32_t bgcol, int dup9)
+{
+ uint32_t font_data, xorcol, v;
+
+ xorcol = bgcol ^ fgcol;
+ do {
+ font_data = font_ptr[0];
+#if BPP == 1
- cpu_to_32wu(((uint32_t *)d)+1, v);
++ stl_p((uint32_t *)d, (dmask16[(font_data >> 4)] & xorcol) ^ bgcol);
+ v = (dmask16[(font_data >> 0) & 0xf] & xorcol) ^ bgcol;
- cpu_to_32wu(((uint32_t *)d)+0, (dmask4[(font_data >> 6)] & xorcol) ^ bgcol);
- cpu_to_32wu(((uint32_t *)d)+1, (dmask4[(font_data >> 4) & 3] & xorcol) ^ bgcol);
- cpu_to_32wu(((uint32_t *)d)+2, (dmask4[(font_data >> 2) & 3] & xorcol) ^ bgcol);
++ stl_p(((uint32_t *)d)+1, v);
+ if (dup9)
+ ((uint8_t *)d)[8] = v >> (24 * (1 - BIG));
+ else
+ ((uint8_t *)d)[8] = bgcol;
+
+#elif BPP == 2
- cpu_to_32wu(((uint32_t *)d)+3, v);
++ stl_p(((uint32_t *)d)+0, (dmask4[(font_data >> 6)] & xorcol) ^ bgcol);
++ stl_p(((uint32_t *)d)+1, (dmask4[(font_data >> 4) & 3] & xorcol) ^ bgcol);
++ stl_p(((uint32_t *)d)+2, (dmask4[(font_data >> 2) & 3] & xorcol) ^ bgcol);
+ v = (dmask4[(font_data >> 0) & 3] & xorcol) ^ bgcol;
++ stl_p(((uint32_t *)d)+3, v);
+ if (dup9)
+ ((uint16_t *)d)[8] = v >> (16 * (1 - BIG));
+ else
+ ((uint16_t *)d)[8] = bgcol;
+#else
+ ((uint32_t *)d)[0] = (-((font_data >> 7)) & xorcol) ^ bgcol;
+ ((uint32_t *)d)[1] = (-((font_data >> 6) & 1) & xorcol) ^ bgcol;
+ ((uint32_t *)d)[2] = (-((font_data >> 5) & 1) & xorcol) ^ bgcol;
+ ((uint32_t *)d)[3] = (-((font_data >> 4) & 1) & xorcol) ^ bgcol;
+ ((uint32_t *)d)[4] = (-((font_data >> 3) & 1) & xorcol) ^ bgcol;
+ ((uint32_t *)d)[5] = (-((font_data >> 2) & 1) & xorcol) ^ bgcol;
+ ((uint32_t *)d)[6] = (-((font_data >> 1) & 1) & xorcol) ^ bgcol;
+ v = (-((font_data >> 0) & 1) & xorcol) ^ bgcol;
+ ((uint32_t *)d)[7] = v;
+ if (dup9)
+ ((uint32_t *)d)[8] = v;
+ else
+ ((uint32_t *)d)[8] = bgcol;
+#endif
+ font_ptr += 4;
+ d += linesize;
+ } while (--h);
+}
+
+/*
+ * 4 color mode
+ */
+static void glue(maru_vga_draw_line2_, DEPTH)(VGACommonState *s1, uint8_t *d,
+ const uint8_t *s, int width)
+{
+ uint32_t plane_mask, *palette, data, v;
+ int x;
+
+ palette = s1->last_palette;
+ plane_mask = mask16[s1->ar[0x12] & 0xf];
+ width >>= 3;
+ for(x = 0; x < width; x++) {
+ data = ((uint32_t *)s)[0];
+ data &= plane_mask;
+ v = expand2[GET_PLANE(data, 0)];
+ v |= expand2[GET_PLANE(data, 2)] << 2;
+ ((PIXEL_TYPE *)d)[0] = palette[v >> 12];
+ ((PIXEL_TYPE *)d)[1] = palette[(v >> 8) & 0xf];
+ ((PIXEL_TYPE *)d)[2] = palette[(v >> 4) & 0xf];
+ ((PIXEL_TYPE *)d)[3] = palette[(v >> 0) & 0xf];
+
+ v = expand2[GET_PLANE(data, 1)];
+ v |= expand2[GET_PLANE(data, 3)] << 2;
+ ((PIXEL_TYPE *)d)[4] = palette[v >> 12];
+ ((PIXEL_TYPE *)d)[5] = palette[(v >> 8) & 0xf];
+ ((PIXEL_TYPE *)d)[6] = palette[(v >> 4) & 0xf];
+ ((PIXEL_TYPE *)d)[7] = palette[(v >> 0) & 0xf];
+ d += BPP * 8;
+ s += 4;
+ }
+}
+
+#if BPP == 1
+#define PUT_PIXEL2(d, n, v) ((uint16_t *)d)[(n)] = (v)
+#elif BPP == 2
+#define PUT_PIXEL2(d, n, v) ((uint32_t *)d)[(n)] = (v)
+#else
+#define PUT_PIXEL2(d, n, v) \
+((uint32_t *)d)[2*(n)] = ((uint32_t *)d)[2*(n)+1] = (v)
+#endif
+
+/*
+ * 4 color mode, dup2 horizontal
+ */
+static void glue(maru_vga_draw_line2d2_, DEPTH)(VGACommonState *s1, uint8_t *d,
+ const uint8_t *s, int width)
+{
+ uint32_t plane_mask, *palette, data, v;
+ int x;
+
+ palette = s1->last_palette;
+ plane_mask = mask16[s1->ar[0x12] & 0xf];
+ width >>= 3;
+ for(x = 0; x < width; x++) {
+ data = ((uint32_t *)s)[0];
+ data &= plane_mask;
+ v = expand2[GET_PLANE(data, 0)];
+ v |= expand2[GET_PLANE(data, 2)] << 2;
+ PUT_PIXEL2(d, 0, palette[v >> 12]);
+ PUT_PIXEL2(d, 1, palette[(v >> 8) & 0xf]);
+ PUT_PIXEL2(d, 2, palette[(v >> 4) & 0xf]);
+ PUT_PIXEL2(d, 3, palette[(v >> 0) & 0xf]);
+
+ v = expand2[GET_PLANE(data, 1)];
+ v |= expand2[GET_PLANE(data, 3)] << 2;
+ PUT_PIXEL2(d, 4, palette[v >> 12]);
+ PUT_PIXEL2(d, 5, palette[(v >> 8) & 0xf]);
+ PUT_PIXEL2(d, 6, palette[(v >> 4) & 0xf]);
+ PUT_PIXEL2(d, 7, palette[(v >> 0) & 0xf]);
+ d += BPP * 16;
+ s += 4;
+ }
+}
+
+/*
+ * 16 color mode
+ */
+static void glue(maru_vga_draw_line4_, DEPTH)(VGACommonState *s1, uint8_t *d,
+ const uint8_t *s, int width)
+{
+ uint32_t plane_mask, data, v, *palette;
+ int x;
+
+ palette = s1->last_palette;
+ plane_mask = mask16[s1->ar[0x12] & 0xf];
+ width >>= 3;
+ for(x = 0; x < width; x++) {
+ data = ((uint32_t *)s)[0];
+ data &= plane_mask;
+ v = expand4[GET_PLANE(data, 0)];
+ v |= expand4[GET_PLANE(data, 1)] << 1;
+ v |= expand4[GET_PLANE(data, 2)] << 2;
+ v |= expand4[GET_PLANE(data, 3)] << 3;
+ ((PIXEL_TYPE *)d)[0] = palette[v >> 28];
+ ((PIXEL_TYPE *)d)[1] = palette[(v >> 24) & 0xf];
+ ((PIXEL_TYPE *)d)[2] = palette[(v >> 20) & 0xf];
+ ((PIXEL_TYPE *)d)[3] = palette[(v >> 16) & 0xf];
+ ((PIXEL_TYPE *)d)[4] = palette[(v >> 12) & 0xf];
+ ((PIXEL_TYPE *)d)[5] = palette[(v >> 8) & 0xf];
+ ((PIXEL_TYPE *)d)[6] = palette[(v >> 4) & 0xf];
+ ((PIXEL_TYPE *)d)[7] = palette[(v >> 0) & 0xf];
+ d += BPP * 8;
+ s += 4;
+ }
+}
+
+/*
+ * 16 color mode, dup2 horizontal
+ */
+static void glue(maru_vga_draw_line4d2_, DEPTH)(VGACommonState *s1, uint8_t *d,
+ const uint8_t *s, int width)
+{
+ uint32_t plane_mask, data, v, *palette;
+ int x;
+
+ palette = s1->last_palette;
+ plane_mask = mask16[s1->ar[0x12] & 0xf];
+ width >>= 3;
+ for(x = 0; x < width; x++) {
+ data = ((uint32_t *)s)[0];
+ data &= plane_mask;
+ v = expand4[GET_PLANE(data, 0)];
+ v |= expand4[GET_PLANE(data, 1)] << 1;
+ v |= expand4[GET_PLANE(data, 2)] << 2;
+ v |= expand4[GET_PLANE(data, 3)] << 3;
+ PUT_PIXEL2(d, 0, palette[v >> 28]);
+ PUT_PIXEL2(d, 1, palette[(v >> 24) & 0xf]);
+ PUT_PIXEL2(d, 2, palette[(v >> 20) & 0xf]);
+ PUT_PIXEL2(d, 3, palette[(v >> 16) & 0xf]);
+ PUT_PIXEL2(d, 4, palette[(v >> 12) & 0xf]);
+ PUT_PIXEL2(d, 5, palette[(v >> 8) & 0xf]);
+ PUT_PIXEL2(d, 6, palette[(v >> 4) & 0xf]);
+ PUT_PIXEL2(d, 7, palette[(v >> 0) & 0xf]);
+ d += BPP * 16;
+ s += 4;
+ }
+}
+
+/*
+ * 256 color mode, double pixels
+ *
+ * XXX: add plane_mask support (never used in standard VGA modes)
+ */
+static void glue(maru_vga_draw_line8d2_, DEPTH)(VGACommonState *s1, uint8_t *d,
+ const uint8_t *s, int width)
+{
+ uint32_t *palette;
+ int x;
+
+ palette = s1->last_palette;
+ width >>= 3;
+ for(x = 0; x < width; x++) {
+ PUT_PIXEL2(d, 0, palette[s[0]]);
+ PUT_PIXEL2(d, 1, palette[s[1]]);
+ PUT_PIXEL2(d, 2, palette[s[2]]);
+ PUT_PIXEL2(d, 3, palette[s[3]]);
+ d += BPP * 8;
+ s += 4;
+ }
+}
+
+/*
+ * standard 256 color mode
+ *
+ * XXX: add plane_mask support (never used in standard VGA modes)
+ */
+static void glue(maru_vga_draw_line8_, DEPTH)(VGACommonState *s1, uint8_t *d,
+ const uint8_t *s, int width)
+{
+ uint32_t *palette;
+ int x;
+
+ palette = s1->last_palette;
+ width >>= 3;
+ for(x = 0; x < width; x++) {
+ ((PIXEL_TYPE *)d)[0] = palette[s[0]];
+ ((PIXEL_TYPE *)d)[1] = palette[s[1]];
+ ((PIXEL_TYPE *)d)[2] = palette[s[2]];
+ ((PIXEL_TYPE *)d)[3] = palette[s[3]];
+ ((PIXEL_TYPE *)d)[4] = palette[s[4]];
+ ((PIXEL_TYPE *)d)[5] = palette[s[5]];
+ ((PIXEL_TYPE *)d)[6] = palette[s[6]];
+ ((PIXEL_TYPE *)d)[7] = palette[s[7]];
+ d += BPP * 8;
+ s += 8;
+ }
+}
+
+#endif /* DEPTH != 15 */
+
+
+/* XXX: optimize */
+
+/*
+ * 15 bit color
+ */
+static void glue(maru_vga_draw_line15_, PIXEL_NAME)(VGACommonState *s1, uint8_t *d,
+ const uint8_t *s, int width)
+{
+#if DEPTH == 15 && defined(HOST_WORDS_BIGENDIAN) == defined(TARGET_WORDS_BIGENDIAN)
+ memcpy(d, s, width * 2);
+#else
+ int w;
+ uint32_t v, r, g, b;
+
+ w = width;
+ do {
+ v = lduw_raw((void *)s);
+ r = (v >> 7) & 0xf8;
+ g = (v >> 2) & 0xf8;
+ b = (v << 3) & 0xf8;
+ ((PIXEL_TYPE *)d)[0] = glue(rgb_to_pixel, PIXEL_NAME)(r, g, b);
+ s += 2;
+ d += BPP;
+ } while (--w != 0);
+#endif
+}
+
+/*
+ * 16 bit color
+ */
+static void glue(maru_vga_draw_line16_, PIXEL_NAME)(VGACommonState *s1, uint8_t *d,
+ const uint8_t *s, int width)
+{
+#if DEPTH == 16 && defined(HOST_WORDS_BIGENDIAN) == defined(TARGET_WORDS_BIGENDIAN)
+ memcpy(d, s, width * 2);
+#else
+ int w;
+ uint32_t v, r, g, b;
+
+ w = width;
+ do {
+ v = lduw_raw((void *)s);
+ r = (v >> 8) & 0xf8;
+ g = (v >> 3) & 0xfc;
+ b = (v << 3) & 0xf8;
+ ((PIXEL_TYPE *)d)[0] = glue(rgb_to_pixel, PIXEL_NAME)(r, g, b);
+ s += 2;
+ d += BPP;
+ } while (--w != 0);
+#endif
+}
+
+/*
+ * 24 bit color
+ */
+static void glue(maru_vga_draw_line24_, PIXEL_NAME)(VGACommonState *s1, uint8_t *d,
+ const uint8_t *s, int width)
+{
+ int w;
+ uint32_t r, g, b;
+
+ w = width;
+ do {
+#if defined(TARGET_WORDS_BIGENDIAN)
+ r = s[0];
+ g = s[1];
+ b = s[2];
+#else
+ b = s[0];
+ g = s[1];
+ r = s[2];
+#endif
+ ((PIXEL_TYPE *)d)[0] = glue(rgb_to_pixel, PIXEL_NAME)(r, g, b);
+ s += 3;
+ d += BPP;
+ } while (--w != 0);
+}
+
+/*
+ * 32 bit color
+ */
+static void glue(maru_vga_draw_line32_, PIXEL_NAME)(VGACommonState *s1, uint8_t *d,
+ const uint8_t *s, int width)
+{
+#if DEPTH == 32 && defined(HOST_WORDS_BIGENDIAN) == defined(TARGET_WORDS_BIGENDIAN) && !defined(BGR_FORMAT)
+ memcpy(d, s, width * 4);
+#else
+ int w;
+ uint32_t r, g, b;
+
+ w = width;
+ do {
+#if defined(TARGET_WORDS_BIGENDIAN)
+ r = s[1];
+ g = s[2];
+ b = s[3];
+#else
+ b = s[0];
+ g = s[1];
+ r = s[2];
+#endif
+ ((PIXEL_TYPE *)d)[0] = glue(rgb_to_pixel, PIXEL_NAME)(r, g, b);
+ s += 4;
+ d += BPP;
+ } while (--w != 0);
+#endif
+}
+
+#undef PUT_PIXEL2
+#undef DEPTH
+#undef BPP
+#undef PIXEL_TYPE
+#undef PIXEL_NAME
+#undef BGR_FORMAT
--- /dev/null
+/*
+ * SDL_WINDOWID hack
+ *
+ * Copyright (C) 2011 - 2013 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Contact:
+ * Jinhyung Jo <jinhyung.jo@samsung.com>
+ * GiWoong Kim <giwoong.kim@samsung.com>
+ * SeokYeon Hwang <syeon.hwang@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 <pthread.h>
+#include <math.h>
+#include <png.h>
+#include "ui/console.h"
++#include "qemu/main-loop.h"
+#include "maru_sdl.h"
+#include "maru_display.h"
+#include "emul_state.h"
+#include "emulator.h"
+#include "maru_finger.h"
+#include "hw/maru_pm.h"
+#include "hw/maru_brightness.h"
+#include "hw/maru_overlay.h"
+#include "debug_ch.h"
+
+MULTI_DEBUG_CHANNEL(tizen, maru_sdl);
+
+static QEMUBH *sdl_init_bh;
+static QEMUBH *sdl_resize_bh;
+static DisplaySurface *dpy_surface;
+
+static SDL_Surface *surface_screen;
+static SDL_Surface *surface_qemu;
+static SDL_Surface *scaled_screen;
+static SDL_Surface *rotated_screen;
+static SDL_Surface *surface_guide; /* blank guide image */
+
+static double current_scale_factor = 1.0;
+static double current_screen_degree;
+static pixman_filter_t sdl_pixman_filter;
+
+static int sdl_alteration;
+
+static unsigned int sdl_skip_update;
+static unsigned int sdl_skip_count;
+
+static bool blank_guide_enable;
+static unsigned int blank_cnt;
+#define MAX_BLANK_FRAME_CNT 10
+#define BLANK_GUIDE_IMAGE_PATH "../images/"
+#define BLANK_GUIDE_IMAGE_NAME "blank-guide.png"
+
+
+#define SDL_THREAD
+
+static pthread_mutex_t sdl_mutex = PTHREAD_MUTEX_INITIALIZER;
+#ifdef SDL_THREAD
+static pthread_cond_t sdl_cond = PTHREAD_COND_INITIALIZER;
+static int sdl_thread_initialized;
+#endif
+
+#define SDL_FLAGS (SDL_SWSURFACE | SDL_ASYNCBLIT | SDL_NOFRAME)
+#define SDL_BPP 32
+
+/* Image processing functions using the pixman library */
+static void maru_do_pixman_dpy_surface(pixman_image_t *dst_image)
+{
+ /* overlay0 */
+ if (overlay0_power) {
+ pixman_image_composite(PIXMAN_OP_OVER,
+ overlay0_image, NULL, dst_image,
+ 0, 0, 0, 0, overlay0_left, overlay0_top,
+ overlay0_width, overlay0_height);
+ }
+ /* overlay1 */
+ if (overlay1_power) {
+ pixman_image_composite(PIXMAN_OP_OVER,
+ overlay1_image, NULL, dst_image,
+ 0, 0, 0, 0, overlay1_left, overlay1_top,
+ overlay1_width, overlay1_height);
+ }
+ /* apply the brightness level */
+ if (brightness_level < BRIGHTNESS_MAX) {
+ pixman_image_composite(PIXMAN_OP_OVER,
+ brightness_image, NULL, dst_image,
+ 0, 0, 0, 0, 0, 0,
+ pixman_image_get_width(dst_image),
+ pixman_image_get_height(dst_image));
+ }
+}
+
+static SDL_Surface *maru_do_pixman_scale(SDL_Surface *rz_src,
+ SDL_Surface *rz_dst,
+ pixman_filter_t filter)
+{
+ pixman_image_t *src = NULL;
+ pixman_image_t *dst = NULL;
+ double sx = 0;
+ double sy = 0;
+ pixman_transform_t matrix;
+ struct pixman_f_transform matrix_f;
+
+ SDL_LockSurface(rz_src);
+ SDL_LockSurface(rz_dst);
+
+ src = pixman_image_create_bits(PIXMAN_a8r8g8b8,
+ rz_src->w, rz_src->h, rz_src->pixels, rz_src->w * 4);
+ dst = pixman_image_create_bits(PIXMAN_a8r8g8b8,
+ rz_dst->w, rz_dst->h, rz_dst->pixels, rz_dst->w * 4);
+
+ sx = (double)rz_src->w / (double)rz_dst->w;
+ sy = (double)rz_src->h / (double)rz_dst->h;
+ pixman_f_transform_init_identity(&matrix_f);
+ pixman_f_transform_scale(&matrix_f, NULL, sx, sy);
+ pixman_transform_from_pixman_f_transform(&matrix, &matrix_f);
+ pixman_image_set_transform(src, &matrix);
+ pixman_image_set_filter(src, filter, NULL, 0);
+ pixman_image_composite(PIXMAN_OP_SRC, src, NULL, dst,
+ 0, 0, 0, 0, 0, 0,
+ rz_dst->w, rz_dst->h);
+
+ pixman_image_unref(src);
+ pixman_image_unref(dst);
+
+ SDL_UnlockSurface(rz_src);
+ SDL_UnlockSurface(rz_dst);
+
+ return rz_dst;
+}
+
+static SDL_Surface *maru_do_pixman_rotate(SDL_Surface *rz_src,
+ SDL_Surface *rz_dst,
+ int angle)
+{
+ pixman_image_t *src = NULL;
+ pixman_image_t *dst = NULL;
+ pixman_transform_t matrix;
+ struct pixman_f_transform matrix_f;
+
+ SDL_LockSurface(rz_src);
+ SDL_LockSurface(rz_dst);
+
+ src = pixman_image_create_bits(PIXMAN_a8r8g8b8,
+ rz_src->w, rz_src->h, rz_src->pixels, rz_src->w * 4);
+ dst = pixman_image_create_bits(PIXMAN_a8r8g8b8,
+ rz_dst->w, rz_dst->h, rz_dst->pixels, rz_dst->w * 4);
+
+ pixman_f_transform_init_identity(&matrix_f);
+ switch(angle) {
+ case 0:
+ pixman_f_transform_rotate(&matrix_f, NULL, 1.0, 0.0);
+ pixman_f_transform_translate(&matrix_f, NULL, 0.0, 0.0);
+ break;
+ case 90:
+ pixman_f_transform_rotate(&matrix_f, NULL, 0.0, 1.0);
+ pixman_f_transform_translate(&matrix_f, NULL,
+ (double)rz_dst->h, 0.0);
+ break;
+ case 180:
+ pixman_f_transform_rotate(&matrix_f, NULL, -1.0, 0.0);
+ pixman_f_transform_translate(&matrix_f, NULL,
+ (double)rz_dst->w, (double)rz_dst->h);
+ break;
+ case 270:
+ pixman_f_transform_rotate(&matrix_f, NULL, 0.0, -1.0);
+ pixman_f_transform_translate(&matrix_f, NULL,
+ 0.0, (double)rz_dst->w);
+ break;
+ default:
+ fprintf(stdout, "not supported angle factor (angle=%d)\n", angle);
+ break;
+ }
+ pixman_transform_from_pixman_f_transform(&matrix, &matrix_f);
+ pixman_image_set_transform(src, &matrix);
+ //pixman_image_set_filter(src, PIXMAN_FILTER_BILINEAR, NULL, 0);
+ pixman_image_composite(PIXMAN_OP_SRC, src, NULL, dst,
+ 0, 0, 0, 0, 0, 0,
+ rz_dst->w, rz_dst->h);
+
+ pixman_image_unref(src);
+ pixman_image_unref(dst);
+
+ SDL_UnlockSurface(rz_src);
+ SDL_UnlockSurface(rz_dst);
+
+ return rz_dst;
+}
+
+static void qemu_ds_sdl_update(DisplayChangeListener *dcl,
+ int x, int y, int w, int h)
+{
+ /* call sdl update */
+#ifdef SDL_THREAD
+ pthread_mutex_lock(&sdl_mutex);
+
+ pthread_cond_signal(&sdl_cond);
+
+ pthread_mutex_unlock(&sdl_mutex);
+#else
+ qemu_update();
+#endif
+}
+
+static void qemu_ds_sdl_switch(DisplayChangeListener *dcl,
+ struct DisplaySurface *new_surface)
+{
+ int console_width = 0, console_height = 0;
+
+ sdl_skip_update = 0;
+ sdl_skip_count = 0;
+
+ if (!new_surface) {
+ ERR("qemu_ds_sdl_switch : new_surface is NULL\n");
+ return;
+ }
+
+ dpy_surface = new_surface;
+ console_width = surface_width(new_surface);
+ console_height = surface_height(new_surface);
+
+ INFO("qemu_ds_sdl_switch : (%d, %d)\n",
+ console_width, console_height);
+
+#ifdef SDL_THREAD
+ pthread_mutex_lock(&sdl_mutex);
+#endif
+
+ if (surface_qemu != NULL) {
+ SDL_FreeSurface(surface_qemu);
+ surface_qemu = NULL;
+ }
+
+ /* create surface_qemu */
+ if (console_width == get_emul_resolution_width() &&
+ console_height == get_emul_resolution_height()) {
+ INFO("create SDL screen : (%d, %d)\n",
+ console_width, console_height);
+
+ surface_qemu = SDL_CreateRGBSurfaceFrom(
+ surface_data(dpy_surface),
+ console_width, console_height,
+ surface_bits_per_pixel(dpy_surface),
+ surface_stride(dpy_surface),
+ dpy_surface->pf.rmask,
+ dpy_surface->pf.gmask,
+ dpy_surface->pf.bmask,
+ dpy_surface->pf.amask);
+ } else {
+ INFO("create blank screen : (%d, %d)\n",
+ get_emul_resolution_width(), get_emul_resolution_height());
+
+ surface_qemu = SDL_CreateRGBSurface(
+ SDL_SWSURFACE,
+ console_width, console_height,
+ surface_bits_per_pixel(dpy_surface),
+ 0, 0, 0, 0);
+ }
+
+#ifdef SDL_THREAD
+ pthread_mutex_unlock(&sdl_mutex);
+#endif
+
+ if (surface_qemu == NULL) {
+ ERR("Unable to set the RGBSurface: %s\n", SDL_GetError());
+ return;
+ }
+}
+
+static png_bytep read_png_file(const char *file_name,
+ unsigned int *width_out, unsigned int *height_out)
+{
+#define PNG_HEADER_SIZE 8
+
+ FILE *fp = NULL;
+ png_byte header[PNG_HEADER_SIZE] = { 0, };
+ png_structp png_ptr = NULL;
+
+ png_infop info_ptr = NULL;
+ png_uint_32 width = 0;
+ png_uint_32 height = 0;
+ png_byte channels = 0;
+ unsigned int stride = 0;
+ int bit_depth = 0;
+ int color_type = 0;
+ int i = 0;
+
+ png_bytep pixel_data = NULL;
+ png_bytepp row_ptr_data = NULL;
+
+ if (file_name == NULL) {
+ ERR("file name is empty\n");
+ return NULL;
+ }
+
+ fp = fopen(file_name, "rb");
+ if (fp == NULL) {
+ ERR("file %s could not be opened\n", file_name);
+ return NULL;
+ }
+
+ if (fread(header, sizeof(png_byte), PNG_HEADER_SIZE, fp) != PNG_HEADER_SIZE) {
+ ERR("failed to read header from png file\n");
+ fclose(fp);
+ return NULL;
+ }
+
+ if (png_sig_cmp(header, 0, PNG_HEADER_SIZE) != 0) {
+ ERR("file %s is not recognized as a PNG image\n", file_name);
+ fclose(fp);
+ return NULL;
+ }
+
+ png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
+ if (png_ptr == NULL) {
+ ERR("failed to allocate png read struct\n");
+ fclose(fp);
+ return NULL;
+ }
+
+ info_ptr = png_create_info_struct(png_ptr);
+ if (info_ptr == NULL) {
+ ERR("failed to allocate png info struct\n");
+ png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
+ fclose(fp);
+ return NULL;
+ }
+
+ if (setjmp(png_jmpbuf(png_ptr)) != 0) {
+ ERR("error during init_io\n");
+ png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
+ png_destroy_info_struct(png_ptr, &info_ptr);
+ fclose(fp);
+ return NULL;
+ }
+
+ png_init_io(png_ptr, fp);
+ png_set_sig_bytes(png_ptr, PNG_HEADER_SIZE);
+
+ /* read the PNG image information */
+ png_read_info(png_ptr, info_ptr);
+ png_get_IHDR(png_ptr, info_ptr,
+ &width, &height, &bit_depth, &color_type,
+ NULL, NULL, NULL);
+
+ channels = png_get_channels(png_ptr, info_ptr);
+ stride = width * bit_depth * channels / 8;
+
+ pixel_data = (png_bytep) g_malloc0(stride * height);
+ if (pixel_data == NULL) {
+ ERR("could not allocate data buffer for pixels\n");
+
+ png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
+ png_destroy_info_struct(png_ptr, &info_ptr);
+ fclose(fp);
+ return NULL;
+ }
+
+ row_ptr_data = (png_bytepp) g_malloc0(sizeof(png_bytep) * height);
+ if (row_ptr_data == NULL) {
+ ERR("could not allocate data buffer for row_ptr\n");
+
+ g_free(pixel_data);
+ png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
+ png_destroy_info_struct(png_ptr, &info_ptr);
+ fclose(fp);
+ return NULL;
+ }
+
+ switch(color_type) {
+ case PNG_COLOR_TYPE_PALETTE :
+ png_set_palette_to_rgb(png_ptr);
+ break;
+ case PNG_COLOR_TYPE_RGB :
+ if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) {
+ /* transparency data for image */
+ png_set_tRNS_to_alpha(png_ptr);
+ } else {
+ png_set_filter(png_ptr, 0xff, PNG_FILLER_AFTER);
+ }
+ break;
+ case PNG_COLOR_TYPE_RGB_ALPHA :
+ break;
+ default :
+ INFO("png file has an unsupported color type\n");
+ break;
+ }
+
+ for (i = 0; i < height; i++) {
+ row_ptr_data[i] = pixel_data + (stride * i);
+ }
+
+ /* read the entire image into memory */
+ png_read_image(png_ptr, row_ptr_data);
+
+ /* image information */
+ INFO("=== blank guide image was loaded ===============\n");
+ INFO("file path : %s\n", file_name);
+ INFO("width : %d, height : %d, stride : %d\n",
+ width, height, stride);
+ INFO("color type : %d, channels : %d, bit depth : %d\n",
+ color_type, channels, bit_depth);
+ INFO("================================================\n");
+
+ if (width_out != NULL) {
+ *width_out = (unsigned int) width;
+ }
+ if (height_out != NULL) {
+ *height_out = (unsigned int) height;
+ }
+
+ g_free(row_ptr_data);
+ png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
+ png_destroy_info_struct(png_ptr, &info_ptr);
+ fclose(fp);
+
+ return pixel_data;
+}
+
+static SDL_Surface *get_blank_guide_image(void)
+{
+ if (surface_guide == NULL) {
+ unsigned int width = 0;
+ unsigned int height = 0;
+ char *guide_image_path = NULL;
+ void *guide_image_data = NULL;
+
+ /* load png image */
+ int path_len = strlen(get_bin_path()) +
+ strlen(BLANK_GUIDE_IMAGE_PATH) +
+ strlen(BLANK_GUIDE_IMAGE_NAME) + 1;
+ guide_image_path = g_malloc0(sizeof(char) * path_len);
+ snprintf(guide_image_path, path_len, "%s%s%s",
+ get_bin_path(), BLANK_GUIDE_IMAGE_PATH,
+ BLANK_GUIDE_IMAGE_NAME);
+
+ guide_image_data = (void *) read_png_file(
+ guide_image_path, &width, &height);
+
+ if (guide_image_data != NULL) {
+ surface_guide = SDL_CreateRGBSurfaceFrom(
+ guide_image_data, width, height,
+ get_emul_sdl_bpp(), width * 4,
+ dpy_surface->pf.bmask,
+ dpy_surface->pf.gmask,
+ dpy_surface->pf.rmask,
+ dpy_surface->pf.amask);
+ } else {
+ ERR("failed to draw a blank guide image\n");
+ }
+
+ g_free(guide_image_path);
+ }
+
+ return surface_guide;
+}
+
+static void qemu_ds_sdl_refresh(DisplayChangeListener *dcl)
+{
+ if (sdl_alteration == 1) {
+ sdl_alteration = 0;
+ sdl_skip_update = 0;
+ sdl_skip_count = 0;
+ }
+
+ /* If the display is turned off,
+ the screen does not update until the display is turned on */
+ if (sdl_skip_update && brightness_off) {
+ if (blank_cnt > MAX_BLANK_FRAME_CNT) {
+ /* do nothing */
+ return;
+ } else if (blank_cnt == MAX_BLANK_FRAME_CNT) {
+ if (blank_guide_enable == true) {
+ INFO("draw a blank guide image\n");
+
+ SDL_Surface *guide = get_blank_guide_image();
+ if (guide != NULL && get_emul_skin_enable() == 1) {
+ /* draw guide image */
+ int dst_x = 0; int dst_y = 0;
+ int dst_w = 0; int dst_h = 0;
+
+ unsigned int screen_width =
+ get_emul_resolution_width() * current_scale_factor;
+ unsigned int screen_height =
+ get_emul_resolution_height() * current_scale_factor;
+
+ int margin_w = screen_width - guide->w;
+ int margin_h = screen_height - guide->h;
+
+ if (margin_w < 0 || margin_h < 0) {
+ /* guide image scaling */
+ int margin = (margin_w < margin_h)? margin_w : margin_h;
+ dst_w = guide->w + margin;
+ dst_h = guide->h + margin;
+
+ SDL_Surface *scaled_guide = SDL_CreateRGBSurface(
+ SDL_SWSURFACE, dst_w, dst_h, get_emul_sdl_bpp(),
+ guide->format->Rmask, guide->format->Gmask,
+ guide->format->Bmask, guide->format->Amask);
+
+ scaled_guide = maru_do_pixman_scale(
+ guide, scaled_guide, PIXMAN_FILTER_BEST);
+
+ dst_x = (surface_screen->w - dst_w) / 2;
+ dst_y = (surface_screen->h - dst_h) / 2;
+ SDL_Rect dst_rect = { dst_x, dst_y, dst_w, dst_h };
+
+ SDL_BlitSurface(scaled_guide, NULL,
+ surface_screen, &dst_rect);
+ SDL_UpdateRect(surface_screen, 0, 0, 0, 0);
+
+ SDL_FreeSurface(scaled_guide);
+ } else {
+ dst_w = guide->w;
+ dst_h = guide->h;
+ dst_x = (surface_screen->w - dst_w) / 2;
+ dst_y = (surface_screen->h - dst_h) / 2;
+ SDL_Rect dst_rect = { dst_x, dst_y, dst_w, dst_h };
+
+ SDL_BlitSurface(guide, NULL,
+ surface_screen, &dst_rect);
+ SDL_UpdateRect(surface_screen, 0, 0, 0, 0);
+ }
+ }
+ }
+ } else if (blank_cnt == 0) {
+ INFO("skipping of the display updating is started\n");
+ }
+
+ blank_cnt++;
+
+ return;
+ } else {
+ if (blank_cnt != 0) {
+ INFO("skipping of the display updating is ended\n");
+ blank_cnt = 0;
+ }
+ }
+
+ graphic_hw_update(NULL);
+
+ /* Usually, continuously updated.
+ When the display is turned off,
+ ten more updates the screen for a black screen. */
+ if (brightness_off) {
+ if (++sdl_skip_count > 10) {
+ sdl_skip_update = 1;
+ } else {
+ sdl_skip_update = 0;
+ }
+ } else {
+ sdl_skip_count = 0;
+ sdl_skip_update = 0;
+ }
+
+#ifdef TARGET_ARM
+#ifdef SDL_THREAD
+ pthread_mutex_lock(&sdl_mutex);
+#endif
+
+ /*
+ * It is necessary only for exynos4210 FIMD in connection with
+ * some WM (xfwm4, for example)
+ */
+
+ SDL_UpdateRect(surface_screen, 0, 0, 0, 0);
+
+#ifdef SDL_THREAD
+ pthread_mutex_unlock(&sdl_mutex);
+#endif
+#endif
+}
+
+DisplayChangeListenerOps maru_dcl_ops = {
+ .dpy_name = "maru_sdl",
+ .dpy_gfx_update = qemu_ds_sdl_update,
+ .dpy_gfx_switch = qemu_ds_sdl_switch,
+ .dpy_refresh = qemu_ds_sdl_refresh,
+};
+
+void maruskin_sdl_interpolation(bool on)
+{
+ if (on == true) {
+ INFO("set PIXMAN_FILTER_BEST filter for image processing\n");
+
+ /* PIXMAN_FILTER_BILINEAR */
+ sdl_pixman_filter = PIXMAN_FILTER_BEST;
+ } else {
+ INFO("set PIXMAN_FILTER_FAST filter for image processing\n");
+
+ /* PIXMAN_FILTER_NEAREST */
+ sdl_pixman_filter = PIXMAN_FILTER_FAST;
+ }
+}
+
+static void qemu_update(void)
+{
+ if (sdl_alteration == -1) {
+ SDL_FreeSurface(scaled_screen);
+ SDL_FreeSurface(rotated_screen);
+ SDL_FreeSurface(surface_qemu);
+ surface_qemu = NULL;
+
+ return;
+ }
+
+ if (surface_qemu != NULL) {
+ int i = 0;
+
+ maru_do_pixman_dpy_surface(dpy_surface->image);
+ set_maru_screenshot(dpy_surface);
+
+ if (current_scale_factor != 1.0) {
+ rotated_screen = maru_do_pixman_rotate(
+ surface_qemu, rotated_screen,
+ (int)current_screen_degree);
+ scaled_screen = maru_do_pixman_scale(
+ rotated_screen, scaled_screen, sdl_pixman_filter);
+
+ SDL_BlitSurface(scaled_screen, NULL, surface_screen, NULL);
+ }
+ else {/* current_scale_factor == 1.0 */
+ if (current_screen_degree != 0.0) {
+ rotated_screen = maru_do_pixman_rotate(
+ surface_qemu, rotated_screen,
+ (int)current_screen_degree);
+
+ SDL_BlitSurface(rotated_screen, NULL, surface_screen, NULL);
+ } else {
+ /* as-is */
+ SDL_BlitSurface(surface_qemu, NULL, surface_screen, NULL);
+ }
+ }
+
+ /* draw multi-touch finger points */
+ MultiTouchState *mts = get_emul_multi_touch_state();
+ if (mts->multitouch_enable != 0 && mts->finger_point_surface != NULL) {
+ FingerPoint *finger = NULL;
+ int finger_point_size_half = mts->finger_point_size / 2;
+ SDL_Rect rect;
+
+ for (i = 0; i < mts->finger_cnt; i++) {
+ finger = get_finger_point_from_slot(i);
+ if (finger != NULL && finger->id != 0) {
+ rect.x = finger->origin_x - finger_point_size_half;
+ rect.y = finger->origin_y - finger_point_size_half;
+ rect.w = rect.h = mts->finger_point_size;
+
+ SDL_BlitSurface(
+ (SDL_Surface *)mts->finger_point_surface,
+ NULL, surface_screen, &rect);
+ }
+ }
+ } /* end of draw multi-touch */
+ }
+
+ SDL_UpdateRect(surface_screen, 0, 0, 0, 0);
+}
+
+
+#ifdef SDL_THREAD
+static void *run_qemu_update(void *arg)
+{
+ while(1) {
+ pthread_mutex_lock(&sdl_mutex);
+
+ pthread_cond_wait(&sdl_cond, &sdl_mutex);
+
+ qemu_update();
+
+ pthread_mutex_unlock(&sdl_mutex);
+ }
+
+ return NULL;
+}
+#endif
+
+static void maru_sdl_resize_bh(void *opaque)
+{
+ int surface_width = 0, surface_height = 0;
+ int display_width = 0, display_height = 0;
+ int temp = 0;
+
+ INFO("Set up a video mode with the specified width, "
+ "height and bits-per-pixel\n");
+
+ sdl_alteration = 1;
+ sdl_skip_update = 0;
+
+#ifdef SDL_THREAD
+ pthread_mutex_lock(&sdl_mutex);
+#endif
+
+ /* get current setting information and calculate screen size */
+ display_width = get_emul_resolution_width();
+ display_height = get_emul_resolution_height();
+ current_scale_factor = get_emul_win_scale();
+
+ short rotaton_type = get_emul_rotation();
+ if (rotaton_type == ROTATION_PORTRAIT) {
+ current_screen_degree = 0.0;
+ } else if (rotaton_type == ROTATION_LANDSCAPE) {
+ current_screen_degree = 90.0;
+ temp = display_width;
+ display_width = display_height;
+ display_height = temp;
+ } else if (rotaton_type == ROTATION_REVERSE_PORTRAIT) {
+ current_screen_degree = 180.0;
+ } else if (rotaton_type == ROTATION_REVERSE_LANDSCAPE) {
+ current_screen_degree = 270.0;
+ temp = display_width;
+ display_width = display_height;
+ display_height = temp;
+ }
+
+ surface_width = display_width * current_scale_factor;
+ surface_height = display_height * current_scale_factor;
+
+ surface_screen = SDL_SetVideoMode(
+ surface_width, surface_height,
+ get_emul_sdl_bpp(), SDL_FLAGS);
+
+ INFO("SDL_SetVideoMode\n");
+
+ if (surface_screen == NULL) {
+ ERR("Could not open SDL display (%dx%dx%d) : %s\n",
+ surface_width, surface_height,
+ get_emul_sdl_bpp(), SDL_GetError());
+
+#ifdef SDL_THREAD
+ pthread_mutex_unlock(&sdl_mutex);
+#endif
+
+ return;
+ }
+
+ /* create buffer for image processing */
+ SDL_FreeSurface(scaled_screen);
+ scaled_screen = SDL_CreateRGBSurface(SDL_SWSURFACE,
+ surface_width, surface_height,
+ get_emul_sdl_bpp(),
+ surface_qemu->format->Rmask,
+ surface_qemu->format->Gmask,
+ surface_qemu->format->Bmask,
+ surface_qemu->format->Amask);
+
+ SDL_FreeSurface(rotated_screen);
+ rotated_screen = SDL_CreateRGBSurface(SDL_SWSURFACE,
+ display_width, display_height,
+ get_emul_sdl_bpp(),
+ surface_qemu->format->Rmask,
+ surface_qemu->format->Gmask,
+ surface_qemu->format->Bmask,
+ surface_qemu->format->Amask);
+
+ /* rearrange multi-touch finger points */
+ if (get_emul_multi_touch_state()->multitouch_enable == 1 ||
+ get_emul_multi_touch_state()->multitouch_enable == 2) {
+ rearrange_finger_points(get_emul_resolution_width(), get_emul_resolution_height(),
+ current_scale_factor, rotaton_type);
+ }
+
+#ifdef SDL_THREAD
+ pthread_mutex_unlock(&sdl_mutex);
+#endif
+}
+
+static void maru_sdl_init_bh(void *opaque)
+{
+ SDL_SysWMinfo info;
+
+ INFO("SDL_Init\n");
+
+ if (SDL_Init(SDL_INIT_VIDEO) < 0) {
+ ERR("unable to init SDL: %s\n", SDL_GetError());
+ // TODO:
+ }
+
+#ifndef _WIN32
+ SDL_VERSION(&info.version);
+ SDL_GetWMInfo(&info);
+#endif
+
+ qemu_bh_schedule(sdl_resize_bh);
+
+#ifdef SDL_THREAD
+ if (sdl_thread_initialized == 0) {
+ sdl_thread_initialized = 1;
+
+ INFO("sdl update thread create\n");
+
+ pthread_t thread_id;
+ if (pthread_create(
+ &thread_id, NULL, run_qemu_update, NULL) != 0) {
+ ERR("pthread_create fail\n");
+ return;
+ }
+ }
+#endif
+}
+
+void maruskin_sdl_init(uint64 swt_handle,
+ unsigned int display_width, unsigned int display_height,
+ bool blank_guide)
+{
+ gchar SDL_windowhack[32] = { 0, };
+ long window_id = swt_handle;
+ blank_guide_enable = blank_guide;
+
+ INFO("maru sdl init\n");
+
+ sdl_init_bh = qemu_bh_new(maru_sdl_init_bh, NULL);
+ sdl_resize_bh = qemu_bh_new(maru_sdl_resize_bh, NULL);
+
+ sprintf(SDL_windowhack, "%ld", window_id);
+ g_setenv("SDL_WINDOWID", SDL_windowhack, 1);
+
+ INFO("register SDL environment variable. "
+ "(SDL_WINDOWID = %s)\n", SDL_windowhack);
+
+ set_emul_resolution(display_width, display_height);
+ set_emul_sdl_bpp(SDL_BPP);
+ maruskin_sdl_interpolation(false);
+ init_multi_touch_state();
+
+ if (blank_guide_enable == true) {
+ INFO("blank guide is on\n");
+ }
+
+ qemu_bh_schedule(sdl_init_bh);
+}
+
+void maruskin_sdl_quit(void)
+{
+ INFO("maru sdl quit\n");
+
+ if (surface_guide != NULL) {
+ g_free(surface_guide->pixels);
+ SDL_FreeSurface(surface_guide);
+ }
+
+ /* remove multi-touch finger points */
+ cleanup_multi_touch_state();
+
+ if (sdl_init_bh != NULL) {
+ qemu_bh_delete(sdl_init_bh);
+ }
+ if (sdl_resize_bh != NULL) {
+ qemu_bh_delete(sdl_resize_bh);
+ }
+
+ sdl_alteration = -1;
+
+#ifdef SDL_THREAD
+ pthread_mutex_lock(&sdl_mutex);
+#endif
+
+ SDL_Quit();
+
+#ifdef SDL_THREAD
+ pthread_mutex_unlock(&sdl_mutex);
+ pthread_cond_destroy(&sdl_cond);
+#endif
+
+ pthread_mutex_destroy(&sdl_mutex);
+}
+
+void maruskin_sdl_resize(void)
+{
+ INFO("maru sdl resize\n");
+
+ qemu_bh_schedule(sdl_resize_bh);
+}
--- /dev/null
- qdev_free(&usbdisk->qdev);
+/*
+ * mainloop_evhandle.c
+ *
+ * Copyright (C) 2011 - 2013 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Contact:
+ * Kitae Kim <kt920.kim@samsung.com>
+ * GiWoong Kim <giwoong.kim@samsung.com>
+ * DoHyung Hong
+ *
+ * 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
+ *
+ */
+
+
+#ifdef _WIN32
+#include <winsock.h>
+#define socklen_t int
+#else
+#include <netinet/in.h>
+#include <sys/ioctl.h>
+#endif
+
+//#include "qobject.h"
+#include "qemu-common.h"
+#include "hw/usb.h"
+#include "hw/irq.h"
+#include "mloop_event.h"
+#include "ui/console.h"
+#include "emul_state.h"
+#include "debug_ch.h"
+#include "monitor/monitor.h"
+#include "hw/pci/pci.h"
+#include "sysemu/sysemu.h"
+#include "exec/memory-internal.h"
+
+#include "emulator.h"
+#include "guest_debug.h"
+#include "skin/maruskin_server.h"
+#include "hw/maru_virtio_touchscreen.h"
+#include "hw/maru_virtio_keyboard.h"
+
+MULTI_DEBUG_CHANNEL(qemu, mloop_event);
+
+struct mloop_evsock {
+ int sockno;
+ unsigned short portno;
+ unsigned char status;
+};
+
+#define MLOOP_EVSOCK_NULL 0
+#define MLOOP_EVSOCK_CREATED 1
+#define MLOOP_EVSOCK_NOTBOUND 2
+#define MLOOP_EVSOCK_BOUND 3
+#define MLOOP_EVSOCK_CONNECTED 4
+
+#define PACKET_LEN 512
+struct mloop_evpack {
+ short type;
+ short size;
+ char data[PACKET_LEN-4];
+};
+
+#define MLOOP_EVTYPE_USB_ADD 1
+#define MLOOP_EVTYPE_USB_DEL 2
+#define MLOOP_EVTYPE_INTR_UP 3
+#define MLOOP_EVTYPE_INTR_DOWN 4
+#define MLOOP_EVTYPE_TOUCH 6
+#define MLOOP_EVTYPE_KEYBOARD 7
+#define MLOOP_EVTYPE_KBD_ADD 8
+#define MLOOP_EVTYPE_KBD_DEL 9
+#define MLOOP_EVTYPE_RAMDUMP 10
+#define MLOOP_EVTYPE_SDCARD_ATTACH 11
+#define MLOOP_EVTYPE_SDCARD_DETACH 12
+
+
+static struct mloop_evsock mloop = {-1, 0, 0};
+
+static int mloop_evsock_create(struct mloop_evsock *ev)
+{
+ struct sockaddr sa;
+ socklen_t sa_size;
+ int ret;
+ unsigned long nonblock = 1;
+
+ if (ev == NULL) {
+ ERR("null pointer\n");
+ return -1;
+ }
+
+ ev->sockno = socket(AF_INET, SOCK_DGRAM, 0);
+ if ( ev->sockno == -1 ) {
+ ERR("socket() failed\n");
+ return -1;
+ }
+
+#ifdef _WIN32
+ ioctlsocket(ev->sockno, FIONBIO, &nonblock );
+#else
+ ioctl(ev->sockno, FIONBIO, &nonblock);
+#endif // _WIN32
+
+ nonblock = 1 ;
+ setsockopt( ev->sockno, SOL_SOCKET, SO_REUSEADDR, (char *)&nonblock, sizeof(nonblock) ) ;
+
+ memset(&sa, '\0', sizeof(sa));
+ ((struct sockaddr_in *) &sa)->sin_family = AF_INET;
+ memcpy(&((struct sockaddr_in *) &sa)->sin_addr, "\177\000\000\001", 4); // 127.0.0.1
+ ((struct sockaddr_in *) &sa)->sin_port = htons(ev->portno);
+ sa_size = sizeof(struct sockaddr_in);
+
+ ret = bind(ev->sockno, &sa, sa_size);
+ if (ret) {
+ ERR("bind() failed\n");
+#ifdef _WIN32
+ closesocket(ev->sockno);
+#else
+ close(ev->sockno);
+#endif
+ ev->sockno = -1;
+ ev->status = 0;
+ return ret;
+ }
+
+ if (ev->portno == 0) {
+ memset(&sa, '\0', sizeof(sa));
+ getsockname(ev->sockno, (struct sockaddr *) &sa, &sa_size);
+ ev->portno = ntohs(((struct sockaddr_in *) &sa)->sin_port);
+ }
+
+ ret = connect(ev->sockno, (struct sockaddr *) &sa, sa_size);
+ if (ret) {
+ ERR("connect() failed\n");
+#ifdef _WIN32
+ closesocket(ev->sockno);
+#else
+ close(ev->sockno);
+#endif
+ ev->sockno = -1;
+ ev->status = 0;
+ return ret;
+ }
+
+ ev->status = MLOOP_EVSOCK_CONNECTED;
+ return 0;
+}
+
+static void mloop_evsock_remove(struct mloop_evsock *ev)
+{
+ if (!ev) {
+ return ;
+ }
+
+ if (ev->sockno > 0) {
+#ifdef _WIN32
+ shutdown(ev->sockno, SD_BOTH);
+ closesocket(ev->sockno);
+#else
+ shutdown(ev->sockno, SHUT_RDWR);
+ close(ev->sockno);
+#endif
+ ev->sockno = -1;
+ ev->status = 0;
+ }
+}
+
+static int mloop_evsock_send(struct mloop_evsock *ev, struct mloop_evpack *p)
+{
+ int ret;
+
+ if (ev == NULL || ev->sockno == -1) {
+ ERR("invalid mloop_evsock\n");
+ return -1;
+ }
+
+ if (p == NULL || p->size <= 0) {
+ ERR("invalid mloop_evpack\n");
+ return -1;
+ }
+
+ do {
+ ret = send(ev->sockno, p, p->size, 0);
+#ifdef _WIN32
+ } while (ret == -1 && (WSAGetLastError() == WSAEWOULDBLOCK));
+#else
+ } while (ret == -1 && (errno == EWOULDBLOCK || errno == EINTR));
+#endif // _WIN32
+
+ return ret;
+}
+
+static USBDevice *usbkbd = NULL;
+static USBDevice *usbdisk = NULL;
+#ifdef TARGET_I386
+static PCIDevice *hostkbd = NULL;
+static PCIDevice *virtio_sdcard = NULL;
+#endif
+
+static void mloop_evhandle_usb_add(char *name)
+{
+ if (name == NULL) {
+ ERR("Packet data for usb device is NULL\n");
+ return;
+ }
+
+ if (strcmp(name, "keyboard") == 0) {
+ if (usbkbd == NULL) {
+ usbkbd = usbdevice_create(name);
+ } else if (usbkbd->attached == 0) {
+ usb_device_attach(usbkbd);
+ }
+ } else if (strncmp(name, "disk:", 5) == 0) {
+ if (usbdisk == NULL) {
+ usbdisk = usbdevice_create(name);
+ }
+ } else {
+ WARN("There is no usb-device for %s.\n", name);
+ }
+}
+
+static void mloop_evhandle_usb_del(char *name)
+{
+ if (name == NULL) {
+ ERR("Packet data for usb device is NULL\n");
+ return;
+ }
+
+ if (strcmp(name, "keyboard") == 0) {
+ if (usbkbd && usbkbd->attached != 0) {
+ usb_device_detach(usbkbd);
+ }
+ } else if (strncmp(name, "disk:", 5) == 0) {
+ if (usbdisk) {
++// qdev_free(&usbdisk->qdev);
+ }
+ } else {
+ WARN("There is no usb-device for %s.\n", name);
+ }
+}
+
+static void mloop_evhandle_intr_up(long data)
+{
+ if (data == 0) {
+ return;
+ }
+
+ qemu_irq_raise((qemu_irq)data);
+}
+
+static void mloop_evhandle_intr_down(long data)
+{
+ if (data == 0) {
+ return;
+ }
+
+ qemu_irq_lower((qemu_irq)data);
+}
+
+static void mloop_evhandle_touch(struct mloop_evpack* pack)
+{
+ maru_virtio_touchscreen_notify();
+}
+
+static void mloop_evhandle_keyboard(long data)
+{
+ virtio_keyboard_notify((void*)data);
+}
+
+#ifdef TARGET_I386
+static void mloop_evhandle_kbd_add(char *name)
+{
+ QDict *qdict;
+
+ TRACE("try to add a keyboard device.\n");
+
+ if (name == NULL) {
+ ERR("packet data is NULL.\n");
+ return;
+ }
+
+ if (hostkbd) {
+ INFO("virtio-keyboard has already been added.\n");
+ return;
+ }
+
+ qdict = qdict_new();
+ qdict_put(qdict, "pci_addr", qstring_from_str("auto"));
+ qdict_put(qdict, "type", qstring_from_str(name));
+
+ hostkbd = do_pci_device_hot_add(cur_mon, qdict);
+ if (hostkbd) {
+ TRACE("virtio-keyboard device: root_bus_path %s, bus %d, slot %d, function %d\n",
+ pci_root_bus_path(hostkbd), pci_bus_num(hostkbd->bus),
+ PCI_SLOT(hostkbd->devfn), PCI_FUNC(hostkbd->devfn));
+ } else {
+ ERR("failed to hot_add keyboard device.\n");
+ }
+
+ QDECREF(qdict);
+}
+
+static void mloop_evhandle_kbd_del(void)
+{
+ QDict *qdict;
+ int slot = 0;
+ char slotbuf[4] = {0,};
+
+ TRACE("try to remove a keyboard device.\n");
+
+ if (!hostkbd) {
+ ERR("Failed to remove a keyboard device "
+ "because the device has not been created yet.\n");
+ return;
+ }
+
+ slot = PCI_SLOT(hostkbd->devfn);
+ snprintf(slotbuf, sizeof(slotbuf), "%x", slot);
+ TRACE("virtio-keyboard slot %s.\n", slotbuf);
+
+ qdict = qdict_new();
+ qdict_put(qdict, "pci_addr", qstring_from_str(slotbuf));
+
+ do_pci_device_hot_remove(cur_mon, qdict);
+ INFO("hot_remove keyboard.\n");
+
+ hostkbd = NULL;
+
+ QDECREF(qdict);
+}
+
+static void mloop_evhandle_sdcard_attach(char *name)
+{
+ char opts[PATH_MAX];
+
+ INFO("try to attach sdcard.\n");
+
+ if (name == NULL) {
+ ERR("Packet data is NULL.\n");
+ return;
+ }
+
+ if (virtio_sdcard) {
+ ERR("sdcard is already attached.\n");
+ return;
+ }
+
+ QDict *qdict = qdict_new();
+
+ qdict_put(qdict, "pci_addr", qstring_from_str("auto"));
+ qdict_put(qdict, "type", qstring_from_str("storage"));
+ snprintf(opts, sizeof(opts), "file=%s,if=virtio", name);
+ qdict_put(qdict, "opts", qstring_from_str(opts));
+
+ virtio_sdcard = do_pci_device_hot_add(cur_mon, qdict);
+ if (virtio_sdcard) {
+ INFO("hot add virtio storage device with [%s]\n", opts);
+ INFO("virtio-sdcard device: root_bus_path %s, bus %d, slot %d, function %d\n",
+ pci_root_bus_path(virtio_sdcard), pci_bus_num(virtio_sdcard->bus),
+ PCI_SLOT(virtio_sdcard->devfn), PCI_FUNC(virtio_sdcard->devfn));
+ } else {
+ ERR("failed to create a sdcard device.\n");
+ }
+
+ QDECREF(qdict);
+}
+
+static void mloop_evhandle_sdcard_detach(void)
+{
+ INFO("try to detach sdcard.\n");
+
+ if (!virtio_sdcard) {
+ ERR("sdcard is not attached yet.\n");
+ return;
+ }
+
+ QDict *qdict = qdict_new();
+ int slot = 0;
+ char slotbuf[4] = {0,};
+
+ slot = PCI_SLOT(virtio_sdcard->devfn);
+ snprintf(slotbuf, sizeof(slotbuf), "%x", slot);
+ INFO("virtio-sdcard slot [%d].\n", slot);
+ qdict_put(qdict, "pci_addr", qstring_from_str(slotbuf));
+
+ do_pci_device_hot_remove(cur_mon, qdict);
+
+ virtio_sdcard = NULL;
+
+ INFO("hot remove virtio storage device.\n");
+
+ QDECREF(qdict);
+}
+
+int mloop_evcmd_get_hostkbd_status(void)
+{
+ return hostkbd ? 1 : 0;
+}
+#endif
+
+static void mloop_evhandle_ramdump(struct mloop_evpack* pack)
+{
+#define MAX_PATH 256
+ INFO("dumping...\n");
+
+#if defined(CONFIG_LINUX) && !defined(TARGET_ARM) /* FIXME: Handle ARM ram as list */
+ MemoryRegion* mr = get_ram_memory();
+ size_t size = mr->size.lo;
+ char dump_fullpath[MAX_PATH];
+ char dump_filename[MAX_PATH];
+
+ char* dump_path = g_path_get_dirname(get_log_path());
+
+ sprintf(dump_filename, "0x%08x%s0x%08x%s", (unsigned int)mr->ram_addr, "-",
+ (unsigned int)(mr->ram_addr + size), "_RAM.dump");
+ sprintf(dump_fullpath, "%s/%s", dump_path, dump_filename);
+ free(dump_path);
+
+ FILE *dump_file = fopen(dump_fullpath, "w+");
+ if(!dump_file) {
+ fprintf(stderr, "Dump file create failed [%s]\n", dump_fullpath);
+
+ return;
+ }
+
+ size_t written;
+ written = fwrite(qemu_get_ram_ptr(mr->ram_addr), sizeof(char), size, dump_file);
+ fprintf(stdout, "Dump file written [%08x][%zu bytes]\n", (unsigned int)mr->ram_addr, written);
+ if(written != size) {
+ fprintf(stderr, "Dump file size error [%zu, %zu, %d]\n", written, size, errno);
+ }
+
+ fprintf(stdout, "Dump file create success [%s, %zu bytes]\n", dump_fullpath, size);
+
+ fclose(dump_file);
+#endif
+
+ /* notify to skin process */
+ notify_ramdump_completed();
+}
+
+static void mloop_evcb_recv(struct mloop_evsock *ev)
+{
+ struct mloop_evpack pack;
+ int ret;
+
+ do {
+ ret = recv(ev->sockno, (void *)&pack, sizeof(pack), 0);
+#ifdef _WIN32
+ } while (ret == -1 && WSAGetLastError() == WSAEINTR);
+#else
+ } while (ret == -1 && errno == EINTR);
+#endif // _WIN32
+
+ if (ret == -1) {
+ return;
+ }
+
+ if (ret == 0) {
+ return;
+ }
+
+ switch (pack.type) {
+ case MLOOP_EVTYPE_USB_ADD:
+ mloop_evhandle_usb_add(pack.data);
+ break;
+ case MLOOP_EVTYPE_USB_DEL:
+ mloop_evhandle_usb_del(pack.data);
+ break;
+ case MLOOP_EVTYPE_INTR_UP:
+ mloop_evhandle_intr_up(*(long*)&pack.data[0]);
+ break;
+ case MLOOP_EVTYPE_INTR_DOWN:
+ mloop_evhandle_intr_down(*(long*)&pack.data[0]);
+ break;
+ case MLOOP_EVTYPE_TOUCH:
+ mloop_evhandle_touch(&pack);
+ break;
+ case MLOOP_EVTYPE_KEYBOARD:
+ mloop_evhandle_keyboard(*(uint64_t*)&pack.data[0]);
+ break;
+#ifdef TARGET_I386
+ case MLOOP_EVTYPE_KBD_ADD:
+ mloop_evhandle_kbd_add(pack.data);
+ break;
+ case MLOOP_EVTYPE_KBD_DEL:
+ mloop_evhandle_kbd_del();
+ break;
+#endif
+ case MLOOP_EVTYPE_RAMDUMP:
+ mloop_evhandle_ramdump(&pack);
+ break;
+#ifdef TARGET_I386
+ case MLOOP_EVTYPE_SDCARD_ATTACH:
+ mloop_evhandle_sdcard_attach(pack.data);
+ break;
+ case MLOOP_EVTYPE_SDCARD_DETACH:
+ mloop_evhandle_sdcard_detach();
+ break;
+#endif
+ default:
+ break;
+ }
+}
+
+void mloop_ev_init(void)
+{
+ int ret = mloop_evsock_create(&mloop);
+ if (ret == 0) {
+ qemu_set_fd_handler(mloop.sockno, (IOHandler *)mloop_evcb_recv, NULL, &mloop);
+ }
+}
+
+void mloop_ev_stop(void)
+{
+ qemu_set_fd_handler(mloop.sockno, NULL, NULL, NULL);
+ mloop_evsock_remove(&mloop);
+}
+
+void mloop_evcmd_raise_intr(void *irq)
+{
+ struct mloop_evpack pack;
+ memset((void*)&pack, 0, sizeof(struct mloop_evpack));
+ pack.type = MLOOP_EVTYPE_INTR_UP;
+ pack.size = 8;
+ *(long*)&pack.data[0] = (long)irq;
+ mloop_evsock_send(&mloop, &pack);
+}
+
+void mloop_evcmd_lower_intr(void *irq)
+{
+ struct mloop_evpack pack;
+ memset((void*)&pack, 0, sizeof(struct mloop_evpack));
+ pack.type = MLOOP_EVTYPE_INTR_DOWN;
+ pack.size = 8;
+ *(long*)&pack.data[0] = (long)irq;
+ mloop_evsock_send(&mloop, &pack);
+}
+
+void mloop_evcmd_usbkbd(int on)
+{
+ struct mloop_evpack pack = { MLOOP_EVTYPE_USB_ADD, 13, "keyboard" };
+ if (on == 0) {
+ pack.type = MLOOP_EVTYPE_USB_DEL;
+ }
+ mloop_evsock_send(&mloop, &pack);
+}
+
+void mloop_evcmd_hostkbd(int on)
+{
+ struct mloop_evpack pack
+ = {MLOOP_EVTYPE_KBD_ADD, 13, "keyboard"};
+ if (on == 0) {
+ pack.type = MLOOP_EVTYPE_KBD_DEL;
+ }
+ mloop_evsock_send(&mloop, &pack);
+}
+
+void mloop_evcmd_usbdisk(char *img)
+{
+ struct mloop_evpack pack;
+
+ if (img) {
+ if (strlen(img) > PACKET_LEN-5) {
+ ERR("The length of disk image path is greater than "
+ "lenth of maximum packet.\n");
+ return;
+ }
+
+ pack.type = MLOOP_EVTYPE_USB_ADD;
+ pack.size = 5 + sprintf(pack.data, "disk:%s", img);
+ } else {
+ pack.type = MLOOP_EVTYPE_USB_DEL;
+ pack.size = 5 + sprintf(pack.data, "disk:");
+ }
+
+ mloop_evsock_send(&mloop, &pack);
+}
+
+void mloop_evcmd_sdcard(char *img)
+{
+ struct mloop_evpack pack;
+
+ if (img) {
+ if (strlen(img) > PACKET_LEN-5) {
+ ERR("The length of disk image path is greater than "
+ "lenth of maximum packet.\n");
+ return;
+ }
+
+ pack.type = MLOOP_EVTYPE_SDCARD_ATTACH;
+ pack.size = 5 + sprintf(pack.data, "%s", img);
+ } else {
+ pack.type = MLOOP_EVTYPE_SDCARD_DETACH;
+ pack.size = 5;
+ }
+
+ mloop_evsock_send(&mloop, &pack);
+}
+
+int mloop_evcmd_get_usbkbd_status(void)
+{
+ return (usbkbd && usbkbd->attached ? 1 : 0);
+}
+
+void mloop_evcmd_set_usbkbd(void *dev)
+{
+ usbkbd = (USBDevice *)dev;
+}
+
+void mloop_evcmd_set_usbdisk(void *dev)
+{
+ usbdisk = (USBDevice *)dev;
+}
+
+void mloop_evcmd_touch(void)
+{
+ struct mloop_evpack pack;
+ memset(&pack, 0, sizeof(struct mloop_evpack));
+
+ pack.type = MLOOP_EVTYPE_TOUCH;
+ pack.size = 5;
+ mloop_evsock_send(&mloop, &pack);
+}
+
+void mloop_evcmd_keyboard(void *data)
+{
+ struct mloop_evpack pack;
+ memset(&pack, 0, sizeof(struct mloop_evpack));
+
+ pack.type = MLOOP_EVTYPE_KEYBOARD;
+ pack.size = 4 + 8;
+ *((VirtIOKeyboard **)pack.data) = (VirtIOKeyboard *)data;
+ mloop_evsock_send(&mloop, &pack);
+}
+
+void mloop_evcmd_ramdump(void)
+{
+ struct mloop_evpack pack;
+ memset(&pack, 0, sizeof(struct mloop_evpack));
+
+ pack.type = MLOOP_EVTYPE_RAMDUMP;
+ pack.size = 5;
+ mloop_evsock_send(&mloop, &pack);
+}
#include "qapi-types.h"
#include "ui/keymaps.h"
+//#include "tizen/src/debug_ch.h"
+
+//MULTI_DEBUG_CHANNEL(tizen, input);
+
struct QEMUPutMouseEntry {
QEMUPutMouseEvent *qemu_put_mouse_event;
void *qemu_put_mouse_event_opaque;
KeyValueList *p;
if (!key_timer) {
- key_timer = qemu_new_timer_ns(vm_clock, release_keys, NULL);
+ key_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, release_keys, NULL);
}
if (keycodes != NULL) {
- qemu_del_timer(key_timer);
+ timer_del(key_timer);
release_keys(NULL);
}
}
/* delayed key up events */
- qemu_mod_timer(key_timer, qemu_get_clock_ns(vm_clock) +
+ timer_mod(key_timer, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) +
muldiv64(get_ticks_per_sec(), hold_time, 1000));
}
if (QTAILQ_EMPTY(&mouse_handlers)) {
return;
}
+#if defined (CONFIG_MARU)
+ QTAILQ_FOREACH(entry, &mouse_handlers, node) {
+ /* if mouse event is wheelup ,wheeldown or move
+ then go to ps2 mouse event(index == 0) */
+ if (buttons_state > 3 && entry->index == 0) {
+ //INFO("input device: %s, event: %d\n", entry->qemu_put_mouse_event_name, buttons_state);
+ buttons_state = 0;
+ mouse_event = entry->qemu_put_mouse_event;
+ mouse_event_opaque = entry->qemu_put_mouse_event_opaque;
+ break;
+ }
+ }
+ /* other events(mouse up, down and drag), go to touch screen */
+ if (!entry) {
+ entry = QTAILQ_FIRST(&mouse_handlers);
+ mouse_event = entry->qemu_put_mouse_event;
+ mouse_event_opaque = entry->qemu_put_mouse_event_opaque;
+ //INFO("input device: %s, event: %d\n", entry->qemu_put_mouse_event_name, buttons_state);
+ }
+#else
entry = QTAILQ_FIRST(&mouse_handlers);
mouse_event = entry->qemu_put_mouse_event;
mouse_event_opaque = entry->qemu_put_mouse_event_opaque;
+#endif
if (mouse_event) {
if (entry->qemu_put_mouse_event_absolute) {
static void do_sdl_resize(int width, int height, int bpp)
{
int flags;
+ SDL_Surface *tmp_screen;
// printf("resizing to %d %d\n", w, h);
if (gui_noframe)
flags |= SDL_NOFRAME;
- real_screen = SDL_SetVideoMode(width, height, bpp, flags);
+ tmp_screen = SDL_SetVideoMode(width, height, bpp, flags);
if (!real_screen) {
- fprintf(stderr, "Could not open SDL display (%dx%dx%d): %s\n", width,
- height, bpp, SDL_GetError());
- exit(1);
+ if (!tmp_screen) {
+ fprintf(stderr, "Could not open SDL display (%dx%dx%d): %s\n",
+ width, height, bpp, SDL_GetError());
+ exit(1);
+ }
+ } else {
+ /*
+ * Revert to the previous video mode if the change of resizing or
+ * resolution failed.
+ */
+ if (!tmp_screen) {
+ fprintf(stderr, "Failed to set SDL display (%dx%dx%d): %s\n",
+ width, height, bpp, SDL_GetError());
+ return;
+ }
}
+
+ real_screen = tmp_screen;
}
static void sdl_switch(DisplayChangeListener *dcl,
#else
-#if defined(SDL_VIDEO_DRIVER_X11)
+#if (defined(SDL_VIDEO_DRIVER_X11) && !defined(__APPLE__))
#include <X11/XKBlib.h>
static int check_for_evdev(void)
else
status = " - Press Ctrl-Alt to exit mouse grab";
}
-
+
if (qemu_name) {
snprintf(win_title, sizeof(win_title), "QEMU (%s)%s", qemu_name, status);
snprintf(icon_title, sizeof(icon_title), "QEMU (%s)", qemu_name);
#include <sys/syscall.h>
#endif
+#ifdef CONFIG_MARU
+#include "../../tizen/src/maru_common.h"
+#endif
+
int qemu_get_thread_id(void)
{
#if defined(__linux__)
void *qemu_oom_check(void *ptr)
{
+#ifdef CONFIG_MARU
+ const char _msg[] = "Failed to allocate memory in qemu.";
+ char cmd[JAVA_MAX_COMMAND_LENGTH] = { 0, };
+ int len;
+#endif
+
if (ptr == NULL) {
fprintf(stderr, "Failed to allocate memory: %s\n", strerror(errno));
+#ifdef CONFIG_MARU
+ len = strlen(JAVA_EXEFILE_PATH) + strlen(JAVA_EXEOPTION) +
+ strlen(JAR_SKINFILE) + strlen(JAVA_SIMPLEMODE_OPTION) +
+ strlen(_msg) + 7;
+ if (len > JAVA_MAX_COMMAND_LENGTH) {
+ len = JAVA_MAX_COMMAND_LENGTH;
+ }
+
+ snprintf(cmd, len, "%s %s %s %s=\"%s\"",
+ JAVA_EXEFILE_PATH, JAVA_EXEOPTION, JAR_SKINFILE, JAVA_SIMPLEMODE_OPTION, _msg);
+ if (system(cmd) == -1) {
+ fprintf(stderr, "failed to execute this command: %s\n", cmd);
+ }
+#endif
abort();
}
return ptr;
size_t offset = QEMU_ALIGN_UP((uintptr_t)ptr, align) - (uintptr_t)ptr;
if (ptr == MAP_FAILED) {
- fprintf(stderr, "Failed to allocate %zu B: %s\n",
- size, strerror(errno));
- abort();
+ return NULL;
}
ptr += offset;
fcntl(fd, F_SETFL, f | O_NONBLOCK);
}
+ int socket_set_fast_reuse(int fd)
+ {
+ int val = 1, ret;
+
+ ret = setsockopt(fd, SOL_SOCKET, SO_REUSEADDR,
+ (const char *)&val, sizeof(val));
+
+ assert(ret == 0);
+
+ return ret;
+ }
+
void qemu_set_cloexec(int fd)
{
int f;
#include "qemu/main-loop.h"
#include "trace.h"
#include "qemu/sockets.h"
-
/* this must come after including "trace.h" */
#include <shlobj.h>
+#ifdef CONFIG_MARU
+typedef BOOL (WINAPI *LPFN_ISWOW64PROCESS) (HANDLE, PBOOL);
+LPFN_ISWOW64PROCESS fnIsWow64Process;
+
+int is_wow64(void)
+{
+ int result = 0;
+
+ /* IsWow64Process is not available on all supported versions of Windows.
+ Use GetModuleHandle to get a handle to the DLL that contains the function
+ and GetProcAddress to get a pointer to the function if available. */
+
+ fnIsWow64Process = (LPFN_ISWOW64PROCESS) GetProcAddress(
+ GetModuleHandle(TEXT("kernel32")),"IsWow64Process");
+
+ if (NULL != fnIsWow64Process) {
+ if (!fnIsWow64Process(GetCurrentProcess(),&result)) {
+ // handle error
+ fprintf(stderr, "Cannot find 'IsWow64Process'\n");
+ }
+ }
+ return result;
+}
+
+bool get_java_path(char** java_path)
+{
+ HKEY hKeyNew;
+ HKEY hKey;
+ //char strJavaRuntimePath[JAVA_MAX_COMMAND_LENGTH] = {0};
+ char strChoosenName[JAVA_MAX_COMMAND_LENGTH] = {0};
+ char strSubKeyName[JAVA_MAX_COMMAND_LENGTH] = {0};
+ char strJavaHome[JAVA_MAX_COMMAND_LENGTH] = {0};
+ int index;
+ DWORD dwSubKeyNameMax = JAVA_MAX_COMMAND_LENGTH;
+ DWORD dwBufLen = JAVA_MAX_COMMAND_LENGTH;
+
+ RegOpenKeyEx(HKEY_LOCAL_MACHINE,
+ "SOFTWARE\\JavaSoft\\Java Runtime Environment",
+ 0,
+ KEY_QUERY_VALUE | KEY_ENUMERATE_SUB_KEYS | MY_KEY_WOW64_64KEY,
+ &hKey);
+ RegEnumKeyEx(hKey, 0, (LPSTR)strSubKeyName, &dwSubKeyNameMax,
+ NULL, NULL, NULL, NULL);
+ strcpy(strChoosenName, strSubKeyName);
+
+ index = 1;
+ while (ERROR_SUCCESS ==
+ RegEnumKeyEx(hKey, index, (LPSTR)strSubKeyName, &dwSubKeyNameMax,
+ NULL, NULL, NULL, NULL)) {
+ if (strcmp(strChoosenName, strSubKeyName) < 0) {
+ strcpy(strChoosenName, strSubKeyName);
+ }
+ index++;
+ }
+
+ RegOpenKeyEx(hKey, strChoosenName, 0,
+ KEY_QUERY_VALUE | MY_KEY_WOW64_64KEY, &hKeyNew);
+ RegQueryValueEx(hKeyNew, "JavaHome", NULL,
+ NULL, (LPBYTE)strJavaHome, &dwBufLen);
+ RegCloseKey(hKey);
+ if (strJavaHome[0] != '\0') {
+ sprintf(*java_path, "\"%s\\bin\\java\"", strJavaHome);
+ //strcpy(*java_path, strJavaHome);
+ //strcat(*java_path, "\\bin\\java");
+ } else {
+ return false;
+ }
+
+ return true;
+}
+#endif
+
void *qemu_oom_check(void *ptr)
{
+#ifdef CONFIG_MARU
+ const char _msg[] = "Failed to allocate memory in qemu.";
+ char cmd[JAVA_MAX_COMMAND_LENGTH] = { 0, };
+ char *JAVA_EXEFILE_PATH = NULL;
+ int len, ret;
+#endif
+
if (ptr == NULL) {
fprintf(stderr, "Failed to allocate memory: %lu\n", GetLastError());
+#ifdef CONFIG_MARU
+ JAVA_EXEFILE_PATH = malloc(JAVA_MAX_COMMAND_LENGTH);
+ if (!JAVA_EXEFILE_PATH) {
+ // TODO: print error message.
+ return ptr;
+ }
+
+ memset(JAVA_EXEFILE_PATH, 0, JAVA_MAX_COMMAND_LENGTH);
+ if (is_wow64()) {
+ if (!get_java_path(&JAVA_EXEFILE_PATH)) {
+ strcpy(JAVA_EXEFILE_PATH, "java");
+ }
+ } else {
+ strcpy(JAVA_EXEFILE_PATH, "java");
+ }
+ len = strlen(JAVA_EXEFILE_PATH) + strlen(JAVA_EXEOPTION) +
+ strlen(JAR_SKINFILE) + strlen(JAVA_SIMPLEMODE_OPTION) +
+ strlen(_msg) + 7;
+ if (len > JAVA_MAX_COMMAND_LENGTH) {
+ len = JAVA_MAX_COMMAND_LENGTH;
+ }
+
+ snprintf(cmd, len, "%s %s %s %s=\"%s\"",
+ JAVA_EXEFILE_PATH, JAVA_EXEOPTION, JAR_SKINFILE,
+ JAVA_SIMPLEMODE_OPTION, _msg);
+ ret = WinExec(cmd, SW_SHOW);
+ if (ret < 32) {
+ // TODO: error handling...
+ }
+
+ /* for 64bit windows */
+ free(JAVA_EXEFILE_PATH);
+ JAVA_EXEFILE_PATH=0;
+#endif
abort();
}
return ptr;
/* FIXME: this is not exactly optimal solution since VirtualAlloc
has 64Kb granularity, but at least it guarantees us that the
memory is page aligned. */
- if (!size) {
- abort();
- }
- ptr = qemu_oom_check(VirtualAlloc(NULL, size, MEM_COMMIT, PAGE_READWRITE));
+ ptr = VirtualAlloc(NULL, size, MEM_COMMIT, PAGE_READWRITE);
trace_qemu_anon_ram_alloc(size, ptr);
return ptr;
}
qemu_fd_register(fd);
}
+ int socket_set_fast_reuse(int fd)
+ {
+ /* Enabling the reuse of an endpoint that was used by a socket still in
+ * TIME_WAIT state is usually performed by setting SO_REUSEADDR. On Windows
+ * fast reuse is the default and SO_REUSEADDR does strange things. So we
+ * don't have to do anything here. More info can be found at:
+ * http://msdn.microsoft.com/en-us/library/windows/desktop/ms740621.aspx */
+ return 0;
+ }
+
int inet_aton(const char *cp, struct in_addr *ia)
{
uint32_t addr = inet_addr(cp);
continue;
}
- qemu_setsockopt(slisten, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
+ socket_set_fast_reuse(slisten);
#ifdef IPV6_V6ONLY
if (e->ai_family == PF_INET6) {
/* listen on both ipv4 and ipv6 */
error_set_errno(errp, errno, QERR_SOCKET_CREATE_FAILED);
return -1;
}
- qemu_setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
+ socket_set_fast_reuse(sock);
if (connect_state != NULL) {
qemu_set_nonblock(sock);
}
ai.ai_family = PF_INET6;
}
+#ifdef CONFIG_MARU
+ // for lookup loopback interface...
+ if (addr[0] == '\0') {
+ ai.ai_flags = 0;
+ addr = NULL;
+ }
+#endif
+
/* lookup */
rc = getaddrinfo(addr, port, &ai, &res);
if (rc != 0) {
error_set_errno(errp, errno, QERR_SOCKET_CREATE_FAILED);
goto err;
}
- qemu_setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
+ socket_set_fast_reuse(sock);
/* bind socket */
if (bind(sock, local->ai_addr, local->ai_addrlen) < 0) {
#ifdef CONFIG_SDL
#if defined(__APPLE__) || defined(main)
#include <SDL.h>
+#ifndef CONFIG_MARU
int qemu_main(int argc, char **argv, char **envp);
int main(int argc, char **argv)
{
#undef main
#define main qemu_main
#endif
+#endif
#endif /* CONFIG_SDL */
#ifdef CONFIG_COCOA
#define main qemu_main
#endif /* CONFIG_COCOA */
+#ifdef CONFIG_MARU
+#ifdef main
+#undef main
+#endif
+int qemu_main(int argc, char **argv, char **envp);
+#define main qemu_main
+#endif
+
#include <glib.h>
#include "hw/hw.h"
#include "audio/audio.h"
#include "migration/migration.h"
#include "sysemu/kvm.h"
+#include "sysemu/hax.h"
#include "qapi/qmp/qjson.h"
#include "qemu/option.h"
#include "qemu/config-file.h"
#include "ui/qemu-spice.h"
#include "qapi/string-input-visitor.h"
+#ifdef CONFIG_MARU
+#include "tizen/src/maru_common.h"
+#include "tizen/src/emulator.h"
+#include "tizen/src/maru_err_table.h"
+#include "tizen/src/emul_state.h"
+#include "tizen/src/maru_display.h"
+#include "tizen/src/skin/maruskin_operation.h"
+#include "tizen/src/ecs/ecs.h"
+#endif
+
//#define DEBUG_NET
//#define DEBUG_SLIRP
#define MAX_VIRTIO_CONSOLES 1
#define MAX_SCLP_CONSOLES 1
+#ifdef CONFIG_MARU
+int skin_disabled = 0;
+//virtio-gl
+extern int enable_gl;
+extern int enable_yagl;
+extern int enable_spice;
+const char *yagl_backend = NULL;
+int enable_vigs = 0;
+char *vigs_backend = NULL;
+#endif
+
static const char *data_dir[16];
static int data_dir_idx;
const char *bios_name = NULL;
int autostart;
static int rtc_utc = 1;
static int rtc_date_offset = -1; /* -1 means no change */
- QEMUClock *rtc_clock;
+ QEMUClockType rtc_clock;
int vga_interface_type = VGA_NONE;
static int full_screen = 0;
static int no_frame = 0;
unsigned long *node_cpumask[MAX_NODES];
uint8_t qemu_uuid[16];
+ bool qemu_uuid_set;
static QEMUBootSetHandler *boot_set_handler;
static void *boot_set_opaque;
static bool tcg_allowed = true;
bool xen_allowed;
+// FIXME: ??
+int hax_allowed = 0;
+//
uint32_t xen_domid;
enum xen_mode xen_mode = XEN_EMULATE;
static int tcg_tb_size;
{ RUN_STATE_WATCHDOG, RUN_STATE_RUNNING },
{ RUN_STATE_WATCHDOG, RUN_STATE_FINISH_MIGRATE },
- { RUN_STATE_GUEST_PANICKED, RUN_STATE_PAUSED },
+ { RUN_STATE_GUEST_PANICKED, RUN_STATE_RUNNING },
{ RUN_STATE_GUEST_PANICKED, RUN_STATE_FINISH_MIGRATE },
- { RUN_STATE_GUEST_PANICKED, RUN_STATE_DEBUG },
{ RUN_STATE_MAX, RUN_STATE_MAX },
};
bool runstate_needs_reset(void)
{
return runstate_check(RUN_STATE_INTERNAL_ERROR) ||
- runstate_check(RUN_STATE_SHUTDOWN) ||
- runstate_check(RUN_STATE_GUEST_PANICKED);
+ runstate_check(RUN_STATE_SHUTDOWN);
}
StatusInfo *qmp_query_status(Error **errp)
value = qemu_opt_get(opts, "clock");
if (value) {
if (!strcmp(value, "host")) {
- rtc_clock = host_clock;
+ rtc_clock = QEMU_CLOCK_HOST;
} else if (!strcmp(value, "rt")) {
- rtc_clock = rt_clock;
+ rtc_clock = QEMU_CLOCK_REALTIME;
} else if (!strcmp(value, "vm")) {
- rtc_clock = vm_clock;
+ rtc_clock = QEMU_CLOCK_VIRTUAL;
} else {
fprintf(stderr, "qemu: invalid option value '%s'\n", value);
exit(1);
static int cur_hci;
static struct HCIInfo *hci_table[MAX_NICS];
- static struct bt_vlan_s {
- struct bt_scatternet_s net;
- int id;
- struct bt_vlan_s *next;
- } *first_bt_vlan;
-
- /* find or alloc a new bluetooth "VLAN" */
- static struct bt_scatternet_s *qemu_find_bt_vlan(int id)
- {
- struct bt_vlan_s **pvlan, *vlan;
- for (vlan = first_bt_vlan; vlan != NULL; vlan = vlan->next) {
- if (vlan->id == id)
- return &vlan->net;
- }
- vlan = g_malloc0(sizeof(struct bt_vlan_s));
- vlan->id = id;
- pvlan = &first_bt_vlan;
- while (*pvlan != NULL)
- pvlan = &(*pvlan)->next;
- *pvlan = vlan;
- return &vlan->net;
- }
-
- static void null_hci_send(struct HCIInfo *hci, const uint8_t *data, int len)
- {
- }
-
- static int null_hci_addr_set(struct HCIInfo *hci, const uint8_t *bd_addr)
- {
- return -ENOTSUP;
- }
-
- static struct HCIInfo null_hci = {
- .cmd_send = null_hci_send,
- .sco_send = null_hci_send,
- .acl_send = null_hci_send,
- .bdaddr_set = null_hci_addr_set,
- };
-
struct HCIInfo *qemu_next_hci(void)
{
if (cur_hci == nb_hcis)
return hci_table[cur_hci++];
}
- static struct HCIInfo *hci_init(const char *str)
- {
- char *endp;
- struct bt_scatternet_s *vlan = 0;
-
- if (!strcmp(str, "null"))
- /* null */
- return &null_hci;
- else if (!strncmp(str, "host", 4) && (str[4] == '\0' || str[4] == ':'))
- /* host[:hciN] */
- return bt_host_hci(str[4] ? str + 5 : "hci0");
- else if (!strncmp(str, "hci", 3)) {
- /* hci[,vlan=n] */
- if (str[3]) {
- if (!strncmp(str + 3, ",vlan=", 6)) {
- vlan = qemu_find_bt_vlan(strtol(str + 9, &endp, 0));
- if (*endp)
- vlan = 0;
- }
- } else
- vlan = qemu_find_bt_vlan(0);
- if (vlan)
- return bt_new_hci(vlan);
- }
-
- fprintf(stderr, "qemu: Unknown bluetooth HCI `%s'.\n", str);
-
- return 0;
- }
-
static int bt_hci_parse(const char *str)
{
struct HCIInfo *hci;
static int usb_device_add(const char *devname)
{
- const char *p;
USBDevice *dev = NULL;
+ #ifndef CONFIG_LINUX
+ const char *p;
+ #endif
if (!usb_enabled(false)) {
return -1;
/* only the linux version is qdev-ified, usb-bsd still needs this */
if (strstart(devname, "host:", &p)) {
dev = usb_host_device_open(usb_bus_find(-1), p);
- } else
- #endif
- if (!strcmp(devname, "bt") || strstart(devname, "bt:", &p)) {
- dev = usb_bt_init(usb_bus_find(-1),
- devname[2] ? hci_init(p)
- : bt_new_hci(qemu_find_bt_vlan(0)));
- } else {
- return -1;
}
+ #endif
if (!dev)
return -1;
void qemu_system_wakeup_request(WakeupReason reason)
{
+
if (!runstate_check(RUN_STATE_SUSPENDED)) {
return;
}
shutdown_signal = signal;
shutdown_pid = pid;
no_shutdown = 0;
+
+#ifdef CONFIG_MARU
+ shutdown_qemu_gracefully();
+#else
qemu_system_shutdown_request();
+#endif
}
void qemu_system_shutdown_request(void)
if (qemu_wakeup_requested()) {
pause_all_vcpus();
cpu_synchronize_all_states();
+#ifndef CONFIG_MARU
+ // A "system reset" causes "virtio_queue" malfunction.
+ // It might be a bug of virtio bus or virtio devices.
+ // We don't want suspend(deep sleep), so It's OK now.
+ // However, we should fix it later.
qemu_system_reset(VMRESET_SILENT);
+#endif
notifier_list_notify(&wakeup_notifiers, &wakeup_reason);
wakeup_reason = QEMU_WAKEUP_REASON_NONE;
resume_all_vcpus();
#ifdef CONFIG_PROFILER
int64_t ti;
#endif
+
+ hax_sync_vcpus();
+
do {
- nonblocking = !kvm_enabled() && !xen_enabled() && last_io > 0;
+ nonblocking = !kvm_enabled() && !xen_enabled() && !hax_enabled() && last_io > 0;
#ifdef CONFIG_PROFILER
ti = profile_getclock();
#endif
return object_class_by_name("qxl-vga");
}
+#ifdef CONFIG_MARU
+static bool maru_vga_available(void)
+{
+ return object_class_by_name("MARU_VGA");
+}
+#endif
+
static void select_vgahw (const char *p)
{
const char *opts;
fprintf(stderr, "Error: QXL VGA not available\n");
exit(0);
}
+#ifdef CONFIG_MARU
+ } else if (strstart(p, "maru", &opts)) {
+ if (maru_vga_available()) {
+ vga_interface_type = VGA_MARU;
+ } else {
+ fprintf(stderr, "Error: MARU VGA not available\n");
+ exit(0);
+ }
+#endif
} else if (!strstart(p, "none", &opts)) {
invalid_vga:
fprintf(stderr, "Unknown vga type: %s\n", p);
{
DeviceState *dev;
+#ifdef CONFIG_MARU
+ if(maru_device_check(opts) == -1) {
+ return 0;
+ }
+#endif
+
dev = qdev_device_add(opts);
if (!dev)
return -1;
qemu_chr_new_from_opts(opts, NULL, &local_err);
if (error_is_set(&local_err)) {
- fprintf(stderr, "%s\n", error_get_pretty(local_err));
+ error_report("%s", error_get_pretty(local_err));
error_free(local_err);
return -1;
}
static int tcg_init(void)
{
+ int ret = 0;
tcg_exec_init(tcg_tb_size * 1024 * 1024);
- return 0;
+ ret = hax_accel_init();
+ return ret;
}
static struct {
if (!init_failed) {
fprintf(stderr, "No accelerator found!\n");
}
+#ifdef CONFIG_MARU
+ maru_register_exit_msg(MARU_EXIT_UNKNOWN, "No accelerator found.");
+#endif
exit(1);
}
for(;;) {
if (!popt->name) {
error_report("invalid option");
+#ifdef CONFIG_MARU
+ maru_register_exit_msg(MARU_EXIT_UNKNOWN, "invalid option.");
+#endif
exit(1);
}
if (!strcmp(popt->name, r + 1))
if (popt->flags & HAS_ARG) {
if (optind >= argc) {
error_report("requires an argument");
+#ifdef CONFIG_MARU
+ maru_register_exit_msg(MARU_EXIT_UNKNOWN, "requires an argument.");
+#endif
exit(1);
}
optarg = argv[optind++];
return 0;
}
+#ifdef CONFIG_MARU
+int use_qemu_display = 0; //0:use tizen qemu sdl, 1:use original qemu sdl
+// W/A for preserve larger continuous heap for RAM.
+void *preallocated_ptr = 0;
+#endif
+
int main(int argc, char **argv, char **envp)
{
int i;
const char *icount_option = NULL;
const char *initrd_filename;
const char *kernel_filename, *kernel_cmdline;
- const char *boot_order = NULL;
+ const char *boot_order;
DisplayState *ds;
int cyls, heads, secs, translation;
QemuOpts *hda_opts = NULL, *opts, *machine_opts;
module_call_init(MODULE_INIT_QOM);
qemu_add_opts(&qemu_drive_opts);
+ qemu_add_drive_opts(&qemu_legacy_drive_opts);
+ qemu_add_drive_opts(&qemu_common_drive_opts);
+ qemu_add_drive_opts(&qemu_drive_opts);
qemu_add_opts(&qemu_chardev_opts);
qemu_add_opts(&qemu_device_opts);
qemu_add_opts(&qemu_netdev_opts);
runstate_init();
init_clocks();
- rtc_clock = host_clock;
+ rtc_clock = QEMU_CLOCK_HOST;
qemu_cache_utils_init(envp);
do_acpitable_option(opts);
break;
case QEMU_OPTION_smbios:
- do_smbios_option(optarg);
+ opts = qemu_opts_parse(qemu_find_opts("smbios"), optarg, 0);
+ do_smbios_option(opts);
break;
case QEMU_OPTION_enable_kvm:
olist = qemu_find_opts("machine");
qemu_opts_parse(olist, "accel=kvm", 0);
break;
+ case QEMU_OPTION_enable_gl:
+#if defined(CONFIG_MARU) && defined(CONFIG_GL_BACKEND)
+ enable_gl = 1;
+#else
+ fprintf(stderr, "Virtio GL support is disabled, ignoring -enable-gl\n");
+#endif
+ break;
+ case QEMU_OPTION_enable_yagl:
+#if defined(CONFIG_YAGL)
+ enable_yagl = 1;
+#else
+ fprintf(stderr, "YaGL openGLES passthrough support is disabled,"
+ " ignoring -enable-yagl\n");
+#endif
+ break;
+ case QEMU_OPTION_yagl_backend:
+#if defined(CONFIG_YAGL)
+ yagl_backend = optarg;
+#else
+ fprintf(stderr, "YaGL openGLES passthrough support is disabled,"
+ " ignoring -yagl-backend\n");
+#endif
+ break;
+ case QEMU_OPTION_enable_vigs:
+#if defined(CONFIG_VIGS)
+ enable_vigs = 1;
+#else
+ fprintf(stderr, "VIGS support is disabled,"
+ " ignoring -enable-vigs\n");
+#endif
+ break;
+ case QEMU_OPTION_vigs_backend:
+#if defined(CONFIG_VIGS)
+ vigs_backend = g_strdup(optarg);
+#else
+ fprintf(stderr, "VIGS support is disabled,"
+ " ignoring -vigs-backend\n");
+#endif
+ break;
case QEMU_OPTION_machine:
olist = qemu_find_opts("machine");
opts = qemu_opts_parse(olist, optarg, 1);
" Wrong format.\n");
exit(1);
}
+ qemu_uuid_set = true;
break;
case QEMU_OPTION_option_rom:
if (nb_option_roms >= MAX_OPTION_ROMS) {
old_param = 1;
break;
case QEMU_OPTION_clock:
- configure_alarms(optarg);
+ /* Clock options no longer exist. Keep this option for
+ * backward compatibility.
+ */
break;
case QEMU_OPTION_startdate:
configure_rtc_date_offset(optarg, 1);
fprintf(stderr, "spice is not supported by this qemu build.\n");
exit(1);
}
+#ifdef CONFIG_MARU
+ enable_spice = 1;
+#endif
opts = qemu_opts_parse(olist, optarg, 0);
if (!opts) {
exit(1);
exit(1);
}
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
case QEMU_OPTION_add_fd:
#ifndef _WIN32
opts = qemu_opts_parse(qemu_find_opts("add-fd"), optarg, 0);
exit(1);
#endif
break;
+#ifdef CONFIG_MARU
+ case QEMU_OPTION_enable_suspend:
+ ecs_set_suspend_state(SUSPEND_UNLOCK);
+ break;
+#endif
case QEMU_OPTION_object:
opts = qemu_opts_parse(qemu_find_opts("object"), optarg, 1);
if (!opts) {
exit(0);
}
+#if defined(CONFIG_MARU)
+ if (enable_gl && enable_yagl) {
+ fprintf (stderr, "Error: only one openGL passthrough device can be used at one time!\n");
+ exit(1);
+ }
+
+ if (enable_vigs) {
+ if (!vigs_backend) {
+ vigs_backend = g_strdup("gl");
+ }
+
+ if (strcmp(vigs_backend, "gl") != 0 && strcmp(vigs_backend, "sw") != 0) {
+ fprintf (stderr, "Error: Bad VIGS backend - %s!\n", vigs_backend);
+ exit(1);
+ }
+ }
+
+ if (enable_yagl) {
+ if (!yagl_backend) {
+ yagl_backend = "offscreen";
+ }
+
+ if (strcmp(yagl_backend, "offscreen") != 0) {
+ if (strcmp(yagl_backend, "vigs") == 0) {
+ if (!enable_vigs) {
+ fprintf (stderr, "Error: Bad YaGL backend - %s, VIGS not enabled!\n", yagl_backend);
+ exit(1);
+ }
+ if (strcmp(vigs_backend, "gl") != 0) {
+ fprintf (stderr, "Error: Bad YaGL backend - %s, VIGS is not configured with gl backend!\n", yagl_backend);
+ exit(1);
+ }
+ } else {
+ fprintf (stderr, "Error: Bad YaGL backend - %s!\n", yagl_backend);
+ exit(1);
+ }
+ }
+ }
+#endif
/* Open the logfile at this point, if necessary. We can't open the logfile
* when encountering either of the logging options (-d or -D) because the
* other one may be encountered later on the command line, changing the
}
if (display_type == DT_DEFAULT && !display_remote) {
-#if defined(CONFIG_GTK)
+#if defined(CONFIG_MARU)
+ display_type = DT_MARU;
+#elif defined(CONFIG_GTK)
display_type = DT_GTK;
#elif defined(CONFIG_SDL) || defined(CONFIG_COCOA)
display_type = DT_SDL;
}
#endif
+#ifndef CONFIG_MARU
socket_init();
+#endif
if (qemu_opts_foreach(qemu_find_opts("chardev"), chardev_init_func, NULL, 1) != 0)
exit(1);
if (ram_size == 0) {
ram_size = DEFAULT_RAM_SIZE * 1024 * 1024;
}
+#ifdef CONFIG_MARU
+ // W/A for preserve larger continuous heap for RAM.
+ preallocated_ptr = g_malloc(ram_size);
+#endif
+
+ hax_pre_init(ram_size);
if (qemu_opts_foreach(qemu_find_opts("device"), device_help_func, NULL, 0)
!= 0) {
initrd_filename = qemu_opt_get(machine_opts, "initrd");
kernel_cmdline = qemu_opt_get(machine_opts, "append");
- if (!boot_order) {
- boot_order = machine->boot_order;
- }
+ boot_order = machine->default_boot_order;
opts = qemu_opts_find(qemu_find_opts("boot-opts"), NULL);
if (opts) {
char *normal_boot_order;
qemu_spice_init();
#endif
- if (icount_option && (kvm_enabled() || xen_enabled())) {
+ if (icount_option && (kvm_enabled() || xen_enabled() || hax_enabled())) {
fprintf(stderr, "-icount is not allowed with kvm or xen\n");
exit(1);
}
qdev_machine_init();
+#ifdef CONFIG_MARU
+ // Returned variable points different address from input variable.
+ kernel_cmdline = prepare_maru_devices(kernel_cmdline);
+#endif
QEMUMachineInitArgs args = { .ram_size = ram_size,
- .boot_device = boot_order,
+ .boot_order = boot_order,
.kernel_filename = kernel_filename,
.kernel_cmdline = kernel_cmdline,
.initrd_filename = initrd_filename,
.cpu_model = cpu_model };
machine->init(&args);
+ // TODO: Check about it...
audio_init();
cpu_synchronize_all_post_init();
current_machine = machine;
+ if (hax_enabled()) {
+ hax_sync_vcpus();
+ }
+
/* init USB devices */
if (usb_enabled(false)) {
if (foreach_device_config(DEV_USB, usb_parse) < 0)
/* init local displays */
switch (display_type) {
case DT_NOGRAPHIC:
+ (void)ds; /* avoid warning if no display is configured */
break;
#if defined(CONFIG_CURSES)
case DT_CURSES:
curses_display_init(ds, full_screen);
break;
#endif
+#if defined(CONFIG_MARU)
+ 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
#if defined(CONFIG_SDL)
case DT_SDL:
sdl_display_init(ds, full_screen, no_frame);
vnc_display_init(ds);
vnc_display_open(ds, vnc_display, &local_err);
if (local_err != NULL) {
- fprintf(stderr, "Failed to start VNC server on `%s': %s\n",
- vnc_display, error_get_pretty(local_err));
+ error_report("Failed to start VNC server on `%s': %s",
+ vnc_display, error_get_pretty(local_err));
error_free(local_err);
exit(1);
}
}
#endif
#ifdef CONFIG_SPICE
- if (using_spice && !spice_displays) {
- qemu_spice_display_init(ds);
+ if (using_spice) {
+ qemu_spice_display_init();
}
#endif
qemu_register_reset(qbus_reset_all_fn, sysbus_get_default());
qemu_run_machine_init_done_notifiers();
+ /* Done notifiers can load ROMs */
+ rom_load_done();
+
qemu_system_reset(VMRESET_SILENT);
if (loadvm) {
if (load_vmstate(loadvm) < 0) {
Error *local_err = NULL;
qemu_start_incoming_migration(incoming, &local_err);
if (local_err) {
- fprintf(stderr, "-incoming %s: %s\n", incoming, error_get_pretty(local_err));
+ error_report("-incoming %s: %s", incoming,
+ error_get_pretty(local_err));
error_free(local_err);
exit(1);
}
vm_start();
}
+#ifdef CONFIG_MARU
+ prepare_maru();
+#endif
+
os_setup_post();
main_loop();
ram_addr_t block_len;
block_len = ram_size;
- if (ram_size >= HVM_BELOW_4G_RAM_END) {
+ if (ram_size >= QEMU_BELOW_4G_RAM_END) {
/* Xen does not allocate the memory continuously, and keep a hole at
- * HVM_BELOW_4G_MMIO_START of HVM_BELOW_4G_MMIO_LENGTH
+ * QEMU_BELOW_4G_RAM_END of QEMU_BELOW_4G_MMIO_LENGTH
*/
- block_len += HVM_BELOW_4G_MMIO_LENGTH;
+ block_len += QEMU_BELOW_4G_MMIO_LENGTH;
}
memory_region_init_ram(&ram_memory, NULL, "xen.ram", block_len);
*ram_memory_p = &ram_memory;
vmstate_register_ram_global(&ram_memory);
- if (ram_size >= HVM_BELOW_4G_RAM_END) {
- above_4g_mem_size = ram_size - HVM_BELOW_4G_RAM_END;
- below_4g_mem_size = HVM_BELOW_4G_RAM_END;
+ if (ram_size >= QEMU_BELOW_4G_RAM_END) {
+ above_4g_mem_size = ram_size - QEMU_BELOW_4G_RAM_END;
+ below_4g_mem_size = QEMU_BELOW_4G_RAM_END;
} else {
below_4g_mem_size = ram_size;
}
port = xc_evtchn_pending(state->xce_handle);
if (port == state->bufioreq_local_port) {
- qemu_mod_timer(state->buffered_io_timer,
- BUFFER_IO_MAX_DELAY + qemu_get_clock_ms(rt_clock));
+ timer_mod(state->buffered_io_timer,
+ BUFFER_IO_MAX_DELAY + qemu_clock_get_ms(QEMU_CLOCK_REALTIME));
return NULL;
}
if (port != -1) {
- for (i = 0; i < smp_cpus; i++) {
+ for (i = 0; i < max_cpus; i++) {
if (state->ioreq_local_port[i] == port) {
break;
}
}
- if (i == smp_cpus) {
+ if (i == max_cpus) {
hw_error("Fatal error while trying to get io event!\n");
}
XenIOState *state = opaque;
if (handle_buffered_iopage(state)) {
- qemu_mod_timer(state->buffered_io_timer,
- BUFFER_IO_MAX_DELAY + qemu_get_clock_ms(rt_clock));
+ timer_mod(state->buffered_io_timer,
+ BUFFER_IO_MAX_DELAY + qemu_clock_get_ms(QEMU_CLOCK_REALTIME));
} else {
- qemu_del_timer(state->buffered_io_timer);
+ timer_del(state->buffered_io_timer);
xc_evtchn_unmask(state->xce_handle, state->bufioreq_local_port);
}
}
exit(1);
}
- snprintf(path, sizeof (path), "/local/domain/0/device-model/%u/state", xen_domid);
+ snprintf(path, sizeof (path), "device-model/%u/state", xen_domid);
if (!xs_write(xs, XBT_NULL, path, state, strlen(state))) {
fprintf(stderr, "error recording dm state\n");
exit(1);
evtchn_fd = xc_evtchn_fd(state->xce_handle);
}
- state->buffered_io_timer = qemu_new_timer_ms(rt_clock, handle_buffered_io,
+ state->buffered_io_timer = timer_new_ms(QEMU_CLOCK_REALTIME, handle_buffered_io,
state);
if (evtchn_fd != -1) {
hw_error("map buffered IO page returned error %d", errno);
}
- state->ioreq_local_port = g_malloc0(smp_cpus * sizeof (evtchn_port_t));
+ state->ioreq_local_port = g_malloc0(max_cpus * sizeof (evtchn_port_t));
/* FIXME: how about if we overflow the page here? */
- for (i = 0; i < smp_cpus; i++) {
+ for (i = 0; i < max_cpus; i++) {
rc = xc_evtchn_bind_interdomain(state->xce_handle, xen_domid,
xen_vcpu_eport(state->shared_page, i));
if (rc == -1) {