sim-card
/
qemu
Archived
10
0
Fork 0

Merge remote branch 'origin/master' into pci

Conflicts:
	exec.c
This commit is contained in:
Michael S. Tsirkin 2011-05-05 16:39:47 +03:00
commit 5300f1a548
393 changed files with 32254 additions and 6506 deletions

3
.gitignore vendored
View File

@ -44,6 +44,9 @@ QMP/qmp-commands.txt
*.ky
*.log
*.pdf
*.cps
*.fns
*.kys
*.pg
*.pyc
*.toc

6
.gitmodules vendored
View File

@ -4,3 +4,9 @@
[submodule "roms/seabios"]
path = roms/seabios
url = git://git.qemu.org/seabios.git/
[submodule "roms/SLOF"]
path = roms/SLOF
url = git://git.qemu.org/SLOF.git
[submodule "roms/ipxe"]
path = roms/ipxe
url = git://git.qemu.org/ipxe.git

View File

@ -214,6 +214,11 @@ M: Michael Walle <michael@walle.cc>
S: Maintained
F: hw/lm32_boards.c
milkymist
M: Michael Walle <michael@walle.cc>
S: Maintained
F: hw/milkymist.c
M68K Machines
-------------
an5206

View File

@ -112,38 +112,6 @@ ui/vnc.o: QEMU_CFLAGS += $(VNC_TLS_CFLAGS)
bt-host.o: QEMU_CFLAGS += $(BLUEZ_CFLAGS)
ifeq ($(TRACE_BACKEND),dtrace)
trace.h: trace.h-timestamp trace-dtrace.h
else
trace.h: trace.h-timestamp
endif
trace.h-timestamp: $(SRC_PATH)/trace-events config-host.mak
$(call quiet-command,sh $(SRC_PATH)/scripts/tracetool --$(TRACE_BACKEND) -h < $< > $@," GEN trace.h")
@cmp -s $@ trace.h || cp $@ trace.h
trace.c: trace.c-timestamp
trace.c-timestamp: $(SRC_PATH)/trace-events config-host.mak
$(call quiet-command,sh $(SRC_PATH)/scripts/tracetool --$(TRACE_BACKEND) -c < $< > $@," GEN trace.c")
@cmp -s $@ trace.c || cp $@ trace.c
trace.o: trace.c $(GENERATED_HEADERS)
trace-dtrace.h: trace-dtrace.dtrace
$(call quiet-command,dtrace -o $@ -h -s $<, " GEN trace-dtrace.h")
# Normal practice is to name DTrace probe file with a '.d' extension
# but that gets picked up by QEMU's Makefile as an external dependancy
# rule file. So we use '.dtrace' instead
trace-dtrace.dtrace: trace-dtrace.dtrace-timestamp
trace-dtrace.dtrace-timestamp: $(SRC_PATH)/trace-events config-host.mak
$(call quiet-command,sh $(SRC_PATH)/scripts/tracetool --$(TRACE_BACKEND) -d < $< > $@," GEN trace-dtrace.dtrace")
@cmp -s $@ trace-dtrace.dtrace || cp $@ trace-dtrace.dtrace
trace-dtrace.o: trace-dtrace.dtrace $(GENERATED_HEADERS)
$(call quiet-command,dtrace -o $@ -G -s $<, " GEN trace-dtrace.o")
simpletrace.o: simpletrace.c $(GENERATED_HEADERS)
version.o: $(SRC_PATH)/version.rc config-host.mak
$(call quiet-command,$(WINDRES) -I. -o $@ $<," RC $(TARGET_DIR)$@")
@ -173,6 +141,8 @@ check-qlist: check-qlist.o qlist.o qint.o $(CHECK_PROG_DEPS)
check-qfloat: check-qfloat.o qfloat.o $(CHECK_PROG_DEPS)
check-qjson: check-qjson.o qfloat.o qint.o qdict.o qstring.o qlist.o qbool.o qjson.o json-streamer.o json-lexer.o json-parser.o $(CHECK_PROG_DEPS)
QEMULIBS=libhw32 libhw64 libuser libdis libdis-user
clean:
# avoid old build problems by removing potentially incorrect old files
rm -f config.mak op-i386.h opc-i386.h gen-op-i386.h op-arm.h opc-arm.h gen-op-arm.h
@ -184,7 +154,7 @@ clean:
rm -f trace-dtrace.dtrace trace-dtrace.dtrace-timestamp
rm -f trace-dtrace.h trace-dtrace.h-timestamp
$(MAKE) -C tests clean
for d in $(ALL_SUBDIRS) libhw32 libhw64 libuser libdis libdis-user; do \
for d in $(ALL_SUBDIRS) $(QEMULIBS) libcacard; do \
if test -d $$d; then $(MAKE) -C $$d $@ || exit 1; fi; \
rm -f $$d/qemu-options.def; \
done
@ -193,9 +163,12 @@ 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
rm -f roms/seabios/config.mak roms/vgabios/config.mak
rm -f qemu-doc.info qemu-doc.aux qemu-doc.cp qemu-doc.dvi qemu-doc.fn qemu-doc.info qemu-doc.ky qemu-doc.log qemu-doc.pdf qemu-doc.pg qemu-doc.toc qemu-doc.tp qemu-doc.vr
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
rm -f qemu-doc.log qemu-doc.pdf qemu-doc.pg qemu-doc.toc qemu-doc.tp
rm -f qemu-doc.vr
rm -f qemu-tech.info qemu-tech.aux qemu-tech.cp qemu-tech.dvi qemu-tech.fn qemu-tech.info qemu-tech.ky qemu-tech.log qemu-tech.pdf qemu-tech.pg qemu-tech.toc qemu-tech.tp qemu-tech.vr
for d in $(TARGET_DIRS) libhw32 libhw64 libuser libdis libdis-user; do \
for d in $(TARGET_DIRS) $(QEMULIBS); do \
rm -rf $$d || exit 1 ; \
done
@ -207,13 +180,12 @@ ifdef INSTALL_BLOBS
BLOBS=bios.bin vgabios.bin vgabios-cirrus.bin \
vgabios-stdvga.bin vgabios-vmware.bin vgabios-qxl.bin \
ppc_rom.bin openbios-sparc32 openbios-sparc64 openbios-ppc \
gpxe-eepro100-80861209.rom \
pxe-e1000.bin \
pxe-ne2k_pci.bin pxe-pcnet.bin \
pxe-rtl8139.bin pxe-virtio.bin \
pxe-e1000.rom pxe-eepro100.rom pxe-ne2k_pci.rom \
pxe-pcnet.rom pxe-rtl8139.rom pxe-virtio.rom \
bamboo.dtb petalogix-s3adsp1800.dtb petalogix-ml605.dtb \
multiboot.bin linuxboot.bin \
s390-zipl.rom
s390-zipl.rom \
spapr-rtas.bin slof.bin
else
BLOBS=
endif
@ -355,10 +327,12 @@ tarbin:
$(datadir)/openbios-sparc32 \
$(datadir)/openbios-sparc64 \
$(datadir)/openbios-ppc \
$(datadir)/pxe-ne2k_pci.bin \
$(datadir)/pxe-rtl8139.bin \
$(datadir)/pxe-pcnet.bin \
$(datadir)/pxe-e1000.bin \
$(datadir)/pxe-e1000.rom \
$(datadir)/pxe-eepro100.rom \
$(datadir)/pxe-ne2k_pci.rom \
$(datadir)/pxe-pcnet.rom \
$(datadir)/pxe-rtl8139.rom \
$(datadir)/pxe-virtio.rom \
$(docdir)/qemu-doc.html \
$(docdir)/qemu-tech.html \
$(mandir)/man1/qemu.1 \

View File

@ -14,7 +14,7 @@ oslib-obj-$(CONFIG_POSIX) += oslib-posix.o
# block-obj-y is code used by both qemu system emulation and qemu-img
block-obj-y = cutils.o cache-utils.o qemu-malloc.o qemu-option.o module.o async.o
block-obj-y += nbd.o block.o aio.o aes.o qemu-config.o
block-obj-y += nbd.o block.o aio.o aes.o qemu-config.o qemu-progress.o qemu-sockets.o
block-obj-$(CONFIG_POSIX) += posix-aio-compat.o
block-obj-$(CONFIG_LINUX_AIO) += linux-aio.o
@ -94,11 +94,11 @@ common-obj-$(CONFIG_SSI_SD) += ssi-sd.o
common-obj-$(CONFIG_SD) += sd.o
common-obj-y += bt.o bt-host.o bt-vhci.o bt-l2cap.o bt-sdp.o bt-hci.o bt-hid.o usb-bt.o
common-obj-y += bt-hci-csr.o
common-obj-y += buffered_file.o migration.o migration-tcp.o qemu-sockets.o
common-obj-y += buffered_file.o migration.o migration-tcp.o
common-obj-y += qemu-char.o savevm.o #aio.o
common-obj-y += msmouse.o ps2.o
common-obj-y += qdev.o qdev-properties.o
common-obj-y += block-migration.o
common-obj-y += block-migration.o iohandler.o
common-obj-y += pflib.o
common-obj-y += bitmap.o bitops.o
@ -200,6 +200,8 @@ hw-obj-$(CONFIG_APM) += pm_smbus.o apm.o
hw-obj-$(CONFIG_DMA) += dma.o
hw-obj-$(CONFIG_HPET) += hpet.o
hw-obj-$(CONFIG_APPLESMC) += applesmc.o
hw-obj-$(CONFIG_SMARTCARD) += usb-ccid.o ccid-card-passthru.o
hw-obj-$(CONFIG_SMARTCARD_NSS) += ccid-card-emulated.o
# PPC devices
hw-obj-$(CONFIG_OPENPIC) += openpic.o
@ -240,7 +242,7 @@ hw-obj-$(CONFIG_LAN9118) += lan9118.o
hw-obj-$(CONFIG_NE2000_ISA) += ne2000-isa.o
# IDE
hw-obj-$(CONFIG_IDE_CORE) += ide/core.o
hw-obj-$(CONFIG_IDE_CORE) += ide/core.o ide/atapi.o
hw-obj-$(CONFIG_IDE_QDEV) += ide/qdev.o
hw-obj-$(CONFIG_IDE_PCI) += ide/pci.o
hw-obj-$(CONFIG_IDE_ISA) += ide/isa.o
@ -283,9 +285,13 @@ sound-obj-$(CONFIG_HDA) += intel-hda.o hda-audio.o
adlib.o fmopl.o: QEMU_CFLAGS += -DBUILD_Y8950=0
hw-obj-$(CONFIG_SOUND) += $(sound-obj-y)
hw-obj-$(CONFIG_REALLY_VIRTFS) += virtio-9p-debug.o
hw-obj-$(CONFIG_VIRTFS) += virtio-9p-local.o virtio-9p-xattr.o
hw-obj-$(CONFIG_VIRTFS) += virtio-9p-xattr-user.o virtio-9p-posix-acl.o
9pfs-nested-$(CONFIG_REALLY_VIRTFS) = virtio-9p-debug.o
9pfs-nested-$(CONFIG_VIRTFS) += virtio-9p-local.o virtio-9p-xattr.o
9pfs-nested-$(CONFIG_VIRTFS) += virtio-9p-xattr-user.o virtio-9p-posix-acl.o
hw-obj-$(CONFIG_VIRTFS) += $(addprefix 9pfs/, $(9pfs-nested-y))
$(addprefix 9pfs/, $(9pfs-nested-y)): CFLAGS += -I$(SRC_PATH)/hw/
######################################################################
# libdis
@ -309,6 +315,38 @@ libdis-$(CONFIG_SPARC_DIS) += sparc-dis.o
######################################################################
# trace
ifeq ($(TRACE_BACKEND),dtrace)
trace.h: trace.h-timestamp trace-dtrace.h
else
trace.h: trace.h-timestamp
endif
trace.h-timestamp: $(SRC_PATH)/trace-events config-host.mak
$(call quiet-command,sh $(SRC_PATH)/scripts/tracetool --$(TRACE_BACKEND) -h < $< > $@," GEN trace.h")
@cmp -s $@ trace.h || cp $@ trace.h
trace.c: trace.c-timestamp
trace.c-timestamp: $(SRC_PATH)/trace-events config-host.mak
$(call quiet-command,sh $(SRC_PATH)/scripts/tracetool --$(TRACE_BACKEND) -c < $< > $@," GEN trace.c")
@cmp -s $@ trace.c || cp $@ trace.c
trace.o: trace.c $(GENERATED_HEADERS)
trace-dtrace.h: trace-dtrace.dtrace
$(call quiet-command,dtrace -o $@ -h -s $<, " GEN trace-dtrace.h")
# Normal practice is to name DTrace probe file with a '.d' extension
# but that gets picked up by QEMU's Makefile as an external dependancy
# rule file. So we use '.dtrace' instead
trace-dtrace.dtrace: trace-dtrace.dtrace-timestamp
trace-dtrace.dtrace-timestamp: $(SRC_PATH)/trace-events config-host.mak
$(call quiet-command,sh $(SRC_PATH)/scripts/tracetool --$(TRACE_BACKEND) -d < $< > $@," GEN trace-dtrace.dtrace")
@cmp -s $@ trace-dtrace.dtrace || cp $@ trace-dtrace.dtrace
trace-dtrace.o: trace-dtrace.dtrace $(GENERATED_HEADERS)
$(call quiet-command,dtrace -o $@ -G -s $<, " GEN trace-dtrace.o")
simpletrace.o: simpletrace.c $(GENERATED_HEADERS)
ifeq ($(TRACE_BACKEND),dtrace)
trace-obj-y = trace-dtrace.o
else
@ -319,6 +357,11 @@ user-obj-y += qemu-timer-common.o
endif
endif
######################################################################
# smartcard
libcacard-y = cac.o event.o vcard.o vreader.o vcard_emul_nss.o vcard_emul_type.o card_7816.o
vl.o: QEMU_CFLAGS+=$(GPROF_CFLAGS)
vl.o: QEMU_CFLAGS+=$(SDL_CFLAGS)

View File

@ -94,7 +94,7 @@ tcg/tcg.o: cpu.h
# HELPER_CFLAGS is used for all the code compiled with static register
# variables
op_helper.o cpu-exec.o: QEMU_CFLAGS += $(HELPER_CFLAGS)
%_helper.o cpu-exec.o: QEMU_CFLAGS += $(HELPER_CFLAGS)
# Note: this is a workaround. The real fix is to avoid compiling
# cpu_signal_handler() in cpu-exec.c.
@ -194,7 +194,7 @@ obj-$(CONFIG_VIRTIO) += virtio-blk.o virtio-balloon.o virtio-net.o virtio-serial
obj-$(CONFIG_VIRTIO_PCI) += virtio-pci.o
obj-y += vhost_net.o
obj-$(CONFIG_VHOST_NET) += vhost.o
obj-$(CONFIG_REALLY_VIRTFS) += virtio-9p.o
obj-$(CONFIG_REALLY_VIRTFS) += 9pfs/virtio-9p.o
obj-y += rwhandler.o
obj-$(CONFIG_KVM) += kvm.o kvm-all.o
obj-$(CONFIG_NO_KVM) += kvm-stub.o
@ -209,7 +209,13 @@ QEMU_CFLAGS += $(VNC_PNG_CFLAGS)
obj-$(CONFIG_XEN) += xen_machine_pv.o xen_domainbuild.o
# Inter-VM PCI shared memory
obj-$(CONFIG_KVM) += ivshmem.o
CONFIG_IVSHMEM =
ifeq ($(CONFIG_KVM), y)
ifeq ($(CONFIG_PCI), y)
CONFIG_IVSHMEM = y
endif
endif
obj-$(CONFIG_IVSHMEM) += ivshmem.o
# Hardware support
obj-i386-y += vga.o
@ -231,6 +237,11 @@ obj-ppc-y += ppc_prep.o
obj-ppc-y += ppc_oldworld.o
# NewWorld PowerMac
obj-ppc-y += ppc_newworld.o
# IBM pSeries (sPAPR)
ifeq ($(CONFIG_FDT)$(TARGET_PPC64),yy)
obj-ppc-y += spapr.o spapr_hcall.o spapr_rtas.o spapr_vio.o
obj-ppc-y += xics.o spapr_vty.o spapr_llan.o spapr_vscsi.o
endif
# PowerPC 4xx boards
obj-ppc-y += ppc4xx_devs.o ppc4xx_pci.o ppc405_uc.o ppc405_boards.o
obj-ppc-y += ppc440.o ppc440_bamboo.o
@ -249,6 +260,7 @@ obj-ppc-y += xilinx_ethlite.o
# LM32 boards
obj-lm32-y += lm32_boards.o
obj-lm32-y += milkymist.o
# LM32 peripherals
obj-lm32-y += lm32_pic.o
@ -256,6 +268,17 @@ obj-lm32-y += lm32_juart.o
obj-lm32-y += lm32_timer.o
obj-lm32-y += lm32_uart.o
obj-lm32-y += lm32_sys.o
obj-lm32-y += milkymist-ac97.o
obj-lm32-y += milkymist-hpdmc.o
obj-lm32-y += milkymist-memcard.o
obj-lm32-y += milkymist-minimac2.o
obj-lm32-y += milkymist-pfpu.o
obj-lm32-y += milkymist-softusb.o
obj-lm32-y += milkymist-sysctl.o
obj-lm32-$(CONFIG_OPENGL) += milkymist-tmu2.o
obj-lm32-y += milkymist-uart.o
obj-lm32-y += milkymist-vgafb.o
obj-lm32-y += framebuffer.o
obj-mips-y = mips_r4k.o mips_jazz.o mips_malta.o mips_mipssim.o
obj-mips-y += mips_addr.o mips_timer.o mips_int.o
@ -328,6 +351,9 @@ obj-arm-y += framebuffer.o
obj-arm-y += syborg.o syborg_fb.o syborg_interrupt.o syborg_keyboard.o
obj-arm-y += syborg_serial.o syborg_timer.o syborg_pointer.o syborg_rtc.o
obj-arm-y += syborg_virtio.o
obj-arm-y += vexpress.o
obj-arm-y += strongarm.o
obj-arm-y += collie.o
obj-sh4-y = shix.o r2d.o sh7750.o sh7750_regnames.o tc58128.o
obj-sh4-y += sh_timer.o sh_serial.o sh_intc.o sh_pci.o sm501.o
@ -353,6 +379,12 @@ obj-y += $(addprefix $(HWDIR)/, $(hw-obj-y))
endif # CONFIG_SOFTMMU
ifndef CONFIG_LINUX_USER
# libcacard needs qemu-thread support, and besides is only needed by devices
# so not requires with linux-user targets
obj-$(CONFIG_SMARTCARD_NSS) += $(addprefix ../libcacard/, $(libcacard-y))
endif # CONFIG_LINUX_USER
obj-y += $(addprefix ../, $(trace-obj-y))
obj-$(CONFIG_GDBSTUB_XML) += gdbstub-xml.o
@ -369,9 +401,11 @@ hmp-commands.h: $(SRC_PATH)/hmp-commands.hx
qmp-commands.h: $(SRC_PATH)/qmp-commands.hx
$(call quiet-command,sh $(SRC_PATH)/scripts/hxtool -h < $< > $@," GEN $(TARGET_DIR)$@")
9pfs/virtio-9p.o: CFLAGS += -I$(SRC_PATH)/hw/
clean:
rm -f *.o *.a *~ $(PROGS) nwfpe/*.o fpu/*.o
rm -f *.d */*.d tcg/*.o ide/*.o
rm -f *.d */*.d tcg/*.o ide/*.o 9pfs/*.o
rm -f hmp-commands.h qmp-commands.h gdbstub-xml.c
ifdef CONFIG_SYSTEMTAP_TRACE
rm -f *.stp

1
acl.c
View File

@ -24,7 +24,6 @@
#include "qemu-common.h"
#include "sysemu.h"
#include "acl.h"
#ifdef CONFIG_FNMATCH

View File

@ -22,8 +22,6 @@ enum {
extern const uint32_t arch_type;
void select_soundhw(const char *optarg);
int ram_save_live(Monitor *mon, QEMUFile *f, int stage, void *opaque);
int ram_load(QEMUFile *f, void *opaque, int version_id);
void do_acpitable_option(const char *optarg);
void do_smbios_option(const char *optarg);
void cpudef_init(void);

View File

@ -33,7 +33,6 @@
#define ARM_ANGEL_HEAP_SIZE (128 * 1024 * 1024)
#else
#include "qemu-common.h"
#include "sysemu.h"
#include "gdbstub.h"
#endif

View File

@ -139,36 +139,36 @@ static int aud_to_sdlfmt (audfmt_e fmt)
}
}
static int sdl_to_audfmt (int sdlfmt, audfmt_e *fmt, int *endianess)
static int sdl_to_audfmt(int sdlfmt, audfmt_e *fmt, int *endianness)
{
switch (sdlfmt) {
case AUDIO_S8:
*endianess = 0;
*endianness = 0;
*fmt = AUD_FMT_S8;
break;
case AUDIO_U8:
*endianess = 0;
*endianness = 0;
*fmt = AUD_FMT_U8;
break;
case AUDIO_S16LSB:
*endianess = 0;
*endianness = 0;
*fmt = AUD_FMT_S16;
break;
case AUDIO_U16LSB:
*endianess = 0;
*endianness = 0;
*fmt = AUD_FMT_U16;
break;
case AUDIO_S16MSB:
*endianess = 1;
*endianness = 1;
*fmt = AUD_FMT_S16;
break;
case AUDIO_U16MSB:
*endianess = 1;
*endianness = 1;
*fmt = AUD_FMT_U16;
break;
@ -338,7 +338,7 @@ static int sdl_init_out (HWVoiceOut *hw, struct audsettings *as)
SDLVoiceOut *sdl = (SDLVoiceOut *) hw;
SDLAudioState *s = &glob_sdl;
SDL_AudioSpec req, obt;
int endianess;
int endianness;
int err;
audfmt_e effective_fmt;
struct audsettings obt_as;
@ -354,7 +354,7 @@ static int sdl_init_out (HWVoiceOut *hw, struct audsettings *as)
return -1;
}
err = sdl_to_audfmt (obt.format, &effective_fmt, &endianess);
err = sdl_to_audfmt(obt.format, &effective_fmt, &endianness);
if (err) {
sdl_close (s);
return -1;
@ -363,7 +363,7 @@ static int sdl_init_out (HWVoiceOut *hw, struct audsettings *as)
obt_as.freq = obt.freq;
obt_as.nchannels = obt.channels;
obt_as.fmt = effective_fmt;
obt_as.endianness = endianess;
obt_as.endianness = endianness;
audio_pcm_init_info (&hw->info, &obt_as);
hw->samples = obt.samples;

View File

@ -22,7 +22,6 @@
* THE SOFTWARE.
*/
#include "sysemu.h"
#include "monitor.h"
#include "qjson.h"
#include "qint.h"

View File

@ -62,7 +62,6 @@ typedef struct BlkMigBlock {
QEMUIOVector qiov;
BlockDriverAIOCB *aiocb;
int ret;
int64_t time;
QSIMPLEQ_ENTRY(BlkMigBlock) entry;
} BlkMigBlock;
@ -78,6 +77,7 @@ typedef struct BlkMigState {
int prev_progress;
int bulk_completed;
long double total_time;
long double prev_time_offset;
int reads;
} BlkMigState;
@ -131,16 +131,10 @@ uint64_t blk_mig_bytes_total(void)
return sum << BDRV_SECTOR_BITS;
}
static inline void add_avg_read_time(int64_t time)
{
block_mig_state.reads++;
block_mig_state.total_time += time;
}
static inline long double compute_read_bwidth(void)
{
assert(block_mig_state.total_time != 0);
return (block_mig_state.reads * BLOCK_SIZE)/ block_mig_state.total_time;
return (block_mig_state.reads / block_mig_state.total_time) * BLOCK_SIZE;
}
static int bmds_aio_inflight(BlkMigDevState *bmds, int64_t sector)
@ -191,13 +185,14 @@ static void alloc_aio_bitmap(BlkMigDevState *bmds)
static void blk_mig_read_cb(void *opaque, int ret)
{
long double curr_time = qemu_get_clock_ns(rt_clock);
BlkMigBlock *blk = opaque;
blk->ret = ret;
blk->time = qemu_get_clock_ns(rt_clock) - blk->time;
add_avg_read_time(blk->time);
block_mig_state.reads++;
block_mig_state.total_time += (curr_time - block_mig_state.prev_time_offset);
block_mig_state.prev_time_offset = curr_time;
QSIMPLEQ_INSERT_TAIL(&block_mig_state.blk_list, blk, entry);
bmds_set_aio_inflight(blk->bmds, blk->sector, blk->nr_sectors, 0);
@ -250,7 +245,9 @@ static int mig_save_device_bulk(Monitor *mon, QEMUFile *f,
blk->iov.iov_len = nr_sectors * BDRV_SECTOR_SIZE;
qemu_iovec_init_external(&blk->qiov, &blk->iov, 1);
blk->time = qemu_get_clock_ns(rt_clock);
if (block_mig_state.submitted == 0) {
block_mig_state.prev_time_offset = qemu_get_clock_ns(rt_clock);
}
blk->aiocb = bdrv_aio_readv(bs, cur_sector, &blk->qiov,
nr_sectors, blk_mig_read_cb, blk);
@ -409,7 +406,9 @@ static int mig_save_device_dirty(Monitor *mon, QEMUFile *f,
blk->iov.iov_len = nr_sectors * BDRV_SECTOR_SIZE;
qemu_iovec_init_external(&blk->qiov, &blk->iov, 1);
blk->time = qemu_get_clock_ns(rt_clock);
if (block_mig_state.submitted == 0) {
block_mig_state.prev_time_offset = qemu_get_clock_ns(rt_clock);
}
blk->aiocb = bdrv_aio_readv(bmds->bs, sector, &blk->qiov,
nr_sectors, blk_mig_read_cb, blk);

28
block.c
View File

@ -697,14 +697,22 @@ void bdrv_close_all(void)
}
}
/* make a BlockDriverState anonymous by removing from bdrv_state list.
Also, NULL terminate the device_name to prevent double remove */
void bdrv_make_anon(BlockDriverState *bs)
{
if (bs->device_name[0] != '\0') {
QTAILQ_REMOVE(&bdrv_states, bs, list);
}
bs->device_name[0] = '\0';
}
void bdrv_delete(BlockDriverState *bs)
{
assert(!bs->peer);
/* remove from list, if necessary */
if (bs->device_name[0] != '\0') {
QTAILQ_REMOVE(&bdrv_states, bs, list);
}
bdrv_make_anon(bs);
bdrv_close(bs);
if (bs->file != NULL) {
@ -1153,14 +1161,12 @@ int64_t bdrv_getlength(BlockDriverState *bs)
if (!drv)
return -ENOMEDIUM;
/* Fixed size devices use the total_sectors value for speed instead of
issuing a length query (like lseek) on each call. Also, legacy block
drivers don't provide a bdrv_getlength function and must use
total_sectors. */
if (!bs->growable || !drv->bdrv_getlength) {
return bs->total_sectors * BDRV_SECTOR_SIZE;
if (bs->growable || bs->removable) {
if (drv->bdrv_getlength) {
return drv->bdrv_getlength(bs);
}
}
return drv->bdrv_getlength(bs);
return bs->total_sectors * BDRV_SECTOR_SIZE;
}
/* return 0 as number of sectors if no device present or error */
@ -2809,6 +2815,8 @@ void bdrv_set_locked(BlockDriverState *bs, int locked)
{
BlockDriver *drv = bs->drv;
trace_bdrv_set_locked(bs, locked);
bs->locked = locked;
if (drv && drv->bdrv_set_locked) {
drv->bdrv_set_locked(bs, locked);

View File

@ -66,6 +66,7 @@ int bdrv_create(BlockDriver *drv, const char* filename,
QEMUOptionParameter *options);
int bdrv_create_file(const char* filename, QEMUOptionParameter *options);
BlockDriverState *bdrv_new(const char *device_name);
void bdrv_make_anon(BlockDriverState *bs);
void bdrv_delete(BlockDriverState *bs);
int bdrv_file_open(BlockDriverState **pbs, const char *filename, int flags);
int bdrv_open(BlockDriverState *bs, const char *filename, int flags,

View File

@ -29,98 +29,154 @@
#include "qemu-common.h"
#include "nbd.h"
#include "module.h"
#include "qemu_socket.h"
#include <sys/types.h>
#include <unistd.h>
#define EN_OPTSTR ":exportname="
/* #define DEBUG_NBD */
#if defined(DEBUG_NBD)
#define logout(fmt, ...) \
fprintf(stderr, "nbd\t%-24s" fmt, __func__, ##__VA_ARGS__)
#else
#define logout(fmt, ...) ((void)0)
#endif
typedef struct BDRVNBDState {
int sock;
off_t size;
size_t blocksize;
char *export_name; /* An NBD server may export several devices */
/* If it begins with '/', this is a UNIX domain socket. Otherwise,
* it's a string of the form <hostname|ip4|\[ip6\]>:port
*/
char *host_spec;
} BDRVNBDState;
static int nbd_open(BlockDriverState *bs, const char* filename, int flags)
static int nbd_config(BDRVNBDState *s, const char *filename, int flags)
{
BDRVNBDState *s = bs->opaque;
uint32_t nbdflags;
char *file;
char *name;
const char *host;
char *export_name;
const char *host_spec;
const char *unixpath;
int sock;
off_t size;
size_t blocksize;
int ret;
int err = -EINVAL;
file = qemu_strdup(filename);
name = strstr(file, EN_OPTSTR);
if (name) {
if (name[strlen(EN_OPTSTR)] == 0) {
export_name = strstr(file, EN_OPTSTR);
if (export_name) {
if (export_name[strlen(EN_OPTSTR)] == 0) {
goto out;
}
name[0] = 0;
name += strlen(EN_OPTSTR);
export_name[0] = 0; /* truncate 'file' */
export_name += strlen(EN_OPTSTR);
s->export_name = qemu_strdup(export_name);
}
if (!strstart(file, "nbd:", &host)) {
/* extract the host_spec - fail if it's not nbd:... */
if (!strstart(file, "nbd:", &host_spec)) {
goto out;
}
if (strstart(host, "unix:", &unixpath)) {
if (unixpath[0] != '/') {
/* are we a UNIX or TCP socket? */
if (strstart(host_spec, "unix:", &unixpath)) {
if (unixpath[0] != '/') { /* We demand an absolute path*/
goto out;
}
sock = unix_socket_outgoing(unixpath);
s->host_spec = qemu_strdup(unixpath);
} else {
uint16_t port = NBD_DEFAULT_PORT;
char *p, *r;
char hostname[128];
pstrcpy(hostname, 128, host);
p = strchr(hostname, ':');
if (p != NULL) {
*p = '\0';
p++;
port = strtol(p, &r, 0);
if (r == p) {
goto out;
}
}
sock = tcp_socket_outgoing(hostname, port);
s->host_spec = qemu_strdup(host_spec);
}
if (sock == -1) {
err = -errno;
goto out;
}
ret = nbd_receive_negotiate(sock, name, &nbdflags, &size, &blocksize);
if (ret == -1) {
err = -errno;
goto out;
}
s->sock = sock;
s->size = size;
s->blocksize = blocksize;
err = 0;
out:
qemu_free(file);
if (err != 0) {
qemu_free(s->export_name);
qemu_free(s->host_spec);
}
return err;
}
static int nbd_establish_connection(BlockDriverState *bs)
{
BDRVNBDState *s = bs->opaque;
int sock;
int ret;
off_t size;
size_t blocksize;
uint32_t nbdflags;
if (s->host_spec[0] == '/') {
sock = unix_socket_outgoing(s->host_spec);
} else {
sock = tcp_socket_outgoing_spec(s->host_spec);
}
/* Failed to establish connection */
if (sock == -1) {
logout("Failed to establish connection to NBD server\n");
return -errno;
}
/* NBD handshake */
ret = nbd_receive_negotiate(sock, s->export_name, &nbdflags, &size,
&blocksize);
if (ret == -1) {
logout("Failed to negotiate with the NBD server\n");
closesocket(sock);
return -errno;
}
/* Now that we're connected, set the socket to be non-blocking */
socket_set_nonblock(sock);
s->sock = sock;
s->size = size;
s->blocksize = blocksize;
logout("Established connection with NBD server\n");
return 0;
}
static void nbd_teardown_connection(BlockDriverState *bs)
{
BDRVNBDState *s = bs->opaque;
struct nbd_request request;
request.type = NBD_CMD_DISC;
request.handle = (uint64_t)(intptr_t)bs;
request.from = 0;
request.len = 0;
nbd_send_request(s->sock, &request);
closesocket(s->sock);
}
static int nbd_open(BlockDriverState *bs, const char* filename, int flags)
{
BDRVNBDState *s = bs->opaque;
int result;
/* Pop the config into our state object. Exit if invalid. */
result = nbd_config(s, filename, flags);
if (result != 0) {
return result;
}
/* establish TCP connection, return error if it fails
* TODO: Configurable retry-until-timeout behaviour.
*/
result = nbd_establish_connection(bs);
return result;
}
static int nbd_read(BlockDriverState *bs, int64_t sector_num,
uint8_t *buf, int nb_sectors)
{
@ -184,15 +240,10 @@ static int nbd_write(BlockDriverState *bs, int64_t sector_num,
static void nbd_close(BlockDriverState *bs)
{
BDRVNBDState *s = bs->opaque;
struct nbd_request request;
qemu_free(s->export_name);
qemu_free(s->host_spec);
request.type = NBD_CMD_DISC;
request.handle = (uint64_t)(intptr_t)bs;
request.from = 0;
request.len = 0;
nbd_send_request(s->sock, &request);
close(s->sock);
nbd_teardown_connection(bs);
}
static int64_t nbd_getlength(BlockDriverState *bs)

View File

@ -18,7 +18,7 @@ typedef struct {
BdrvCheckResult *result;
bool fix; /* whether to fix invalid offsets */
size_t nclusters;
uint64_t nclusters;
uint32_t *used_clusters; /* referenced cluster bitmap */
QEDRequest request;
@ -72,7 +72,8 @@ static unsigned int qed_check_l2_table(QEDCheck *check, QEDTable *table)
for (i = 0; i < s->table_nelems; i++) {
uint64_t offset = table->offsets[i];
if (!offset) {
if (qed_offset_is_unalloc_cluster(offset) ||
qed_offset_is_zero_cluster(offset)) {
continue;
}
@ -111,7 +112,7 @@ static int qed_check_l1_table(QEDCheck *check, QEDTable *table)
unsigned int num_invalid_l2;
uint64_t offset = table->offsets[i];
if (!offset) {
if (qed_offset_is_unalloc_cluster(offset)) {
continue;
}
@ -176,7 +177,7 @@ static int qed_check_l1_table(QEDCheck *check, QEDTable *table)
static void qed_check_for_leaks(QEDCheck *check)
{
BDRVQEDState *s = check->s;
size_t i;
uint64_t i;
for (i = s->header.header_size; i < check->nclusters; i++) {
if (!qed_test_bit(check->used_clusters, i)) {

View File

@ -23,7 +23,8 @@
* @n: Maximum number of clusters
* @offset: Set to first cluster offset
*
* This function scans tables for contiguous allocated or free clusters.
* This function scans tables for contiguous clusters. A contiguous run of
* clusters may be allocated, unallocated, or zero.
*/
static unsigned int qed_count_contiguous_clusters(BDRVQEDState *s,
QEDTable *table,
@ -38,9 +39,14 @@ static unsigned int qed_count_contiguous_clusters(BDRVQEDState *s,
*offset = last;
for (i = index + 1; i < end; i++) {
if (last == 0) {
/* Counting free clusters */
if (table->offsets[i] != 0) {
if (qed_offset_is_unalloc_cluster(last)) {
/* Counting unallocated clusters */
if (!qed_offset_is_unalloc_cluster(table->offsets[i])) {
break;
}
} else if (qed_offset_is_zero_cluster(last)) {
/* Counting zero clusters */
if (!qed_offset_is_zero_cluster(table->offsets[i])) {
break;
}
} else {
@ -87,14 +93,19 @@ static void qed_find_cluster_cb(void *opaque, int ret)
n = qed_count_contiguous_clusters(s, request->l2_table->table,
index, n, &offset);
ret = offset ? QED_CLUSTER_FOUND : QED_CLUSTER_L2;
len = MIN(find_cluster_cb->len, n * s->header.cluster_size -
qed_offset_into_cluster(s, find_cluster_cb->pos));
if (offset && !qed_check_cluster_offset(s, offset)) {
if (qed_offset_is_unalloc_cluster(offset)) {
ret = QED_CLUSTER_L2;
} else if (qed_offset_is_zero_cluster(offset)) {
ret = QED_CLUSTER_ZERO;
} else if (qed_check_cluster_offset(s, offset)) {
ret = QED_CLUSTER_FOUND;
} else {
ret = -EINVAL;
}
len = MIN(find_cluster_cb->len, n * s->header.cluster_size -
qed_offset_into_cluster(s, find_cluster_cb->pos));
out:
find_cluster_cb->cb(find_cluster_cb->opaque, ret, offset, len);
qemu_free(find_cluster_cb);
@ -132,7 +143,7 @@ void qed_find_cluster(BDRVQEDState *s, QEDRequest *request, uint64_t pos,
len = MIN(len, (((pos >> s->l1_shift) + 1) << s->l1_shift) - pos);
l2_offset = s->l1_table->offsets[qed_l1_index(s, pos)];
if (!l2_offset) {
if (qed_offset_is_unalloc_cluster(l2_offset)) {
cb(opaque, QED_CLUSTER_L1, 0, len);
return;
}

View File

@ -573,7 +573,7 @@ static void qed_is_allocated_cb(void *opaque, int ret, uint64_t offset, size_t l
{
QEDIsAllocatedCB *cb = opaque;
*cb->pnum = len / BDRV_SECTOR_SIZE;
cb->is_allocated = ret == QED_CLUSTER_FOUND;
cb->is_allocated = (ret == QED_CLUSTER_FOUND || ret == QED_CLUSTER_ZERO);
}
static int bdrv_qed_is_allocated(BlockDriverState *bs, int64_t sector_num,
@ -745,7 +745,10 @@ static void qed_copy_from_backing_file(BDRVQEDState *s, uint64_t pos,
* @table: L2 table
* @index: First cluster index
* @n: Number of contiguous clusters
* @cluster: First cluster byte offset in image file
* @cluster: First cluster offset
*
* The cluster offset may be an allocated byte offset in the image file, the
* zero cluster marker, or the unallocated cluster marker.
*/
static void qed_update_l2_table(BDRVQEDState *s, QEDTable *table, int index,
unsigned int n, uint64_t cluster)
@ -753,7 +756,10 @@ static void qed_update_l2_table(BDRVQEDState *s, QEDTable *table, int index,
int i;
for (i = index; i < index + n; i++) {
table->offsets[i] = cluster;
cluster += s->header.cluster_size;
if (!qed_offset_is_unalloc_cluster(cluster) &&
!qed_offset_is_zero_cluster(cluster)) {
cluster += s->header.cluster_size;
}
}
}
@ -1075,6 +1081,7 @@ static void qed_aio_write_data(void *opaque, int ret,
case QED_CLUSTER_L2:
case QED_CLUSTER_L1:
case QED_CLUSTER_ZERO:
qed_aio_write_alloc(acb, len);
break;
@ -1114,8 +1121,12 @@ static void qed_aio_read_data(void *opaque, int ret,
qemu_iovec_copy(&acb->cur_qiov, acb->qiov, acb->qiov_offset, len);
/* Handle backing file and unallocated sparse hole reads */
if (ret != QED_CLUSTER_FOUND) {
/* Handle zero cluster and backing file reads */
if (ret == QED_CLUSTER_ZERO) {
qemu_iovec_memset(&acb->cur_qiov, 0, acb->cur_qiov.size);
qed_aio_next_io(acb, 0);
return;
} else if (ret != QED_CLUSTER_FOUND) {
qed_read_backing_file(s, acb->cur_pos, &acb->cur_qiov,
qed_aio_next_io, acb);
return;

View File

@ -161,6 +161,7 @@ typedef struct {
enum {
QED_CLUSTER_FOUND, /* cluster found */
QED_CLUSTER_ZERO, /* zero cluster found */
QED_CLUSTER_L2, /* cluster missing in L2 */
QED_CLUSTER_L1, /* cluster missing in L1 */
};
@ -251,7 +252,7 @@ static inline uint64_t qed_offset_into_cluster(BDRVQEDState *s, uint64_t offset)
return offset & (s->header.cluster_size - 1);
}
static inline unsigned int qed_bytes_to_clusters(BDRVQEDState *s, size_t bytes)
static inline uint64_t qed_bytes_to_clusters(BDRVQEDState *s, uint64_t bytes)
{
return qed_start_of_cluster(s, bytes + (s->header.cluster_size - 1)) /
(s->header.cluster_size - 1);
@ -298,4 +299,29 @@ static inline bool qed_check_table_offset(BDRVQEDState *s, uint64_t offset)
qed_check_cluster_offset(s, end_offset);
}
static inline bool qed_offset_is_cluster_aligned(BDRVQEDState *s,
uint64_t offset)
{
if (qed_offset_into_cluster(s, offset)) {
return false;
}
return true;
}
static inline bool qed_offset_is_unalloc_cluster(uint64_t offset)
{
if (offset == 0) {
return true;
}
return false;
}
static inline bool qed_offset_is_zero_cluster(uint64_t offset)
{
if (offset == 1) {
return true;
}
return false;
}
#endif /* BLOCK_QED_H */

View File

@ -13,6 +13,7 @@
#include "qemu-error.h"
#include "qemu_socket.h"
#include "block_int.h"
#include "bitops.h"
#define SD_PROTO_VER 0x01
@ -1829,20 +1830,6 @@ static int sd_snapshot_delete(BlockDriverState *bs, const char *snapshot_id)
return 0;
}
#define DIV_ROUND_UP(n,d) (((n) + (d) - 1) / (d))
#define BITS_PER_BYTE 8
#define BITS_TO_LONGS(nr) DIV_ROUND_UP(nr, BITS_PER_BYTE * sizeof(long))
#define DECLARE_BITMAP(name,bits) \
unsigned long name[BITS_TO_LONGS(bits)]
#define BITS_PER_LONG (BITS_PER_BYTE * sizeof(long))
static inline int test_bit(unsigned int nr, const unsigned long *addr)
{
return ((1UL << (nr % BITS_PER_LONG)) &
(((unsigned long *)addr)[nr / BITS_PER_LONG])) != 0;
}
static int sd_snapshot_list(BlockDriverState *bs, QEMUSnapshotInfo **psn_tab)
{
BDRVSheepdogState *s = bs->opaque;

View File

@ -113,7 +113,7 @@ void uuid_unparse(const uuid_t uu, char *out);
*/
#define VDI_TEXT "<<< QEMU VM Virtual Disk Image >>>\n"
/* Unallocated blocks use this index (no need to convert endianess). */
/* Unallocated blocks use this index (no need to convert endianness). */
#define VDI_UNALLOCATED UINT32_MAX
#if !defined(CONFIG_UUID)
@ -194,7 +194,7 @@ typedef struct {
uint32_t block_sectors;
/* First sector of block map. */
uint32_t bmap_sector;
/* VDI header (converted to host endianess). */
/* VDI header (converted to host endianness). */
VdiHeader header;
} BDRVVdiState;

View File

@ -505,12 +505,8 @@ static int vpc_create(const char *filename, QEMUOptionParameter *options)
int ret = -EIO;
// Read out options
while (options && options->name) {
if (!strcmp(options->name, "size")) {
total_sectors = options->value.n / 512;
}
options++;
}
total_sectors = get_option_parameter(options, BLOCK_OPT_SIZE)->value.n /
BDRV_SECTOR_SIZE;
// Create the file
fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, 0644);

View File

@ -503,7 +503,7 @@ DriveInfo *drive_init(QemuOpts *opts, int default_to_scsi)
case IF_VIRTIO:
/* add virtio block device */
opts = qemu_opts_create(qemu_find_opts("device"), NULL, 0);
qemu_opt_set(opts, "driver", "virtio-blk-pci");
qemu_opt_set(opts, "driver", "virtio-blk");
qemu_opt_set(opts, "drive", dinfo->id);
if (devaddr)
qemu_opt_set(opts, "addr", devaddr);
@ -737,8 +737,6 @@ int do_drive_del(Monitor *mon, const QDict *qdict, QObject **ret_data)
{
const char *id = qdict_get_str(qdict, "id");
BlockDriverState *bs;
BlockDriverState **ptr;
Property *prop;
bs = bdrv_find(id);
if (!bs) {
@ -755,24 +753,17 @@ int do_drive_del(Monitor *mon, const QDict *qdict, QObject **ret_data)
bdrv_flush(bs);
bdrv_close(bs);
/* clean up guest state from pointing to host resource by
* finding and removing DeviceState "drive" property */
/* if we have a device associated with this BlockDriverState (bs->peer)
* then we need to make the drive anonymous until the device
* can be removed. If this is a drive with no device backing
* then we can just get rid of the block driver state right here.
*/
if (bs->peer) {
for (prop = bs->peer->info->props; prop && prop->name; prop++) {
if (prop->info->type == PROP_TYPE_DRIVE) {
ptr = qdev_get_prop_ptr(bs->peer, prop);
if (*ptr == bs) {
bdrv_detach(bs, bs->peer);
*ptr = NULL;
break;
}
}
}
bdrv_make_anon(bs);
} else {
drive_uninit(drive_get_by_blockdev(bs));
}
/* clean up host side */
drive_uninit(drive_get_by_blockdev(bs));
return 0;
}

View File

@ -19,7 +19,6 @@
#include "qemu-common.h"
#include "qemu-char.h"
#include "sysemu.h"
#include "net.h"
#include "bt-host.h"

View File

@ -19,7 +19,6 @@
#include "qemu-common.h"
#include "qemu-char.h"
#include "sysemu.h"
#include "net.h"
#include "hw/bt.h"

View File

@ -14,7 +14,6 @@
#include "qemu-common.h"
#include "hw/hw.h"
#include "qemu-timer.h"
#include "sysemu.h"
#include "qemu-char.h"
#include "buffered_file.h"

149
configure vendored
View File

@ -175,6 +175,9 @@ trace_backend="nop"
trace_file="trace"
spice=""
rbd=""
smartcard=""
smartcard_nss=""
opengl=""
# parse CC options first
for opt do
@ -281,7 +284,7 @@ else
fi
case "$cpu" in
alpha|cris|ia64|lm32|m68k|microblaze|ppc|ppc64|sparc64)
alpha|cris|ia64|lm32|m68k|microblaze|ppc|ppc64|sparc64|unicore32)
cpu="$cpu"
;;
i386|i486|i586|i686|i86pc|BePC)
@ -492,6 +495,8 @@ for opt do
case "$opt" in
--help|-h) show_help=yes
;;
--version|-V) exec cat $source_path/VERSION
;;
--prefix=*) prefix="$optarg"
;;
--interp-prefix=*) interp_prefix="$optarg"
@ -718,12 +723,24 @@ for opt do
;;
--enable-vhost-net) vhost_net="yes"
;;
--disable-opengl) opengl="no"
;;
--enable-opengl) opengl="yes"
;;
--*dir)
;;
--disable-rbd) rbd="no"
;;
--enable-rbd) rbd="yes"
;;
--disable-smartcard) smartcard="no"
;;
--enable-smartcard) smartcard="yes"
;;
--disable-smartcard-nss) smartcard_nss="no"
;;
--enable-smartcard-nss) smartcard_nss="yes"
;;
*) echo "ERROR: unknown option $opt"; show_help="yes"
;;
esac
@ -798,6 +815,9 @@ case "$cpu" in
hppa*)
host_guest_base="yes"
;;
unicore32*)
host_guest_base="yes"
;;
esac
[ -z "$guest_base" ] && guest_base="$host_guest_base"
@ -921,6 +941,10 @@ echo " Default:trace-<pid>"
echo " --disable-spice disable spice"
echo " --enable-spice enable spice"
echo " --enable-rbd enable building the rados block device (rbd)"
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 ""
echo "NOTE: The object files are built at the place where configure is launched"
exit 1
@ -1028,6 +1052,7 @@ sh4eb-linux-user \
sparc-linux-user \
sparc64-linux-user \
sparc32plus-linux-user \
unicore32-linux-user \
"
fi
# the following are Darwin specific
@ -1213,7 +1238,7 @@ else
fi
sdl=no
fi
if test -n "$cross_prefix" && test "`basename $sdlconfig`" = sdl-config; then
if test -n "$cross_prefix" && test "$(basename "$sdlconfig")" = sdl-config; then
echo warning: using "\"$sdlconfig\"" to detect cross-compiled sdl >&2
fi
@ -1921,15 +1946,36 @@ int main(void) { return 0; }
EOF
if compile_prog "" "$fdt_libs" ; then
fdt=yes
libs_softmmu="$fdt_libs $libs_softmmu"
else
if test "$fdt" = "yes" ; then
feature_not_found "fdt"
fi
fdt_libs=
fdt=no
fi
fi
##########################################
# opengl probe, used by milkymist-tmu2
if test "$opengl" != "no" ; then
opengl_libs="-lGL"
cat > $TMPC << EOF
#include <X11/Xlib.h>
#include <GL/gl.h>
#include <GL/glx.h>
int main(void) { GL_VERSION; return 0; }
EOF
if compile_prog "" "-lGL" ; then
opengl=yes
else
if test "$opengl" = "yes" ; then
feature_not_found "opengl"
fi
opengl_libs=
opengl=no
fi
fi
#
# Check for xxxat() functions when we are building linux-user
# emulator. This is done because older glibc versions don't
@ -2179,7 +2225,15 @@ cat > $TMPC << EOF
int main(void)
{
epoll_create1(0);
/* Note that we use epoll_create1 as a value, not as
* a function being called. This is necessary so that on
* old SPARC glibc versions where the function was present in
* the library but not declared in the header file we will
* fail the configure check. (Otherwise we will get a compiler
* warning but not an error, and will proceed to fail the
* qemu compile where we compile with -Werror.)
*/
epoll_create1;
return 0;
}
EOF
@ -2304,6 +2358,31 @@ EOF
fi
fi
# check for libcacard for smartcard support
if test "$smartcard" != "no" ; then
smartcard="yes"
smartcard_cflags=""
# TODO - what's the minimal nss version we support?
if test "$smartcard_nss" != "no"; then
if $pkg_config --atleast-version=3.12.8 nss >/dev/null 2>&1 ; then
smartcard_nss="yes"
smartcard_cflags="-I\$(SRC_PATH)/libcacard"
libcacard_libs=$($pkg_config --libs nss 2>/dev/null)
libcacard_cflags=$($pkg_config --cflags nss 2>/dev/null)
QEMU_CFLAGS="$QEMU_CFLAGS $smartcard_cflags $libcacard_cflags"
LIBS="$libcacard_libs $LIBS"
else
if test "$smartcard_nss" = "yes"; then
feature_not_found "nss"
fi
smartcard_nss="no"
fi
fi
fi
if test "$smartcard" = "no" ; then
smartcard_nss="no"
fi
##########################################
##########################################
@ -2461,7 +2540,9 @@ if test \( "$cpu" = "i386" -o "$cpu" = "x86_64" \) -a \
"$softmmu" = yes ; then
roms="optionrom"
fi
if test "$cpu" = "ppc64" ; then
roms="$roms spapr-rtas"
fi
echo "Install prefix $prefix"
echo "BIOS directory `eval echo $datadir`"
@ -2540,6 +2621,8 @@ echo "Trace output file $trace_file-<pid>"
echo "spice support $spice"
echo "rbd support $rbd"
echo "xfsctl support $xfs"
echo "nss used $smartcard_nss"
echo "OpenGL support $opengl"
if test $sdl_too_old = "yes"; then
echo "-> Your SDL version is too old - please upgrade to have SDL support"
@ -2563,7 +2646,7 @@ echo "docdir=$docdir" >> $config_host_mak
echo "confdir=$confdir" >> $config_host_mak
case "$cpu" in
i386|x86_64|alpha|cris|hppa|ia64|lm32|m68k|microblaze|mips|mips64|ppc|ppc64|s390|s390x|sparc|sparc64)
i386|x86_64|alpha|cris|hppa|ia64|lm32|m68k|microblaze|mips|mips64|ppc|ppc64|s390|s390x|sparc|sparc64|unicore32)
ARCH=$cpu
;;
armv4b|armv4l)
@ -2822,6 +2905,18 @@ if test "$spice" = "yes" ; then
echo "CONFIG_SPICE=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
fi
if test "$opengl" = "yes" ; then
echo "CONFIG_OPENGL=y" >> $config_host_mak
fi
# XXX: suppress that
if [ "$bsd" = "yes" ] ; then
echo "CONFIG_BSD=y" >> $config_host_mak
@ -2967,6 +3062,7 @@ mkdir -p $target_dir
mkdir -p $target_dir/fpu
mkdir -p $target_dir/tcg
mkdir -p $target_dir/ide
mkdir -p $target_dir/9pfs
if test "$target" = "arm-linux-user" -o "$target" = "armeb-linux-user" -o "$target" = "arm-bsd-user" -o "$target" = "armeb-bsd-user" ; then
mkdir -p $target_dir/nwfpe
fi
@ -2984,6 +3080,7 @@ target_short_alignment=2
target_int_alignment=4
target_long_alignment=4
target_llong_alignment=8
target_libs_softmmu=
TARGET_ARCH="$target_arch2"
TARGET_BASE_ARCH=""
@ -3017,6 +3114,7 @@ case "$target_arch2" in
;;
lm32)
target_phys_bits=32
target_libs_softmmu="$opengl_libs"
;;
m68k)
bflt="yes"
@ -3031,6 +3129,7 @@ case "$target_arch2" in
bflt="yes"
target_nptl="yes"
target_phys_bits=32
target_libs_softmmu="$fdt_libs"
;;
mips|mipsel)
TARGET_ARCH=mips
@ -3055,6 +3154,7 @@ case "$target_arch2" in
gdb_xml_files="power-core.xml power-fpu.xml power-altivec.xml power-spe.xml"
target_phys_bits=32
target_nptl="yes"
target_libs_softmmu="$fdt_libs"
;;
ppcemb)
TARGET_BASE_ARCH=ppc
@ -3062,6 +3162,7 @@ case "$target_arch2" in
gdb_xml_files="power-core.xml power-fpu.xml power-altivec.xml power-spe.xml"
target_phys_bits=64
target_nptl="yes"
target_libs_softmmu="$fdt_libs"
;;
ppc64)
TARGET_BASE_ARCH=ppc
@ -3069,6 +3170,7 @@ case "$target_arch2" in
gdb_xml_files="power64-core.xml power-fpu.xml power-altivec.xml power-spe.xml"
target_phys_bits=64
target_long_alignment=8
target_libs_softmmu="$fdt_libs"
;;
ppc64abi32)
TARGET_ARCH=ppc64
@ -3077,6 +3179,7 @@ case "$target_arch2" in
echo "TARGET_ABI32=y" >> $config_target_mak
gdb_xml_files="power64-core.xml power-fpu.xml power-altivec.xml power-spe.xml"
target_phys_bits=64
target_libs_softmmu="$fdt_libs"
;;
sh4|sh4eb)
TARGET_ARCH=sh4
@ -3100,7 +3203,12 @@ case "$target_arch2" in
target_phys_bits=64
;;
s390x)
target_nptl="yes"
target_phys_bits=64
target_long_alignment=8
;;
unicore32)
target_phys_bits=32
;;
*)
echo "Unsupported target CPU"
@ -3157,7 +3265,7 @@ fi
if test "$target_softmmu" = "yes" ; then
echo "TARGET_PHYS_ADDR_BITS=$target_phys_bits" >> $config_target_mak
echo "CONFIG_SOFTMMU=y" >> $config_target_mak
echo "LIBS+=$libs_softmmu" >> $config_target_mak
echo "LIBS+=$libs_softmmu $target_libs_softmmu" >> $config_target_mak
echo "HWDIR=../libhw$target_phys_bits" >> $config_target_mak
echo "subdir-$target: subdir-libhw$target_phys_bits" >> $config_host_mak
fi
@ -3170,6 +3278,11 @@ fi
if test "$target_darwin_user" = "yes" ; then
echo "CONFIG_DARWIN_USER=y" >> $config_target_mak
fi
if test "$smartcard_nss" = "yes" ; then
echo "subdir-$target: subdir-libcacard" >> $config_host_mak
echo "libcacard_libs=$libcacard_libs" >> $config_host_mak
echo "libcacard_cflags=$libcacard_cflags" >> $config_host_mak
fi
list=""
if test ! -z "$gdb_xml_files" ; then
for x in $gdb_xml_files; do
@ -3178,14 +3291,7 @@ if test ! -z "$gdb_xml_files" ; then
echo "TARGET_XML_FILES=$list" >> $config_target_mak
fi
case "$target_arch2" in
i386|x86_64)
echo "CONFIG_NOSOFTFLOAT=y" >> $config_target_mak
;;
*)
echo "CONFIG_SOFTFLOAT=y" >> $config_target_mak
;;
esac
echo "CONFIG_SOFTFLOAT=y" >> $config_target_mak
if test "$target_user_only" = "yes" -a "$bflt" = "yes"; then
echo "TARGET_HAS_BFLT=y" >> $config_target_mak
@ -3294,6 +3400,9 @@ if test "$target_softmmu" = "yes" ; then
arm)
cflags="-DHAS_AUDIO $cflags"
;;
lm32)
cflags="-DHAS_AUDIO $cflags"
;;
i386|mips|ppc)
cflags="-DHAS_AUDIO -DHAS_AUDIO_CHOICE $cflags"
;;
@ -3354,7 +3463,7 @@ FILES="Makefile tests/Makefile"
FILES="$FILES tests/cris/Makefile tests/cris/.gdbinit"
FILES="$FILES pc-bios/optionrom/Makefile pc-bios/keymaps"
FILES="$FILES roms/seabios/Makefile roms/vgabios/Makefile"
for bios_file in $source_path/pc-bios/*.bin $source_path/pc-bios/*.dtb $source_path/pc-bios/openbios-*; do
for bios_file in $source_path/pc-bios/*.bin $source_path/pc-bios/*.rom $source_path/pc-bios/*.dtb $source_path/pc-bios/openbios-*; do
FILES="$FILES pc-bios/`basename $bios_file`"
done
mkdir -p $DIRS
@ -3380,9 +3489,17 @@ for hwlib in 32 64; do
mkdir -p $d
mkdir -p $d/ide
symlink $source_path/Makefile.hw $d/Makefile
mkdir -p $d/9pfs
echo "QEMU_CFLAGS+=-DTARGET_PHYS_ADDR_BITS=$hwlib" > $d/config.mak
done
if [ "$source_path" != `pwd` ]; then
# out of tree build
mkdir -p libcacard
rm -f libcacard/Makefile
ln -s "$source_path/libcacard/Makefile" libcacard/Makefile
fi
d=libuser
mkdir -p $d
symlink $source_path/Makefile.user $d/Makefile

View File

@ -138,11 +138,20 @@ typedef union {
uint64_t ll;
} CPU_DoubleU;
#ifdef TARGET_SPARC
#if defined(FLOATX80)
typedef union {
floatx80 d;
struct {
uint64_t lower;
uint16_t upper;
} l;
} CPU_LDoubleU;
#endif
#if defined(CONFIG_SOFTFLOAT)
typedef union {
float128 q;
#if defined(HOST_WORDS_BIGENDIAN) \
|| (defined(__arm__) && !defined(__VFP_FP__) && !defined(CONFIG_SOFTFLOAT))
#if defined(HOST_WORDS_BIGENDIAN)
struct {
uint32_t upmost;
uint32_t upper;
@ -790,7 +799,19 @@ extern CPUState *cpu_single_env;
#define CPU_INTERRUPT_SIPI 0x800 /* SIPI pending. */
#define CPU_INTERRUPT_MCE 0x1000 /* (x86 only) MCE pending. */
void cpu_interrupt(CPUState *s, int mask);
#ifndef CONFIG_USER_ONLY
typedef void (*CPUInterruptHandler)(CPUState *, int);
extern CPUInterruptHandler cpu_interrupt_handler;
static inline void cpu_interrupt(CPUState *s, int mask)
{
cpu_interrupt_handler(s, mask);
}
#else /* USER_ONLY */
void cpu_interrupt(CPUState *env, int mask);
#endif /* USER_ONLY */
void cpu_reset_interrupt(CPUState *env, int mask);
void cpu_exit(CPUState *s);

View File

@ -79,14 +79,14 @@ void cpu_unregister_io_memory(int table_address);
void cpu_physical_memory_rw(target_phys_addr_t addr, uint8_t *buf,
int len, int is_write);
static inline void cpu_physical_memory_read(target_phys_addr_t addr,
uint8_t *buf, int len)
void *buf, int len)
{
cpu_physical_memory_rw(addr, buf, len, 0);
}
static inline void cpu_physical_memory_write(target_phys_addr_t addr,
const uint8_t *buf, int len)
const void *buf, int len)
{
cpu_physical_memory_rw(addr, (uint8_t *)buf, len, 1);
cpu_physical_memory_rw(addr, (void *)buf, len, 1);
}
void *cpu_physical_memory_map(target_phys_addr_t addr,
target_phys_addr_t *plen,

View File

@ -267,6 +267,7 @@ int cpu_exec(CPUState *env1)
env->cc_x = (env->sr >> 4) & 1;
#elif defined(TARGET_ALPHA)
#elif defined(TARGET_ARM)
#elif defined(TARGET_UNICORE32)
#elif defined(TARGET_PPC)
#elif defined(TARGET_LM32)
#elif defined(TARGET_MICROBLAZE)
@ -335,6 +336,8 @@ int cpu_exec(CPUState *env1)
do_interrupt(env);
#elif defined(TARGET_ARM)
do_interrupt(env);
#elif defined(TARGET_UNICORE32)
do_interrupt(env);
#elif defined(TARGET_SH4)
do_interrupt(env);
#elif defined(TARGET_ALPHA)
@ -343,6 +346,8 @@ int cpu_exec(CPUState *env1)
do_interrupt(env);
#elif defined(TARGET_M68K)
do_interrupt(0);
#elif defined(TARGET_S390X)
do_interrupt(env);
#endif
env->exception_index = -1;
#endif
@ -367,7 +372,7 @@ int cpu_exec(CPUState *env1)
}
#if defined(TARGET_ARM) || defined(TARGET_SPARC) || defined(TARGET_MIPS) || \
defined(TARGET_PPC) || defined(TARGET_ALPHA) || defined(TARGET_CRIS) || \
defined(TARGET_MICROBLAZE) || defined(TARGET_LM32)
defined(TARGET_MICROBLAZE) || defined(TARGET_LM32) || defined(TARGET_UNICORE32)
if (interrupt_request & CPU_INTERRUPT_HALT) {
env->interrupt_request &= ~CPU_INTERRUPT_HALT;
env->halted = 1;
@ -514,6 +519,12 @@ int cpu_exec(CPUState *env1)
do_interrupt(env);
next_tb = 0;
}
#elif defined(TARGET_UNICORE32)
if (interrupt_request & CPU_INTERRUPT_HARD
&& !(env->uncached_asr & ASR_I)) {
do_interrupt(env);
next_tb = 0;
}
#elif defined(TARGET_SH4)
if (interrupt_request & CPU_INTERRUPT_HARD) {
do_interrupt(env);
@ -551,6 +562,12 @@ int cpu_exec(CPUState *env1)
do_interrupt(1);
next_tb = 0;
}
#elif defined(TARGET_S390X) && !defined(CONFIG_USER_ONLY)
if ((interrupt_request & CPU_INTERRUPT_HARD) &&
(env->psw.mask & PSW_MASK_EXT)) {
do_interrupt(env);
next_tb = 0;
}
#endif
/* Don't use the cached interupt_request value,
do_interrupt may have updated the EXITTB flag. */
@ -664,6 +681,7 @@ int cpu_exec(CPUState *env1)
env->eflags = env->eflags | helper_cc_compute_all(CC_OP) | (DF & DF_MASK);
#elif defined(TARGET_ARM)
/* XXX: Save/restore host fpu exception state?. */
#elif defined(TARGET_UNICORE32)
#elif defined(TARGET_SPARC)
#elif defined(TARGET_PPC)
#elif defined(TARGET_LM32)
@ -790,7 +808,7 @@ static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
if (tb) {
/* the PC is inside the translated code. It means that we have
a virtual CPU fault */
cpu_restore_state(tb, env, pc, puc);
cpu_restore_state(tb, env, pc);
}
/* we restore the process signal mask as the sigreturn should

13
cpus.c
View File

@ -155,7 +155,7 @@ static bool cpu_thread_is_idle(CPUState *env)
return true;
}
static bool all_cpu_threads_idle(void)
bool all_cpu_threads_idle(void)
{
CPUState *env;
@ -739,6 +739,9 @@ static void qemu_tcg_wait_io_event(void)
CPUState *env;
while (all_cpu_threads_idle()) {
/* Start accounting real time to the virtual clock if the CPUs
are idle. */
qemu_clock_warp(vm_clock);
qemu_cond_wait(tcg_halt_cond, &qemu_global_mutex);
}
@ -830,6 +833,9 @@ static void *qemu_tcg_cpu_thread_fn(void *arg)
while (1) {
cpu_exec_all();
if (use_icount && qemu_next_icount_deadline() <= 0) {
qemu_notify_event();
}
qemu_tcg_wait_io_event();
}
@ -1044,7 +1050,7 @@ static int tcg_cpu_exec(CPUState *env)
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_next_deadline());
count = qemu_icount_round(qemu_next_icount_deadline());
qemu_icount += count;
decr = (count > 0xffff) ? 0xffff : count;
count -= decr;
@ -1070,6 +1076,9 @@ bool cpu_exec_all(void)
{
int r;
/* Account partial waits to the vm_clock. */
qemu_clock_warp(vm_clock);
if (next_cpu == NULL) {
next_cpu = first_cpu;
}

4
cpus.h
View File

@ -8,6 +8,10 @@ void resume_all_vcpus(void);
void pause_all_vcpus(void);
void cpu_stop_current(void);
void cpu_synchronize_all_states(void);
void cpu_synchronize_all_post_reset(void);
void cpu_synchronize_all_post_init(void);
/* vl.c */
extern int smp_cores;
extern int smp_threads;

View File

@ -211,7 +211,7 @@ void do_compare_and_swap32(void *cpu_env, int num)
uint32_t *value = (uint32_t*)((CPUX86State*)cpu_env)->regs[R_ECX];
DPRINTF("commpage: compare_and_swap32(%x,new,%p)\n", old, value);
if(value && old == tswap32(*value))
if(old == tswap32(*value))
{
uint32_t new = ((CPUX86State*)cpu_env)->regs[R_EDX];
*value = tswap32(new);

View File

@ -1,4 +1,6 @@
# Default configuration for lm32-softmmu
CONFIG_PTIMER=y
CONFIG_PFLASH_CFI01=y
CONFIG_PFLASH_CFI02=y
CONFIG_SD=y

View File

@ -0,0 +1 @@
# Default configuration for unicore32-linux-user

View File

@ -20,7 +20,6 @@
#include "config.h"
#include "qemu-common.h"
#include "sysemu.h"
#include "device_tree.h"
#include "hw/loader.h"
@ -74,7 +73,7 @@ fail:
}
int qemu_devtree_setprop(void *fdt, const char *node_path,
const char *property, uint32_t *val_array, int size)
const char *property, void *val_array, int size)
{
int offset;

View File

@ -17,7 +17,7 @@
void *load_device_tree(const char *filename_path, int *sizep);
int qemu_devtree_setprop(void *fdt, const char *node_path,
const char *property, uint32_t *val_array, int size);
const char *property, void *val_array, int size);
int qemu_devtree_setprop_cell(void *fdt, const char *node_path,
const char *property, uint32_t val);
int qemu_devtree_setprop_string(void *fdt, const char *node_path,

View File

@ -215,6 +215,9 @@ void target_disas(FILE *out, target_ulong code, target_ulong size, int flags)
disasm_info.mach = bfd_mach_cris_v32;
print_insn = print_insn_crisv32;
}
#elif defined(TARGET_S390X)
disasm_info.mach = bfd_mach_s390_64;
print_insn = print_insn_s390;
#elif defined(TARGET_MICROBLAZE)
disasm_info.mach = bfd_arch_microblaze;
print_insn = print_insn_microblaze;
@ -342,7 +345,7 @@ monitor_read_memory (bfd_vma memaddr, bfd_byte *myaddr, int length,
struct disassemble_info *info)
{
if (monitor_disas_is_physical) {
cpu_physical_memory_rw(memaddr, myaddr, length, 0);
cpu_physical_memory_read(memaddr, myaddr, length);
} else {
cpu_memory_rw_debug(monitor_disas_env, memaddr,myaddr, length, 0);
}
@ -414,6 +417,9 @@ void monitor_disas(Monitor *mon, CPUState *env,
#elif defined(TARGET_SH4)
disasm_info.mach = bfd_mach_sh4;
print_insn = print_insn_sh;
#elif defined(TARGET_S390X)
disasm_info.mach = bfd_mach_s390_64;
print_insn = print_insn_s390;
#else
monitor_printf(mon, "0x" TARGET_FMT_lx
": Asm output not supported on this arch\n", pc);

135
docs/ccid.txt Normal file
View File

@ -0,0 +1,135 @@
Qemu CCID Device Documentation.
Contents
1. USB CCID device
2. Building
3. Using ccid-card-emulated with hardware
4. Using ccid-card-emulated with certificates
5. Using ccid-card-passthru with client side hardware
6. Using ccid-card-passthru with client side certificates
7. Passthrough protocol scenario
8. libcacard
1. USB CCID device
The USB CCID device is a USB device implementing the CCID specification, which
lets one connect smart card readers that implement the same spec. For more
information see the specification:
Universal Serial Bus
Device Class: Smart Card
CCID
Specification for
Integrated Circuit(s) Cards Interface Devices
Revision 1.1
April 22rd, 2005
Smartcard are used for authentication, single sign on, decryption in
public/private schemes and digital signatures. A smartcard reader on the client
cannot be used on a guest with simple usb passthrough since it will then not be
available on the client, possibly locking the computer when it is "removed". On
the other hand this device can let you use the smartcard on both the client and
the guest machine. It is also possible to have a completely virtual smart card
reader and smart card (i.e. not backed by a physical device) using this device.
2. Building
The cryptographic functions and access to the physical card is done via NSS.
Installing NSS:
In redhat/fedora:
yum install nss-devel
In ubuntu/debian:
apt-get install libnss3-dev
(not tested on ubuntu)
Configuring and building:
./configure --enable-smartcard && make
3. Using ccid-card-emulated with hardware
Assuming you have a working smartcard on the host with the current
user, using NSS, qemu acts as another NSS client using ccid-card-emulated:
qemu -usb -device usb-ccid -device ccid-card-emualated
4. Using ccid-card-emulated with certificates
You must create the certificates. This is a one time process. We use NSS
certificates:
certutil -d /etc/pki/nssdb -x -t "CT,CT,CT" -S -s "CN=cert1" -n cert1
Note: you must have exactly three certificates.
Assuming the current user can access the certificates (use certutil -L to
verify), you can use the emulated card type with the certificates backend:
qemu -usb -device usb-ccid -device ccid-card-emulated,backend=certificates,cert1=cert1,cert2=cert2,cert3=cert3
5. Using ccid-card-passthru with client side hardware
on the host specify the ccid-card-passthru device with a suitable chardev:
qemu -chardev socket,server,host=0.0.0.0,port=2001,id=ccid,nowait -usb -device usb-ccid -device ccid-card-passthru,chardev=ccid
on the client run vscclient, built when you built the libcacard library:
libcacard/vscclient <qemu-host> 2001
6. Using ccid-card-passthru with client side certificates
Run qemu as per #5, and run vscclient as follows:
(Note: vscclient command line interface is in a state of change)
libcacard/vscclient -e "db=\"/etc/pki/nssdb\" use_hw=no soft=(,Test,CAC,,cert1,cert2,cert3)" <qemu-host> 2001
7. Passthrough protocol scenario
This is a typical interchange of messages when using the passthru card device.
usb-ccid is a usb device. It defaults to an unattached usb device on startup.
usb-ccid expects a chardev and expects the protocol defined in
cac_card/vscard_common.h to be passed over that.
The usb-ccid device can be in one of three modes:
* detached
* attached with no card
* attached with card
A typical interchange is: (the arrow shows who started each exchange, it can be client
originated or guest originated)
client event | vscclient | passthru | usb-ccid | guest event
----------------------------------------------------------------------------------------------
| VSC_Init | | |
| VSC_ReaderAdd | | attach |
| | | | sees new usb device.
card inserted -> | | | |
| VSC_ATR | insert | insert | see new card
| | | |
| VSC_APDU | VSC_APDU | | <- guest sends APDU
client<->physical | | | |
card APDU exchange| | | |
client response ->| VSC_APDU | VSC_APDU | | receive APDU response
...
[APDU<->APDU repeats several times]
...
card removed -> | | | |
| VSC_CardRemove | remove | remove | card removed
...
[(card insert, apdu's, card remove) repeat]
...
kill/quit | | | |
vscclient | | | |
| VSC_ReaderRemove | | detach |
| | | | usb device removed.
8. libcacard
ccid-card-passthru and vscclient use libcacard as the card emulator.
libcacard implements a completely virtual CAC (DoD standard for smart cards)
compliant card and uses NSS to actually retrive certificates and do any
encryption using the backend (real reader + card or file backed certificates).
For documentation of cac_card see README in libcacard subdirectory.

483
docs/libcacard.txt Normal file
View File

@ -0,0 +1,483 @@
This file documents the CAC (Common Access Card) library in the libcacard
subdirectory.
Virtual Smart Card Emulator
This emulator is designed to provide emulation of actual smart cards to a
virtual card reader running in a guest virtual machine. The emulated smart
cards can be representations of real smart cards, where the necessary functions
such as signing, card removal/insertion, etc. are mapped to real, physical
cards which are shared with the client machine the emulator is running on, or
the cards could be pure software constructs.
The emulator is structured to allow multiple replacable or additional pieces,
so it can be easily modified for future requirements. The primary envisioned
modifications are:
1) The socket connection to the virtual card reader (presumably a CCID reader,
but other ISO-7816 compatible readers could be used). The code that handles
this is in vscclient.c.
2) The virtual card low level emulation. This is currently supplied by using
NSS. This emulation could be replaced by implementations based on other
security libraries, including but not limitted to openssl+pkcs#11 library,
raw pkcs#11, Microsoft CAPI, direct opensc calls, etc. The code that handles
this is in vcard_emul_nss.c.
3) Emulation for new types of cards. The current implementation emulates the
original DoD CAC standard with separate pki containers. This emulator lives in
cac.c. More than one card type emulator could be included. Other cards could
be emulated as well, including PIV, newer versions of CAC, PKCS #15, etc.
--------------------
Replacing the Socket Based Virtual Reader Interface.
The current implementation contains a replacable module vscclient.c. The
current vscclient.c implements a sockets interface to the virtual ccid reader
on the guest. CCID commands that are pertinent to emulation are passed
across the socket, and their responses are passed back along that same socket.
The protocol that vscclient uses is defined in vscard_common.h and connects
to a qemu ccid usb device. Since this socket runs as a client, vscclient.c
implements a program with a main entry. It also handles argument parsing for
the emulator.
An application that wants to use the virtual reader can replace vscclient.c
with it's own implementation that connects to it's own CCID reader. The calls
that the CCID reader can call are:
VReaderList * vreader_get_reader_list();
This function returns a list of virtual readers. These readers may map to
physical devices, or simulated devices depending on vcard the back end. Each
reader in the list should represent a reader to the virtual machine. Virtual
USB address mapping is left to the CCID reader front end. This call can be
made any time to get an updated list. The returned list is a copy of the
internal list that can be referenced by the caller without locking. This copy
must be freed by the caller with vreader_list_delete when it is no longer
needed.
VReaderListEntry *vreader_list_get_first(VReaderList *);
This function gets the first entry on the reader list. Along with
vreader_list_get_next(), vreader_list_get_first() can be used to walk the
reader list returned from vreader_get_reader_list(). VReaderListEntries are
part of the list themselves and do not need to be freed separately from the
list. If there are no entries on the list, it will return NULL.
VReaderListEntry *vreader_list_get_next(VReaderListEntry *);
This function gets the next entry in the list. If there are no more entries
it will return NULL.
VReader * vreader_list_get_reader(VReaderListEntry *)
This function returns the reader stored in the reader List entry. Caller gets
a new reference to a reader. The caller must free it's reference when it is
finished with vreader_free().
void vreader_free(VReader *reader);
This function frees a reference to a reader. Reader's are reference counted
and are automatically deleted when the last reference is freed.
void vreader_list_delete(VReaderList *list);
This function frees the list, all the elements on the list, and all the
reader references held by the list.
VReaderStatus vreader_power_on(VReader *reader, char *atr, int *len);
This functions simulates a card power on. Virtual cards do not care about
the actual voltage and other physical parameters, but it does care that the
card is actually on or off. Cycling the card causes the card to reset. If
the caller provides enough space, vreader_power_on will return the ATR of
the virtual card. The amount of space provided in atr should be indicated
in *len. The function modifies *len to be the actual length of of the
returned ATR.
VReaderStatus vreader_power_off(VReader *reader);
This function simulates a power off of a virtual card.
VReaderStatus vreader_xfer_bytes(VReader *reader, unsigne char *send_buf,
int send_buf_len,
unsigned char *receive_buf,
int receive_buf_len);
This functions send a raw apdu to a card and returns the card's response.
The CCID front end should return the response back. Most of the emulation
is driven from these APDUs.
VReaderStatus vreader_card_is_present(VReader *reader);
This function returns whether or not the reader has a card inserted. The
vreader_power_on, vreader_power_off, and vreader_xfer_bytes will return
VREADER_NO_CARD.
const char *vreader_get_name(VReader *reader);
This function returns the name of the reader. The name comes from the card
emulator level and is usually related to the name of the physical reader.
VReaderID vreader_get_id(VReader *reader);
This function returns the id of a reader. All readers start out with an id
of -1. The application can set the id with vreader_set_id.
VReaderStatus vreader_get_id(VReader *reader, VReaderID id);
This function sets the reader id. The application is responsible for making
sure that the id is unique for all readers it is actively using.
VReader *vreader_find_reader_by_id(VReaderID id);
This function returns the reader which matches the id. If two readers match,
only one is returned. The function returns NULL if the id is -1.
Event *vevent_wait_next_vevent();
This function blocks waiting for reader and card insertion events. There
will be one event for each card insertion, each card removal, each reader
insertion and each reader removal. At start up, events are created for all
the initial readers found, as well as all the cards that are inserted.
Event *vevent_get_next_vevent();
This function returns a pending event if it exists, otherwise it returns
NULL. It does not block.
----------------
Card Type Emulator: Adding a New Virtual Card Type
The ISO 7816 card spec describes 2 types of cards:
1) File system cards, where the smartcard is managed by reading and writing
data to files in a file system. There is currently only boiler plate
implemented for file system cards.
2) VM cards, where the card has loadable applets which perform the card
functions. The current implementation supports VM cards.
In the case of VM cards, the difference between various types of cards is
really what applets have been installed in that card. This structure is
mirrored in card type emulators. The 7816 emulator already handles the basic
ISO 7186 commands. Card type emulators simply need to add the virtual applets
which emulate the real card applets. Card type emulators have exactly one
public entry point:
VCARDStatus xxx_card_init(VCard *card, const char *flags,
const unsigned char *cert[],
int cert_len[],
VCardKey *key[],
int cert_count);
The parameters for this are:
card - the virtual card structure which will prepresent this card.
flags - option flags that may be specific to this card type.
cert - array of binary certificates.
cert_len - array of lengths of each of the certificates specified in cert.
key - array of opaque key structures representing the private keys on
the card.
cert_count - number of entries in cert, cert_len, and key arrays.
Any cert, cert_len, or key with the same index are matching sets. That is
cert[0] is cert_len[0] long and has the corresponsing private key of key[0].
The card type emulator is expected to own the VCardKeys, but it should copy
any raw cert data it wants to save. It can create new applets and add them to
the card using the following functions:
VCardApplet *vcard_new_applet(VCardProcessAPDU apdu_func,
VCardResetApplet reset_func,
const unsigned char *aid,
int aid_len);
This function creates a new applet. Applet structures store the following
information:
1) the AID of the applet (set by aid and aid_len).
2) a function to handle APDUs for this applet. (set by apdu_func, more on
this below).
3) a function to reset the applet state when the applet is selected.
(set by reset_func, more on this below).
3) applet private data, a data pointer used by the card type emulator to
store any data or state it needs to complete requests. (set by a
separate call).
4) applet private data free, a function used to free the applet private
data when the applet itself is destroyed.
The created applet can be added to the card with vcard_add_applet below.
void vcard_set_applet_private(VCardApplet *applet,
VCardAppletPrivate *private,
VCardAppletPrivateFree private_free);
This function sets the private data and the corresponding free function.
VCardAppletPrivate is an opaque data structure to the rest of the emulator.
The card type emulator can define it any way it wants by defining
struct VCardAppletPrivateStruct {};. If there is already a private data
structure on the applet, the old one is freed before the new one is set up.
passing two NULL clear any existing private data.
VCardStatus vcard_add_applet(VCard *card, VCardApplet *applet);
Add an applet onto the list of applets attached to the card. Once an applet
has been added, it can be selected by it's aid, and then commands will be
routed to it VCardProcessAPDU function. This function adopts the applet the
passed int applet. Note: 2 applets with the same AID should not be added to
the same card. It's permissible to add more than one applet. Multiple applets
may have the same VCardPRocessAPDU entry point.
The certs and keys should be attached to private data associated with one or
more appropriate applets for that card. Control will come to the card type
emulators once one of its applets are selected through the VCardProcessAPDU
function it specified when it created the applet.
The signature of VCardResetApplet is:
VCardStatus (*VCardResetApplet) (VCard *card, int channel);
This function will reset the any internal applet state that needs to be
cleared after a select applet call. It should return VCARD_DONE;
The signature of VCardProcessAPDU is:
VCardStatus (*VCardProcessAPDU)(VCard *card, VCardAPDU *apdu,
VCardResponse **response);
This function examines the APDU and determines whether it should process
the apdu directly, reject the apdu as invalid, or pass the apdu on to
the basic 7816 emulator for processing.
If the 7816 emulator should process the apdu, then the VCardProcessAPDU
should return VCARD_NEXT.
If there is an error, then VCardProcessAPDU should return an error
response using vcard_make_response and the appropriate 7816 error code
(see card_7816t.h) or vcard_make_response with a card type specific error
code. It should then return VCARD_DONE.
If the apdu can be processed correctly, VCardProcessAPDU should do so,
set the response value appropriately for that APDU, and return VCARD_DONE.
VCardProcessAPDU should always set the response if it returns VCARD_DONE.
It should always either return VCARD_DONE or VCARD_NEXT.
Parsing the APDU --
Prior to processing calling the card type emulator's VCardProcessAPDU function, the emulator has already decoded the APDU header and set several fields:
apdu->a_data - The raw apdu data bytes.
apdu->a_len - The len of the raw apdu data.
apdu->a_body - The start of any post header parameter data.
apdu->a_Lc - The parameter length value.
apdu->a_Le - The expected length of any returned data.
apdu->a_cla - The raw apdu class.
apdu->a_channel - The channel (decoded from the class).
apdu->a_secure_messaging_type - The decoded secure messagin type
(from class).
apdu->a_type - The decode class type.
apdu->a_gen_type - the generic class type (7816, PROPRIETARY, RFU, PTS).
apdu->a_ins - The instruction byte.
apdu->a_p1 - Parameter 1.
apdu->a_p2 - Parameter 2.
Creating a Response --
The expected result of any APDU call is a response. The card type emulator must
set *response with an appropriate VCardResponse value if it returns VCARD_DONE.
Reponses could be as simple as returning a 2 byte status word response, to as
complex as returning a block of data along with a 2 byte response. Which is
returned will depend on the semantics of the APDU. The following functions will
create card responses.
VCardResponse *vcard_make_response(VCard7816Status status);
This is the most basic function to get a response. This function will
return a response the consists soley one 2 byte status code. If that status
code is defined in card_7816t.h, then this function is guarrenteed to
return a response with that status. If a cart type specific status code
is passed and vcard_make_response fails to allocate the appropriate memory
for that response, then vcard_make_response will return a VCardResponse
of VCARD7816_STATUS_EXC_ERROR_MEMORY. In any case, this function is
guarrenteed to return a valid VCardResponse.
VCardResponse *vcard_response_new(unsigned char *buf, int len,
VCard7816Status status);
This function is similar to vcard_make_response except it includes some
returned data with the response. It could also fail to allocate enough
memory, in which case it will return NULL.
VCardResponse *vcard_response_new_status_bytes(unsigned char sw1,
unsigned char sw2);
Sometimes in 7816 the response bytes are treated as two separate bytes with
split meanings. This function allows you to create a response based on
two separate bytes. This function could fail, in which case it will return
NULL.
VCardResponse *vcard_response_new_bytes(unsigned char *buf, int len,
unsigned char sw1,
unsigned char sw2);
This function is the same as vcard_response_new except you may specify
the status as two separate bytes like vcard_response_new_status_bytes.
Implementing functionality ---
The following helper functions access information about the current card
and applet.
VCARDAppletPrivate *vcard_get_current_applet_private(VCard *card,
int channel);
This function returns any private data set by the card type emulator on
the currently selected applet. The card type emulator keeps track of the
current applet state in this data structure. Any certs and keys associated
with a particular applet is also stored here.
int vcard_emul_get_login_count(VCard *card);
This function returns the the number of remaing login attempts for this
card. If the card emulator does not know, or the card does not have a
way of giving this information, this function returns -1.
VCard7816Status vcard_emul_login(VCard *card, unsigned char *pin,
int pin_len);
This function logins into the card and return the standard 7816 status
word depending on the success or failure of the call.
void vcard_emul_delete_key(VCardKey *key);
This function frees the VCardKey passed in to xxxx_card_init. The card
type emulator is responsible for freeing this key when it no longer needs
it.
VCard7816Status vcard_emul_rsa_op(VCard *card, VCardKey *key,
unsigned char *buffer,
int buffer_size);
This function does a raw rsa op on the buffer with the given key.
The sample card type emulator is found in cac.c. It implements the cac specific
applets. Only those applets needed by the coolkey pkcs#11 driver on the guest
have been implemented. To support the full range CAC middleware, a complete CAC
card according to the CAC specs should be implemented here.
------------------------------
Virtual Card Emulator
This code accesses both real smart cards and simulated smart cards through
services provided on the client. The current implementation uses NSS, which
already knows how to talk to various PKCS #11 modules on the client, and is
portable to most operating systems. A particular emulator can have only one
virtual card implementation at a time.
The virtual card emulator consists of a series of virtual card services. In
addition to the services describe above (services starting with
vcard_emul_xxxx), the virtual card emulator also provides the following
functions:
VCardEmulError vcard_emul_init(cont VCardEmulOptions *options);
The options structure is built by another function in the virtual card
interface where a string of virtual card emulator specific strings are
mapped to the options. The actual structure is defined by the virutal card
emulator and is used to determine the configuration of soft cards, or to
determine which physical cards to present to the guest.
The vcard_emul_init function will build up sets of readers, create any
threads that are needed to watch for changes in the reader state. If readers
have cards present in them, they are also initialized.
Readers are created with the function.
VReader *vreader_new(VReaderEmul *reader_emul,
VReaderEmulFree reader_emul_free);
The freeFunc is used to free the VReaderEmul * when the reader is
destroyed. The VReaderEmul structure is an opaque structure to the
rest of the code, but defined by the virtual card emulator, which can
use it to store any reader specific state.
Once the reader has been created, it can be added to the front end with the
call:
VReaderStatus vreader_add_reader(VReader *reader);
This function will automatically generate the appropriate new reader
events and add the reader to the list.
To create a new card, the virtual card emulator will call a similiar
function.
VCard *vcard_new(VCardEmul *card_emul,
VCardEmulFree card_emul_free);
Like vreader_new, this function takes a virtual card emulator specific
structure which it uses to keep track of the card state.
Once the card is created, it is attached to a card type emulator with the
following function:
VCardStatus vcard_init(VCard *vcard, VCardEmulType type,
const char *flags,
unsigned char *const *certs,
int *cert_len,
VCardKey *key[],
int cert_count);
The vcard is the value returned from vcard_new. The type is the
card type emulator that this card should presented to the guest as.
The flags are card type emulator specific options. The certs,
cert_len, and keys are all arrays of length cert_count. These are the
the same of the parameters xxxx_card_init() accepts.
Finally the card is associated with it's reader by the call:
VReaderStatus vreader_insert_card(VReader *vreader, VCard *vcard);
This function, like vreader_add_reader, will take care of any event
notification for the card insert.
VCardEmulError vcard_emul_force_card_remove(VReader *vreader);
Force a card that is present to appear to be removed to the guest, even if
that card is a physical card and is present.
VCardEmulError vcard_emul_force_card_insert(VReader *reader);
Force a card that has been removed by vcard_emul_force_card_remove to be
reinserted from the point of view of the guest. This will only work if the
card is physically present (which is always true fro a soft card).
void vcard_emul_get_atr(Vcard *card, unsigned char *atr, int *atr_len);
Return the virtual ATR for the card. By convention this should be the value
VCARD_ATR_PREFIX(size) followed by several ascii bytes related to this
particular emulator. For instance the NSS emulator returns
{VCARD_ATR_PREFIX(3), 'N', 'S', 'S' }. Do ot return more data then *atr_len;
void vcard_emul_reset(VCard *card, VCardPower power)
Set the state of 'card' to the current power level and reset its internal
state (logout, etc).
-------------------------------------------------------
List of files and their function:
README - This file
card_7816.c - emulate basic 7816 functionality. Parse APDUs.
card_7816.h - apdu and response services definitions.
card_7816t.h - 7816 specific structures, types and definitions.
event.c - event handling code.
event.h - event handling services definitions.
eventt.h - event handling structures and types
vcard.c - handle common virtual card services like creation, destruction, and
applet management.
vcard.h - common virtual card services function definitions.
vcardt.h - comon virtual card types
vreader.c - common virtual reader services.
vreader.h - common virtual reader services definitions.
vreadert.h - comon virtual reader types.
vcard_emul_type.c - manage the card type emulators.
vcard_emul_type.h - definitions for card type emulators.
cac.c - card type emulator for CAC cards
vcard_emul.h - virtual card emulator service definitions.
vcard_emul_nss.c - virtual card emulator implementation for nss.
vscclient.c - socket connection to guest qemu usb driver.
vscard_common.h - common header with the guest qemu usb driver.
mutex.h - header file for machine independent mutexes.
link_test.c - static test to make sure all the symbols are properly defined.

View File

@ -89,6 +89,7 @@ L1, L2, and data cluster offsets must be aligned to header.cluster_size. The fo
===Data cluster offsets===
* 0 - unallocated. The data cluster is not yet allocated.
* 1 - zero. The data cluster contents are all zeroes and no cluster is allocated.
Future format extensions may wish to store per-offset information. The least significant 12 bits of an offset are reserved for this purpose and must be set to zero. Image files with cluster_size > 2^12 will have more unused bits which should also be zeroed.
@ -97,6 +98,13 @@ Reads to an unallocated area of the image file access the backing file. If ther
Writes to an unallocated area cause a new data clusters to be allocated, and a new L2 table if that is also unallocated. The new data cluster is populated with data from the backing file (or zeroes if no backing file) and the data being written.
===Zero data clusters===
Zero data clusters are a space-efficient way of storing zeroed regions of the image.
Reads to a zero data cluster produce zeroes. Note that the difference between an unallocated and a zero data cluster is that zero data clusters stop the reading of contents from the backing file.
Writes to a zero data cluster cause a new data cluster to be allocated. The new data cluster is populated with zeroes and the data being written.
===Logical offset translation===
Logical offsets are translated into cluster offsets as follows:

View File

@ -26,14 +26,14 @@ for debugging, profiling, and observing execution.
== Trace events ==
There is a set of static trace events declared in the trace-events source
There is a set of static trace events declared in the "trace-events" source
file. Each trace event declaration names the event, its arguments, and the
format string which can be used for pretty-printing:
qemu_malloc(size_t size, void *ptr) "size %zu ptr %p"
qemu_free(void *ptr) "ptr %p"
The trace-events file is processed by the tracetool script during build to
The "trace-events" file is processed by the "tracetool" script during build to
generate code for the trace events. Trace events are invoked directly from
source code like this:
@ -52,10 +52,10 @@ source code like this:
=== Declaring trace events ===
The tracetool script produces the trace.h header file which is included by
The "tracetool" script produces the trace.h header file which is included by
every source file that uses trace events. Since many source files include
trace.h, it uses a minimum of types and other header files included to keep
the namespace clean and compile times and dependencies down.
trace.h, it uses a minimum of types and other header files included to keep the
namespace clean and compile times and dependencies down.
Trace events should use types as follows:
@ -69,6 +69,11 @@ Trace events should use types as follows:
cannot include all user-defined struct declarations and it is therefore
necessary to use void * for pointers to structs.
Pointers (including char *) cannot be dereferenced easily (or at all) in
some trace backends. If pointers are used, ensure they are meaningful by
themselves and do not assume the data they point to will be traced. Do
not pass in string arguments.
* For everything else, use primitive scalar types (char, int, long) with the
appropriate signedness.
@ -105,10 +110,10 @@ portability macros, ensure they are preceded and followed by double quotes:
== Trace backends ==
The tracetool script automates tedious trace event code generation and also
The "tracetool" script automates tedious trace event code generation and also
keeps the trace event declarations independent of the trace backend. The trace
events are not tightly coupled to a specific trace backend, such as LTTng or
SystemTap. Support for trace backends can be added by extending the tracetool
SystemTap. Support for trace backends can be added by extending the "tracetool"
script.
The trace backend is chosen at configure time and only one trace backend can
@ -176,12 +181,12 @@ events at runtime inside QEMU:
==== Analyzing trace files ====
The "simple" backend produces binary trace files that can be formatted with the
simpletrace.py script. The script takes the trace-events file and the binary
simpletrace.py script. The script takes the "trace-events" file and the binary
trace:
./simpletrace.py trace-events trace-12345
You must ensure that the same trace-events file was used to build QEMU,
You must ensure that the same "trace-events" file was used to build QEMU,
otherwise trace event declarations may have changed and output will not be
consistent.

2
elf.h
View File

@ -106,6 +106,8 @@ typedef int64_t Elf64_Sxword;
#define EM_H8S 48 /* Hitachi H8S */
#define EM_LATTICEMICO32 138 /* LatticeMico32 */
#define EM_UNICORE32 110 /* UniCore32 */
/*
* This is an interim value that we will use until the committee comes
* up with a final number.

View File

@ -77,15 +77,14 @@ extern uint16_t gen_opc_icount[OPC_BUF_SIZE];
void gen_intermediate_code(CPUState *env, struct TranslationBlock *tb);
void gen_intermediate_code_pc(CPUState *env, struct TranslationBlock *tb);
void gen_pc_load(CPUState *env, struct TranslationBlock *tb,
unsigned long searched_pc, int pc_pos, void *puc);
void restore_state_to_opc(CPUState *env, struct TranslationBlock *tb,
int pc_pos);
void cpu_gen_init(void);
int cpu_gen_code(CPUState *env, struct TranslationBlock *tb,
int *gen_code_size_ptr);
int cpu_restore_state(struct TranslationBlock *tb,
CPUState *env, unsigned long searched_pc,
void *puc);
CPUState *env, unsigned long searched_pc);
void cpu_resume_from_signal(CPUState *env1, void *puc);
void cpu_io_recompile(CPUState *env, void *retaddr);
TranslationBlock *tb_gen_code(CPUState *env,

39
exec.c
View File

@ -1070,8 +1070,7 @@ void tb_invalidate_phys_page_range(tb_page_addr_t start, tb_page_addr_t end,
restore the CPU state */
current_tb_modified = 1;
cpu_restore_state(current_tb, env,
env->mem_io_pc, NULL);
cpu_restore_state(current_tb, env, env->mem_io_pc);
cpu_get_tb_cpu_state(env, &current_pc, &current_cs_base,
&current_flags);
}
@ -1179,7 +1178,7 @@ static void tb_invalidate_phys_page(tb_page_addr_t addr,
restore the CPU state */
current_tb_modified = 1;
cpu_restore_state(current_tb, env, pc, puc);
cpu_restore_state(current_tb, env, pc);
cpu_get_tb_cpu_state(env, &current_pc, &current_cs_base,
&current_flags);
}
@ -1630,15 +1629,15 @@ static void cpu_unlink_tb(CPUState *env)
spin_unlock(&interrupt_lock);
}
#ifndef CONFIG_USER_ONLY
/* mask must never be zero, except for A20 change call */
void cpu_interrupt(CPUState *env, int mask)
static void tcg_handle_interrupt(CPUState *env, int mask)
{
int old_mask;
old_mask = env->interrupt_request;
env->interrupt_request |= mask;
#ifndef CONFIG_USER_ONLY
/*
* If called from iothread context, wake the target cpu in
* case its halted.
@ -1647,21 +1646,29 @@ void cpu_interrupt(CPUState *env, int mask)
qemu_cpu_kick(env);
return;
}
#endif
if (use_icount) {
env->icount_decr.u16.high = 0xffff;
#ifndef CONFIG_USER_ONLY
if (!can_do_io(env)
&& (mask & ~old_mask) != 0) {
cpu_abort(env, "Raised interrupt while not in I/O function");
}
#endif
} else {
cpu_unlink_tb(env);
}
}
CPUInterruptHandler cpu_interrupt_handler = tcg_handle_interrupt;
#else /* CONFIG_USER_ONLY */
void cpu_interrupt(CPUState *env, int mask)
{
env->interrupt_request |= mask;
cpu_unlink_tb(env);
}
#endif /* CONFIG_USER_ONLY */
void cpu_reset_interrupt(CPUState *env, int mask)
{
env->interrupt_request &= ~mask;
@ -2621,6 +2628,7 @@ void cpu_register_physical_memory_log(target_phys_addr_t start_addr,
ram_addr_t orig_size = size;
subpage_t *subpage;
assert(size);
cpu_notify_set_memory(start_addr, size, phys_offset, log_dirty);
if (phys_offset == IO_MEM_UNASSIGNED) {
@ -2629,7 +2637,9 @@ void cpu_register_physical_memory_log(target_phys_addr_t start_addr,
region_offset &= TARGET_PAGE_MASK;
size = (size + TARGET_PAGE_SIZE - 1) & TARGET_PAGE_MASK;
end_addr = start_addr + (target_phys_addr_t)size;
for(addr = start_addr; addr != end_addr; addr += TARGET_PAGE_SIZE) {
addr = start_addr;
do {
p = phys_page_find(addr >> TARGET_PAGE_BITS);
if (p && p->phys_offset != IO_MEM_UNASSIGNED) {
ram_addr_t orig_memory = p->phys_offset;
@ -2681,7 +2691,8 @@ void cpu_register_physical_memory_log(target_phys_addr_t start_addr,
}
}
region_offset += TARGET_PAGE_SIZE;
}
addr += TARGET_PAGE_SIZE;
} while (addr != end_addr);
/* since each CPU stores ram addresses in its TLB cache, we must
reset the modified entries */
@ -3272,7 +3283,7 @@ static void check_watchpoint(int offset, int len_mask, int flags)
cpu_abort(env, "check_watchpoint: could not find TB for "
"pc=%p", (void *)env->mem_io_pc);
}
cpu_restore_state(tb, env, env->mem_io_pc, NULL);
cpu_restore_state(tb, env, env->mem_io_pc);
tb_phys_invalidate(tb, -1);
if (wp->flags & BP_STOP_BEFORE_ACCESS) {
env->exception_index = EXCP_DEBUG;
@ -3938,7 +3949,7 @@ void *cpu_physical_memory_map(target_phys_addr_t addr,
bounce.addr = addr;
bounce.len = l;
if (!is_write) {
cpu_physical_memory_rw(addr, bounce.buffer, l, 0);
cpu_physical_memory_read(addr, bounce.buffer, l);
}
ptr = bounce.buffer;
} else {
@ -4259,7 +4270,7 @@ void stw_phys(target_phys_addr_t addr, uint32_t val)
void stq_phys(target_phys_addr_t addr, uint64_t val)
{
val = tswap64(val);
cpu_physical_memory_write(addr, (const uint8_t *)&val, 8);
cpu_physical_memory_write(addr, &val, 8);
}
/* virtual memory access for debug (includes writing to ROM) */
@ -4307,7 +4318,7 @@ void cpu_io_recompile(CPUState *env, void *retaddr)
retaddr);
}
n = env->icount_decr.u16.low + tb->icount;
cpu_restore_state(tb, env, (unsigned long)retaddr, NULL);
cpu_restore_state(tb, env, (unsigned long)retaddr);
/* Calculate how many instructions had been executed before the fault
occurred. */
n = n - env->icount_decr.u16.low;

View File

@ -35,6 +35,17 @@ these four paragraphs for those parts of this code that are retained.
=============================================================================*/
/*----------------------------------------------------------------------------
| This macro tests for minimum version of the GNU C compiler.
*----------------------------------------------------------------------------*/
#if defined(__GNUC__) && defined(__GNUC_MINOR__)
# define SOFTFLOAT_GNUC_PREREQ(maj, min) \
((__GNUC__ << 16) + __GNUC_MINOR__ >= ((maj) << 16) + (min))
#else
# define SOFTFLOAT_GNUC_PREREQ(maj, min) 0
#endif
/*----------------------------------------------------------------------------
| Shifts `a' right by the number of bits given in `count'. If any nonzero
| bits are shifted off, they are ``jammed'' into the least significant bit of
@ -616,6 +627,13 @@ static uint32_t estimateSqrt32( int16 aExp, uint32_t a )
static int8 countLeadingZeros32( uint32_t a )
{
#if SOFTFLOAT_GNUC_PREREQ(3, 4)
if (a) {
return __builtin_clz(a);
} else {
return 32;
}
#else
static const int8 countLeadingZerosHigh[] = {
8, 7, 6, 6, 5, 5, 5, 5, 4, 4, 4, 4, 4, 4, 4, 4,
3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
@ -647,7 +665,7 @@ static int8 countLeadingZeros32( uint32_t a )
}
shiftCount += countLeadingZerosHigh[ a>>24 ];
return shiftCount;
#endif
}
/*----------------------------------------------------------------------------
@ -657,6 +675,13 @@ static int8 countLeadingZeros32( uint32_t a )
static int8 countLeadingZeros64( uint64_t a )
{
#if SOFTFLOAT_GNUC_PREREQ(3, 4)
if (a) {
return __builtin_clzll(a);
} else {
return 64;
}
#else
int8 shiftCount;
shiftCount = 0;
@ -668,7 +693,7 @@ static int8 countLeadingZeros64( uint64_t a )
}
shiftCount += countLeadingZeros32( a );
return shiftCount;
#endif
}
/*----------------------------------------------------------------------------

View File

@ -263,6 +263,15 @@ int float32_is_quiet_nan( float32 a1 )
return ( 0xFF800000 < ( a<<1 ) );
}
int float32_is_any_nan( float32 a1 )
{
float32u u;
uint32_t a;
u.f = a1;
a = u.i;
return (a & ~(1 << 31)) > 0x7f800000U;
}
/*----------------------------------------------------------------------------
| Software IEC/IEEE double-precision conversion routines.
*----------------------------------------------------------------------------*/
@ -422,6 +431,16 @@ int float64_is_quiet_nan( float64 a1 )
}
int float64_is_any_nan( float64 a1 )
{
float64u u;
uint64_t a;
u.f = a1;
a = u.i;
return (a & ~(1ULL << 63)) > LIT64 (0x7FF0000000000000 );
}
#ifdef FLOATX80
/*----------------------------------------------------------------------------
@ -511,4 +530,11 @@ int floatx80_is_quiet_nan( floatx80 a1 )
return ( ( u.i.high & 0x7FFF ) == 0x7FFF ) && (uint64_t) ( u.i.low<<1 );
}
int floatx80_is_any_nan( floatx80 a1 )
{
floatx80u u;
u.f = a1;
return ((u.i.high & 0x7FFF) == 0x7FFF) && ( u.i.low<<1 );
}
#endif

View File

@ -171,6 +171,15 @@ floatx80 int64_to_floatx80( int64_t STATUS_PARAM);
float128 int64_to_float128( int64_t STATUS_PARAM);
#endif
/*----------------------------------------------------------------------------
| Software IEC/IEEE single-precision conversion constants.
*----------------------------------------------------------------------------*/
#define float32_zero (0.0)
#define float32_one (1.0)
#define float32_ln2 (0.6931471)
#define float32_pi (3.1415926)
#define float32_half (0.5)
/*----------------------------------------------------------------------------
| Software IEC/IEEE single-precision conversion routines.
*----------------------------------------------------------------------------*/
@ -210,7 +219,7 @@ INLINE float32 float32_div( float32 a, float32 b STATUS_PARAM)
}
float32 float32_rem( float32, float32 STATUS_PARAM);
float32 float32_sqrt( float32 STATUS_PARAM);
INLINE int float32_eq( float32 a, float32 b STATUS_PARAM)
INLINE int float32_eq_quiet( float32 a, float32 b STATUS_PARAM)
{
return a == b;
}
@ -222,7 +231,7 @@ INLINE int float32_lt( float32 a, float32 b STATUS_PARAM)
{
return a < b;
}
INLINE int float32_eq_signaling( float32 a, float32 b STATUS_PARAM)
INLINE int float32_eq( float32 a, float32 b STATUS_PARAM)
{
return a <= b && a >= b;
}
@ -237,12 +246,16 @@ INLINE int float32_lt_quiet( float32 a, float32 b STATUS_PARAM)
INLINE int float32_unordered( float32 a, float32 b STATUS_PARAM)
{
return isunordered(a, b);
}
INLINE int float32_unordered_quiet( float32 a, float32 b STATUS_PARAM)
{
return isunordered(a, b);
}
int float32_compare( float32, float32 STATUS_PARAM );
int float32_compare_quiet( float32, float32 STATUS_PARAM );
int float32_is_signaling_nan( float32 );
int float32_is_quiet_nan( float32 );
int float32_is_any_nan( float32 );
INLINE float32 float32_abs(float32 a)
{
@ -271,11 +284,20 @@ INLINE float32 float32_is_zero(float32 a)
return fpclassify(a) == FP_ZERO;
}
INLINE float32 float32_scalbn(float32 a, int n)
INLINE float32 float32_scalbn(float32 a, int n STATUS_PARAM)
{
return scalbnf(a, n);
}
/*----------------------------------------------------------------------------
| Software IEC/IEEE double-precision conversion constants.
*----------------------------------------------------------------------------*/
#define float64_zero (0.0)
#define float64_one (1.0)
#define float64_ln2 (0.693147180559945)
#define float64_pi (3.141592653589793)
#define float64_half (0.5)
/*----------------------------------------------------------------------------
| Software IEC/IEEE double-precision conversion routines.
*----------------------------------------------------------------------------*/
@ -318,7 +340,7 @@ INLINE float64 float64_div( float64 a, float64 b STATUS_PARAM)
}
float64 float64_rem( float64, float64 STATUS_PARAM );
float64 float64_sqrt( float64 STATUS_PARAM );
INLINE int float64_eq( float64 a, float64 b STATUS_PARAM)
INLINE int float64_eq_quiet( float64 a, float64 b STATUS_PARAM)
{
return a == b;
}
@ -330,7 +352,7 @@ INLINE int float64_lt( float64 a, float64 b STATUS_PARAM)
{
return a < b;
}
INLINE int float64_eq_signaling( float64 a, float64 b STATUS_PARAM)
INLINE int float64_eq( float64 a, float64 b STATUS_PARAM)
{
return a <= b && a >= b;
}
@ -346,11 +368,15 @@ INLINE int float64_lt_quiet( float64 a, float64 b STATUS_PARAM)
INLINE int float64_unordered( float64 a, float64 b STATUS_PARAM)
{
return isunordered(a, b);
}
INLINE int float64_unordered_quiet( float64 a, float64 b STATUS_PARAM)
{
return isunordered(a, b);
}
int float64_compare( float64, float64 STATUS_PARAM );
int float64_compare_quiet( float64, float64 STATUS_PARAM );
int float64_is_signaling_nan( float64 );
int float64_is_any_nan( float64 );
int float64_is_quiet_nan( float64 );
INLINE float64 float64_abs(float64 a)
@ -380,13 +406,22 @@ INLINE float64 float64_is_zero(float64 a)
return fpclassify(a) == FP_ZERO;
}
INLINE float64 float64_scalbn(float64 a, int n)
INLINE float64 float64_scalbn(float64 a, int n STATUS_PARAM)
{
return scalbn(a, n);
}
#ifdef FLOATX80
/*----------------------------------------------------------------------------
| Software IEC/IEEE extended double-precision conversion constants.
*----------------------------------------------------------------------------*/
#define floatx80_zero (0.0L)
#define floatx80_one (1.0L)
#define floatx80_ln2 (0.69314718055994530943L)
#define floatx80_pi (3.14159265358979323851L)
#define floatx80_half (0.5L)
/*----------------------------------------------------------------------------
| Software IEC/IEEE extended double-precision conversion routines.
*----------------------------------------------------------------------------*/
@ -422,7 +457,7 @@ INLINE floatx80 floatx80_div( floatx80 a, floatx80 b STATUS_PARAM)
}
floatx80 floatx80_rem( floatx80, floatx80 STATUS_PARAM );
floatx80 floatx80_sqrt( floatx80 STATUS_PARAM );
INLINE int floatx80_eq( floatx80 a, floatx80 b STATUS_PARAM)
INLINE int floatx80_eq_quiet( floatx80 a, floatx80 b STATUS_PARAM)
{
return a == b;
}
@ -434,7 +469,7 @@ INLINE int floatx80_lt( floatx80 a, floatx80 b STATUS_PARAM)
{
return a < b;
}
INLINE int floatx80_eq_signaling( floatx80 a, floatx80 b STATUS_PARAM)
INLINE int floatx80_eq( floatx80 a, floatx80 b STATUS_PARAM)
{
return a <= b && a >= b;
}
@ -450,12 +485,16 @@ INLINE int floatx80_lt_quiet( floatx80 a, floatx80 b STATUS_PARAM)
INLINE int floatx80_unordered( floatx80 a, floatx80 b STATUS_PARAM)
{
return isunordered(a, b);
}
INLINE int floatx80_unordered_quiet( floatx80 a, floatx80 b STATUS_PARAM)
{
return isunordered(a, b);
}
int floatx80_compare( floatx80, floatx80 STATUS_PARAM );
int floatx80_compare_quiet( floatx80, floatx80 STATUS_PARAM );
int floatx80_is_signaling_nan( floatx80 );
int floatx80_is_quiet_nan( floatx80 );
int floatx80_is_any_nan( floatx80 );
INLINE floatx80 floatx80_abs(floatx80 a)
{
@ -484,7 +523,7 @@ INLINE floatx80 floatx80_is_zero(floatx80 a)
return fpclassify(a) == FP_ZERO;
}
INLINE floatx80 floatx80_scalbn(floatx80 a, int n)
INLINE floatx80 floatx80_scalbn(floatx80 a, int n STATUS_PARAM)
{
return scalbnl(a, n);
}

View File

@ -93,7 +93,7 @@ float16 float16_maybe_silence_nan(float16 a_)
{
if (float16_is_signaling_nan(a_)) {
#if SNAN_BIT_IS_ONE
# if defined(TARGET_MIPS) || defined(TARGET_SH4)
# if defined(TARGET_MIPS) || defined(TARGET_SH4) || defined(TARGET_UNICORE32)
return float16_default_nan;
# else
# error Rules for silencing a signaling NaN are target-specific
@ -184,7 +184,7 @@ float32 float32_maybe_silence_nan( float32 a_ )
{
if (float32_is_signaling_nan(a_)) {
#if SNAN_BIT_IS_ONE
# if defined(TARGET_MIPS) || defined(TARGET_SH4)
# if defined(TARGET_MIPS) || defined(TARGET_SH4) || defined(TARGET_UNICORE32)
return float32_default_nan;
# else
# error Rules for silencing a signaling NaN are target-specific
@ -430,7 +430,7 @@ float64 float64_maybe_silence_nan( float64 a_ )
{
if (float64_is_signaling_nan(a_)) {
#if SNAN_BIT_IS_ONE
# if defined(TARGET_MIPS) || defined(TARGET_SH4)
# if defined(TARGET_MIPS) || defined(TARGET_SH4) || defined(TARGET_UNICORE32)
return float64_default_nan;
# else
# error Rules for silencing a signaling NaN are target-specific
@ -578,7 +578,7 @@ floatx80 floatx80_maybe_silence_nan( floatx80 a )
{
if (floatx80_is_signaling_nan(a)) {
#if SNAN_BIT_IS_ONE
# if defined(TARGET_MIPS) || defined(TARGET_SH4)
# if defined(TARGET_MIPS) || defined(TARGET_SH4) || defined(TARGET_UNICORE32)
a.low = floatx80_default_nan_low;
a.high = floatx80_default_nan_high;
# else
@ -603,9 +603,15 @@ static commonNaNT floatx80ToCommonNaN( floatx80 a STATUS_PARAM)
commonNaNT z;
if ( floatx80_is_signaling_nan( a ) ) float_raise( float_flag_invalid STATUS_VAR);
z.sign = a.high>>15;
z.low = 0;
z.high = a.low;
if ( a.low >> 63 ) {
z.sign = a.high >> 15;
z.low = 0;
z.high = a.low << 1;
} else {
z.sign = floatx80_default_nan_high >> 15;
z.low = 0;
z.high = floatx80_default_nan_low << 1;
}
return z;
}
@ -624,11 +630,14 @@ static floatx80 commonNaNToFloatx80( commonNaNT a STATUS_PARAM)
return z;
}
if (a.high)
z.low = a.high;
else
if (a.high >> 1) {
z.low = LIT64( 0x8000000000000000 ) | a.high >> 1;
z.high = ( ( (uint16_t) a.sign )<<15 ) | 0x7FFF;
} else {
z.low = floatx80_default_nan_low;
z.high = ( ( (uint16_t) a.sign )<<15 ) | 0x7FFF;
z.high = floatx80_default_nan_high;
}
return z;
}
@ -721,7 +730,7 @@ float128 float128_maybe_silence_nan( float128 a )
{
if (float128_is_signaling_nan(a)) {
#if SNAN_BIT_IS_ONE
# if defined(TARGET_MIPS) || defined(TARGET_SH4)
# if defined(TARGET_MIPS) || defined(TARGET_SH4) || defined(TARGET_UNICORE32)
a.low = float128_default_nan_low;
a.high = float128_default_nan_high;
# else

View File

@ -2314,33 +2314,33 @@ float32 float32_log2( float32 a STATUS_PARAM )
/*----------------------------------------------------------------------------
| Returns 1 if the single-precision floating-point value `a' is equal to
| the corresponding value `b', and 0 otherwise. The comparison is performed
| the corresponding value `b', and 0 otherwise. The invalid exception is
| raised if either operand is a NaN. Otherwise, the comparison is performed
| according to the IEC/IEEE Standard for Binary Floating-Point Arithmetic.
*----------------------------------------------------------------------------*/
int float32_eq( float32 a, float32 b STATUS_PARAM )
{
uint32_t av, bv;
a = float32_squash_input_denormal(a STATUS_VAR);
b = float32_squash_input_denormal(b STATUS_VAR);
if ( ( ( extractFloat32Exp( a ) == 0xFF ) && extractFloat32Frac( a ) )
|| ( ( extractFloat32Exp( b ) == 0xFF ) && extractFloat32Frac( b ) )
) {
if ( float32_is_signaling_nan( a ) || float32_is_signaling_nan( b ) ) {
float_raise( float_flag_invalid STATUS_VAR);
}
float_raise( float_flag_invalid STATUS_VAR);
return 0;
}
return ( float32_val(a) == float32_val(b) ) ||
( (uint32_t) ( ( float32_val(a) | float32_val(b) )<<1 ) == 0 );
av = float32_val(a);
bv = float32_val(b);
return ( av == bv ) || ( (uint32_t) ( ( av | bv )<<1 ) == 0 );
}
/*----------------------------------------------------------------------------
| Returns 1 if the single-precision floating-point value `a' is less than
| or equal to the corresponding value `b', and 0 otherwise. The comparison
| is performed according to the IEC/IEEE Standard for Binary Floating-Point
| Arithmetic.
| or equal to the corresponding value `b', and 0 otherwise. The invalid
| exception is raised if either operand is a NaN. The comparison is performed
| according to the IEC/IEEE Standard for Binary Floating-Point Arithmetic.
*----------------------------------------------------------------------------*/
int float32_le( float32 a, float32 b STATUS_PARAM )
@ -2367,8 +2367,9 @@ int float32_le( float32 a, float32 b STATUS_PARAM )
/*----------------------------------------------------------------------------
| Returns 1 if the single-precision floating-point value `a' is less than
| the corresponding value `b', and 0 otherwise. The comparison is performed
| according to the IEC/IEEE Standard for Binary Floating-Point Arithmetic.
| the corresponding value `b', and 0 otherwise. The invalid exception is
| raised if either operand is a NaN. The comparison is performed according
| to the IEC/IEEE Standard for Binary Floating-Point Arithmetic.
*----------------------------------------------------------------------------*/
int float32_lt( float32 a, float32 b STATUS_PARAM )
@ -2394,15 +2395,14 @@ int float32_lt( float32 a, float32 b STATUS_PARAM )
}
/*----------------------------------------------------------------------------
| Returns 1 if the single-precision floating-point value `a' is equal to
| the corresponding value `b', and 0 otherwise. The invalid exception is
| raised if either operand is a NaN. Otherwise, the comparison is performed
| according to the IEC/IEEE Standard for Binary Floating-Point Arithmetic.
| Returns 1 if the single-precision floating-point values `a' and `b' cannot
| be compared, and 0 otherwise. The invalid exception is raised if either
| operand is a NaN. The comparison is performed according to the IEC/IEEE
| Standard for Binary Floating-Point Arithmetic.
*----------------------------------------------------------------------------*/
int float32_eq_signaling( float32 a, float32 b STATUS_PARAM )
int float32_unordered( float32 a, float32 b STATUS_PARAM )
{
uint32_t av, bv;
a = float32_squash_input_denormal(a STATUS_VAR);
b = float32_squash_input_denormal(b STATUS_VAR);
@ -2410,12 +2410,33 @@ int float32_eq_signaling( float32 a, float32 b STATUS_PARAM )
|| ( ( extractFloat32Exp( b ) == 0xFF ) && extractFloat32Frac( b ) )
) {
float_raise( float_flag_invalid STATUS_VAR);
return 1;
}
return 0;
}
/*----------------------------------------------------------------------------
| Returns 1 if the single-precision floating-point value `a' is equal to
| the corresponding value `b', and 0 otherwise. Quiet NaNs do not cause an
| exception. The comparison is performed according to the IEC/IEEE Standard
| for Binary Floating-Point Arithmetic.
*----------------------------------------------------------------------------*/
int float32_eq_quiet( float32 a, float32 b STATUS_PARAM )
{
a = float32_squash_input_denormal(a STATUS_VAR);
b = float32_squash_input_denormal(b STATUS_VAR);
if ( ( ( extractFloat32Exp( a ) == 0xFF ) && extractFloat32Frac( a ) )
|| ( ( extractFloat32Exp( b ) == 0xFF ) && extractFloat32Frac( b ) )
) {
if ( float32_is_signaling_nan( a ) || float32_is_signaling_nan( b ) ) {
float_raise( float_flag_invalid STATUS_VAR);
}
return 0;
}
av = float32_val(a);
bv = float32_val(b);
return ( av == bv ) || ( (uint32_t) ( ( av | bv )<<1 ) == 0 );
return ( float32_val(a) == float32_val(b) ) ||
( (uint32_t) ( ( float32_val(a) | float32_val(b) )<<1 ) == 0 );
}
/*----------------------------------------------------------------------------
@ -2480,6 +2501,29 @@ int float32_lt_quiet( float32 a, float32 b STATUS_PARAM )
}
/*----------------------------------------------------------------------------
| Returns 1 if the single-precision floating-point values `a' and `b' cannot
| be compared, and 0 otherwise. Quiet NaNs do not cause an exception. The
| comparison is performed according to the IEC/IEEE Standard for Binary
| Floating-Point Arithmetic.
*----------------------------------------------------------------------------*/
int float32_unordered_quiet( float32 a, float32 b STATUS_PARAM )
{
a = float32_squash_input_denormal(a STATUS_VAR);
b = float32_squash_input_denormal(b STATUS_VAR);
if ( ( ( extractFloat32Exp( a ) == 0xFF ) && extractFloat32Frac( a ) )
|| ( ( extractFloat32Exp( b ) == 0xFF ) && extractFloat32Frac( b ) )
) {
if ( float32_is_signaling_nan( a ) || float32_is_signaling_nan( b ) ) {
float_raise( float_flag_invalid STATUS_VAR);
}
return 1;
}
return 0;
}
/*----------------------------------------------------------------------------
| Returns the result of converting the double-precision floating-point value
| `a' to the 32-bit two's complement integer format. The conversion is
@ -3536,7 +3580,8 @@ float64 float64_log2( float64 a STATUS_PARAM )
/*----------------------------------------------------------------------------
| Returns 1 if the double-precision floating-point value `a' is equal to the
| corresponding value `b', and 0 otherwise. The comparison is performed
| corresponding value `b', and 0 otherwise. The invalid exception is raised
| if either operand is a NaN. Otherwise, the comparison is performed
| according to the IEC/IEEE Standard for Binary Floating-Point Arithmetic.
*----------------------------------------------------------------------------*/
@ -3549,9 +3594,7 @@ int float64_eq( float64 a, float64 b STATUS_PARAM )
if ( ( ( extractFloat64Exp( a ) == 0x7FF ) && extractFloat64Frac( a ) )
|| ( ( extractFloat64Exp( b ) == 0x7FF ) && extractFloat64Frac( b ) )
) {
if ( float64_is_signaling_nan( a ) || float64_is_signaling_nan( b ) ) {
float_raise( float_flag_invalid STATUS_VAR);
}
float_raise( float_flag_invalid STATUS_VAR);
return 0;
}
av = float64_val(a);
@ -3562,9 +3605,9 @@ int float64_eq( float64 a, float64 b STATUS_PARAM )
/*----------------------------------------------------------------------------
| Returns 1 if the double-precision floating-point value `a' is less than or
| equal to the corresponding value `b', and 0 otherwise. The comparison is
| performed according to the IEC/IEEE Standard for Binary Floating-Point
| Arithmetic.
| equal to the corresponding value `b', and 0 otherwise. The invalid
| exception is raised if either operand is a NaN. The comparison is performed
| according to the IEC/IEEE Standard for Binary Floating-Point Arithmetic.
*----------------------------------------------------------------------------*/
int float64_le( float64 a, float64 b STATUS_PARAM )
@ -3591,8 +3634,9 @@ int float64_le( float64 a, float64 b STATUS_PARAM )
/*----------------------------------------------------------------------------
| Returns 1 if the double-precision floating-point value `a' is less than
| the corresponding value `b', and 0 otherwise. The comparison is performed
| according to the IEC/IEEE Standard for Binary Floating-Point Arithmetic.
| the corresponding value `b', and 0 otherwise. The invalid exception is
| raised if either operand is a NaN. The comparison is performed according
| to the IEC/IEEE Standard for Binary Floating-Point Arithmetic.
*----------------------------------------------------------------------------*/
int float64_lt( float64 a, float64 b STATUS_PARAM )
@ -3618,13 +3662,34 @@ int float64_lt( float64 a, float64 b STATUS_PARAM )
}
/*----------------------------------------------------------------------------
| Returns 1 if the double-precision floating-point value `a' is equal to the
| corresponding value `b', and 0 otherwise. The invalid exception is raised
| if either operand is a NaN. Otherwise, the comparison is performed
| according to the IEC/IEEE Standard for Binary Floating-Point Arithmetic.
| Returns 1 if the double-precision floating-point values `a' and `b' cannot
| be compared, and 0 otherwise. The invalid exception is raised if either
| operand is a NaN. The comparison is performed according to the IEC/IEEE
| Standard for Binary Floating-Point Arithmetic.
*----------------------------------------------------------------------------*/
int float64_eq_signaling( float64 a, float64 b STATUS_PARAM )
int float64_unordered( float64 a, float64 b STATUS_PARAM )
{
a = float64_squash_input_denormal(a STATUS_VAR);
b = float64_squash_input_denormal(b STATUS_VAR);
if ( ( ( extractFloat64Exp( a ) == 0x7FF ) && extractFloat64Frac( a ) )
|| ( ( extractFloat64Exp( b ) == 0x7FF ) && extractFloat64Frac( b ) )
) {
float_raise( float_flag_invalid STATUS_VAR);
return 1;
}
return 0;
}
/*----------------------------------------------------------------------------
| Returns 1 if the double-precision floating-point value `a' is equal to the
| corresponding value `b', and 0 otherwise. Quiet NaNs do not cause an
| exception.The comparison is performed according to the IEC/IEEE Standard
| for Binary Floating-Point Arithmetic.
*----------------------------------------------------------------------------*/
int float64_eq_quiet( float64 a, float64 b STATUS_PARAM )
{
uint64_t av, bv;
a = float64_squash_input_denormal(a STATUS_VAR);
@ -3633,7 +3698,9 @@ int float64_eq_signaling( float64 a, float64 b STATUS_PARAM )
if ( ( ( extractFloat64Exp( a ) == 0x7FF ) && extractFloat64Frac( a ) )
|| ( ( extractFloat64Exp( b ) == 0x7FF ) && extractFloat64Frac( b ) )
) {
float_raise( float_flag_invalid STATUS_VAR);
if ( float64_is_signaling_nan( a ) || float64_is_signaling_nan( b ) ) {
float_raise( float_flag_invalid STATUS_VAR);
}
return 0;
}
av = float64_val(a);
@ -3704,6 +3771,29 @@ int float64_lt_quiet( float64 a, float64 b STATUS_PARAM )
}
/*----------------------------------------------------------------------------
| Returns 1 if the double-precision floating-point values `a' and `b' cannot
| be compared, and 0 otherwise. Quiet NaNs do not cause an exception. The
| comparison is performed according to the IEC/IEEE Standard for Binary
| Floating-Point Arithmetic.
*----------------------------------------------------------------------------*/
int float64_unordered_quiet( float64 a, float64 b STATUS_PARAM )
{
a = float64_squash_input_denormal(a STATUS_VAR);
b = float64_squash_input_denormal(b STATUS_VAR);
if ( ( ( extractFloat64Exp( a ) == 0x7FF ) && extractFloat64Frac( a ) )
|| ( ( extractFloat64Exp( b ) == 0x7FF ) && extractFloat64Frac( b ) )
) {
if ( float64_is_signaling_nan( a ) || float64_is_signaling_nan( b ) ) {
float_raise( float_flag_invalid STATUS_VAR);
}
return 1;
}
return 0;
}
#ifdef FLOATX80
/*----------------------------------------------------------------------------
@ -4501,10 +4591,10 @@ floatx80 floatx80_sqrt( floatx80 a STATUS_PARAM )
}
/*----------------------------------------------------------------------------
| Returns 1 if the extended double-precision floating-point value `a' is
| equal to the corresponding value `b', and 0 otherwise. The comparison is
| performed according to the IEC/IEEE Standard for Binary Floating-Point
| Arithmetic.
| Returns 1 if the extended double-precision floating-point value `a' is equal
| to the corresponding value `b', and 0 otherwise. The invalid exception is
| raised if either operand is a NaN. Otherwise, the comparison is performed
| according to the IEC/IEEE Standard for Binary Floating-Point Arithmetic.
*----------------------------------------------------------------------------*/
int floatx80_eq( floatx80 a, floatx80 b STATUS_PARAM )
@ -4515,10 +4605,7 @@ int floatx80_eq( floatx80 a, floatx80 b STATUS_PARAM )
|| ( ( extractFloatx80Exp( b ) == 0x7FFF )
&& (uint64_t) ( extractFloatx80Frac( b )<<1 ) )
) {
if ( floatx80_is_signaling_nan( a )
|| floatx80_is_signaling_nan( b ) ) {
float_raise( float_flag_invalid STATUS_VAR);
}
float_raise( float_flag_invalid STATUS_VAR);
return 0;
}
return
@ -4533,8 +4620,9 @@ int floatx80_eq( floatx80 a, floatx80 b STATUS_PARAM )
/*----------------------------------------------------------------------------
| Returns 1 if the extended double-precision floating-point value `a' is
| less than or equal to the corresponding value `b', and 0 otherwise. The
| comparison is performed according to the IEC/IEEE Standard for Binary
| Floating-Point Arithmetic.
| invalid exception is raised if either operand is a NaN. The comparison is
| performed according to the IEC/IEEE Standard for Binary Floating-Point
| Arithmetic.
*----------------------------------------------------------------------------*/
int floatx80_le( floatx80 a, floatx80 b STATUS_PARAM )
@ -4565,9 +4653,9 @@ int floatx80_le( floatx80 a, floatx80 b STATUS_PARAM )
/*----------------------------------------------------------------------------
| Returns 1 if the extended double-precision floating-point value `a' is
| less than the corresponding value `b', and 0 otherwise. The comparison
| is performed according to the IEC/IEEE Standard for Binary Floating-Point
| Arithmetic.
| less than the corresponding value `b', and 0 otherwise. The invalid
| exception is raised if either operand is a NaN. The comparison is performed
| according to the IEC/IEEE Standard for Binary Floating-Point Arithmetic.
*----------------------------------------------------------------------------*/
int floatx80_lt( floatx80 a, floatx80 b STATUS_PARAM )
@ -4597,13 +4685,32 @@ int floatx80_lt( floatx80 a, floatx80 b STATUS_PARAM )
}
/*----------------------------------------------------------------------------
| Returns 1 if the extended double-precision floating-point value `a' is equal
| to the corresponding value `b', and 0 otherwise. The invalid exception is
| raised if either operand is a NaN. Otherwise, the comparison is performed
| according to the IEC/IEEE Standard for Binary Floating-Point Arithmetic.
| Returns 1 if the extended double-precision floating-point values `a' and `b'
| cannot be compared, and 0 otherwise. The invalid exception is raised if
| either operand is a NaN. The comparison is performed according to the
| IEC/IEEE Standard for Binary Floating-Point Arithmetic.
*----------------------------------------------------------------------------*/
int floatx80_unordered( floatx80 a, floatx80 b STATUS_PARAM )
{
if ( ( ( extractFloatx80Exp( a ) == 0x7FFF )
&& (uint64_t) ( extractFloatx80Frac( a )<<1 ) )
|| ( ( extractFloatx80Exp( b ) == 0x7FFF )
&& (uint64_t) ( extractFloatx80Frac( b )<<1 ) )
) {
float_raise( float_flag_invalid STATUS_VAR);
return 1;
}
return 0;
}
/*----------------------------------------------------------------------------
| Returns 1 if the extended double-precision floating-point value `a' is
| equal to the corresponding value `b', and 0 otherwise. Quiet NaNs do not
| cause an exception. The comparison is performed according to the IEC/IEEE
| Standard for Binary Floating-Point Arithmetic.
*----------------------------------------------------------------------------*/
int floatx80_eq_signaling( floatx80 a, floatx80 b STATUS_PARAM )
int floatx80_eq_quiet( floatx80 a, floatx80 b STATUS_PARAM )
{
if ( ( ( extractFloatx80Exp( a ) == 0x7FFF )
@ -4611,7 +4718,10 @@ int floatx80_eq_signaling( floatx80 a, floatx80 b STATUS_PARAM )
|| ( ( extractFloatx80Exp( b ) == 0x7FFF )
&& (uint64_t) ( extractFloatx80Frac( b )<<1 ) )
) {
float_raise( float_flag_invalid STATUS_VAR);
if ( floatx80_is_signaling_nan( a )
|| floatx80_is_signaling_nan( b ) ) {
float_raise( float_flag_invalid STATUS_VAR);
}
return 0;
}
return
@ -4695,6 +4805,28 @@ int floatx80_lt_quiet( floatx80 a, floatx80 b STATUS_PARAM )
}
/*----------------------------------------------------------------------------
| Returns 1 if the extended double-precision floating-point values `a' and `b'
| cannot be compared, and 0 otherwise. Quiet NaNs do not cause an exception.
| The comparison is performed according to the IEC/IEEE Standard for Binary
| Floating-Point Arithmetic.
*----------------------------------------------------------------------------*/
int floatx80_unordered_quiet( floatx80 a, floatx80 b STATUS_PARAM )
{
if ( ( ( extractFloatx80Exp( a ) == 0x7FFF )
&& (uint64_t) ( extractFloatx80Frac( a )<<1 ) )
|| ( ( extractFloatx80Exp( b ) == 0x7FFF )
&& (uint64_t) ( extractFloatx80Frac( b )<<1 ) )
) {
if ( floatx80_is_signaling_nan( a )
|| floatx80_is_signaling_nan( b ) ) {
float_raise( float_flag_invalid STATUS_VAR);
}
return 1;
}
return 0;
}
#endif
#ifdef FLOAT128
@ -5625,7 +5757,8 @@ float128 float128_sqrt( float128 a STATUS_PARAM )
/*----------------------------------------------------------------------------
| Returns 1 if the quadruple-precision floating-point value `a' is equal to
| the corresponding value `b', and 0 otherwise. The comparison is performed
| the corresponding value `b', and 0 otherwise. The invalid exception is
| raised if either operand is a NaN. Otherwise, the comparison is performed
| according to the IEC/IEEE Standard for Binary Floating-Point Arithmetic.
*----------------------------------------------------------------------------*/
@ -5637,10 +5770,7 @@ int float128_eq( float128 a, float128 b STATUS_PARAM )
|| ( ( extractFloat128Exp( b ) == 0x7FFF )
&& ( extractFloat128Frac0( b ) | extractFloat128Frac1( b ) ) )
) {
if ( float128_is_signaling_nan( a )
|| float128_is_signaling_nan( b ) ) {
float_raise( float_flag_invalid STATUS_VAR);
}
float_raise( float_flag_invalid STATUS_VAR);
return 0;
}
return
@ -5654,9 +5784,9 @@ int float128_eq( float128 a, float128 b STATUS_PARAM )
/*----------------------------------------------------------------------------
| Returns 1 if the quadruple-precision floating-point value `a' is less than
| or equal to the corresponding value `b', and 0 otherwise. The comparison
| is performed according to the IEC/IEEE Standard for Binary Floating-Point
| Arithmetic.
| or equal to the corresponding value `b', and 0 otherwise. The invalid
| exception is raised if either operand is a NaN. The comparison is performed
| according to the IEC/IEEE Standard for Binary Floating-Point Arithmetic.
*----------------------------------------------------------------------------*/
int float128_le( float128 a, float128 b STATUS_PARAM )
@ -5687,8 +5817,9 @@ int float128_le( float128 a, float128 b STATUS_PARAM )
/*----------------------------------------------------------------------------
| Returns 1 if the quadruple-precision floating-point value `a' is less than
| the corresponding value `b', and 0 otherwise. The comparison is performed
| according to the IEC/IEEE Standard for Binary Floating-Point Arithmetic.
| the corresponding value `b', and 0 otherwise. The invalid exception is
| raised if either operand is a NaN. The comparison is performed according
| to the IEC/IEEE Standard for Binary Floating-Point Arithmetic.
*----------------------------------------------------------------------------*/
int float128_lt( float128 a, float128 b STATUS_PARAM )
@ -5718,13 +5849,33 @@ int float128_lt( float128 a, float128 b STATUS_PARAM )
}
/*----------------------------------------------------------------------------
| Returns 1 if the quadruple-precision floating-point value `a' is equal to
| the corresponding value `b', and 0 otherwise. The invalid exception is
| raised if either operand is a NaN. Otherwise, the comparison is performed
| according to the IEC/IEEE Standard for Binary Floating-Point Arithmetic.
| Returns 1 if the quadruple-precision floating-point values `a' and `b' cannot
| be compared, and 0 otherwise. The invalid exception is raised if either
| operand is a NaN. The comparison is performed according to the IEC/IEEE
| Standard for Binary Floating-Point Arithmetic.
*----------------------------------------------------------------------------*/
int float128_eq_signaling( float128 a, float128 b STATUS_PARAM )
int float128_unordered( float128 a, float128 b STATUS_PARAM )
{
if ( ( ( extractFloat128Exp( a ) == 0x7FFF )
&& ( extractFloat128Frac0( a ) | extractFloat128Frac1( a ) ) )
|| ( ( extractFloat128Exp( b ) == 0x7FFF )
&& ( extractFloat128Frac0( b ) | extractFloat128Frac1( b ) ) )
) {
float_raise( float_flag_invalid STATUS_VAR);
return 1;
}
return 0;
}
/*----------------------------------------------------------------------------
| Returns 1 if the quadruple-precision floating-point value `a' is equal to
| the corresponding value `b', and 0 otherwise. Quiet NaNs do not cause an
| exception. The comparison is performed according to the IEC/IEEE Standard
| for Binary Floating-Point Arithmetic.
*----------------------------------------------------------------------------*/
int float128_eq_quiet( float128 a, float128 b STATUS_PARAM )
{
if ( ( ( extractFloat128Exp( a ) == 0x7FFF )
@ -5732,7 +5883,10 @@ int float128_eq_signaling( float128 a, float128 b STATUS_PARAM )
|| ( ( extractFloat128Exp( b ) == 0x7FFF )
&& ( extractFloat128Frac0( b ) | extractFloat128Frac1( b ) ) )
) {
float_raise( float_flag_invalid STATUS_VAR);
if ( float128_is_signaling_nan( a )
|| float128_is_signaling_nan( b ) ) {
float_raise( float_flag_invalid STATUS_VAR);
}
return 0;
}
return
@ -5816,6 +5970,29 @@ int float128_lt_quiet( float128 a, float128 b STATUS_PARAM )
}
/*----------------------------------------------------------------------------
| Returns 1 if the quadruple-precision floating-point values `a' and `b' cannot
| be compared, and 0 otherwise. Quiet NaNs do not cause an exception. The
| comparison is performed according to the IEC/IEEE Standard for Binary
| Floating-Point Arithmetic.
*----------------------------------------------------------------------------*/
int float128_unordered_quiet( float128 a, float128 b STATUS_PARAM )
{
if ( ( ( extractFloat128Exp( a ) == 0x7FFF )
&& ( extractFloat128Frac0( a ) | extractFloat128Frac1( a ) ) )
|| ( ( extractFloat128Exp( b ) == 0x7FFF )
&& ( extractFloat128Frac0( b ) | extractFloat128Frac1( b ) ) )
) {
if ( float128_is_signaling_nan( a )
|| float128_is_signaling_nan( b ) ) {
float_raise( float_flag_invalid STATUS_VAR);
}
return 1;
}
return 0;
}
#endif
/* misc functions */
@ -6013,6 +6190,52 @@ int float ## s ## _compare_quiet( float ## s a, float ## s b STATUS_PARAM ) \
COMPARE(32, 0xff)
COMPARE(64, 0x7ff)
INLINE int floatx80_compare_internal( floatx80 a, floatx80 b,
int is_quiet STATUS_PARAM )
{
flag aSign, bSign;
if (( ( extractFloatx80Exp( a ) == 0x7fff ) &&
( extractFloatx80Frac( a )<<1 ) ) ||
( ( extractFloatx80Exp( b ) == 0x7fff ) &&
( extractFloatx80Frac( b )<<1 ) )) {
if (!is_quiet ||
floatx80_is_signaling_nan( a ) ||
floatx80_is_signaling_nan( b ) ) {
float_raise( float_flag_invalid STATUS_VAR);
}
return float_relation_unordered;
}
aSign = extractFloatx80Sign( a );
bSign = extractFloatx80Sign( b );
if ( aSign != bSign ) {
if ( ( ( (uint16_t) ( ( a.high | b.high ) << 1 ) ) == 0) &&
( ( a.low | b.low ) == 0 ) ) {
/* zero case */
return float_relation_equal;
} else {
return 1 - (2 * aSign);
}
} else {
if (a.low == b.low && a.high == b.high) {
return float_relation_equal;
} else {
return 1 - 2 * (aSign ^ ( lt128( a.high, a.low, b.high, b.low ) ));
}
}
}
int floatx80_compare( floatx80 a, floatx80 b STATUS_PARAM )
{
return floatx80_compare_internal(a, b, 0 STATUS_VAR);
}
int floatx80_compare_quiet( floatx80 a, floatx80 b STATUS_PARAM )
{
return floatx80_compare_internal(a, b, 1 STATUS_VAR);
}
INLINE int float128_compare_internal( float128 a, float128 b,
int is_quiet STATUS_PARAM )
{
@ -6057,11 +6280,60 @@ int float128_compare_quiet( float128 a, float128 b STATUS_PARAM )
return float128_compare_internal(a, b, 1 STATUS_VAR);
}
/* min() and max() functions. These can't be implemented as
* 'compare and pick one input' because that would mishandle
* NaNs and +0 vs -0.
*/
#define MINMAX(s, nan_exp) \
INLINE float ## s float ## s ## _minmax(float ## s a, float ## s b, \
int ismin STATUS_PARAM ) \
{ \
flag aSign, bSign; \
uint ## s ## _t av, bv; \
a = float ## s ## _squash_input_denormal(a STATUS_VAR); \
b = float ## s ## _squash_input_denormal(b STATUS_VAR); \
if (float ## s ## _is_any_nan(a) || \
float ## s ## _is_any_nan(b)) { \
return propagateFloat ## s ## NaN(a, b STATUS_VAR); \
} \
aSign = extractFloat ## s ## Sign(a); \
bSign = extractFloat ## s ## Sign(b); \
av = float ## s ## _val(a); \
bv = float ## s ## _val(b); \
if (aSign != bSign) { \
if (ismin) { \
return aSign ? a : b; \
} else { \
return aSign ? b : a; \
} \
} else { \
if (ismin) { \
return (aSign ^ (av < bv)) ? a : b; \
} else { \
return (aSign ^ (av < bv)) ? b : a; \
} \
} \
} \
\
float ## s float ## s ## _min(float ## s a, float ## s b STATUS_PARAM) \
{ \
return float ## s ## _minmax(a, b, 1 STATUS_VAR); \
} \
\
float ## s float ## s ## _max(float ## s a, float ## s b STATUS_PARAM) \
{ \
return float ## s ## _minmax(a, b, 0 STATUS_VAR); \
}
MINMAX(32, 0xff)
MINMAX(64, 0x7ff)
/* Multiply A by 2 raised to the power N. */
float32 float32_scalbn( float32 a, int n STATUS_PARAM )
{
flag aSign;
int16 aExp;
int16_t aExp;
uint32_t aSig;
a = float32_squash_input_denormal(a STATUS_VAR);
@ -6070,6 +6342,9 @@ float32 float32_scalbn( float32 a, int n STATUS_PARAM )
aSign = extractFloat32Sign( a );
if ( aExp == 0xFF ) {
if ( aSig ) {
return propagateFloat32NaN( a, a STATUS_VAR );
}
return a;
}
if ( aExp != 0 )
@ -6077,6 +6352,12 @@ float32 float32_scalbn( float32 a, int n STATUS_PARAM )
else if ( aSig == 0 )
return a;
if (n > 0x200) {
n = 0x200;
} else if (n < -0x200) {
n = -0x200;
}
aExp += n - 1;
aSig <<= 7;
return normalizeRoundAndPackFloat32( aSign, aExp, aSig STATUS_VAR );
@ -6085,7 +6366,7 @@ float32 float32_scalbn( float32 a, int n STATUS_PARAM )
float64 float64_scalbn( float64 a, int n STATUS_PARAM )
{
flag aSign;
int16 aExp;
int16_t aExp;
uint64_t aSig;
a = float64_squash_input_denormal(a STATUS_VAR);
@ -6094,6 +6375,9 @@ float64 float64_scalbn( float64 a, int n STATUS_PARAM )
aSign = extractFloat64Sign( a );
if ( aExp == 0x7FF ) {
if ( aSig ) {
return propagateFloat64NaN( a, a STATUS_VAR );
}
return a;
}
if ( aExp != 0 )
@ -6101,6 +6385,12 @@ float64 float64_scalbn( float64 a, int n STATUS_PARAM )
else if ( aSig == 0 )
return a;
if (n > 0x1000) {
n = 0x1000;
} else if (n < -0x1000) {
n = -0x1000;
}
aExp += n - 1;
aSig <<= 10;
return normalizeRoundAndPackFloat64( aSign, aExp, aSig STATUS_VAR );
@ -6110,19 +6400,29 @@ float64 float64_scalbn( float64 a, int n STATUS_PARAM )
floatx80 floatx80_scalbn( floatx80 a, int n STATUS_PARAM )
{
flag aSign;
int16 aExp;
int32_t aExp;
uint64_t aSig;
aSig = extractFloatx80Frac( a );
aExp = extractFloatx80Exp( a );
aSign = extractFloatx80Sign( a );
if ( aExp == 0x7FF ) {
if ( aExp == 0x7FFF ) {
if ( aSig<<1 ) {
return propagateFloatx80NaN( a, a STATUS_VAR );
}
return a;
}
if (aExp == 0 && aSig == 0)
return a;
if (n > 0x10000) {
n = 0x10000;
} else if (n < -0x10000) {
n = -0x10000;
}
aExp += n;
return normalizeRoundAndPackFloatx80( STATUS(floatx80_rounding_precision),
aSign, aExp, aSig, 0 STATUS_VAR );
@ -6133,7 +6433,7 @@ floatx80 floatx80_scalbn( floatx80 a, int n STATUS_PARAM )
float128 float128_scalbn( float128 a, int n STATUS_PARAM )
{
flag aSign;
int32 aExp;
int32_t aExp;
uint64_t aSig0, aSig1;
aSig1 = extractFloat128Frac1( a );
@ -6141,6 +6441,9 @@ float128 float128_scalbn( float128 a, int n STATUS_PARAM )
aExp = extractFloat128Exp( a );
aSign = extractFloat128Sign( a );
if ( aExp == 0x7FFF ) {
if ( aSig0 | aSig1 ) {
return propagateFloat128NaN( a, a STATUS_VAR );
}
return a;
}
if ( aExp != 0 )
@ -6148,6 +6451,12 @@ float128 float128_scalbn( float128 a, int n STATUS_PARAM )
else if ( aSig0 == 0 && aSig1 == 0 )
return a;
if (n > 0x10000) {
n = 0x10000;
} else if (n < -0x10000) {
n = -0x10000;
}
aExp += n - 1;
return normalizeRoundAndPackFloat128( aSign, aExp, aSig0, aSig1
STATUS_VAR );

View File

@ -68,7 +68,7 @@ typedef int64_t int64;
#define LIT64( a ) a##LL
#define INLINE static inline
#if defined(TARGET_MIPS) || defined(TARGET_SH4)
#if defined(TARGET_MIPS) || defined(TARGET_SH4) || defined(TARGET_UNICORE32)
#define SNAN_BIT_IS_ONE 1
#else
#define SNAN_BIT_IS_ONE 0
@ -154,6 +154,7 @@ typedef struct {
uint64_t low;
uint16_t high;
} floatx80;
#define make_floatx80(exp, mant) ((floatx80) { mant, exp })
#endif
#ifdef FLOAT128
typedef struct {
@ -211,6 +212,10 @@ typedef struct float_status {
void set_float_rounding_mode(int val STATUS_PARAM);
void set_float_exception_flags(int val STATUS_PARAM);
INLINE void set_float_detect_tininess(int val STATUS_PARAM)
{
STATUS(float_detect_tininess) = val;
}
INLINE void set_flush_to_zero(flag val STATUS_PARAM)
{
STATUS(flush_to_zero) = val;
@ -319,11 +324,15 @@ float32 float32_log2( float32 STATUS_PARAM );
int float32_eq( float32, float32 STATUS_PARAM );
int float32_le( float32, float32 STATUS_PARAM );
int float32_lt( float32, float32 STATUS_PARAM );
int float32_eq_signaling( float32, float32 STATUS_PARAM );
int float32_unordered( float32, float32 STATUS_PARAM );
int float32_eq_quiet( float32, float32 STATUS_PARAM );
int float32_le_quiet( float32, float32 STATUS_PARAM );
int float32_lt_quiet( float32, float32 STATUS_PARAM );
int float32_unordered_quiet( float32, float32 STATUS_PARAM );
int float32_compare( float32, float32 STATUS_PARAM );
int float32_compare_quiet( float32, float32 STATUS_PARAM );
float32 float32_min(float32, float32 STATUS_PARAM);
float32 float32_max(float32, float32 STATUS_PARAM);
int float32_is_quiet_nan( float32 );
int float32_is_signaling_nan( float32 );
float32 float32_maybe_silence_nan( float32 );
@ -378,6 +387,7 @@ INLINE float32 float32_set_sign(float32 a, int sign)
#define float32_zero make_float32(0)
#define float32_one make_float32(0x3f800000)
#define float32_ln2 make_float32(0x3f317218)
#define float32_pi make_float32(0x40490fdb)
#define float32_half make_float32(0x3f000000)
#define float32_infinity make_float32(0x7f800000)
@ -431,11 +441,15 @@ float64 float64_log2( float64 STATUS_PARAM );
int float64_eq( float64, float64 STATUS_PARAM );
int float64_le( float64, float64 STATUS_PARAM );
int float64_lt( float64, float64 STATUS_PARAM );
int float64_eq_signaling( float64, float64 STATUS_PARAM );
int float64_unordered( float64, float64 STATUS_PARAM );
int float64_eq_quiet( float64, float64 STATUS_PARAM );
int float64_le_quiet( float64, float64 STATUS_PARAM );
int float64_lt_quiet( float64, float64 STATUS_PARAM );
int float64_unordered_quiet( float64, float64 STATUS_PARAM );
int float64_compare( float64, float64 STATUS_PARAM );
int float64_compare_quiet( float64, float64 STATUS_PARAM );
float64 float64_min(float64, float64 STATUS_PARAM);
float64 float64_max(float64, float64 STATUS_PARAM);
int float64_is_quiet_nan( float64 a );
int float64_is_signaling_nan( float64 );
float64 float64_maybe_silence_nan( float64 );
@ -486,6 +500,7 @@ INLINE float64 float64_set_sign(float64 a, int sign)
#define float64_zero make_float64(0)
#define float64_one make_float64(0x3ff0000000000000LL)
#define float64_ln2 make_float64(0x3fe62e42fefa39efLL)
#define float64_pi make_float64(0x400921fb54442d18LL)
#define float64_half make_float64(0x3fe0000000000000LL)
#define float64_infinity make_float64(0x7ff0000000000000LL)
@ -530,9 +545,13 @@ floatx80 floatx80_sqrt( floatx80 STATUS_PARAM );
int floatx80_eq( floatx80, floatx80 STATUS_PARAM );
int floatx80_le( floatx80, floatx80 STATUS_PARAM );
int floatx80_lt( floatx80, floatx80 STATUS_PARAM );
int floatx80_eq_signaling( floatx80, floatx80 STATUS_PARAM );
int floatx80_unordered( floatx80, floatx80 STATUS_PARAM );
int floatx80_eq_quiet( floatx80, floatx80 STATUS_PARAM );
int floatx80_le_quiet( floatx80, floatx80 STATUS_PARAM );
int floatx80_lt_quiet( floatx80, floatx80 STATUS_PARAM );
int floatx80_unordered_quiet( floatx80, floatx80 STATUS_PARAM );
int floatx80_compare( floatx80, floatx80 STATUS_PARAM );
int floatx80_compare_quiet( floatx80, floatx80 STATUS_PARAM );
int floatx80_is_quiet_nan( floatx80 );
int floatx80_is_signaling_nan( floatx80 );
floatx80 floatx80_maybe_silence_nan( floatx80 );
@ -552,7 +571,7 @@ INLINE floatx80 floatx80_chs(floatx80 a)
INLINE int floatx80_is_infinity(floatx80 a)
{
return (a.high & 0x7fff) == 0x7fff && a.low == 0;
return (a.high & 0x7fff) == 0x7fff && a.low == 0x8000000000000000LL;
}
INLINE int floatx80_is_neg(floatx80 a)
@ -570,6 +589,13 @@ INLINE int floatx80_is_any_nan(floatx80 a)
return ((a.high & 0x7fff) == 0x7fff) && (a.low<<1);
}
#define floatx80_zero make_floatx80(0x0000, 0x0000000000000000LL)
#define floatx80_one make_floatx80(0x3fff, 0x8000000000000000LL)
#define floatx80_ln2 make_floatx80(0x3ffe, 0xb17217f7d1cf79acLL)
#define floatx80_pi make_floatx80(0x4000, 0xc90fdaa22168c235LL)
#define floatx80_half make_floatx80(0x3ffe, 0x8000000000000000LL)
#define floatx80_infinity make_floatx80(0x7fff, 0x8000000000000000LL)
/*----------------------------------------------------------------------------
| The pattern for a default generated extended double-precision NaN. The
| `high' and `low' values hold the most- and least-significant bits,
@ -613,9 +639,11 @@ float128 float128_sqrt( float128 STATUS_PARAM );
int float128_eq( float128, float128 STATUS_PARAM );
int float128_le( float128, float128 STATUS_PARAM );
int float128_lt( float128, float128 STATUS_PARAM );
int float128_eq_signaling( float128, float128 STATUS_PARAM );
int float128_unordered( float128, float128 STATUS_PARAM );
int float128_eq_quiet( float128, float128 STATUS_PARAM );
int float128_le_quiet( float128, float128 STATUS_PARAM );
int float128_lt_quiet( float128, float128 STATUS_PARAM );
int float128_unordered_quiet( float128, float128 STATUS_PARAM );
int float128_compare( float128, float128 STATUS_PARAM );
int float128_compare_quiet( float128, float128 STATUS_PARAM );
int float128_is_quiet_nan( float128 );

View File

@ -13,7 +13,7 @@
#ifndef QEMU_FSDEV_H
#define QEMU_FSDEV_H
#include "qemu-option.h"
#include "hw/file-op-9p.h"
#include "file-op-9p.h"
/*

View File

@ -45,7 +45,12 @@
enum {
GDB_SIGNAL_0 = 0,
GDB_SIGNAL_INT = 2,
GDB_SIGNAL_QUIT = 3,
GDB_SIGNAL_TRAP = 5,
GDB_SIGNAL_ABRT = 6,
GDB_SIGNAL_ALRM = 14,
GDB_SIGNAL_IO = 23,
GDB_SIGNAL_XCPU = 24,
GDB_SIGNAL_UNKNOWN = 143
};
@ -2270,14 +2275,11 @@ static void gdb_vm_state_change(void *opaque, int running, int reason)
const char *type;
int ret;
if (running || (reason != VMSTOP_DEBUG && reason != VMSTOP_USER) ||
s->state == RS_INACTIVE || s->state == RS_SYSCALL) {
if (running || s->state == RS_INACTIVE || s->state == RS_SYSCALL) {
return;
}
/* disable single step if it was enable */
cpu_single_step(env, 0);
if (reason == VMSTOP_DEBUG) {
switch (reason) {
case VMSTOP_DEBUG:
if (env->watchpoint_hit) {
switch (env->watchpoint_hit->flags & BP_MEM_ACCESS) {
case BP_MEM_READ:
@ -2294,17 +2296,44 @@ static void gdb_vm_state_change(void *opaque, int running, int reason)
"T%02xthread:%02x;%swatch:" TARGET_FMT_lx ";",
GDB_SIGNAL_TRAP, gdb_id(env), type,
env->watchpoint_hit->vaddr);
put_packet(s, buf);
env->watchpoint_hit = NULL;
return;
goto send_packet;
}
tb_flush(env);
tb_flush(env);
ret = GDB_SIGNAL_TRAP;
} else {
break;
case VMSTOP_USER:
ret = GDB_SIGNAL_INT;
break;
case VMSTOP_SHUTDOWN:
ret = GDB_SIGNAL_QUIT;
break;
case VMSTOP_DISKFULL:
ret = GDB_SIGNAL_IO;
break;
case VMSTOP_WATCHDOG:
ret = GDB_SIGNAL_ALRM;
break;
case VMSTOP_PANIC:
ret = GDB_SIGNAL_ABRT;
break;
case VMSTOP_SAVEVM:
case VMSTOP_LOADVM:
return;
case VMSTOP_MIGRATE:
ret = GDB_SIGNAL_XCPU;
break;
default:
ret = GDB_SIGNAL_UNKNOWN;
break;
}
snprintf(buf, sizeof(buf), "T%02xthread:%02x;", ret, gdb_id(env));
send_packet:
put_packet(s, buf);
/* disable single step if it was enabled */
cpu_single_step(env, 0);
}
#endif

View File

@ -29,7 +29,7 @@ static void gen_icount_end(TranslationBlock *tb, int num_insns)
if (use_icount) {
*icount_arg = num_insns;
gen_set_label(icount_label);
tcg_gen_exit_tb((long)tb + 2);
tcg_gen_exit_tb((tcg_target_long)tb + 2);
}
}

View File

@ -370,7 +370,7 @@ static int local_symlink(FsContext *fs_ctx, const char *oldpath,
return fd;
}
/* Write the oldpath (target) to the file. */
oldpath_size = strlen(oldpath) + 1;
oldpath_size = strlen(oldpath);
do {
write_size = write(fd, (void *)oldpath, oldpath_size);
} while (write_size == -1 && errno == EINTR);

View File

@ -15,7 +15,7 @@
#include <attr/xattr.h>
#include "virtio.h"
#include "virtio-9p.h"
#include "file-op-9p.h"
#include "fsdev/file-op-9p.h"
#include "virtio-9p-xattr.h"
#define MAP_ACL_ACCESS "user.virtfs.system.posix_acl_access"
@ -60,7 +60,7 @@ static int mp_pacl_removexattr(FsContext *ctx,
ret = lremovexattr(rpath(ctx, path), MAP_ACL_ACCESS);
if (ret == -1 && errno == ENODATA) {
/*
* We don't get ENODATA error when trying to remote a
* We don't get ENODATA error when trying to remove a
* posix acl that is not present. So don't throw the error
* even in case of mapped security model
*/
@ -103,7 +103,18 @@ static int mp_dacl_setxattr(FsContext *ctx, const char *path, const char *name,
static int mp_dacl_removexattr(FsContext *ctx,
const char *path, const char *name)
{
return lremovexattr(rpath(ctx, path), MAP_ACL_DEFAULT);
int ret;
ret = lremovexattr(rpath(ctx, path), MAP_ACL_DEFAULT);
if (ret == -1 && errno == ENODATA) {
/*
* We don't get ENODATA error when trying to remove a
* posix acl that is not present. So don't throw the error
* even in case of mapped security model
*/
errno = 0;
ret = 0;
}
return ret;
}

View File

@ -14,7 +14,7 @@
#include <sys/types.h>
#include "virtio.h"
#include "virtio-9p.h"
#include "file-op-9p.h"
#include "fsdev/file-op-9p.h"
#include "virtio-9p-xattr.h"

View File

@ -13,7 +13,7 @@
#include "virtio.h"
#include "virtio-9p.h"
#include "file-op-9p.h"
#include "fsdev/file-op-9p.h"
#include "virtio-9p-xattr.h"

View File

@ -596,7 +596,10 @@ static V9fsPDU *alloc_pdu(V9fsState *s)
static void free_pdu(V9fsState *s, V9fsPDU *pdu)
{
if (pdu) {
QLIST_INSERT_HEAD(&s->free_list, pdu, next);
if (debug_9p_pdu) {
pprint_pdu(pdu);
}
QLIST_INSERT_HEAD(&s->free_list, pdu, next);
}
}
@ -696,25 +699,22 @@ static size_t pdu_unmarshal(V9fsPDU *pdu, size_t offset, const char *fmt, ...)
case 'w': {
uint16_t val, *valp;
valp = va_arg(ap, uint16_t *);
val = le16_to_cpupu(valp);
offset += pdu_unpack(&val, pdu, offset, sizeof(val));
*valp = val;
*valp = le16_to_cpu(val);
break;
}
case 'd': {
uint32_t val, *valp;
valp = va_arg(ap, uint32_t *);
val = le32_to_cpupu(valp);
offset += pdu_unpack(&val, pdu, offset, sizeof(val));
*valp = val;
*valp = le32_to_cpu(val);
break;
}
case 'q': {
uint64_t val, *valp;
valp = va_arg(ap, uint64_t *);
val = le64_to_cpup(valp);
offset += pdu_unpack(&val, pdu, offset, sizeof(val));
*valp = val;
*valp = le64_to_cpu(val);
break;
}
case 'v': {
@ -1482,7 +1482,7 @@ static void v9fs_walk_complete(V9fsState *s, V9fsWalkState *vs, int err)
{
complete_pdu(s, vs->pdu, err);
if (vs->nwnames) {
if (vs->nwnames && vs->nwnames <= P9_MAXWELEM) {
for (vs->name_idx = 0; vs->name_idx < vs->nwnames; vs->name_idx++) {
v9fs_string_free(&vs->wnames[vs->name_idx]);
}
@ -1578,7 +1578,7 @@ static void v9fs_walk(V9fsState *s, V9fsPDU *pdu)
vs->offset += pdu_unmarshal(vs->pdu, vs->offset, "ddw", &fid,
&newfid, &vs->nwnames);
if (vs->nwnames) {
if (vs->nwnames && vs->nwnames <= P9_MAXWELEM) {
vs->wnames = qemu_mallocz(sizeof(vs->wnames[0]) * vs->nwnames);
vs->qids = qemu_mallocz(sizeof(vs->qids[0]) * vs->nwnames);
@ -1587,6 +1587,9 @@ static void v9fs_walk(V9fsState *s, V9fsPDU *pdu)
vs->offset += pdu_unmarshal(vs->pdu, vs->offset, "s",
&vs->wnames[i]);
}
} else if (vs->nwnames > P9_MAXWELEM) {
err = -EINVAL;
goto out;
}
vs->fidp = lookup_fid(s, fid);
@ -1771,7 +1774,7 @@ static void v9fs_post_lcreate(V9fsState *s, V9fsLcreateState *vs, int err)
v9fs_string_copy(&vs->fidp->path, &vs->fullname);
stat_to_qid(&vs->stbuf, &vs->qid);
vs->offset += pdu_marshal(vs->pdu, vs->offset, "Qd", &vs->qid,
&vs->iounit);
vs->iounit);
err = vs->offset;
} else {
vs->fidp->fid_type = P9_FID_NONE;

View File

@ -6,7 +6,7 @@
#include <sys/time.h>
#include <utime.h>
#include "file-op-9p.h"
#include "fsdev/file-op-9p.h"
/* The feature bitmap for virtio 9P */
/* The mount point is specified in a config variable */
@ -282,7 +282,7 @@ typedef struct V9fsStatStateDotl {
typedef struct V9fsWalkState {
V9fsPDU *pdu;
size_t offset;
int16_t nwnames;
uint16_t nwnames;
int name_idx;
V9fsQID *qids;
V9fsFidState *fidp;

197
hw/acpi.c
View File

@ -15,6 +15,7 @@
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, see <http://www.gnu.org/licenses/>
*/
#include "sysemu.h"
#include "hw.h"
#include "pc.h"
#include "acpi.h"
@ -197,3 +198,199 @@ out:
}
return -1;
}
/* ACPI PM1a EVT */
uint16_t acpi_pm1_evt_get_sts(ACPIPM1EVT *pm1, int64_t overflow_time)
{
int64_t d = acpi_pm_tmr_get_clock();
if (d >= overflow_time) {
pm1->sts |= ACPI_BITMASK_TIMER_STATUS;
}
return pm1->sts;
}
void acpi_pm1_evt_write_sts(ACPIPM1EVT *pm1, ACPIPMTimer *tmr, uint16_t val)
{
uint16_t pm1_sts = acpi_pm1_evt_get_sts(pm1, tmr->overflow_time);
if (pm1_sts & val & ACPI_BITMASK_TIMER_STATUS) {
/* if TMRSTS is reset, then compute the new overflow time */
acpi_pm_tmr_calc_overflow_time(tmr);
}
pm1->sts &= ~val;
}
void acpi_pm1_evt_power_down(ACPIPM1EVT *pm1, ACPIPMTimer *tmr)
{
if (!pm1) {
qemu_system_shutdown_request();
} else if (pm1->en & ACPI_BITMASK_POWER_BUTTON_ENABLE) {
pm1->sts |= ACPI_BITMASK_POWER_BUTTON_STATUS;
tmr->update_sci(tmr);
}
}
void acpi_pm1_evt_reset(ACPIPM1EVT *pm1)
{
pm1->sts = 0;
pm1->en = 0;
}
/* ACPI PM_TMR */
void acpi_pm_tmr_update(ACPIPMTimer *tmr, bool enable)
{
int64_t expire_time;
/* schedule a timer interruption if needed */
if (enable) {
expire_time = muldiv64(tmr->overflow_time, get_ticks_per_sec(),
PM_TIMER_FREQUENCY);
qemu_mod_timer(tmr->timer, expire_time);
} else {
qemu_del_timer(tmr->timer);
}
}
void acpi_pm_tmr_calc_overflow_time(ACPIPMTimer *tmr)
{
int64_t d = acpi_pm_tmr_get_clock();
tmr->overflow_time = (d + 0x800000LL) & ~0x7fffffLL;
}
uint32_t acpi_pm_tmr_get(ACPIPMTimer *tmr)
{
uint32_t d = acpi_pm_tmr_get_clock();;
return d & 0xffffff;
}
static void acpi_pm_tmr_timer(void *opaque)
{
ACPIPMTimer *tmr = opaque;
tmr->update_sci(tmr);
}
void acpi_pm_tmr_init(ACPIPMTimer *tmr, acpi_update_sci_fn update_sci)
{
tmr->update_sci = update_sci;
tmr->timer = qemu_new_timer_ns(vm_clock, acpi_pm_tmr_timer, tmr);
}
void acpi_pm_tmr_reset(ACPIPMTimer *tmr)
{
tmr->overflow_time = 0;
qemu_del_timer(tmr->timer);
}
/* ACPI PM1aCNT */
void acpi_pm1_cnt_init(ACPIPM1CNT *pm1_cnt, qemu_irq cmos_s3)
{
pm1_cnt->cmos_s3 = cmos_s3;
}
void acpi_pm1_cnt_write(ACPIPM1EVT *pm1a, ACPIPM1CNT *pm1_cnt, uint16_t val)
{
pm1_cnt->cnt = val & ~(ACPI_BITMASK_SLEEP_ENABLE);
if (val & ACPI_BITMASK_SLEEP_ENABLE) {
/* change suspend type */
uint16_t sus_typ = (val >> 10) & 7;
switch(sus_typ) {
case 0: /* soft power off */
qemu_system_shutdown_request();
break;
case 1:
/* ACPI_BITMASK_WAKE_STATUS should be set on resume.
Pretend that resume was caused by power button */
pm1a->sts |=
(ACPI_BITMASK_WAKE_STATUS | ACPI_BITMASK_POWER_BUTTON_STATUS);
qemu_system_reset_request();
qemu_irq_raise(pm1_cnt->cmos_s3);
default:
break;
}
}
}
void acpi_pm1_cnt_update(ACPIPM1CNT *pm1_cnt,
bool sci_enable, bool sci_disable)
{
/* ACPI specs 3.0, 4.7.2.5 */
if (sci_enable) {
pm1_cnt->cnt |= ACPI_BITMASK_SCI_ENABLE;
} else if (sci_disable) {
pm1_cnt->cnt &= ~ACPI_BITMASK_SCI_ENABLE;
}
}
void acpi_pm1_cnt_reset(ACPIPM1CNT *pm1_cnt)
{
pm1_cnt->cnt = 0;
if (pm1_cnt->cmos_s3) {
qemu_irq_lower(pm1_cnt->cmos_s3);
}
}
/* ACPI GPE */
void acpi_gpe_init(ACPIGPE *gpe, uint8_t len)
{
gpe->len = len;
gpe->sts = qemu_mallocz(len / 2);
gpe->en = qemu_mallocz(len / 2);
}
void acpi_gpe_blk(ACPIGPE *gpe, uint32_t blk)
{
gpe->blk = blk;
}
void acpi_gpe_reset(ACPIGPE *gpe)
{
memset(gpe->sts, 0, gpe->len / 2);
memset(gpe->en, 0, gpe->len / 2);
}
static uint8_t *acpi_gpe_ioport_get_ptr(ACPIGPE *gpe, uint32_t addr)
{
uint8_t *cur = NULL;
if (addr < gpe->len / 2) {
cur = gpe->sts + addr;
} else if (addr < gpe->len) {
cur = gpe->en + addr - gpe->len / 2;
} else {
abort();
}
return cur;
}
void acpi_gpe_ioport_writeb(ACPIGPE *gpe, uint32_t addr, uint32_t val)
{
uint8_t *cur;
addr -= gpe->blk;
cur = acpi_gpe_ioport_get_ptr(gpe, addr);
if (addr < gpe->len / 2) {
/* GPE_STS */
*cur = (*cur) & ~val;
} else if (addr < gpe->len) {
/* GPE_EN */
*cur = val;
} else {
abort();
}
}
uint32_t acpi_gpe_ioport_readb(ACPIGPE *gpe, uint32_t addr)
{
uint8_t *cur;
uint32_t val;
addr -= gpe->blk;
cur = acpi_gpe_ioport_get_ptr(gpe, addr);
val = 0;
if (cur != NULL) {
val = *cur;
}
return val;
}

View File

@ -74,5 +74,73 @@
#define ACPI_BITMASK_ARB_DISABLE 0x0001
/* PM_TMR */
struct ACPIPMTimer;
typedef struct ACPIPMTimer ACPIPMTimer;
typedef void (*acpi_update_sci_fn)(ACPIPMTimer *tmr);
struct ACPIPMTimer {
QEMUTimer *timer;
int64_t overflow_time;
acpi_update_sci_fn update_sci;
};
void acpi_pm_tmr_update(ACPIPMTimer *tmr, bool enable);
void acpi_pm_tmr_calc_overflow_time(ACPIPMTimer *tmr);
uint32_t acpi_pm_tmr_get(ACPIPMTimer *tmr);
void acpi_pm_tmr_init(ACPIPMTimer *tmr, acpi_update_sci_fn update_sci);
void acpi_pm_tmr_reset(ACPIPMTimer *tmr);
#include "qemu-timer.h"
static inline int64_t acpi_pm_tmr_get_clock(void)
{
return muldiv64(qemu_get_clock_ns(vm_clock), PM_TIMER_FREQUENCY,
get_ticks_per_sec());
}
/* PM1a_EVT: piix and ich9 don't implement PM1b. */
struct ACPIPM1EVT
{
uint16_t sts;
uint16_t en;
};
typedef struct ACPIPM1EVT ACPIPM1EVT;
uint16_t acpi_pm1_evt_get_sts(ACPIPM1EVT *pm1, int64_t overflow_time);
void acpi_pm1_evt_write_sts(ACPIPM1EVT *pm1, ACPIPMTimer *tmr, uint16_t val);
void acpi_pm1_evt_power_down(ACPIPM1EVT *pm1, ACPIPMTimer *tmr);
void acpi_pm1_evt_reset(ACPIPM1EVT *pm1);
/* PM1a_CNT: piix and ich9 don't implement PM1b CNT. */
struct ACPIPM1CNT {
uint16_t cnt;
qemu_irq cmos_s3;
};
typedef struct ACPIPM1CNT ACPIPM1CNT;
void acpi_pm1_cnt_init(ACPIPM1CNT *pm1_cnt, qemu_irq cmos_s3);
void acpi_pm1_cnt_write(ACPIPM1EVT *pm1a, ACPIPM1CNT *pm1_cnt, uint16_t val);
void acpi_pm1_cnt_update(ACPIPM1CNT *pm1_cnt,
bool sci_enable, bool sci_disable);
void acpi_pm1_cnt_reset(ACPIPM1CNT *pm1_cnt);
/* GPE0 */
struct ACPIGPE {
uint32_t blk;
uint8_t len;
uint8_t *sts;
uint8_t *en;
};
typedef struct ACPIGPE ACPIGPE;
void acpi_gpe_init(ACPIGPE *gpe, uint8_t len);
void acpi_gpe_blk(ACPIGPE *gpe, uint32_t blk);
void acpi_gpe_reset(ACPIGPE *gpe);
void acpi_gpe_ioport_writeb(ACPIGPE *gpe, uint32_t addr, uint32_t val);
uint32_t acpi_gpe_ioport_readb(ACPIGPE *gpe, uint32_t addr);
#endif /* !QEMU_HW_ACPI_H */

View File

@ -35,17 +35,13 @@
#define ACPI_DBG_IO_ADDR 0xb044
#define GPE_BASE 0xafe0
#define GPE_LEN 4
#define PCI_BASE 0xae00
#define PCI_EJ_BASE 0xae08
#define PCI_RMV_BASE 0xae0c
#define PIIX4_PCI_HOTPLUG_STATUS 2
struct gpe_regs {
uint16_t sts; /* status */
uint16_t en; /* enabled */
};
struct pci_status {
uint32_t up;
uint32_t down;
@ -54,25 +50,22 @@ struct pci_status {
typedef struct PIIX4PMState {
PCIDevice dev;
IORange ioport;
uint16_t pmsts;
uint16_t pmen;
uint16_t pmcntrl;
ACPIPM1EVT pm1a;
ACPIPM1CNT pm1_cnt;
APMState apm;
QEMUTimer *tmr_timer;
int64_t tmr_overflow_time;
ACPIPMTimer tmr;
PMSMBus smb;
uint32_t smb_io_base;
qemu_irq irq;
qemu_irq cmos_s3;
qemu_irq smi_irq;
int kvm_enabled;
/* for pci hotplug */
struct gpe_regs gpe;
ACPIGPE gpe;
struct pci_status pci0_status;
uint32_t pci0_hotplug_enable;
} PIIX4PMState;
@ -82,52 +75,27 @@ static void piix4_acpi_system_hot_add_init(PCIBus *bus, PIIX4PMState *s);
#define ACPI_ENABLE 0xf1
#define ACPI_DISABLE 0xf0
static uint32_t get_pmtmr(PIIX4PMState *s)
{
uint32_t d;
d = muldiv64(qemu_get_clock_ns(vm_clock), PM_TIMER_FREQUENCY, get_ticks_per_sec());
return d & 0xffffff;
}
static int get_pmsts(PIIX4PMState *s)
{
int64_t d;
d = muldiv64(qemu_get_clock_ns(vm_clock), PM_TIMER_FREQUENCY,
get_ticks_per_sec());
if (d >= s->tmr_overflow_time)
s->pmsts |= ACPI_BITMASK_TIMER_STATUS;
return s->pmsts;
}
static void pm_update_sci(PIIX4PMState *s)
{
int sci_level, pmsts;
int64_t expire_time;
pmsts = get_pmsts(s);
sci_level = (((pmsts & s->pmen) &
pmsts = acpi_pm1_evt_get_sts(&s->pm1a, s->tmr.overflow_time);
sci_level = (((pmsts & s->pm1a.en) &
(ACPI_BITMASK_RT_CLOCK_ENABLE |
ACPI_BITMASK_POWER_BUTTON_ENABLE |
ACPI_BITMASK_GLOBAL_LOCK_ENABLE |
ACPI_BITMASK_TIMER_ENABLE)) != 0) ||
(((s->gpe.sts & s->gpe.en) & PIIX4_PCI_HOTPLUG_STATUS) != 0);
(((s->gpe.sts[0] & s->gpe.en[0]) & PIIX4_PCI_HOTPLUG_STATUS) != 0);
qemu_set_irq(s->irq, sci_level);
/* schedule a timer interruption if needed */
if ((s->pmen & ACPI_BITMASK_TIMER_ENABLE) &&
!(pmsts & ACPI_BITMASK_TIMER_STATUS)) {
expire_time = muldiv64(s->tmr_overflow_time, get_ticks_per_sec(),
PM_TIMER_FREQUENCY);
qemu_mod_timer(s->tmr_timer, expire_time);
} else {
qemu_del_timer(s->tmr_timer);
}
acpi_pm_tmr_update(&s->tmr, (s->pm1a.en & ACPI_BITMASK_TIMER_ENABLE) &&
!(pmsts & ACPI_BITMASK_TIMER_STATUS));
}
static void pm_tmr_timer(void *opaque)
static void pm_tmr_timer(ACPIPMTimer *tmr)
{
PIIX4PMState *s = opaque;
PIIX4PMState *s = container_of(tmr, PIIX4PMState, tmr);
pm_update_sci(s);
}
@ -143,54 +111,21 @@ static void pm_ioport_write(IORange *ioport, uint64_t addr, unsigned width,
switch(addr) {
case 0x00:
{
int64_t d;
int pmsts;
pmsts = get_pmsts(s);
if (pmsts & val & ACPI_BITMASK_TIMER_STATUS) {
/* if TMRSTS is reset, then compute the new overflow time */
d = muldiv64(qemu_get_clock_ns(vm_clock), PM_TIMER_FREQUENCY,
get_ticks_per_sec());
s->tmr_overflow_time = (d + 0x800000LL) & ~0x7fffffLL;
}
s->pmsts &= ~val;
pm_update_sci(s);
}
acpi_pm1_evt_write_sts(&s->pm1a, &s->tmr, val);
pm_update_sci(s);
break;
case 0x02:
s->pmen = val;
s->pm1a.en = val;
pm_update_sci(s);
break;
case 0x04:
{
int sus_typ;
s->pmcntrl = val & ~(ACPI_BITMASK_SLEEP_ENABLE);
if (val & ACPI_BITMASK_SLEEP_ENABLE) {
/* change suspend type */
sus_typ = (val >> 10) & 7;
switch(sus_typ) {
case 0: /* soft power off */
qemu_system_shutdown_request();
break;
case 1:
/* ACPI_BITMASK_WAKE_STATUS should be set on resume.
Pretend that resume was caused by power button */
s->pmsts |= (ACPI_BITMASK_WAKE_STATUS |
ACPI_BITMASK_POWER_BUTTON_STATUS);
qemu_system_reset_request();
if (s->cmos_s3) {
qemu_irq_raise(s->cmos_s3);
}
default:
break;
}
}
}
acpi_pm1_cnt_write(&s->pm1a, &s->pm1_cnt, val);
break;
default:
break;
}
PIIX4_DPRINTF("PM writew port=0x%04x val=0x%04x\n", addr, val);
PIIX4_DPRINTF("PM writew port=0x%04x val=0x%04x\n", (unsigned int)addr,
(unsigned int)val);
}
static void pm_ioport_read(IORange *ioport, uint64_t addr, unsigned width,
@ -201,22 +136,22 @@ static void pm_ioport_read(IORange *ioport, uint64_t addr, unsigned width,
switch(addr) {
case 0x00:
val = get_pmsts(s);
val = acpi_pm1_evt_get_sts(&s->pm1a, s->tmr.overflow_time);
break;
case 0x02:
val = s->pmen;
val = s->pm1a.en;
break;
case 0x04:
val = s->pmcntrl;
val = s->pm1_cnt.cnt;
break;
case 0x08:
val = get_pmtmr(s);
val = acpi_pm_tmr_get(&s->tmr);
break;
default:
val = 0;
break;
}
PIIX4_DPRINTF("PM readw port=0x%04x val=0x%04x\n", addr, val);
PIIX4_DPRINTF("PM readw port=0x%04x val=0x%04x\n", (unsigned int)addr, val);
*data = val;
}
@ -230,11 +165,7 @@ static void apm_ctrl_changed(uint32_t val, void *arg)
PIIX4PMState *s = arg;
/* ACPI specs 3.0, 4.7.2.5 */
if (val == ACPI_ENABLE) {
s->pmcntrl |= ACPI_BITMASK_SCI_ENABLE;
} else if (val == ACPI_DISABLE) {
s->pmcntrl &= ~ACPI_BITMASK_SCI_ENABLE;
}
acpi_pm1_cnt_update(&s->pm1_cnt, val == ACPI_ENABLE, val == ACPI_DISABLE);
if (s->dev.config[0x5b] & (1 << 1)) {
if (s->smi_irq) {
@ -279,14 +210,25 @@ static int vmstate_acpi_post_load(void *opaque, int version_id)
return 0;
}
#define VMSTATE_GPE_ARRAY(_field, _state) \
{ \
.name = (stringify(_field)), \
.version_id = 0, \
.num = GPE_LEN, \
.info = &vmstate_info_uint16, \
.size = sizeof(uint16_t), \
.flags = VMS_ARRAY | VMS_POINTER, \
.offset = vmstate_offset_pointer(_state, _field, uint8_t), \
}
static const VMStateDescription vmstate_gpe = {
.name = "gpe",
.version_id = 1,
.minimum_version_id = 1,
.minimum_version_id_old = 1,
.fields = (VMStateField []) {
VMSTATE_UINT16(sts, struct gpe_regs),
VMSTATE_UINT16(en, struct gpe_regs),
VMSTATE_GPE_ARRAY(sts, ACPIGPE),
VMSTATE_GPE_ARRAY(en, ACPIGPE),
VMSTATE_END_OF_LIST()
}
};
@ -311,13 +253,13 @@ static const VMStateDescription vmstate_acpi = {
.post_load = vmstate_acpi_post_load,
.fields = (VMStateField []) {
VMSTATE_PCI_DEVICE(dev, PIIX4PMState),
VMSTATE_UINT16(pmsts, PIIX4PMState),
VMSTATE_UINT16(pmen, PIIX4PMState),
VMSTATE_UINT16(pmcntrl, PIIX4PMState),
VMSTATE_UINT16(pm1a.sts, PIIX4PMState),
VMSTATE_UINT16(pm1a.en, PIIX4PMState),
VMSTATE_UINT16(pm1_cnt.cnt, PIIX4PMState),
VMSTATE_STRUCT(apm, PIIX4PMState, 0, vmstate_apm, APMState),
VMSTATE_TIMER(tmr_timer, PIIX4PMState),
VMSTATE_INT64(tmr_overflow_time, PIIX4PMState),
VMSTATE_STRUCT(gpe, PIIX4PMState, 2, vmstate_gpe, struct gpe_regs),
VMSTATE_TIMER(tmr.timer, PIIX4PMState),
VMSTATE_INT64(tmr.overflow_time, PIIX4PMState),
VMSTATE_STRUCT(gpe, PIIX4PMState, 2, vmstate_gpe, ACPIGPE),
VMSTATE_STRUCT(pci0_status, PIIX4PMState, 2, vmstate_pci_status,
struct pci_status),
VMSTATE_END_OF_LIST()
@ -363,13 +305,10 @@ static void piix4_reset(void *opaque)
static void piix4_powerdown(void *opaque, int irq, int power_failing)
{
PIIX4PMState *s = opaque;
ACPIPM1EVT *pm1a = s? &s->pm1a: NULL;
ACPIPMTimer *tmr = s? &s->tmr: NULL;
if (!s) {
qemu_system_shutdown_request();
} else if (s->pmen & ACPI_BITMASK_POWER_BUTTON_ENABLE) {
s->pmsts |= ACPI_BITMASK_POWER_BUTTON_STATUS;
pm_update_sci(s);
}
acpi_pm1_evt_power_down(pm1a, tmr);
}
static int piix4_pm_initfn(PCIDevice *dev)
@ -413,7 +352,8 @@ static int piix4_pm_initfn(PCIDevice *dev)
register_ioport_write(s->smb_io_base, 64, 1, smb_ioport_writeb, &s->smb);
register_ioport_read(s->smb_io_base, 64, 1, smb_ioport_readb, &s->smb);
s->tmr_timer = qemu_new_timer_ns(vm_clock, pm_tmr_timer, s);
acpi_pm_tmr_init(&s->tmr, pm_tmr_timer);
acpi_gpe_init(&s->gpe, GPE_LEN);
qemu_system_powerdown = *qemu_allocate_irqs(piix4_powerdown, s, 1);
@ -436,7 +376,7 @@ i2c_bus *piix4_pm_init(PCIBus *bus, int devfn, uint32_t smb_io_base,
s = DO_UPCAST(PIIX4PMState, dev, dev);
s->irq = sci_irq;
s->cmos_s3 = cmos_s3;
acpi_pm1_cnt_init(&s->pm1_cnt, cmos_s3);
s->smi_irq = smi_irq;
s->kvm_enabled = kvm_enabled;
@ -467,74 +407,20 @@ static void piix4_pm_register(void)
device_init(piix4_pm_register);
static uint32_t gpe_read_val(uint16_t val, uint32_t addr)
{
if (addr & 1)
return (val >> 8) & 0xff;
return val & 0xff;
}
static uint32_t gpe_readb(void *opaque, uint32_t addr)
{
uint32_t val = 0;
PIIX4PMState *s = opaque;
struct gpe_regs *g = &s->gpe;
switch (addr) {
case GPE_BASE:
case GPE_BASE + 1:
val = gpe_read_val(g->sts, addr);
break;
case GPE_BASE + 2:
case GPE_BASE + 3:
val = gpe_read_val(g->en, addr);
break;
default:
break;
}
uint32_t val = acpi_gpe_ioport_readb(&s->gpe, addr);
PIIX4_DPRINTF("gpe read %x == %x\n", addr, val);
return val;
}
static void gpe_write_val(uint16_t *cur, int addr, uint32_t val)
{
if (addr & 1)
*cur = (*cur & 0xff) | (val << 8);
else
*cur = (*cur & 0xff00) | (val & 0xff);
}
static void gpe_reset_val(uint16_t *cur, int addr, uint32_t val)
{
uint16_t x1, x0 = val & 0xff;
int shift = (addr & 1) ? 8 : 0;
x1 = (*cur >> shift) & 0xff;
x1 = x1 & ~x0;
*cur = (*cur & (0xff << (8 - shift))) | (x1 << shift);
}
static void gpe_writeb(void *opaque, uint32_t addr, uint32_t val)
{
PIIX4PMState *s = opaque;
struct gpe_regs *g = &s->gpe;
switch (addr) {
case GPE_BASE:
case GPE_BASE + 1:
gpe_reset_val(&g->sts, addr, val);
break;
case GPE_BASE + 2:
case GPE_BASE + 3:
gpe_write_val(&g->en, addr, val);
break;
default:
break;
}
acpi_gpe_ioport_writeb(&s->gpe, addr, val);
pm_update_sci(s);
PIIX4_DPRINTF("gpe write %x <== %d\n", addr, val);
@ -617,8 +503,9 @@ static void piix4_acpi_system_hot_add_init(PCIBus *bus, PIIX4PMState *s)
{
struct pci_status *pci0_status = &s->pci0_status;
register_ioport_write(GPE_BASE, 4, 1, gpe_writeb, s);
register_ioport_read(GPE_BASE, 4, 1, gpe_readb, s);
register_ioport_write(GPE_BASE, GPE_LEN, 1, gpe_writeb, s);
register_ioport_read(GPE_BASE, GPE_LEN, 1, gpe_readb, s);
acpi_gpe_blk(&s->gpe, GPE_BASE);
register_ioport_write(PCI_BASE, 8, 4, pcihotplug_write, pci0_status);
register_ioport_read(PCI_BASE, 8, 4, pcihotplug_read, pci0_status);
@ -634,13 +521,13 @@ static void piix4_acpi_system_hot_add_init(PCIBus *bus, PIIX4PMState *s)
static void enable_device(PIIX4PMState *s, int slot)
{
s->gpe.sts |= PIIX4_PCI_HOTPLUG_STATUS;
s->gpe.sts[0] |= PIIX4_PCI_HOTPLUG_STATUS;
s->pci0_status.up |= (1 << slot);
}
static void disable_device(PIIX4PMState *s, int slot)
{
s->gpe.sts |= PIIX4_PCI_HOTPLUG_STATUS;
s->gpe.sts[0] |= PIIX4_PCI_HOTPLUG_STATUS;
s->pci0_status.down |= (1 << slot);
}

View File

@ -261,30 +261,19 @@ static int adb_kbd_request(ADBDevice *d, uint8_t *obuf,
return olen;
}
static void adb_kbd_save(QEMUFile *f, void *opaque)
{
KBDState *s = (KBDState *)opaque;
qemu_put_buffer(f, s->data, sizeof(s->data));
qemu_put_sbe32s(f, &s->rptr);
qemu_put_sbe32s(f, &s->wptr);
qemu_put_sbe32s(f, &s->count);
}
static int adb_kbd_load(QEMUFile *f, void *opaque, int version_id)
{
KBDState *s = (KBDState *)opaque;
if (version_id != 1)
return -EINVAL;
qemu_get_buffer(f, s->data, sizeof(s->data));
qemu_get_sbe32s(f, &s->rptr);
qemu_get_sbe32s(f, &s->wptr);
qemu_get_sbe32s(f, &s->count);
return 0;
}
static const VMStateDescription vmstate_adb_kbd = {
.name = "adb_kbd",
.version_id = 1,
.minimum_version_id = 1,
.minimum_version_id_old = 1,
.fields = (VMStateField[]) {
VMSTATE_BUFFER(data, KBDState),
VMSTATE_INT32(rptr, KBDState),
VMSTATE_INT32(wptr, KBDState),
VMSTATE_INT32(count, KBDState),
VMSTATE_END_OF_LIST()
}
};
static int adb_kbd_reset(ADBDevice *d)
{
@ -305,8 +294,7 @@ void adb_kbd_init(ADBBusState *bus)
d = adb_register_device(bus, ADB_KEYBOARD, adb_kbd_request,
adb_kbd_reset, s);
qemu_add_kbd_event_handler(adb_kbd_put_keycode, d);
register_savevm(NULL, "adb_kbd", -1, 1, adb_kbd_save,
adb_kbd_load, s);
vmstate_register(NULL, -1, &vmstate_adb_kbd, s);
}
/***************************************************************/
@ -439,32 +427,20 @@ static int adb_mouse_reset(ADBDevice *d)
return 0;
}
static void adb_mouse_save(QEMUFile *f, void *opaque)
{
MouseState *s = (MouseState *)opaque;
qemu_put_sbe32s(f, &s->buttons_state);
qemu_put_sbe32s(f, &s->last_buttons_state);
qemu_put_sbe32s(f, &s->dx);
qemu_put_sbe32s(f, &s->dy);
qemu_put_sbe32s(f, &s->dz);
}
static int adb_mouse_load(QEMUFile *f, void *opaque, int version_id)
{
MouseState *s = (MouseState *)opaque;
if (version_id != 1)
return -EINVAL;
qemu_get_sbe32s(f, &s->buttons_state);
qemu_get_sbe32s(f, &s->last_buttons_state);
qemu_get_sbe32s(f, &s->dx);
qemu_get_sbe32s(f, &s->dy);
qemu_get_sbe32s(f, &s->dz);
return 0;
}
static const VMStateDescription vmstate_adb_mouse = {
.name = "adb_mouse",
.version_id = 1,
.minimum_version_id = 1,
.minimum_version_id_old = 1,
.fields = (VMStateField[]) {
VMSTATE_INT32(buttons_state, MouseState),
VMSTATE_INT32(last_buttons_state, MouseState),
VMSTATE_INT32(dx, MouseState),
VMSTATE_INT32(dy, MouseState),
VMSTATE_INT32(dz, MouseState),
VMSTATE_END_OF_LIST()
}
};
void adb_mouse_init(ADBBusState *bus)
{
@ -475,6 +451,5 @@ void adb_mouse_init(ADBBusState *bus)
d = adb_register_device(bus, ADB_MOUSE, adb_mouse_request,
adb_mouse_reset, s);
qemu_add_mouse_event_handler(adb_mouse_event, d, 0, "QEMU ADB Mouse");
register_savevm(NULL, "adb_mouse", -1, 1, adb_mouse_save,
adb_mouse_load, s);
vmstate_register(NULL, -1, &vmstate_adb_mouse, s);
}

View File

@ -105,35 +105,30 @@ static void ads7846_ts_event(void *opaque,
}
}
static void ads7846_save(QEMUFile *f, void *opaque)
static int ads7856_post_load(void *opaque, int version_id)
{
ADS7846State *s = (ADS7846State *) opaque;
int i;
for (i = 0; i < 8; i ++)
qemu_put_be32(f, s->input[i]);
qemu_put_be32(f, s->noise);
qemu_put_be32(f, s->cycle);
qemu_put_be32(f, s->output);
}
static int ads7846_load(QEMUFile *f, void *opaque, int version_id)
{
ADS7846State *s = (ADS7846State *) opaque;
int i;
for (i = 0; i < 8; i ++)
s->input[i] = qemu_get_be32(f);
s->noise = qemu_get_be32(f);
s->cycle = qemu_get_be32(f);
s->output = qemu_get_be32(f);
ADS7846State *s = opaque;
s->pressure = 0;
ads7846_int_update(s);
return 0;
}
static const VMStateDescription vmstate_ads7846 = {
.name = "ads7846",
.version_id = 0,
.minimum_version_id = 0,
.minimum_version_id_old = 0,
.post_load = ads7856_post_load,
.fields = (VMStateField[]) {
VMSTATE_INT32_ARRAY(input, ADS7846State, 8),
VMSTATE_INT32(noise, ADS7846State),
VMSTATE_INT32(cycle, ADS7846State),
VMSTATE_INT32(output, ADS7846State),
VMSTATE_END_OF_LIST()
}
};
static int ads7846_init(SSISlave *dev)
{
ADS7846State *s = FROM_SSI_SLAVE(ADS7846State, dev);
@ -151,7 +146,7 @@ static int ads7846_init(SSISlave *dev)
ads7846_int_update(s);
register_savevm(NULL, "ads7846", -1, 0, ads7846_save, ads7846_load, s);
vmstate_register(NULL, -1, &vmstate_ads7846, s);
return 0;
}

View File

@ -9,7 +9,6 @@
#include "hw.h"
#include "pc.h"
#include "mcf.h"
#include "sysemu.h"
#include "boards.h"
#include "loader.h"
#include "elf.h"

View File

@ -15,7 +15,7 @@
#define KERNEL_ARGS_ADDR 0x100
#define KERNEL_LOAD_ADDR 0x00010000
#define INITRD_LOAD_ADDR 0x00800000
#define INITRD_LOAD_ADDR 0x00d00000
/* The worlds second smallest bootloader. Set r0-r2, then jump to kernel. */
static uint32_t bootloader[] = {

View File

@ -140,28 +140,19 @@ static void arm_timer_tick(void *opaque)
arm_timer_update(s);
}
static void arm_timer_save(QEMUFile *f, void *opaque)
{
arm_timer_state *s = (arm_timer_state *)opaque;
qemu_put_be32(f, s->control);
qemu_put_be32(f, s->limit);
qemu_put_be32(f, s->int_level);
qemu_put_ptimer(f, s->timer);
}
static int arm_timer_load(QEMUFile *f, void *opaque, int version_id)
{
arm_timer_state *s = (arm_timer_state *)opaque;
if (version_id != 1)
return -EINVAL;
s->control = qemu_get_be32(f);
s->limit = qemu_get_be32(f);
s->int_level = qemu_get_be32(f);
qemu_get_ptimer(f, s->timer);
return 0;
}
static const VMStateDescription vmstate_arm_timer = {
.name = "arm_timer",
.version_id = 1,
.minimum_version_id = 1,
.minimum_version_id_old = 1,
.fields = (VMStateField[]) {
VMSTATE_UINT32(control, arm_timer_state),
VMSTATE_UINT32(limit, arm_timer_state),
VMSTATE_INT32(int_level, arm_timer_state),
VMSTATE_PTIMER(timer, arm_timer_state),
VMSTATE_END_OF_LIST()
}
};
static arm_timer_state *arm_timer_init(uint32_t freq)
{
@ -174,7 +165,7 @@ static arm_timer_state *arm_timer_init(uint32_t freq)
bh = qemu_bh_new(arm_timer_tick, s);
s->timer = ptimer_init(bh);
register_savevm(NULL, "arm_timer", -1, 1, arm_timer_save, arm_timer_load, s);
vmstate_register(NULL, -1, &vmstate_arm_timer, s);
return s;
}
@ -235,24 +226,17 @@ static CPUWriteMemoryFunc * const sp804_writefn[] = {
sp804_write
};
static void sp804_save(QEMUFile *f, void *opaque)
{
sp804_state *s = (sp804_state *)opaque;
qemu_put_be32(f, s->level[0]);
qemu_put_be32(f, s->level[1]);
}
static int sp804_load(QEMUFile *f, void *opaque, int version_id)
{
sp804_state *s = (sp804_state *)opaque;
if (version_id != 1)
return -EINVAL;
s->level[0] = qemu_get_be32(f);
s->level[1] = qemu_get_be32(f);
return 0;
}
static const VMStateDescription vmstate_sp804 = {
.name = "sp804",
.version_id = 1,
.minimum_version_id = 1,
.minimum_version_id_old = 1,
.fields = (VMStateField[]) {
VMSTATE_INT32_ARRAY(level, sp804_state, 2),
VMSTATE_END_OF_LIST()
}
};
static int sp804_init(SysBusDevice *dev)
{
@ -271,7 +255,7 @@ static int sp804_init(SysBusDevice *dev)
iomemtype = cpu_register_io_memory(sp804_readfn,
sp804_writefn, s, DEVICE_NATIVE_ENDIAN);
sysbus_init_mmio(dev, 0x1000, iomemtype);
register_savevm(&dev->qdev, "sp804", -1, 1, sp804_save, sp804_load, s);
vmstate_register(&dev->qdev, -1, &vmstate_sp804, s);
return 0;
}

View File

@ -9,7 +9,6 @@
#include "sysbus.h"
#include "arm-misc.h"
#include "sysemu.h"
#include "loader.h"
#include "elf.h"

View File

@ -365,30 +365,19 @@ static void nvic_writel(void *opaque, uint32_t offset, uint32_t value)
}
}
static void nvic_save(QEMUFile *f, void *opaque)
{
nvic_state *s = (nvic_state *)opaque;
qemu_put_be32(f, s->systick.control);
qemu_put_be32(f, s->systick.reload);
qemu_put_be64(f, s->systick.tick);
qemu_put_timer(f, s->systick.timer);
}
static int nvic_load(QEMUFile *f, void *opaque, int version_id)
{
nvic_state *s = (nvic_state *)opaque;
if (version_id != 1)
return -EINVAL;
s->systick.control = qemu_get_be32(f);
s->systick.reload = qemu_get_be32(f);
s->systick.tick = qemu_get_be64(f);
qemu_get_timer(f, s->systick.timer);
return 0;
}
static const VMStateDescription vmstate_nvic = {
.name = "armv7m_nvic",
.version_id = 1,
.minimum_version_id = 1,
.minimum_version_id_old = 1,
.fields = (VMStateField[]) {
VMSTATE_UINT32(systick.control, nvic_state),
VMSTATE_UINT32(systick.reload, nvic_state),
VMSTATE_INT64(systick.tick, nvic_state),
VMSTATE_TIMER(systick.timer, nvic_state),
VMSTATE_END_OF_LIST()
}
};
static int armv7m_nvic_init(SysBusDevice *dev)
{
@ -397,7 +386,7 @@ static int armv7m_nvic_init(SysBusDevice *dev)
gic_init(&s->gic);
cpu_register_physical_memory(0xe000e000, 0x1000, s->gic.iomemtype);
s->systick.timer = qemu_new_timer_ns(vm_clock, systick_timer_tick, s);
register_savevm(&dev->qdev, "armv7m_nvic", -1, 1, nvic_save, nvic_load, s);
vmstate_register(&dev->qdev, -1, &vmstate_nvic, s);
return 0;
}

View File

@ -26,7 +26,6 @@
#include "net.h"
#include "flash.h"
#include "boards.h"
#include "sysemu.h"
#include "etraxfs.h"
#include "loader.h"
#include "elf.h"

View File

@ -19,7 +19,6 @@
*/
#include "qemu-common.h"
#include "sysemu.h"
#include "console.h"
#include "devices.h"
#include "vga_int.h"

View File

@ -22,7 +22,6 @@
#include "qemu-char.h"
#include "qemu-timer.h"
#include "irq.h"
#include "sysemu.h"
#include "net.h"
#include "bt.h"

595
hw/ccid-card-emulated.c Normal file
View File

@ -0,0 +1,595 @@
/*
* CCID Card Device. Emulated card.
*
* Copyright (c) 2011 Red Hat.
* Written by Alon Levy.
*
* This code is licenced under the GNU LGPL, version 2 or later.
*/
/*
* It can be used to provide access to the local hardware in a non exclusive
* way, or it can use certificates. It requires the usb-ccid bus.
*
* Usage 1: standard, mirror hardware reader+card:
* qemu .. -usb -device usb-ccid -device ccid-card-emulated
*
* Usage 2: use certificates, no hardware required
* one time: create the certificates:
* for i in 1 2 3; do
* certutil -d /etc/pki/nssdb -x -t "CT,CT,CT" -S -s "CN=user$i" -n user$i
* done
* qemu .. -usb -device usb-ccid \
* -device ccid-card-emulated,cert1=user1,cert2=user2,cert3=user3
*
* If you use a non default db for the certificates you can specify it using
* the db parameter.
*/
#include <eventt.h>
#include <vevent.h>
#include <vreader.h>
#include <vcard_emul.h>
#include "qemu-thread.h"
#include "qemu-char.h"
#include "monitor.h"
#include "hw/ccid.h"
#define DPRINTF(card, lvl, fmt, ...) \
do {\
if (lvl <= card->debug) {\
printf("ccid-card-emul: %s: " fmt , __func__, ## __VA_ARGS__);\
} \
} while (0)
#define EMULATED_DEV_NAME "ccid-card-emulated"
#define BACKEND_NSS_EMULATED_NAME "nss-emulated"
#define BACKEND_CERTIFICATES_NAME "certificates"
enum {
BACKEND_NSS_EMULATED = 1,
BACKEND_CERTIFICATES
};
#define DEFAULT_BACKEND BACKEND_NSS_EMULATED
typedef struct EmulatedState EmulatedState;
enum {
EMUL_READER_INSERT = 0,
EMUL_READER_REMOVE,
EMUL_CARD_INSERT,
EMUL_CARD_REMOVE,
EMUL_GUEST_APDU,
EMUL_RESPONSE_APDU,
EMUL_ERROR,
};
static const char *emul_event_to_string(uint32_t emul_event)
{
switch (emul_event) {
case EMUL_READER_INSERT:
return "EMUL_READER_INSERT";
case EMUL_READER_REMOVE:
return "EMUL_READER_REMOVE";
case EMUL_CARD_INSERT:
return "EMUL_CARD_INSERT";
case EMUL_CARD_REMOVE:
return "EMUL_CARD_REMOVE";
case EMUL_GUEST_APDU:
return "EMUL_GUEST_APDU";
case EMUL_RESPONSE_APDU:
return "EMUL_RESPONSE_APDU";
case EMUL_ERROR:
return "EMUL_ERROR";
}
return "UNKNOWN";
}
typedef struct EmulEvent {
QSIMPLEQ_ENTRY(EmulEvent) entry;
union {
struct {
uint32_t type;
} gen;
struct {
uint32_t type;
uint64_t code;
} error;
struct {
uint32_t type;
uint32_t len;
uint8_t data[];
} data;
} p;
} EmulEvent;
#define MAX_ATR_SIZE 40
struct EmulatedState {
CCIDCardState base;
uint8_t debug;
char *backend_str;
uint32_t backend;
char *cert1;
char *cert2;
char *cert3;
char *db;
uint8_t atr[MAX_ATR_SIZE];
uint8_t atr_length;
QSIMPLEQ_HEAD(event_list, EmulEvent) event_list;
QemuMutex event_list_mutex;
VReader *reader;
QSIMPLEQ_HEAD(guest_apdu_list, EmulEvent) guest_apdu_list;
QemuMutex vreader_mutex; /* and guest_apdu_list mutex */
QemuMutex handle_apdu_mutex;
QemuCond handle_apdu_cond;
int pipe[2];
int quit_apdu_thread;
QemuMutex apdu_thread_quit_mutex;
QemuCond apdu_thread_quit_cond;
};
static void emulated_apdu_from_guest(CCIDCardState *base,
const uint8_t *apdu, uint32_t len)
{
EmulatedState *card = DO_UPCAST(EmulatedState, base, base);
EmulEvent *event = (EmulEvent *)qemu_malloc(sizeof(EmulEvent) + len);
assert(event);
event->p.data.type = EMUL_GUEST_APDU;
event->p.data.len = len;
memcpy(event->p.data.data, apdu, len);
qemu_mutex_lock(&card->vreader_mutex);
QSIMPLEQ_INSERT_TAIL(&card->guest_apdu_list, event, entry);
qemu_mutex_unlock(&card->vreader_mutex);
qemu_mutex_lock(&card->handle_apdu_mutex);
qemu_cond_signal(&card->handle_apdu_cond);
qemu_mutex_unlock(&card->handle_apdu_mutex);
}
static const uint8_t *emulated_get_atr(CCIDCardState *base, uint32_t *len)
{
EmulatedState *card = DO_UPCAST(EmulatedState, base, base);
*len = card->atr_length;
return card->atr;
}
static void emulated_push_event(EmulatedState *card, EmulEvent *event)
{
qemu_mutex_lock(&card->event_list_mutex);
QSIMPLEQ_INSERT_TAIL(&(card->event_list), event, entry);
qemu_mutex_unlock(&card->event_list_mutex);
if (write(card->pipe[1], card, 1) != 1) {
DPRINTF(card, 1, "write to pipe failed\n");
}
}
static void emulated_push_type(EmulatedState *card, uint32_t type)
{
EmulEvent *event = (EmulEvent *)qemu_malloc(sizeof(EmulEvent));
assert(event);
event->p.gen.type = type;
emulated_push_event(card, event);
}
static void emulated_push_error(EmulatedState *card, uint64_t code)
{
EmulEvent *event = (EmulEvent *)qemu_malloc(sizeof(EmulEvent));
assert(event);
event->p.error.type = EMUL_ERROR;
event->p.error.code = code;
emulated_push_event(card, event);
}
static void emulated_push_data_type(EmulatedState *card, uint32_t type,
const uint8_t *data, uint32_t len)
{
EmulEvent *event = (EmulEvent *)qemu_malloc(sizeof(EmulEvent) + len);
assert(event);
event->p.data.type = type;
event->p.data.len = len;
memcpy(event->p.data.data, data, len);
emulated_push_event(card, event);
}
static void emulated_push_reader_insert(EmulatedState *card)
{
emulated_push_type(card, EMUL_READER_INSERT);
}
static void emulated_push_reader_remove(EmulatedState *card)
{
emulated_push_type(card, EMUL_READER_REMOVE);
}
static void emulated_push_card_insert(EmulatedState *card,
const uint8_t *atr, uint32_t len)
{
emulated_push_data_type(card, EMUL_CARD_INSERT, atr, len);
}
static void emulated_push_card_remove(EmulatedState *card)
{
emulated_push_type(card, EMUL_CARD_REMOVE);
}
static void emulated_push_response_apdu(EmulatedState *card,
const uint8_t *apdu, uint32_t len)
{
emulated_push_data_type(card, EMUL_RESPONSE_APDU, apdu, len);
}
#define APDU_BUF_SIZE 270
static void *handle_apdu_thread(void* arg)
{
EmulatedState *card = arg;
uint8_t recv_data[APDU_BUF_SIZE];
int recv_len;
VReaderStatus reader_status;
EmulEvent *event;
while (1) {
qemu_mutex_lock(&card->handle_apdu_mutex);
qemu_cond_wait(&card->handle_apdu_cond, &card->handle_apdu_mutex);
qemu_mutex_unlock(&card->handle_apdu_mutex);
if (card->quit_apdu_thread) {
card->quit_apdu_thread = 0; /* debugging */
break;
}
qemu_mutex_lock(&card->vreader_mutex);
while (!QSIMPLEQ_EMPTY(&card->guest_apdu_list)) {
event = QSIMPLEQ_FIRST(&card->guest_apdu_list);
assert((unsigned long)event > 1000);
QSIMPLEQ_REMOVE_HEAD(&card->guest_apdu_list, entry);
if (event->p.data.type != EMUL_GUEST_APDU) {
DPRINTF(card, 1, "unexpected message in handle_apdu_thread\n");
qemu_free(event);
continue;
}
if (card->reader == NULL) {
DPRINTF(card, 1, "reader is NULL\n");
qemu_free(event);
continue;
}
recv_len = sizeof(recv_data);
reader_status = vreader_xfr_bytes(card->reader,
event->p.data.data, event->p.data.len,
recv_data, &recv_len);
DPRINTF(card, 2, "got back apdu of length %d\n", recv_len);
if (reader_status == VREADER_OK) {
emulated_push_response_apdu(card, recv_data, recv_len);
} else {
emulated_push_error(card, reader_status);
}
qemu_free(event);
}
qemu_mutex_unlock(&card->vreader_mutex);
}
qemu_mutex_lock(&card->apdu_thread_quit_mutex);
qemu_cond_signal(&card->apdu_thread_quit_cond);
qemu_mutex_unlock(&card->apdu_thread_quit_mutex);
return NULL;
}
static void *event_thread(void *arg)
{
int atr_len = MAX_ATR_SIZE;
uint8_t atr[MAX_ATR_SIZE];
VEvent *event = NULL;
EmulatedState *card = arg;
while (1) {
const char *reader_name;
event = vevent_wait_next_vevent();
if (event == NULL || event->type == VEVENT_LAST) {
break;
}
if (event->type != VEVENT_READER_INSERT) {
if (card->reader == NULL && event->reader != NULL) {
/* Happens after device_add followed by card remove or insert.
* XXX: create synthetic add_reader events if vcard_emul_init
* already called, which happens if device_del and device_add
* are called */
card->reader = vreader_reference(event->reader);
} else {
if (event->reader != card->reader) {
fprintf(stderr,
"ERROR: wrong reader: quiting event_thread\n");
break;
}
}
}
switch (event->type) {
case VEVENT_READER_INSERT:
/* TODO: take a specific reader. i.e. track which reader
* we are seeing here, check it is the one we want (the first,
* or by a particular name), and ignore if we don't want it.
*/
reader_name = vreader_get_name(event->reader);
if (card->reader != NULL) {
DPRINTF(card, 2, "READER INSERT - replacing %s with %s\n",
vreader_get_name(card->reader), reader_name);
qemu_mutex_lock(&card->vreader_mutex);
vreader_free(card->reader);
qemu_mutex_unlock(&card->vreader_mutex);
emulated_push_reader_remove(card);
}
qemu_mutex_lock(&card->vreader_mutex);
DPRINTF(card, 2, "READER INSERT %s\n", reader_name);
card->reader = vreader_reference(event->reader);
qemu_mutex_unlock(&card->vreader_mutex);
emulated_push_reader_insert(card);
break;
case VEVENT_READER_REMOVE:
DPRINTF(card, 2, " READER REMOVE: %s\n",
vreader_get_name(event->reader));
qemu_mutex_lock(&card->vreader_mutex);
vreader_free(card->reader);
card->reader = NULL;
qemu_mutex_unlock(&card->vreader_mutex);
emulated_push_reader_remove(card);
break;
case VEVENT_CARD_INSERT:
/* get the ATR (intended as a response to a power on from the
* reader */
atr_len = MAX_ATR_SIZE;
vreader_power_on(event->reader, atr, &atr_len);
card->atr_length = (uint8_t)atr_len;
DPRINTF(card, 2, " CARD INSERT\n");
emulated_push_card_insert(card, atr, atr_len);
break;
case VEVENT_CARD_REMOVE:
DPRINTF(card, 2, " CARD REMOVE\n");
emulated_push_card_remove(card);
break;
case VEVENT_LAST: /* quit */
vevent_delete(event);
return NULL;
break;
default:
break;
}
vevent_delete(event);
}
return NULL;
}
static void pipe_read(void *opaque)
{
EmulatedState *card = opaque;
EmulEvent *event, *next;
char dummy;
int len;
do {
len = read(card->pipe[0], &dummy, sizeof(dummy));
} while (len == sizeof(dummy));
qemu_mutex_lock(&card->event_list_mutex);
QSIMPLEQ_FOREACH_SAFE(event, &card->event_list, entry, next) {
DPRINTF(card, 2, "event %s\n", emul_event_to_string(event->p.gen.type));
switch (event->p.gen.type) {
case EMUL_RESPONSE_APDU:
ccid_card_send_apdu_to_guest(&card->base, event->p.data.data,
event->p.data.len);
break;
case EMUL_READER_INSERT:
ccid_card_ccid_attach(&card->base);
break;
case EMUL_READER_REMOVE:
ccid_card_ccid_detach(&card->base);
break;
case EMUL_CARD_INSERT:
assert(event->p.data.len <= MAX_ATR_SIZE);
card->atr_length = event->p.data.len;
memcpy(card->atr, event->p.data.data, card->atr_length);
ccid_card_card_inserted(&card->base);
break;
case EMUL_CARD_REMOVE:
ccid_card_card_removed(&card->base);
break;
case EMUL_ERROR:
ccid_card_card_error(&card->base, event->p.error.code);
break;
default:
DPRINTF(card, 2, "unexpected event\n");
break;
}
qemu_free(event);
}
QSIMPLEQ_INIT(&card->event_list);
qemu_mutex_unlock(&card->event_list_mutex);
}
static int init_pipe_signaling(EmulatedState *card)
{
if (pipe(card->pipe) < 0) {
DPRINTF(card, 2, "pipe creation failed\n");
return -1;
}
fcntl(card->pipe[0], F_SETFL, O_NONBLOCK);
fcntl(card->pipe[1], F_SETFL, O_NONBLOCK);
fcntl(card->pipe[0], F_SETOWN, getpid());
qemu_set_fd_handler(card->pipe[0], pipe_read, NULL, card);
return 0;
}
#define CERTIFICATES_DEFAULT_DB "/etc/pki/nssdb"
#define CERTIFICATES_ARGS_TEMPLATE\
"db=\"%s\" use_hw=no soft=(,Virtual Reader,CAC,,%s,%s,%s)"
static int wrap_vcard_emul_init(VCardEmulOptions *options)
{
static int called;
static int options_was_null;
if (called) {
if ((options == NULL) != options_was_null) {
printf("%s: warning: running emulated with certificates"
" and emulated side by side is not supported\n",
__func__);
return VCARD_EMUL_FAIL;
}
vcard_emul_replay_insertion_events();
return VCARD_EMUL_OK;
}
options_was_null = (options == NULL);
called = 1;
return vcard_emul_init(options);
}
static int emulated_initialize_vcard_from_certificates(EmulatedState *card)
{
char emul_args[200];
VCardEmulOptions *options = NULL;
snprintf(emul_args, sizeof(emul_args) - 1, CERTIFICATES_ARGS_TEMPLATE,
card->db ? card->db : CERTIFICATES_DEFAULT_DB,
card->cert1, card->cert2, card->cert3);
options = vcard_emul_options(emul_args);
if (options == NULL) {
printf("%s: warning: not using certificates due to"
" initialization error\n", __func__);
}
return wrap_vcard_emul_init(options);
}
typedef struct EnumTable {
const char *name;
uint32_t value;
} EnumTable;
EnumTable backend_enum_table[] = {
{BACKEND_NSS_EMULATED_NAME, BACKEND_NSS_EMULATED},
{BACKEND_CERTIFICATES_NAME, BACKEND_CERTIFICATES},
{NULL, 0},
};
static uint32_t parse_enumeration(char *str,
EnumTable *table, uint32_t not_found_value)
{
uint32_t ret = not_found_value;
while (table->name != NULL) {
if (strcmp(table->name, str) == 0) {
ret = table->value;
break;
}
table++;
}
return ret;
}
static int emulated_initfn(CCIDCardState *base)
{
EmulatedState *card = DO_UPCAST(EmulatedState, base, base);
QemuThread thread_id;
VCardEmulError ret;
EnumTable *ptable;
QSIMPLEQ_INIT(&card->event_list);
QSIMPLEQ_INIT(&card->guest_apdu_list);
qemu_mutex_init(&card->event_list_mutex);
qemu_mutex_init(&card->vreader_mutex);
qemu_mutex_init(&card->handle_apdu_mutex);
qemu_cond_init(&card->handle_apdu_cond);
card->reader = NULL;
card->quit_apdu_thread = 0;
if (init_pipe_signaling(card) < 0) {
return -1;
}
card->backend = parse_enumeration(card->backend_str, backend_enum_table, 0);
if (card->backend == 0) {
printf("unknown backend, must be one of:\n");
for (ptable = backend_enum_table; ptable->name != NULL; ++ptable) {
printf("%s\n", ptable->name);
}
return -1;
}
/* TODO: a passthru backened that works on local machine. third card type?*/
if (card->backend == BACKEND_CERTIFICATES) {
if (card->cert1 != NULL && card->cert2 != NULL && card->cert3 != NULL) {
ret = emulated_initialize_vcard_from_certificates(card);
} else {
printf("%s: you must provide all three certs for"
" certificates backend\n", EMULATED_DEV_NAME);
return -1;
}
} else {
if (card->backend != BACKEND_NSS_EMULATED) {
printf("%s: bad backend specified. The options are:\n%s (default),"
" %s.\n", EMULATED_DEV_NAME, BACKEND_NSS_EMULATED_NAME,
BACKEND_CERTIFICATES_NAME);
return -1;
}
if (card->cert1 != NULL || card->cert2 != NULL || card->cert3 != NULL) {
printf("%s: unexpected cert parameters to nss emulated backend\n",
EMULATED_DEV_NAME);
return -1;
}
/* default to mirroring the local hardware readers */
ret = wrap_vcard_emul_init(NULL);
}
if (ret != VCARD_EMUL_OK) {
printf("%s: failed to initialize vcard\n", EMULATED_DEV_NAME);
return -1;
}
qemu_thread_create(&thread_id, event_thread, card);
qemu_thread_create(&thread_id, handle_apdu_thread, card);
return 0;
}
static int emulated_exitfn(CCIDCardState *base)
{
EmulatedState *card = DO_UPCAST(EmulatedState, base, base);
VEvent *vevent = vevent_new(VEVENT_LAST, NULL, NULL);
vevent_queue_vevent(vevent); /* stop vevent thread */
qemu_mutex_lock(&card->apdu_thread_quit_mutex);
card->quit_apdu_thread = 1; /* stop handle_apdu thread */
qemu_cond_signal(&card->handle_apdu_cond);
qemu_cond_wait(&card->apdu_thread_quit_cond,
&card->apdu_thread_quit_mutex);
/* handle_apdu thread stopped, can destroy all of it's mutexes */
qemu_cond_destroy(&card->handle_apdu_cond);
qemu_cond_destroy(&card->apdu_thread_quit_cond);
qemu_mutex_destroy(&card->apdu_thread_quit_mutex);
qemu_mutex_destroy(&card->handle_apdu_mutex);
qemu_mutex_destroy(&card->vreader_mutex);
qemu_mutex_destroy(&card->event_list_mutex);
return 0;
}
static CCIDCardInfo emulated_card_info = {
.qdev.name = EMULATED_DEV_NAME,
.qdev.desc = "emulated smartcard",
.qdev.size = sizeof(EmulatedState),
.initfn = emulated_initfn,
.exitfn = emulated_exitfn,
.get_atr = emulated_get_atr,
.apdu_from_guest = emulated_apdu_from_guest,
.qdev.unplug = qdev_simple_unplug_cb,
.qdev.props = (Property[]) {
DEFINE_PROP_STRING("backend", EmulatedState, backend_str),
DEFINE_PROP_STRING("cert1", EmulatedState, cert1),
DEFINE_PROP_STRING("cert2", EmulatedState, cert2),
DEFINE_PROP_STRING("cert3", EmulatedState, cert3),
DEFINE_PROP_STRING("db", EmulatedState, db),
DEFINE_PROP_UINT8("debug", EmulatedState, debug, 0),
DEFINE_PROP_END_OF_LIST(),
},
};
static void ccid_card_emulated_register_devices(void)
{
ccid_card_qdev_register(&emulated_card_info);
}
device_init(ccid_card_emulated_register_devices)

339
hw/ccid-card-passthru.c Normal file
View File

@ -0,0 +1,339 @@
/*
* CCID Passthru Card Device emulation
*
* Copyright (c) 2011 Red Hat.
* Written by Alon Levy.
*
* This work is licensed under the terms of the GNU GPL, version 2.1 or later.
* See the COPYING file in the top-level directory.
*/
#include "qemu-char.h"
#include "qemu_socket.h"
#include "monitor.h"
#include "hw/ccid.h"
#include "libcacard/vscard_common.h"
#define DPRINTF(card, lvl, fmt, ...) \
do { \
if (lvl <= card->debug) { \
printf("ccid-card-passthru: " fmt , ## __VA_ARGS__); \
} \
} while (0)
#define D_WARN 1
#define D_INFO 2
#define D_MORE_INFO 3
#define D_VERBOSE 4
/* TODO: do we still need this? */
uint8_t DEFAULT_ATR[] = {
/*
* From some example somewhere
* 0x3B, 0xB0, 0x18, 0x00, 0xD1, 0x81, 0x05, 0xB1, 0x40, 0x38, 0x1F, 0x03, 0x28
*/
/* From an Athena smart card */
0x3B, 0xD5, 0x18, 0xFF, 0x80, 0x91, 0xFE, 0x1F, 0xC3, 0x80, 0x73, 0xC8, 0x21,
0x13, 0x08
};
#define PASSTHRU_DEV_NAME "ccid-card-passthru"
#define VSCARD_IN_SIZE 65536
/* maximum size of ATR - from 7816-3 */
#define MAX_ATR_SIZE 40
typedef struct PassthruState PassthruState;
struct PassthruState {
CCIDCardState base;
CharDriverState *cs;
uint8_t vscard_in_data[VSCARD_IN_SIZE];
uint32_t vscard_in_pos;
uint32_t vscard_in_hdr;
uint8_t atr[MAX_ATR_SIZE];
uint8_t atr_length;
uint8_t debug;
};
/*
* VSCard protocol over chardev
* This code should not depend on the card type.
*/
static void ccid_card_vscard_send_msg(PassthruState *s,
VSCMsgType type, uint32_t reader_id,
const uint8_t *payload, uint32_t length)
{
VSCMsgHeader scr_msg_header;
scr_msg_header.type = htonl(type);
scr_msg_header.reader_id = htonl(reader_id);
scr_msg_header.length = htonl(length);
qemu_chr_write(s->cs, (uint8_t *)&scr_msg_header, sizeof(VSCMsgHeader));
qemu_chr_write(s->cs, payload, length);
}
static void ccid_card_vscard_send_apdu(PassthruState *s,
const uint8_t *apdu, uint32_t length)
{
ccid_card_vscard_send_msg(
s, VSC_APDU, VSCARD_MINIMAL_READER_ID, apdu, length);
}
static void ccid_card_vscard_send_error(PassthruState *s,
uint32_t reader_id, VSCErrorCode code)
{
VSCMsgError msg = {.code = htonl(code)};
ccid_card_vscard_send_msg(
s, VSC_Error, reader_id, (uint8_t *)&msg, sizeof(msg));
}
static void ccid_card_vscard_send_init(PassthruState *s)
{
VSCMsgInit msg = {
.version = htonl(VSCARD_VERSION),
.magic = VSCARD_MAGIC,
.capabilities = {0}
};
ccid_card_vscard_send_msg(s, VSC_Init, VSCARD_UNDEFINED_READER_ID,
(uint8_t *)&msg, sizeof(msg));
}
static int ccid_card_vscard_can_read(void *opaque)
{
PassthruState *card = opaque;
return VSCARD_IN_SIZE >= card->vscard_in_pos ?
VSCARD_IN_SIZE - card->vscard_in_pos : 0;
}
static void ccid_card_vscard_handle_init(
PassthruState *card, VSCMsgHeader *hdr, VSCMsgInit *init)
{
uint32_t *capabilities;
int num_capabilities;
int i;
capabilities = init->capabilities;
num_capabilities =
1 + ((hdr->length - sizeof(VSCMsgInit)) / sizeof(uint32_t));
init->version = ntohl(init->version);
for (i = 0 ; i < num_capabilities; ++i) {
capabilities[i] = ntohl(capabilities[i]);
}
if (init->magic != VSCARD_MAGIC) {
error_report("wrong magic");
/* we can't disconnect the chardev */
}
if (init->version != VSCARD_VERSION) {
DPRINTF(card, D_WARN,
"got version %d, have %d", init->version, VSCARD_VERSION);
}
/* future handling of capabilities, none exist atm */
ccid_card_vscard_send_init(card);
}
static void ccid_card_vscard_handle_message(PassthruState *card,
VSCMsgHeader *scr_msg_header)
{
uint8_t *data = (uint8_t *)&scr_msg_header[1];
switch (scr_msg_header->type) {
case VSC_ATR:
DPRINTF(card, D_INFO, "VSC_ATR %d\n", scr_msg_header->length);
if (scr_msg_header->length > MAX_ATR_SIZE) {
error_report("ATR size exceeds spec, ignoring");
ccid_card_vscard_send_error(card, scr_msg_header->reader_id,
VSC_GENERAL_ERROR);
}
memcpy(card->atr, data, scr_msg_header->length);
card->atr_length = scr_msg_header->length;
ccid_card_card_inserted(&card->base);
ccid_card_vscard_send_error(card, scr_msg_header->reader_id,
VSC_SUCCESS);
break;
case VSC_APDU:
ccid_card_send_apdu_to_guest(
&card->base, data, scr_msg_header->length);
break;
case VSC_CardRemove:
DPRINTF(card, D_INFO, "VSC_CardRemove\n");
ccid_card_card_removed(&card->base);
ccid_card_vscard_send_error(card,
scr_msg_header->reader_id, VSC_SUCCESS);
break;
case VSC_Init:
ccid_card_vscard_handle_init(
card, scr_msg_header, (VSCMsgInit *)data);
break;
case VSC_Error:
ccid_card_card_error(&card->base, *(uint32_t *)data);
break;
case VSC_ReaderAdd:
if (ccid_card_ccid_attach(&card->base) < 0) {
ccid_card_vscard_send_error(card, VSCARD_UNDEFINED_READER_ID,
VSC_CANNOT_ADD_MORE_READERS);
} else {
ccid_card_vscard_send_error(card, VSCARD_MINIMAL_READER_ID,
VSC_SUCCESS);
}
break;
case VSC_ReaderRemove:
ccid_card_ccid_detach(&card->base);
ccid_card_vscard_send_error(card,
scr_msg_header->reader_id, VSC_SUCCESS);
break;
default:
printf("usb-ccid: chardev: unexpected message of type %X\n",
scr_msg_header->type);
ccid_card_vscard_send_error(card, scr_msg_header->reader_id,
VSC_GENERAL_ERROR);
}
}
static void ccid_card_vscard_drop_connection(PassthruState *card)
{
qemu_chr_close(card->cs);
card->vscard_in_pos = card->vscard_in_hdr = 0;
}
static void ccid_card_vscard_read(void *opaque, const uint8_t *buf, int size)
{
PassthruState *card = opaque;
VSCMsgHeader *hdr;
if (card->vscard_in_pos + size > VSCARD_IN_SIZE) {
error_report(
"no room for data: pos %d + size %d > %d. dropping connection.",
card->vscard_in_pos, size, VSCARD_IN_SIZE);
ccid_card_vscard_drop_connection(card);
return;
}
assert(card->vscard_in_pos < VSCARD_IN_SIZE);
assert(card->vscard_in_hdr < VSCARD_IN_SIZE);
memcpy(card->vscard_in_data + card->vscard_in_pos, buf, size);
card->vscard_in_pos += size;
hdr = (VSCMsgHeader *)(card->vscard_in_data + card->vscard_in_hdr);
while ((card->vscard_in_pos - card->vscard_in_hdr >= sizeof(VSCMsgHeader))
&&(card->vscard_in_pos - card->vscard_in_hdr >=
sizeof(VSCMsgHeader) + ntohl(hdr->length))) {
hdr->reader_id = ntohl(hdr->reader_id);
hdr->length = ntohl(hdr->length);
hdr->type = ntohl(hdr->type);
ccid_card_vscard_handle_message(card, hdr);
card->vscard_in_hdr += hdr->length + sizeof(VSCMsgHeader);
hdr = (VSCMsgHeader *)(card->vscard_in_data + card->vscard_in_hdr);
}
if (card->vscard_in_hdr == card->vscard_in_pos) {
card->vscard_in_pos = card->vscard_in_hdr = 0;
}
}
static void ccid_card_vscard_event(void *opaque, int event)
{
PassthruState *card = opaque;
switch (event) {
case CHR_EVENT_BREAK:
card->vscard_in_pos = card->vscard_in_hdr = 0;
break;
case CHR_EVENT_FOCUS:
break;
case CHR_EVENT_OPENED:
DPRINTF(card, D_INFO, "%s: CHR_EVENT_OPENED\n", __func__);
break;
}
}
/* End VSCard handling */
static void passthru_apdu_from_guest(
CCIDCardState *base, const uint8_t *apdu, uint32_t len)
{
PassthruState *card = DO_UPCAST(PassthruState, base, base);
if (!card->cs) {
printf("ccid-passthru: no chardev, discarding apdu length %d\n", len);
return;
}
ccid_card_vscard_send_apdu(card, apdu, len);
}
static const uint8_t *passthru_get_atr(CCIDCardState *base, uint32_t *len)
{
PassthruState *card = DO_UPCAST(PassthruState, base, base);
*len = card->atr_length;
return card->atr;
}
static int passthru_initfn(CCIDCardState *base)
{
PassthruState *card = DO_UPCAST(PassthruState, base, base);
card->vscard_in_pos = 0;
card->vscard_in_hdr = 0;
if (card->cs) {
DPRINTF(card, D_INFO, "initing chardev\n");
qemu_chr_add_handlers(card->cs,
ccid_card_vscard_can_read,
ccid_card_vscard_read,
ccid_card_vscard_event, card);
ccid_card_vscard_send_init(card);
} else {
error_report("missing chardev");
return -1;
}
assert(sizeof(DEFAULT_ATR) <= MAX_ATR_SIZE);
memcpy(card->atr, DEFAULT_ATR, sizeof(DEFAULT_ATR));
card->atr_length = sizeof(DEFAULT_ATR);
return 0;
}
static int passthru_exitfn(CCIDCardState *base)
{
return 0;
}
static VMStateDescription passthru_vmstate = {
.name = PASSTHRU_DEV_NAME,
.version_id = 1,
.minimum_version_id = 1,
.fields = (VMStateField[]) {
VMSTATE_BUFFER(vscard_in_data, PassthruState),
VMSTATE_UINT32(vscard_in_pos, PassthruState),
VMSTATE_UINT32(vscard_in_hdr, PassthruState),
VMSTATE_BUFFER(atr, PassthruState),
VMSTATE_UINT8(atr_length, PassthruState),
VMSTATE_END_OF_LIST()
}
};
static CCIDCardInfo passthru_card_info = {
.qdev.name = PASSTHRU_DEV_NAME,
.qdev.desc = "passthrough smartcard",
.qdev.size = sizeof(PassthruState),
.qdev.vmsd = &passthru_vmstate,
.initfn = passthru_initfn,
.exitfn = passthru_exitfn,
.get_atr = passthru_get_atr,
.apdu_from_guest = passthru_apdu_from_guest,
.qdev.props = (Property[]) {
DEFINE_PROP_CHR("chardev", PassthruState, cs),
DEFINE_PROP_UINT8("debug", PassthruState, debug, 0),
DEFINE_PROP_END_OF_LIST(),
},
};
static void ccid_card_passthru_register_devices(void)
{
ccid_card_qdev_register(&passthru_card_info);
}
device_init(ccid_card_passthru_register_devices)

59
hw/ccid.h Normal file
View File

@ -0,0 +1,59 @@
/*
* CCID Passthru Card Device emulation
*
* Copyright (c) 2011 Red Hat.
* Written by Alon Levy.
*
* This code is licenced under the GNU LGPL, version 2 or later.
*/
#ifndef CCID_H
#define CCID_H
#include "qdev.h"
typedef struct CCIDCardState CCIDCardState;
typedef struct CCIDCardInfo CCIDCardInfo;
/*
* state of the CCID Card device (i.e. hw/ccid-card-*.c)
*/
struct CCIDCardState {
DeviceState qdev;
uint32_t slot; /* For future use with multiple slot reader. */
};
/*
* callbacks to be used by the CCID device (hw/usb-ccid.c) to call
* into the smartcard device (hw/ccid-card-*.c)
*/
struct CCIDCardInfo {
DeviceInfo qdev;
void (*print)(Monitor *mon, CCIDCardState *card, int indent);
const uint8_t *(*get_atr)(CCIDCardState *card, uint32_t *len);
void (*apdu_from_guest)(CCIDCardState *card,
const uint8_t *apdu,
uint32_t len);
int (*exitfn)(CCIDCardState *card);
int (*initfn)(CCIDCardState *card);
};
/*
* API for smartcard calling the CCID device (used by hw/ccid-card-*.c)
*/
void ccid_card_send_apdu_to_guest(CCIDCardState *card,
uint8_t *apdu,
uint32_t len);
void ccid_card_card_removed(CCIDCardState *card);
void ccid_card_card_inserted(CCIDCardState *card);
void ccid_card_card_error(CCIDCardState *card, uint64_t error);
void ccid_card_qdev_register(CCIDCardInfo *card);
/*
* support guest visible insertion/removal of ccid devices based on actual
* devices connected/removed. Called by card implementation (passthru, local)
*/
int ccid_card_ccid_attach(CCIDCardState *card);
void ccid_card_ccid_detach(CCIDCardState *card);
#endif /* CCID_H */

69
hw/collie.c Normal file
View File

@ -0,0 +1,69 @@
/*
* SA-1110-based Sharp Zaurus SL-5500 platform.
*
* Copyright (C) 2011 Dmitry Eremin-Solenikov
*
* This code is licensed under GNU GPL v2.
*/
#include "hw.h"
#include "sysbus.h"
#include "boards.h"
#include "devices.h"
#include "strongarm.h"
#include "arm-misc.h"
#include "flash.h"
#include "blockdev.h"
static struct arm_boot_info collie_binfo = {
.loader_start = SA_SDCS0,
.ram_size = 0x20000000,
};
static void collie_init(ram_addr_t ram_size,
const char *boot_device,
const char *kernel_filename, const char *kernel_cmdline,
const char *initrd_filename, const char *cpu_model)
{
StrongARMState *s;
DriveInfo *dinfo;
ram_addr_t phys_flash;
if (!cpu_model) {
cpu_model = "sa1110";
}
s = sa1110_init(collie_binfo.ram_size, cpu_model);
phys_flash = qemu_ram_alloc(NULL, "collie.fl1", 0x02000000);
dinfo = drive_get(IF_PFLASH, 0, 0);
pflash_cfi01_register(SA_CS0, phys_flash,
dinfo ? dinfo->bdrv : NULL, (64 * 1024),
512, 4, 0x00, 0x00, 0x00, 0x00, 0);
phys_flash = qemu_ram_alloc(NULL, "collie.fl2", 0x02000000);
dinfo = drive_get(IF_PFLASH, 0, 1);
pflash_cfi01_register(SA_CS1, phys_flash,
dinfo ? dinfo->bdrv : NULL, (64 * 1024),
512, 4, 0x00, 0x00, 0x00, 0x00, 0);
sysbus_create_simple("scoop", 0x40800000, NULL);
collie_binfo.kernel_filename = kernel_filename;
collie_binfo.kernel_cmdline = kernel_cmdline;
collie_binfo.initrd_filename = initrd_filename;
collie_binfo.board_id = 0x208;
arm_load_kernel(s->env, &collie_binfo);
}
static QEMUMachine collie_machine = {
.name = "collie",
.desc = "Collie PDA (SA-1110)",
.init = collie_init,
};
static void collie_machine_init(void)
{
qemu_register_machine(&collie_machine);
}
machine_init(collie_machine_init)

View File

@ -23,7 +23,6 @@
*/
#include "hw.h"
#include "sysemu.h"
#include "loader.h"
#include "elf.h"
#include "cris-boot.h"

118
hw/cuda.c
View File

@ -644,80 +644,56 @@ static CPUReadMemoryFunc * const cuda_read[] = {
&cuda_readl,
};
static void cuda_save_timer(QEMUFile *f, CUDATimer *s)
static bool cuda_timer_exist(void *opaque, int version_id)
{
qemu_put_be16s(f, &s->latch);
qemu_put_be16s(f, &s->counter_value);
qemu_put_sbe64s(f, &s->load_time);
qemu_put_sbe64s(f, &s->next_irq_time);
if (s->timer)
qemu_put_timer(f, s->timer);
CUDATimer *s = opaque;
return s->timer != NULL;
}
static void cuda_save(QEMUFile *f, void *opaque)
{
CUDAState *s = (CUDAState *)opaque;
static const VMStateDescription vmstate_cuda_timer = {
.name = "cuda_timer",
.version_id = 0,
.minimum_version_id = 0,
.minimum_version_id_old = 0,
.fields = (VMStateField[]) {
VMSTATE_UINT16(latch, CUDATimer),
VMSTATE_UINT16(counter_value, CUDATimer),
VMSTATE_INT64(load_time, CUDATimer),
VMSTATE_INT64(next_irq_time, CUDATimer),
VMSTATE_TIMER_TEST(timer, CUDATimer, cuda_timer_exist),
VMSTATE_END_OF_LIST()
}
};
qemu_put_ubyte(f, s->b);
qemu_put_ubyte(f, s->a);
qemu_put_ubyte(f, s->dirb);
qemu_put_ubyte(f, s->dira);
qemu_put_ubyte(f, s->sr);
qemu_put_ubyte(f, s->acr);
qemu_put_ubyte(f, s->pcr);
qemu_put_ubyte(f, s->ifr);
qemu_put_ubyte(f, s->ier);
qemu_put_ubyte(f, s->anh);
qemu_put_sbe32s(f, &s->data_in_size);
qemu_put_sbe32s(f, &s->data_in_index);
qemu_put_sbe32s(f, &s->data_out_index);
qemu_put_ubyte(f, s->autopoll);
qemu_put_buffer(f, s->data_in, sizeof(s->data_in));
qemu_put_buffer(f, s->data_out, sizeof(s->data_out));
qemu_put_be32s(f, &s->tick_offset);
cuda_save_timer(f, &s->timers[0]);
cuda_save_timer(f, &s->timers[1]);
}
static void cuda_load_timer(QEMUFile *f, CUDATimer *s)
{
qemu_get_be16s(f, &s->latch);
qemu_get_be16s(f, &s->counter_value);
qemu_get_sbe64s(f, &s->load_time);
qemu_get_sbe64s(f, &s->next_irq_time);
if (s->timer)
qemu_get_timer(f, s->timer);
}
static int cuda_load(QEMUFile *f, void *opaque, int version_id)
{
CUDAState *s = (CUDAState *)opaque;
if (version_id != 1)
return -EINVAL;
s->b = qemu_get_ubyte(f);
s->a = qemu_get_ubyte(f);
s->dirb = qemu_get_ubyte(f);
s->dira = qemu_get_ubyte(f);
s->sr = qemu_get_ubyte(f);
s->acr = qemu_get_ubyte(f);
s->pcr = qemu_get_ubyte(f);
s->ifr = qemu_get_ubyte(f);
s->ier = qemu_get_ubyte(f);
s->anh = qemu_get_ubyte(f);
qemu_get_sbe32s(f, &s->data_in_size);
qemu_get_sbe32s(f, &s->data_in_index);
qemu_get_sbe32s(f, &s->data_out_index);
s->autopoll = qemu_get_ubyte(f);
qemu_get_buffer(f, s->data_in, sizeof(s->data_in));
qemu_get_buffer(f, s->data_out, sizeof(s->data_out));
qemu_get_be32s(f, &s->tick_offset);
cuda_load_timer(f, &s->timers[0]);
cuda_load_timer(f, &s->timers[1]);
return 0;
}
static const VMStateDescription vmstate_cuda = {
.name = "cuda",
.version_id = 1,
.minimum_version_id = 1,
.minimum_version_id_old = 1,
.fields = (VMStateField[]) {
VMSTATE_UINT8(a, CUDAState),
VMSTATE_UINT8(b, CUDAState),
VMSTATE_UINT8(dira, CUDAState),
VMSTATE_UINT8(dirb, CUDAState),
VMSTATE_UINT8(sr, CUDAState),
VMSTATE_UINT8(acr, CUDAState),
VMSTATE_UINT8(pcr, CUDAState),
VMSTATE_UINT8(ifr, CUDAState),
VMSTATE_UINT8(ier, CUDAState),
VMSTATE_UINT8(anh, CUDAState),
VMSTATE_INT32(data_in_size, CUDAState),
VMSTATE_INT32(data_in_index, CUDAState),
VMSTATE_INT32(data_out_index, CUDAState),
VMSTATE_UINT8(autopoll, CUDAState),
VMSTATE_BUFFER(data_in, CUDAState),
VMSTATE_BUFFER(data_out, CUDAState),
VMSTATE_UINT32(tick_offset, CUDAState),
VMSTATE_STRUCT_ARRAY(timers, CUDAState, 2, 1,
vmstate_cuda_timer, CUDATimer),
VMSTATE_END_OF_LIST()
}
};
static void cuda_reset(void *opaque)
{
@ -764,6 +740,6 @@ void cuda_init (int *cuda_mem_index, qemu_irq irq)
s->adb_poll_timer = qemu_new_timer_ns(vm_clock, cuda_adb_poll, s);
*cuda_mem_index = cpu_register_io_memory(cuda_read, cuda_write, s,
DEVICE_NATIVE_ENDIAN);
register_savevm(NULL, "cuda", -1, 1, cuda_save, cuda_load, s);
vmstate_register(NULL, -1, &vmstate_cuda, s);
qemu_register_reset(cuda_reset, s);
}

View File

@ -7,7 +7,6 @@
*/
#include "hw.h"
#include "sysemu.h"
#include "boards.h"
#include "loader.h"
#include "elf.h"

View File

@ -517,6 +517,14 @@ txdesc_writeback(target_phys_addr_t base, struct e1000_tx_desc *dp)
return E1000_ICR_TXDW;
}
static uint64_t tx_desc_base(E1000State *s)
{
uint64_t bah = s->mac_reg[TDBAH];
uint64_t bal = s->mac_reg[TDBAL] & ~0xf;
return (bah << 32) + bal;
}
static void
start_xmit(E1000State *s)
{
@ -530,7 +538,7 @@ start_xmit(E1000State *s)
}
while (s->mac_reg[TDH] != s->mac_reg[TDT]) {
base = ((uint64_t)s->mac_reg[TDBAH] << 32) + s->mac_reg[TDBAL] +
base = tx_desc_base(s) +
sizeof(struct e1000_tx_desc) * s->mac_reg[TDH];
cpu_physical_memory_read(base, (void *)&desc, sizeof(desc));
@ -651,6 +659,14 @@ e1000_can_receive(VLANClientState *nc)
return (s->mac_reg[RCTL] & E1000_RCTL_EN) && e1000_has_rxbufs(s, 1);
}
static uint64_t rx_desc_base(E1000State *s)
{
uint64_t bah = s->mac_reg[RDBAH];
uint64_t bal = s->mac_reg[RDBAL] & ~0xf;
return (bah << 32) + bal;
}
static ssize_t
e1000_receive(VLANClientState *nc, const uint8_t *buf, size_t size)
{
@ -700,8 +716,7 @@ e1000_receive(VLANClientState *nc, const uint8_t *buf, size_t size)
if (desc_size > s->rxbuf_size) {
desc_size = s->rxbuf_size;
}
base = ((uint64_t)s->mac_reg[RDBAH] << 32) + s->mac_reg[RDBAL] +
sizeof(desc) * s->mac_reg[RDH];
base = rx_desc_base(s) + sizeof(desc) * s->mac_reg[RDH];
cpu_physical_memory_read(base, (void *)&desc, sizeof(desc));
desc.special = vlan_special;
desc.status |= (vlan_status | E1000_RXD_STAT_DD);
@ -1205,7 +1220,7 @@ static PCIDeviceInfo e1000_info = {
.qdev.vmsd = &vmstate_e1000,
.init = pci_e1000_init,
.exit = pci_e1000_uninit,
.romfile = "pxe-e1000.bin",
.romfile = "pxe-e1000.rom",
.qdev.props = (Property[]) {
DEFINE_NIC_PROPERTIES(E1000State, conf),
DEFINE_PROP_END_OF_LIST(),

View File

@ -2174,7 +2174,7 @@ static void eepro100_register_devices(void)
PCIDeviceInfo *pci_dev = &e100_devices[i].pci;
/* We use the same rom file for all device ids.
QEMU fixes the device id during rom load. */
pci_dev->romfile = "gpxe-eepro100-80861209.rom";
pci_dev->romfile = "pxe-eepro100.rom";
pci_dev->init = e100_nic_init;
pci_dev->exit = pci_nic_uninit;
pci_dev->qdev.props = e100_properties;

View File

@ -53,18 +53,21 @@ static CPUWriteMemoryFunc * const empty_slot_write[3] = {
void empty_slot_init(target_phys_addr_t addr, uint64_t slot_size)
{
DeviceState *dev;
SysBusDevice *s;
EmptySlot *e;
if (slot_size > 0) {
/* Only empty slots larger than 0 byte need handling. */
DeviceState *dev;
SysBusDevice *s;
EmptySlot *e;
dev = qdev_create(NULL, "empty_slot");
s = sysbus_from_qdev(dev);
e = FROM_SYSBUS(EmptySlot, s);
e->size = slot_size;
dev = qdev_create(NULL, "empty_slot");
s = sysbus_from_qdev(dev);
e = FROM_SYSBUS(EmptySlot, s);
e->size = slot_size;
qdev_init_nofail(dev);
qdev_init_nofail(dev);
sysbus_mmio_map(s, 0, addr);
sysbus_mmio_map(s, 0, addr);
}
}
static int empty_slot_init1(SysBusDevice *dev)

View File

@ -24,7 +24,6 @@
#include "sysbus.h"
#include "boards.h"
#include "sysemu.h"
#include "net.h"
#include "flash.h"
#include "etraxfs.h"

View File

@ -36,6 +36,7 @@
#include "qdev-addr.h"
#include "blockdev.h"
#include "sysemu.h"
#include "block_int.h"
/********************************************************/
/* debug Floppy devices */
@ -82,6 +83,7 @@ typedef struct FDrive {
uint8_t max_track; /* Nb of tracks */
uint16_t bps; /* Bytes per sector */
uint8_t ro; /* Is read-only */
uint8_t media_changed; /* Is media changed */
} FDrive;
static void fd_init(FDrive *drv)
@ -533,16 +535,63 @@ static CPUWriteMemoryFunc * const fdctrl_mem_write_strict[3] = {
NULL,
};
static void fdrive_media_changed_pre_save(void *opaque)
{
FDrive *drive = opaque;
drive->media_changed = drive->bs->media_changed;
}
static int fdrive_media_changed_post_load(void *opaque, int version_id)
{
FDrive *drive = opaque;
if (drive->bs != NULL) {
drive->bs->media_changed = drive->media_changed;
}
/* User ejected the floppy when drive->bs == NULL */
return 0;
}
static bool fdrive_media_changed_needed(void *opaque)
{
FDrive *drive = opaque;
return (drive->bs != NULL && drive->bs->media_changed != 1);
}
static const VMStateDescription vmstate_fdrive_media_changed = {
.name = "fdrive/media_changed",
.version_id = 1,
.minimum_version_id = 1,
.minimum_version_id_old = 1,
.pre_save = fdrive_media_changed_pre_save,
.post_load = fdrive_media_changed_post_load,
.fields = (VMStateField[]) {
VMSTATE_UINT8(media_changed, FDrive),
VMSTATE_END_OF_LIST()
}
};
static const VMStateDescription vmstate_fdrive = {
.name = "fdrive",
.version_id = 1,
.minimum_version_id = 1,
.minimum_version_id_old = 1,
.fields = (VMStateField []) {
.fields = (VMStateField[]) {
VMSTATE_UINT8(head, FDrive),
VMSTATE_UINT8(track, FDrive),
VMSTATE_UINT8(sect, FDrive),
VMSTATE_END_OF_LIST()
},
.subsections = (VMStateSubsection[]) {
{
.vmsd = &vmstate_fdrive_media_changed,
.needed = &fdrive_media_changed_needed,
} , {
/* empty */
}
}
};

View File

@ -21,8 +21,8 @@ pflash_t *pflash_cfi02_register(target_phys_addr_t base, ram_addr_t off,
typedef struct NANDFlashState NANDFlashState;
NANDFlashState *nand_init(int manf_id, int chip_id);
void nand_done(NANDFlashState *s);
void nand_setpins(NANDFlashState *s,
int cle, int ale, int ce, int wp, int gnd);
void nand_setpins(NANDFlashState *s, uint8_t cle, uint8_t ale,
uint8_t ce, uint8_t wp, uint8_t gnd);
void nand_getpins(NANDFlashState *s, int *rb);
void nand_setio(NANDFlashState *s, uint8_t value);
uint8_t nand_getio(NANDFlashState *s);

View File

@ -133,7 +133,7 @@ grlib_apbuart_writel(void *opaque, target_phys_addr_t addr, uint32_t value)
break;
}
trace_grlib_apbuart_unknown_register("write", addr);
trace_grlib_apbuart_writel_unknown(addr, value);
}
static CPUReadMemoryFunc * const grlib_apbuart_read[] = {

View File

@ -165,15 +165,15 @@ static uint32_t grlib_gptimer_readl(void *opaque, target_phys_addr_t addr)
/* Unit registers */
switch (addr) {
case SCALER_OFFSET:
trace_grlib_gptimer_readl(-1, "scaler:", unit->scaler);
trace_grlib_gptimer_readl(-1, addr, unit->scaler);
return unit->scaler;
case SCALER_RELOAD_OFFSET:
trace_grlib_gptimer_readl(-1, "reload:", unit->reload);
trace_grlib_gptimer_readl(-1, addr, unit->reload);
return unit->reload;
case CONFIG_OFFSET:
trace_grlib_gptimer_readl(-1, "config:", unit->config);
trace_grlib_gptimer_readl(-1, addr, unit->config);
return unit->config;
default:
@ -189,17 +189,16 @@ static uint32_t grlib_gptimer_readl(void *opaque, target_phys_addr_t addr)
switch (timer_addr) {
case COUNTER_OFFSET:
value = ptimer_get_count(unit->timers[id].ptimer);
trace_grlib_gptimer_readl(id, "counter value:", value);
trace_grlib_gptimer_readl(id, addr, value);
return value;
case COUNTER_RELOAD_OFFSET:
value = unit->timers[id].reload;
trace_grlib_gptimer_readl(id, "reload value:", value);
trace_grlib_gptimer_readl(id, addr, value);
return value;
case CONFIG_OFFSET:
trace_grlib_gptimer_readl(id, "scaler value:",
unit->timers[id].config);
trace_grlib_gptimer_readl(id, addr, unit->timers[id].config);
return unit->timers[id].config;
default:
@ -208,7 +207,7 @@ static uint32_t grlib_gptimer_readl(void *opaque, target_phys_addr_t addr)
}
trace_grlib_gptimer_unknown_register("read", addr);
trace_grlib_gptimer_readl(-1, addr, 0);
return 0;
}
@ -226,19 +225,19 @@ grlib_gptimer_writel(void *opaque, target_phys_addr_t addr, uint32_t value)
case SCALER_OFFSET:
value &= 0xFFFF; /* clean up the value */
unit->scaler = value;
trace_grlib_gptimer_writel(-1, "scaler:", unit->scaler);
trace_grlib_gptimer_writel(-1, addr, unit->scaler);
return;
case SCALER_RELOAD_OFFSET:
value &= 0xFFFF; /* clean up the value */
unit->reload = value;
trace_grlib_gptimer_writel(-1, "reload:", unit->reload);
trace_grlib_gptimer_writel(-1, addr, unit->reload);
grlib_gptimer_set_scaler(unit, value);
return;
case CONFIG_OFFSET:
/* Read Only (disable timer freeze not supported) */
trace_grlib_gptimer_writel(-1, "config (Read Only):", 0);
trace_grlib_gptimer_writel(-1, addr, 0);
return;
default:
@ -253,18 +252,18 @@ grlib_gptimer_writel(void *opaque, target_phys_addr_t addr, uint32_t value)
/* GPTimer registers */
switch (timer_addr) {
case COUNTER_OFFSET:
trace_grlib_gptimer_writel(id, "counter:", value);
trace_grlib_gptimer_writel(id, addr, value);
unit->timers[id].counter = value;
grlib_gptimer_enable(&unit->timers[id]);
return;
case COUNTER_RELOAD_OFFSET:
trace_grlib_gptimer_writel(id, "reload:", value);
trace_grlib_gptimer_writel(id, addr, value);
unit->timers[id].reload = value;
return;
case CONFIG_OFFSET:
trace_grlib_gptimer_writel(id, "config:", value);
trace_grlib_gptimer_writel(id, addr, value);
if (value & GPTIMER_INT_PENDING) {
/* clear pending bit */
@ -297,7 +296,7 @@ grlib_gptimer_writel(void *opaque, target_phys_addr_t addr, uint32_t value)
}
trace_grlib_gptimer_unknown_register("write", addr);
trace_grlib_gptimer_writel(-1, addr, value);
}
static CPUReadMemoryFunc * const grlib_gptimer_read[] = {

View File

@ -220,7 +220,7 @@ static uint32_t grlib_irqmp_readl(void *opaque, target_phys_addr_t addr)
return state->extended[cpu];
}
trace_grlib_irqmp_unknown_register("read", addr);
trace_grlib_irqmp_readl_unknown(addr);
return 0;
}
@ -308,7 +308,7 @@ grlib_irqmp_writel(void *opaque, target_phys_addr_t addr, uint32_t value)
return;
}
trace_grlib_irqmp_unknown_register("write", addr);
trace_grlib_irqmp_writel_unknown(addr, value);
}
static CPUReadMemoryFunc * const grlib_irqmp_read[] = {

View File

@ -35,7 +35,6 @@
#include "pxa.h"
#include "net.h"
#include "flash.h"
#include "sysemu.h"
#include "devices.h"
#include "boards.h"
#include "blockdev.h"

View File

@ -159,42 +159,31 @@ static void heathrow_pic_set_irq(void *opaque, int num, int level)
heathrow_pic_update(s);
}
static void heathrow_pic_save_one(QEMUFile *f, HeathrowPIC *s)
{
qemu_put_be32s(f, &s->events);
qemu_put_be32s(f, &s->mask);
qemu_put_be32s(f, &s->levels);
qemu_put_be32s(f, &s->level_triggered);
}
static const VMStateDescription vmstate_heathrow_pic_one = {
.name = "heathrow_pic_one",
.version_id = 0,
.minimum_version_id = 0,
.minimum_version_id_old = 0,
.fields = (VMStateField[]) {
VMSTATE_UINT32(events, HeathrowPIC),
VMSTATE_UINT32(mask, HeathrowPIC),
VMSTATE_UINT32(levels, HeathrowPIC),
VMSTATE_UINT32(level_triggered, HeathrowPIC),
VMSTATE_END_OF_LIST()
}
};
static void heathrow_pic_save(QEMUFile *f, void *opaque)
{
HeathrowPICS *s = (HeathrowPICS *)opaque;
heathrow_pic_save_one(f, &s->pics[0]);
heathrow_pic_save_one(f, &s->pics[1]);
}
static void heathrow_pic_load_one(QEMUFile *f, HeathrowPIC *s)
{
qemu_get_be32s(f, &s->events);
qemu_get_be32s(f, &s->mask);
qemu_get_be32s(f, &s->levels);
qemu_get_be32s(f, &s->level_triggered);
}
static int heathrow_pic_load(QEMUFile *f, void *opaque, int version_id)
{
HeathrowPICS *s = (HeathrowPICS *)opaque;
if (version_id != 1)
return -EINVAL;
heathrow_pic_load_one(f, &s->pics[0]);
heathrow_pic_load_one(f, &s->pics[1]);
return 0;
}
static const VMStateDescription vmstate_heathrow_pic = {
.name = "heathrow_pic",
.version_id = 1,
.minimum_version_id = 1,
.minimum_version_id_old = 1,
.fields = (VMStateField[]) {
VMSTATE_STRUCT_ARRAY(pics, HeathrowPICS, 2, 1,
vmstate_heathrow_pic_one, HeathrowPIC),
VMSTATE_END_OF_LIST()
}
};
static void heathrow_pic_reset_one(HeathrowPIC *s)
{
@ -223,8 +212,7 @@ qemu_irq *heathrow_pic_init(int *pmem_index,
*pmem_index = cpu_register_io_memory(pic_read, pic_write, s,
DEVICE_LITTLE_ENDIAN);
register_savevm(NULL, "heathrow_pic", -1, 1, heathrow_pic_save,
heathrow_pic_load, s);
vmstate_register(NULL, -1, &vmstate_heathrow_pic, s);
qemu_register_reset(heathrow_pic_reset, s);
return qemu_allocate_irqs(heathrow_pic_set_irq, s, 64);
}

17
hw/hw.h
View File

@ -689,6 +689,17 @@ extern const VMStateDescription vmstate_usb_device;
.offset = vmstate_offset_macaddr(_state, _field), \
}
extern const VMStateDescription vmstate_ptimer;
#define VMSTATE_PTIMER(_field, _state) { \
.name = (stringify(_field)), \
.version_id = (1), \
.vmsd = &vmstate_ptimer, \
.size = sizeof(ptimer_state *), \
.flags = VMS_STRUCT|VMS_POINTER, \
.offset = vmstate_offset_pointer(_state, _field, ptimer_state), \
}
/* _f : field name
_f_n : num of elements field_name
_n : num of elements
@ -784,12 +795,6 @@ extern const VMStateDescription vmstate_usb_device;
#define VMSTATE_TIMER_ARRAY(_f, _s, _n) \
VMSTATE_ARRAY_OF_POINTER(_f, _s, _n, 0, vmstate_info_timer, QEMUTimer *)
#define VMSTATE_PTIMER_V(_f, _s, _v) \
VMSTATE_POINTER(_f, _s, _v, vmstate_info_ptimer, ptimer_state *)
#define VMSTATE_PTIMER(_f, _s) \
VMSTATE_PTIMER_V(_f, _s, 0)
#define VMSTATE_BOOL_ARRAY_V(_f, _s, _n, _v) \
VMSTATE_ARRAY(_f, _s, _n, _v, vmstate_info_bool, bool)

View File

@ -28,4 +28,7 @@ void mmio_ide_init (target_phys_addr_t membase, target_phys_addr_t membase2,
void ide_get_bs(BlockDriverState *bs[], BusState *qbus);
/* ide/core.c */
void ide_drive_get(DriveInfo **hd, int max_bus);
#endif /* HW_IDE_H */

1138
hw/ide/atapi.c Normal file

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -67,7 +67,6 @@
#include <hw/isa.h>
#include "block.h"
#include "block_int.h"
#include "sysemu.h"
#include "dma.h"
#include <hw/ide/pci.h>

Some files were not shown because too many files have changed in this diff Show More