Compare commits
193 Commits
python-nex
...
ppc-for-2.
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e451b85f1b | ||
|
|
0fc84331d6 | ||
|
|
ecba28dbf2 | ||
|
|
1d27f351af | ||
|
|
2bb4a98f90 | ||
|
|
1ec26c757d | ||
|
|
15fcedb26f | ||
|
|
5aec066c41 | ||
|
|
53a04e8e79 | ||
|
|
30b3bc5aa9 | ||
|
|
5abdf67009 | ||
|
|
5261158d21 | ||
|
|
332f7721cb | ||
|
|
14b0d74887 | ||
|
|
82be8e7394 | ||
|
|
58b6283586 | ||
|
|
4f7265ff17 | ||
|
|
7745388249 | ||
|
|
3c0622897e | ||
|
|
c8bd35260d | ||
|
|
4c46f372b0 | ||
|
|
81bb29ace5 | ||
|
|
9ffe4ce56b | ||
|
|
d7145b66c6 | ||
|
|
712b25c4cb | ||
|
|
6977afda16 | ||
|
|
31bc1d8481 | ||
|
|
2509dda283 | ||
|
|
35deebb232 | ||
|
|
a9b16ab368 | ||
|
|
0789700019 | ||
|
|
af5eeb2c3b | ||
|
|
e837acfda1 | ||
|
|
2098b073f3 | ||
|
|
2c5b1d2a47 | ||
|
|
77fc026cdf | ||
|
|
98e8790326 | ||
|
|
a295d244e5 | ||
|
|
6ec83befe1 | ||
|
|
b9710bc911 | ||
|
|
401bc051d7 | ||
|
|
5746c1cd15 | ||
|
|
c39cdbf6f6 | ||
|
|
3947ecfc0a | ||
|
|
c5e2ac7e5e | ||
|
|
0a4f9ad1eb | ||
|
|
8960393847 | ||
|
|
982d009a18 | ||
|
|
68179923a1 | ||
|
|
b24f9882cc | ||
|
|
ab7f9f7d78 | ||
|
|
5a49c1b34e | ||
|
|
37f8043def | ||
|
|
0e0d345b4f | ||
|
|
c6427ff7a0 | ||
|
|
39d96847c9 | ||
|
|
0f9f39d491 | ||
|
|
2b521a654c | ||
|
|
1e3ee83408 | ||
|
|
8b81253332 | ||
|
|
a693437037 | ||
|
|
9397067221 | ||
|
|
319a56cde7 | ||
|
|
cfa3ad635c | ||
|
|
13146a8395 | ||
|
|
e2aad34d73 | ||
|
|
0e7e4fb0a6 | ||
|
|
460b6c8e58 | ||
|
|
bb86d05f4a | ||
|
|
6bbb6c0644 | ||
|
|
95eeeba669 | ||
|
|
07241c205c | ||
|
|
9bad2a6b9d | ||
|
|
fe8fc5ae5c | ||
|
|
b855f8d175 | ||
|
|
c348b54ab5 | ||
|
|
bef81b3eb5 | ||
|
|
159a9df021 | ||
|
|
54ae0886b1 | ||
|
|
5553499f04 | ||
|
|
d7651f150d | ||
|
|
58110f0acb | ||
|
|
86e1167e9a | ||
|
|
c646762736 | ||
|
|
d7788151a0 | ||
|
|
fc7deeea26 | ||
|
|
ab089e058e | ||
|
|
e595a01ab6 | ||
|
|
f986c3d256 | ||
|
|
0fb86605ea | ||
|
|
4075fb1ca4 | ||
|
|
30126bbf1f | ||
|
|
428d89084c | ||
|
|
8e1a1931ca | ||
|
|
2a543bfdfa | ||
|
|
4f0fae7f2b | ||
|
|
a664607440 | ||
|
|
3aaa8d4499 | ||
|
|
a43415ebfd | ||
|
|
3f2d07b3b0 | ||
|
|
4f6afe41f2 | ||
|
|
b7f404201e | ||
|
|
d72c55c3a5 | ||
|
|
18023821b6 | ||
|
|
b1fb9a63fc | ||
|
|
fdfaa33291 | ||
|
|
5cd2b13851 | ||
|
|
111e30c0c4 | ||
|
|
fb15a57032 | ||
|
|
ff2ebff079 | ||
|
|
57446e32ac | ||
|
|
6b560c76ca | ||
|
|
22491a2f2e | ||
|
|
b8bd2f598b | ||
|
|
0475a03eb8 | ||
|
|
392fb64351 | ||
|
|
8eca288989 | ||
|
|
cc7923fc07 | ||
|
|
b878b652df | ||
|
|
7b62bf5a70 | ||
|
|
b11499117c | ||
|
|
8ecc89f6e7 | ||
|
|
e2ad6f16a8 | ||
|
|
27ad39ba61 | ||
|
|
f300ca63c7 | ||
|
|
18d4e35f93 | ||
|
|
4470749186 | ||
|
|
82659e844a | ||
|
|
d8a2f5116d | ||
|
|
05790dafef | ||
|
|
5e8a7fe673 | ||
|
|
7fc581c295 | ||
|
|
3f2ff267af | ||
|
|
9b4154a570 | ||
|
|
6fe3ae3f19 | ||
|
|
1fddbf7c5e | ||
|
|
7c9e527659 | ||
|
|
092aa2fc65 | ||
|
|
e673ba9af9 | ||
|
|
02d9651d6a | ||
|
|
202fc01b05 | ||
|
|
b516572f31 | ||
|
|
5e8fd947e2 | ||
|
|
67ace39b25 | ||
|
|
967dc9b119 | ||
|
|
0221848764 | ||
|
|
9bf561e36c | ||
|
|
89c177bbdd | ||
|
|
8629d3fcb7 | ||
|
|
9950322a59 | ||
|
|
166206845f | ||
|
|
c775252378 | ||
|
|
66a6df1dc6 | ||
|
|
cc94cd6d36 | ||
|
|
9a62e24f45 | ||
|
|
e76bb18f7e | ||
|
|
447b0d0b9e | ||
|
|
0a8066f0c0 | ||
|
|
6d262dcb7d | ||
|
|
ebc1fbb4a1 | ||
|
|
268ee7deb4 | ||
|
|
0ee1e1f469 | ||
|
|
96401bad45 | ||
|
|
fc14cf0e95 | ||
|
|
28dc207f5f | ||
|
|
13dfde3320 | ||
|
|
27f5bab84d | ||
|
|
940caf1f7e | ||
|
|
7b675f1f97 | ||
|
|
4ce31af4ae | ||
|
|
5cb18069d7 | ||
|
|
437d59c17e | ||
|
|
3f1e0eb7c3 | ||
|
|
5d4791991d | ||
|
|
49c80c380d | ||
|
|
7208b426c7 | ||
|
|
331f4bae6c | ||
|
|
94a34abe32 | ||
|
|
80ac239035 | ||
|
|
e6a0d3500d | ||
|
|
2fb50a3340 | ||
|
|
ff96c64aec | ||
|
|
e1be0a576b | ||
|
|
028b0da424 | ||
|
|
3b2e934463 | ||
|
|
5255fcf8e4 | ||
|
|
e93bc2ac11 | ||
|
|
17906a162a | ||
|
|
50f11062d4 | ||
|
|
db81b99537 | ||
|
|
05e015f73c | ||
|
|
3110cdbd8a | ||
|
|
55289fb036 |
1
.gitignore
vendored
1
.gitignore
vendored
@@ -52,6 +52,7 @@
|
||||
/vscclient
|
||||
/vhost-user-scsi
|
||||
/fsdev/virtfs-proxy-helper
|
||||
*.tmp
|
||||
*.[1-9]
|
||||
*.a
|
||||
*.aux
|
||||
|
||||
44
MAINTAINERS
44
MAINTAINERS
@@ -380,6 +380,7 @@ M: Peter Maydell <peter.maydell@linaro.org>
|
||||
L: qemu-arm@nongnu.org
|
||||
S: Maintained
|
||||
F: hw/char/pl011.c
|
||||
F: include/hw/char/pl011.h
|
||||
F: hw/display/pl110*
|
||||
F: hw/dma/pl080.c
|
||||
F: hw/dma/pl330.c
|
||||
@@ -403,13 +404,15 @@ F: hw/intc/gic_internal.h
|
||||
F: hw/misc/a9scu.c
|
||||
F: hw/misc/arm11scu.c
|
||||
F: hw/timer/a9gtimer*
|
||||
F: hw/timer/arm_*
|
||||
F: include/hw/arm/arm.h
|
||||
F: hw/timer/arm*
|
||||
F: include/hw/arm/arm*.h
|
||||
F: include/hw/intc/arm*
|
||||
F: include/hw/misc/a9scu.h
|
||||
F: include/hw/misc/arm11scu.h
|
||||
F: include/hw/timer/a9gtimer.h
|
||||
F: include/hw/timer/arm_mptimer.h
|
||||
F: include/hw/timer/armv7m_systick.h
|
||||
F: tests/test-arm-mptimer.c
|
||||
|
||||
Exynos
|
||||
M: Igor Mitsyanko <i.mitsyanko@gmail.com>
|
||||
@@ -512,6 +515,7 @@ M: Peter Maydell <peter.maydell@linaro.org>
|
||||
L: qemu-arm@nongnu.org
|
||||
S: Maintained
|
||||
F: hw/*/versatile*
|
||||
F: hw/misc/arm_sysctl.c
|
||||
|
||||
Xilinx Zynq
|
||||
M: Edgar E. Iglesias <edgar.iglesias@gmail.com>
|
||||
@@ -548,6 +552,7 @@ F: hw/char/stm32f2xx_usart.c
|
||||
F: hw/timer/stm32f2xx_timer.c
|
||||
F: hw/adc/*
|
||||
F: hw/ssi/stm32f2xx_spi.c
|
||||
F: include/hw/*/stm32*.h
|
||||
|
||||
Netduino 2
|
||||
M: Alistair Francis <alistair@alistair23.me>
|
||||
@@ -925,6 +930,8 @@ F: include/hw/pci/*
|
||||
F: hw/misc/pci-testdev.c
|
||||
F: hw/pci/*
|
||||
F: hw/pci-bridge/*
|
||||
F: docs/pci*
|
||||
F: docs/specs/*pci*
|
||||
|
||||
ACPI/SMBIOS
|
||||
M: Michael S. Tsirkin <mst@redhat.com>
|
||||
@@ -983,10 +990,13 @@ F: hw/scsi/lsi53c895a.c
|
||||
|
||||
SSI
|
||||
M: Peter Crosthwaite <crosthwaite.peter@gmail.com>
|
||||
M: Alistair Francis <alistair.francis@xilinx.com>
|
||||
S: Maintained
|
||||
F: hw/ssi/*
|
||||
F: hw/block/m25p80.c
|
||||
F: include/hw/ssi/ssi.h
|
||||
X: hw/ssi/xilinx_*
|
||||
F: tests/m25p80-test.c
|
||||
|
||||
Xilinx SPI
|
||||
M: Alistair Francis <alistair.francis@xilinx.com>
|
||||
@@ -1029,6 +1039,7 @@ vhost
|
||||
M: Michael S. Tsirkin <mst@redhat.com>
|
||||
S: Supported
|
||||
F: hw/*/*vhost*
|
||||
F: docs/interop/vhost-user.txt
|
||||
|
||||
virtio
|
||||
M: Michael S. Tsirkin <mst@redhat.com>
|
||||
@@ -1126,6 +1137,7 @@ M: Dmitry Fleytman <dmitry@daynix.com>
|
||||
S: Maintained
|
||||
F: hw/net/vmxnet*
|
||||
F: hw/scsi/vmw_pvscsi*
|
||||
F: tests/vmxnet3-test.c
|
||||
|
||||
Rocker
|
||||
M: Jiri Pirko <jiri@resnulli.us>
|
||||
@@ -1156,6 +1168,7 @@ M: Alistair Francis <alistair.francis@xilinx.com>
|
||||
S: Maintained
|
||||
F: hw/core/generic-loader.c
|
||||
F: include/hw/core/generic-loader.h
|
||||
F: docs/generic-loader.txt
|
||||
|
||||
CHRP NVRAM
|
||||
M: Thomas Huth <thuth@redhat.com>
|
||||
@@ -1217,6 +1230,7 @@ F: util/aio-*.c
|
||||
F: block/io.c
|
||||
F: migration/block*
|
||||
F: include/block/aio.h
|
||||
F: scripts/qemugdb/aio.py
|
||||
T: git git://github.com/stefanha/qemu.git block
|
||||
|
||||
Block SCSI subsystem
|
||||
@@ -1257,7 +1271,7 @@ F: block/dirty-bitmap.c
|
||||
F: include/qemu/hbitmap.h
|
||||
F: include/block/dirty-bitmap.h
|
||||
F: tests/test-hbitmap.c
|
||||
F: docs/bitmaps.md
|
||||
F: docs/interop/bitmaps.rst
|
||||
T: git git://github.com/famz/qemu.git bitmaps
|
||||
T: git git://github.com/jnsnow/qemu.git bitmaps
|
||||
|
||||
@@ -1426,7 +1440,7 @@ F: tests/test-qapi-*.c
|
||||
F: tests/test-qmp-*.c
|
||||
F: tests/test-visitor-serialization.c
|
||||
F: scripts/qapi*
|
||||
F: docs/qapi*
|
||||
F: docs/devel/qapi*
|
||||
T: git git://repo.or.cz/qemu/armbru.git qapi-next
|
||||
|
||||
QAPI Schema
|
||||
@@ -1455,6 +1469,10 @@ QEMU Guest Agent
|
||||
M: Michael Roth <mdroth@linux.vnet.ibm.com>
|
||||
S: Maintained
|
||||
F: qga/
|
||||
F: qemu-ga.texi
|
||||
F: scripts/qemu-guest-agent/
|
||||
F: tests/test-qga.c
|
||||
F: docs/interop/qemu-ga-ref.texi
|
||||
T: git git://github.com/mdroth/qemu.git qga
|
||||
|
||||
QOM
|
||||
@@ -1474,7 +1492,7 @@ M: Markus Armbruster <armbru@redhat.com>
|
||||
S: Supported
|
||||
F: qmp.c
|
||||
F: monitor.c
|
||||
F: docs/*qmp-*
|
||||
F: docs/devel/*qmp-*
|
||||
F: scripts/qmp/
|
||||
F: tests/qmp-test.c
|
||||
T: git git://repo.or.cz/qemu/armbru.git qapi-next
|
||||
@@ -1505,7 +1523,7 @@ S: Maintained
|
||||
F: trace/
|
||||
F: scripts/tracetool.py
|
||||
F: scripts/tracetool/
|
||||
F: docs/tracing.txt
|
||||
F: docs/devel/tracing.txt
|
||||
T: git git://github.com/stefanha/qemu.git tracing
|
||||
|
||||
TPM
|
||||
@@ -1528,7 +1546,7 @@ F: include/migration/
|
||||
F: migration/
|
||||
F: scripts/vmstate-static-checker.py
|
||||
F: tests/vmstate-static-checker-data/
|
||||
F: docs/migration.txt
|
||||
F: docs/devel/migration.txt
|
||||
F: qapi/migration.json
|
||||
|
||||
Seccomp
|
||||
@@ -1543,6 +1561,7 @@ S: Maintained
|
||||
F: crypto/
|
||||
F: include/crypto/
|
||||
F: tests/test-crypto-*
|
||||
F: tests/benchmark-crypto-*
|
||||
F: qemu.sasl
|
||||
|
||||
Coroutines
|
||||
@@ -1579,8 +1598,10 @@ M: Alberto Garcia <berto@igalia.com>
|
||||
S: Supported
|
||||
F: block/throttle-groups.c
|
||||
F: include/block/throttle-groups.h
|
||||
F: include/qemu/throttle.h
|
||||
F: include/qemu/throttle*.h
|
||||
F: util/throttle.c
|
||||
F: docs/throttle.txt
|
||||
F: tests/test-throttle.c
|
||||
L: qemu-block@nongnu.org
|
||||
|
||||
UUID
|
||||
@@ -1836,7 +1857,7 @@ M: Denis V. Lunev <den@openvz.org>
|
||||
L: qemu-block@nongnu.org
|
||||
S: Supported
|
||||
F: block/parallels.c
|
||||
F: docs/specs/parallels.txt
|
||||
F: docs/interop/parallels.txt
|
||||
|
||||
qed
|
||||
M: Stefan Hajnoczi <stefanha@redhat.com>
|
||||
@@ -1861,6 +1882,7 @@ M: Max Reitz <mreitz@redhat.com>
|
||||
L: qemu-block@nongnu.org
|
||||
S: Supported
|
||||
F: block/qcow2*
|
||||
F: docs/interop/qcow2.txt
|
||||
|
||||
qcow
|
||||
M: Kevin Wolf <kwolf@redhat.com>
|
||||
@@ -1904,6 +1926,7 @@ F: docs/block-replication.txt
|
||||
|
||||
Build and test automation
|
||||
-------------------------
|
||||
Build and test automation
|
||||
M: Alex Bennée <alex.bennee@linaro.org>
|
||||
M: Fam Zheng <famz@redhat.com>
|
||||
R: Philippe Mathieu-Daudé <f4bug@amsat.org>
|
||||
@@ -1912,6 +1935,7 @@ S: Maintained
|
||||
F: .travis.yml
|
||||
F: .shippable.yml
|
||||
F: tests/docker/
|
||||
F: tests/vm/
|
||||
W: https://travis-ci.org/qemu/qemu
|
||||
W: https://app.shippable.com/github/qemu/qemu
|
||||
W: http://patchew.org/QEMU/
|
||||
@@ -1921,5 +1945,5 @@ Documentation
|
||||
Build system architecture
|
||||
M: Daniel P. Berrange <berrange@redhat.com>
|
||||
S: Odd Fixes
|
||||
F: docs/build-system.txt
|
||||
F: docs/devel/build-system.txt
|
||||
|
||||
|
||||
9
Makefile
9
Makefile
@@ -372,6 +372,11 @@ qemu-bridge-helper$(EXESUF): qemu-bridge-helper.o $(COMMON_LDADDS)
|
||||
fsdev/virtfs-proxy-helper$(EXESUF): fsdev/virtfs-proxy-helper.o fsdev/9p-marshal.o fsdev/9p-iov-marshal.o $(COMMON_LDADDS)
|
||||
fsdev/virtfs-proxy-helper$(EXESUF): LIBS += -lcap
|
||||
|
||||
scsi/qemu-pr-helper$(EXESUF): scsi/qemu-pr-helper.o scsi/utils.o $(crypto-obj-y) $(io-obj-y) $(qom-obj-y) $(COMMON_LDADDS)
|
||||
ifdef CONFIG_MPATH
|
||||
scsi/qemu-pr-helper$(EXESUF): LIBS += -ludev -lmultipath -lmpathpersist
|
||||
endif
|
||||
|
||||
qemu-img-cmds.h: $(SRC_PATH)/qemu-img-cmds.hx $(SRC_PATH)/scripts/hxtool
|
||||
$(call quiet-command,sh $(SRC_PATH)/scripts/hxtool -h < $< > $@,"GEN","$@")
|
||||
|
||||
@@ -488,7 +493,7 @@ clean:
|
||||
rm -f *.msi
|
||||
find . \( -name '*.so' -o -name '*.dll' -o -name '*.mo' -o -name '*.[oda]' \) -type f -exec rm {} +
|
||||
rm -f $(filter-out %.tlb,$(TOOLS)) $(HELPERS-y) qemu-ga TAGS cscope.* *.pod *~ */*~
|
||||
rm -f fsdev/*.pod
|
||||
rm -f fsdev/*.pod scsi/*.pod
|
||||
rm -f qemu-img-cmds.h
|
||||
rm -f ui/shader/*-vert.h ui/shader/*-frag.h
|
||||
@# May not be present in GENERATED_FILES
|
||||
@@ -811,6 +816,7 @@ endif
|
||||
-include $(wildcard *.d tests/*.d)
|
||||
|
||||
include $(SRC_PATH)/tests/docker/Makefile.include
|
||||
include $(SRC_PATH)/tests/vm/Makefile.include
|
||||
|
||||
.PHONY: help
|
||||
help:
|
||||
@@ -834,6 +840,7 @@ help:
|
||||
@echo 'Test targets:'
|
||||
@echo ' check - Run all tests (check-help for details)'
|
||||
@echo ' docker - Help about targets running tests inside Docker containers'
|
||||
@echo ' vm-test - Help about targets running tests inside VM'
|
||||
@echo ''
|
||||
@echo 'Documentation targets:'
|
||||
@echo ' html info pdf txt'
|
||||
|
||||
@@ -171,6 +171,7 @@ trace-events-subdirs += qapi
|
||||
trace-events-subdirs += accel/tcg
|
||||
trace-events-subdirs += accel/kvm
|
||||
trace-events-subdirs += nbd
|
||||
trace-events-subdirs += scsi
|
||||
|
||||
trace-events-files = $(SRC_PATH)/trace-events $(trace-events-subdirs:%=$(SRC_PATH)/%/trace-events)
|
||||
|
||||
|
||||
@@ -722,7 +722,6 @@ static void kvm_set_phys_mem(KVMMemoryListener *kml,
|
||||
mem = kvm_lookup_matching_slot(kml, start_addr, size);
|
||||
if (!add) {
|
||||
if (!mem) {
|
||||
g_assert(!memory_region_is_ram(mr) && !writeable && !mr->romd_mode);
|
||||
return;
|
||||
}
|
||||
if (mem->flags & KVM_MEM_LOG_DIRTY_PAGES) {
|
||||
|
||||
@@ -765,7 +765,7 @@ static uint64_t io_readx(CPUArchState *env, CPUIOTLBEntry *iotlbentry,
|
||||
|
||||
cpu->mem_io_vaddr = addr;
|
||||
|
||||
if (mr->global_locking) {
|
||||
if (mr->global_locking && !qemu_mutex_iothread_locked()) {
|
||||
qemu_mutex_lock_iothread();
|
||||
locked = true;
|
||||
}
|
||||
@@ -800,7 +800,7 @@ static void io_writex(CPUArchState *env, CPUIOTLBEntry *iotlbentry,
|
||||
cpu->mem_io_vaddr = addr;
|
||||
cpu->mem_io_pc = retaddr;
|
||||
|
||||
if (mr->global_locking) {
|
||||
if (mr->global_locking && !qemu_mutex_iothread_locked()) {
|
||||
qemu_mutex_lock_iothread();
|
||||
locked = true;
|
||||
}
|
||||
|
||||
@@ -11,3 +11,9 @@ common-obj-$(CONFIG_AUDIO_WIN_INT) += audio_win_int.o
|
||||
common-obj-y += wavcapture.o
|
||||
|
||||
sdlaudio.o-cflags := $(SDL_CFLAGS)
|
||||
sdlaudio.o-libs := $(SDL_LIBS)
|
||||
alsaaudio.o-libs := $(ALSA_LIBS)
|
||||
paaudio.o-libs := $(PULSE_LIBS)
|
||||
coreaudio.o-libs := $(COREAUDIO_LIBS)
|
||||
dsoundaudio.o-libs := $(DSOUND_LIBS)
|
||||
ossaudio.o-libs := $(OSS_LIBS)
|
||||
|
||||
@@ -33,6 +33,9 @@
|
||||
#include "block/raw-aio.h"
|
||||
#include "qapi/qmp/qstring.h"
|
||||
|
||||
#include "scsi/pr-manager.h"
|
||||
#include "scsi/constants.h"
|
||||
|
||||
#if defined(__APPLE__) && (__MACH__)
|
||||
#include <paths.h>
|
||||
#include <sys/param.h>
|
||||
@@ -155,6 +158,8 @@ typedef struct BDRVRawState {
|
||||
bool page_cache_inconsistent:1;
|
||||
bool has_fallocate;
|
||||
bool needs_alignment;
|
||||
|
||||
PRManager *pr_mgr;
|
||||
} BDRVRawState;
|
||||
|
||||
typedef struct BDRVRawReopenState {
|
||||
@@ -402,6 +407,11 @@ static QemuOptsList raw_runtime_opts = {
|
||||
.type = QEMU_OPT_STRING,
|
||||
.help = "file locking mode (on/off/auto, default: auto)",
|
||||
},
|
||||
{
|
||||
.name = "pr-manager",
|
||||
.type = QEMU_OPT_STRING,
|
||||
.help = "id of persistent reservation manager object (default: none)",
|
||||
},
|
||||
{ /* end of list */ }
|
||||
},
|
||||
};
|
||||
@@ -413,6 +423,7 @@ static int raw_open_common(BlockDriverState *bs, QDict *options,
|
||||
QemuOpts *opts;
|
||||
Error *local_err = NULL;
|
||||
const char *filename = NULL;
|
||||
const char *str;
|
||||
BlockdevAioOptions aio, aio_default;
|
||||
int fd, ret;
|
||||
struct stat st;
|
||||
@@ -476,6 +487,16 @@ static int raw_open_common(BlockDriverState *bs, QDict *options,
|
||||
abort();
|
||||
}
|
||||
|
||||
str = qemu_opt_get(opts, "pr-manager");
|
||||
if (str) {
|
||||
s->pr_mgr = pr_manager_lookup(str, &local_err);
|
||||
if (local_err) {
|
||||
error_propagate(errp, local_err);
|
||||
ret = -EINVAL;
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
|
||||
s->open_flags = open_flags;
|
||||
raw_parse_flags(bdrv_flags, &s->open_flags);
|
||||
|
||||
@@ -2597,6 +2618,15 @@ static BlockAIOCB *hdev_aio_ioctl(BlockDriverState *bs,
|
||||
if (fd_open(bs) < 0)
|
||||
return NULL;
|
||||
|
||||
if (req == SG_IO && s->pr_mgr) {
|
||||
struct sg_io_hdr *io_hdr = buf;
|
||||
if (io_hdr->cmdp[0] == PERSISTENT_RESERVE_OUT ||
|
||||
io_hdr->cmdp[0] == PERSISTENT_RESERVE_IN) {
|
||||
return pr_manager_execute(s->pr_mgr, bdrv_get_aio_context(bs),
|
||||
s->fd, io_hdr, cb, opaque);
|
||||
}
|
||||
}
|
||||
|
||||
acb = g_new(RawPosixAIOData, 1);
|
||||
acb->bs = bs;
|
||||
acb->aio_type = QEMU_AIO_IOCTL;
|
||||
|
||||
@@ -31,8 +31,8 @@
|
||||
#include "qapi/error.h"
|
||||
#include "nbd-client.h"
|
||||
|
||||
#define HANDLE_TO_INDEX(bs, handle) ((handle) ^ ((uint64_t)(intptr_t)bs))
|
||||
#define INDEX_TO_HANDLE(bs, index) ((index) ^ ((uint64_t)(intptr_t)bs))
|
||||
#define HANDLE_TO_INDEX(bs, handle) ((handle) ^ (uint64_t)(intptr_t)(bs))
|
||||
#define INDEX_TO_HANDLE(bs, index) ((index) ^ (uint64_t)(intptr_t)(bs))
|
||||
|
||||
static void nbd_recv_coroutines_wake_all(NBDClientSession *s)
|
||||
{
|
||||
@@ -161,6 +161,8 @@ static int nbd_co_send_request(BlockDriverState *bs,
|
||||
NULL) < 0) {
|
||||
rc = -EIO;
|
||||
}
|
||||
} else if (rc >= 0) {
|
||||
rc = -EIO;
|
||||
}
|
||||
qio_channel_set_cork(s->ioc, false);
|
||||
} else {
|
||||
@@ -178,26 +180,27 @@ err:
|
||||
return rc;
|
||||
}
|
||||
|
||||
static void nbd_co_receive_reply(NBDClientSession *s,
|
||||
NBDRequest *request,
|
||||
NBDReply *reply,
|
||||
QEMUIOVector *qiov)
|
||||
static int nbd_co_receive_reply(NBDClientSession *s,
|
||||
NBDRequest *request,
|
||||
QEMUIOVector *qiov)
|
||||
{
|
||||
int ret;
|
||||
int i = HANDLE_TO_INDEX(s, request->handle);
|
||||
|
||||
/* Wait until we're woken up by nbd_read_reply_entry. */
|
||||
s->requests[i].receiving = true;
|
||||
qemu_coroutine_yield();
|
||||
s->requests[i].receiving = false;
|
||||
*reply = s->reply;
|
||||
if (reply->handle != request->handle || !s->ioc || s->quit) {
|
||||
reply->error = EIO;
|
||||
if (!s->ioc || s->quit) {
|
||||
ret = -EIO;
|
||||
} else {
|
||||
if (qiov && reply->error == 0) {
|
||||
assert(s->reply.handle == request->handle);
|
||||
ret = -s->reply.error;
|
||||
if (qiov && s->reply.error == 0) {
|
||||
assert(request->len == iov_size(qiov->iov, qiov->niov));
|
||||
if (qio_channel_readv_all(s->ioc, qiov->iov, qiov->niov,
|
||||
NULL) < 0) {
|
||||
reply->error = EIO;
|
||||
ret = -EIO;
|
||||
s->quit = true;
|
||||
}
|
||||
}
|
||||
@@ -217,6 +220,8 @@ static void nbd_co_receive_reply(NBDClientSession *s,
|
||||
s->in_flight--;
|
||||
qemu_co_queue_next(&s->free_sema);
|
||||
qemu_co_mutex_unlock(&s->send_mutex);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int nbd_co_request(BlockDriverState *bs,
|
||||
@@ -224,7 +229,6 @@ static int nbd_co_request(BlockDriverState *bs,
|
||||
QEMUIOVector *qiov)
|
||||
{
|
||||
NBDClientSession *client = nbd_get_client_session(bs);
|
||||
NBDReply reply;
|
||||
int ret;
|
||||
|
||||
assert(!qiov || request->type == NBD_CMD_WRITE ||
|
||||
@@ -232,12 +236,11 @@ static int nbd_co_request(BlockDriverState *bs,
|
||||
ret = nbd_co_send_request(bs, request,
|
||||
request->type == NBD_CMD_WRITE ? qiov : NULL);
|
||||
if (ret < 0) {
|
||||
reply.error = -ret;
|
||||
} else {
|
||||
nbd_co_receive_reply(client, request, &reply,
|
||||
request->type == NBD_CMD_READ ? qiov : NULL);
|
||||
return ret;
|
||||
}
|
||||
return -reply.error;
|
||||
|
||||
return nbd_co_receive_reply(client, request,
|
||||
request->type == NBD_CMD_READ ? qiov : NULL);
|
||||
}
|
||||
|
||||
int nbd_client_co_preadv(BlockDriverState *bs, uint64_t offset,
|
||||
|
||||
@@ -20,5 +20,6 @@ chardev-obj-$(CONFIG_WIN32) += char-win-stdio.o
|
||||
common-obj-y += msmouse.o wctablet.o testdev.o
|
||||
common-obj-$(CONFIG_BRLAPI) += baum.o
|
||||
baum.o-cflags := $(SDL_CFLAGS)
|
||||
baum.o-libs := $(BRLAPI_LIBS)
|
||||
|
||||
common-obj-$(CONFIG_SPICE) += spice.o
|
||||
|
||||
@@ -643,6 +643,7 @@ static void baum_chr_open(Chardev *chr,
|
||||
error_setg(errp, "brlapi__openConnection: %s",
|
||||
brlapi_strerror(brlapi_error_location()));
|
||||
g_free(handle);
|
||||
baum->brlapi = NULL;
|
||||
return;
|
||||
}
|
||||
baum->deferred_init = 0;
|
||||
|
||||
@@ -84,8 +84,7 @@ static GSource *fd_chr_add_watch(Chardev *chr, GIOCondition cond)
|
||||
return qio_channel_create_watch(s->ioc_out, cond);
|
||||
}
|
||||
|
||||
static void fd_chr_update_read_handler(Chardev *chr,
|
||||
GMainContext *context)
|
||||
static void fd_chr_update_read_handler(Chardev *chr)
|
||||
{
|
||||
FDChardev *s = FD_CHARDEV(chr);
|
||||
|
||||
@@ -94,7 +93,7 @@ static void fd_chr_update_read_handler(Chardev *chr,
|
||||
chr->gsource = io_add_watch_poll(chr, s->ioc_in,
|
||||
fd_chr_read_poll,
|
||||
fd_chr_read, chr,
|
||||
context);
|
||||
chr->gcontext);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -253,7 +253,6 @@ void qemu_chr_fe_set_handlers(CharBackend *b,
|
||||
bool set_open)
|
||||
{
|
||||
Chardev *s;
|
||||
ChardevClass *cc;
|
||||
int fe_open;
|
||||
|
||||
s = b->chr;
|
||||
@@ -261,7 +260,6 @@ void qemu_chr_fe_set_handlers(CharBackend *b,
|
||||
return;
|
||||
}
|
||||
|
||||
cc = CHARDEV_GET_CLASS(s);
|
||||
if (!opaque && !fd_can_read && !fd_read && !fd_event) {
|
||||
fe_open = 0;
|
||||
remove_fd_in_watch(s);
|
||||
@@ -273,9 +271,8 @@ void qemu_chr_fe_set_handlers(CharBackend *b,
|
||||
b->chr_event = fd_event;
|
||||
b->chr_be_change = be_change;
|
||||
b->opaque = opaque;
|
||||
if (cc->chr_update_read_handler) {
|
||||
cc->chr_update_read_handler(s, context);
|
||||
}
|
||||
|
||||
qemu_chr_be_update_read_handlers(s, context);
|
||||
|
||||
if (set_open) {
|
||||
qemu_chr_fe_set_open(b, fe_open);
|
||||
|
||||
@@ -112,8 +112,7 @@ static void pty_chr_update_read_handler_locked(Chardev *chr)
|
||||
}
|
||||
}
|
||||
|
||||
static void pty_chr_update_read_handler(Chardev *chr,
|
||||
GMainContext *context)
|
||||
static void pty_chr_update_read_handler(Chardev *chr)
|
||||
{
|
||||
qemu_mutex_lock(&chr->chr_write_lock);
|
||||
pty_chr_update_read_handler_locked(chr);
|
||||
@@ -219,7 +218,7 @@ static void pty_chr_state(Chardev *chr, int connected)
|
||||
chr->gsource = io_add_watch_poll(chr, s->ioc,
|
||||
pty_chr_read_poll,
|
||||
pty_chr_read,
|
||||
chr, NULL);
|
||||
chr, chr->gcontext);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -516,13 +516,12 @@ static void tcp_chr_connect(void *opaque)
|
||||
chr->gsource = io_add_watch_poll(chr, s->ioc,
|
||||
tcp_chr_read_poll,
|
||||
tcp_chr_read,
|
||||
chr, NULL);
|
||||
chr, chr->gcontext);
|
||||
}
|
||||
qemu_chr_be_event(chr, CHR_EVENT_OPENED);
|
||||
}
|
||||
|
||||
static void tcp_chr_update_read_handler(Chardev *chr,
|
||||
GMainContext *context)
|
||||
static void tcp_chr_update_read_handler(Chardev *chr)
|
||||
{
|
||||
SocketChardev *s = SOCKET_CHARDEV(chr);
|
||||
|
||||
@@ -535,7 +534,7 @@ static void tcp_chr_update_read_handler(Chardev *chr,
|
||||
chr->gsource = io_add_watch_poll(chr, s->ioc,
|
||||
tcp_chr_read_poll,
|
||||
tcp_chr_read, chr,
|
||||
context);
|
||||
chr->gcontext);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -100,8 +100,7 @@ static gboolean udp_chr_read(QIOChannel *chan, GIOCondition cond, void *opaque)
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void udp_chr_update_read_handler(Chardev *chr,
|
||||
GMainContext *context)
|
||||
static void udp_chr_update_read_handler(Chardev *chr)
|
||||
{
|
||||
UdpChardev *s = UDP_CHARDEV(chr);
|
||||
|
||||
@@ -110,7 +109,7 @@ static void udp_chr_update_read_handler(Chardev *chr,
|
||||
chr->gsource = io_add_watch_poll(chr, s->ioc,
|
||||
udp_chr_read_poll,
|
||||
udp_chr_read, chr,
|
||||
context);
|
||||
chr->gcontext);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -180,6 +180,17 @@ void qemu_chr_be_write(Chardev *s, uint8_t *buf, int len)
|
||||
}
|
||||
}
|
||||
|
||||
void qemu_chr_be_update_read_handlers(Chardev *s,
|
||||
GMainContext *context)
|
||||
{
|
||||
ChardevClass *cc = CHARDEV_GET_CLASS(s);
|
||||
|
||||
s->gcontext = context;
|
||||
if (cc->chr_update_read_handler) {
|
||||
cc->chr_update_read_handler(s);
|
||||
}
|
||||
}
|
||||
|
||||
int qemu_chr_add_client(Chardev *s, int fd)
|
||||
{
|
||||
return CHARDEV_GET_CLASS(s)->chr_add_client ?
|
||||
|
||||
115
configure
vendored
115
configure
vendored
@@ -290,6 +290,7 @@ netmap="no"
|
||||
sdl=""
|
||||
sdlabi=""
|
||||
virtfs=""
|
||||
mpath=""
|
||||
vnc="yes"
|
||||
sparse="no"
|
||||
vde=""
|
||||
@@ -745,7 +746,6 @@ SunOS)
|
||||
solaris="yes"
|
||||
make="${MAKE-gmake}"
|
||||
install="${INSTALL-ginstall}"
|
||||
ld="gld"
|
||||
smbd="${SMBD-/usr/sfw/sbin/smbd}"
|
||||
if test -f /usr/include/sys/soundcard.h ; then
|
||||
audio_drv_list="oss"
|
||||
@@ -936,6 +936,10 @@ for opt do
|
||||
;;
|
||||
--enable-virtfs) virtfs="yes"
|
||||
;;
|
||||
--disable-mpath) mpath="no"
|
||||
;;
|
||||
--enable-mpath) mpath="yes"
|
||||
;;
|
||||
--disable-vnc) vnc="no"
|
||||
;;
|
||||
--enable-vnc) vnc="yes"
|
||||
@@ -1479,6 +1483,7 @@ disabled with --disable-FEATURE, default is enabled if available:
|
||||
vnc-png PNG compression for VNC server
|
||||
cocoa Cocoa UI (Mac OS X only)
|
||||
virtfs VirtFS
|
||||
mpath Multipath persistent reservation passthrough
|
||||
xen xen backend driver support
|
||||
xen-pci-passthrough
|
||||
brlapi BrlAPI (Braile)
|
||||
@@ -2788,7 +2793,6 @@ EOF
|
||||
sdl_cflags="$sdl_cflags $x11_cflags"
|
||||
sdl_libs="$sdl_libs $x11_libs"
|
||||
fi
|
||||
libs_softmmu="$sdl_libs $libs_softmmu"
|
||||
fi
|
||||
|
||||
##########################################
|
||||
@@ -2801,7 +2805,6 @@ EOF
|
||||
rdma_libs="-lrdmacm -libverbs"
|
||||
if compile_prog "" "$rdma_libs" ; then
|
||||
rdma="yes"
|
||||
libs_softmmu="$libs_softmmu $rdma_libs"
|
||||
else
|
||||
if test "$rdma" = "yes" ; then
|
||||
error_exit \
|
||||
@@ -2946,8 +2949,6 @@ int main(void)
|
||||
EOF
|
||||
if compile_prog "" "$vde_libs" ; then
|
||||
vde=yes
|
||||
libs_softmmu="$vde_libs $libs_softmmu"
|
||||
libs_tools="$vde_libs $libs_tools"
|
||||
else
|
||||
if test "$vde" = "yes" ; then
|
||||
feature_not_found "vde" "Install vde (Virtual Distributed Ethernet) devel"
|
||||
@@ -3035,13 +3036,13 @@ for drv in $audio_drv_list; do
|
||||
alsa)
|
||||
audio_drv_probe $drv alsa/asoundlib.h -lasound \
|
||||
"return snd_pcm_close((snd_pcm_t *)0);"
|
||||
libs_softmmu="-lasound $libs_softmmu"
|
||||
alsa_libs="-lasound"
|
||||
;;
|
||||
|
||||
pa)
|
||||
audio_drv_probe $drv pulse/pulseaudio.h "-lpulse" \
|
||||
"pa_context_set_source_output_volume(NULL, 0, NULL, NULL, NULL); return 0;"
|
||||
libs_softmmu="-lpulse $libs_softmmu"
|
||||
pulse_libs="-lpulse"
|
||||
audio_pt_int="yes"
|
||||
;;
|
||||
|
||||
@@ -3052,16 +3053,16 @@ for drv in $audio_drv_list; do
|
||||
;;
|
||||
|
||||
coreaudio)
|
||||
libs_softmmu="-framework CoreAudio $libs_softmmu"
|
||||
coreaudio_libs="-framework CoreAudio"
|
||||
;;
|
||||
|
||||
dsound)
|
||||
libs_softmmu="-lole32 -ldxguid $libs_softmmu"
|
||||
dsound_libs="-lole32 -ldxguid"
|
||||
audio_win_int="yes"
|
||||
;;
|
||||
|
||||
oss)
|
||||
libs_softmmu="$oss_lib $libs_softmmu"
|
||||
oss_libs="$oss_lib"
|
||||
;;
|
||||
|
||||
wav)
|
||||
@@ -3089,7 +3090,6 @@ int main( void ) { return brlapi__openConnection (NULL, NULL, NULL); }
|
||||
EOF
|
||||
if compile_prog "" "$brlapi_libs" ; then
|
||||
brlapi=yes
|
||||
libs_softmmu="$brlapi_libs $libs_softmmu"
|
||||
else
|
||||
if test "$brlapi" = "yes" ; then
|
||||
feature_not_found "brlapi" "Install brlapi devel"
|
||||
@@ -3299,6 +3299,30 @@ else
|
||||
"Please install the pixman devel package."
|
||||
fi
|
||||
|
||||
##########################################
|
||||
# libmpathpersist probe
|
||||
|
||||
if test "$mpath" != "no" ; then
|
||||
cat > $TMPC <<EOF
|
||||
#include <libudev.h>
|
||||
#include <mpath_persist.h>
|
||||
unsigned mpath_mx_alloc_len = 1024;
|
||||
int logsink;
|
||||
int main(void) {
|
||||
struct udev *udev = udev_new();
|
||||
mpath_lib_init(udev);
|
||||
return 0;
|
||||
}
|
||||
EOF
|
||||
if compile_prog "" "-ludev -lmultipath -lmpathpersist" ; then
|
||||
mpathpersist=yes
|
||||
else
|
||||
mpathpersist=no
|
||||
fi
|
||||
else
|
||||
mpathpersist=no
|
||||
fi
|
||||
|
||||
##########################################
|
||||
# libcap probe
|
||||
|
||||
@@ -4204,13 +4228,10 @@ EOF
|
||||
fi
|
||||
|
||||
# check for smartcard support
|
||||
smartcard_cflags=""
|
||||
if test "$smartcard" != "no"; then
|
||||
if $pkg_config libcacard; then
|
||||
libcacard_cflags=$($pkg_config --cflags libcacard)
|
||||
libcacard_libs=$($pkg_config --libs libcacard)
|
||||
QEMU_CFLAGS="$QEMU_CFLAGS $libcacard_cflags"
|
||||
libs_softmmu="$libs_softmmu $libcacard_libs"
|
||||
smartcard="yes"
|
||||
else
|
||||
if test "$smartcard" = "yes"; then
|
||||
@@ -4226,8 +4247,6 @@ if test "$libusb" != "no" ; then
|
||||
libusb="yes"
|
||||
libusb_cflags=$($pkg_config --cflags libusb-1.0)
|
||||
libusb_libs=$($pkg_config --libs libusb-1.0)
|
||||
QEMU_CFLAGS="$QEMU_CFLAGS $libusb_cflags"
|
||||
libs_softmmu="$libs_softmmu $libusb_libs"
|
||||
else
|
||||
if test "$libusb" = "yes"; then
|
||||
feature_not_found "libusb" "Install libusb devel >= 1.0.13"
|
||||
@@ -4242,8 +4261,6 @@ if test "$usb_redir" != "no" ; then
|
||||
usb_redir="yes"
|
||||
usb_redir_cflags=$($pkg_config --cflags libusbredirparser-0.5)
|
||||
usb_redir_libs=$($pkg_config --libs libusbredirparser-0.5)
|
||||
QEMU_CFLAGS="$QEMU_CFLAGS $usb_redir_cflags"
|
||||
libs_softmmu="$libs_softmmu $usb_redir_libs"
|
||||
else
|
||||
if test "$usb_redir" = "yes"; then
|
||||
feature_not_found "usb-redir" "Install usbredir devel"
|
||||
@@ -4406,6 +4423,18 @@ if compile_prog "" "" ; then
|
||||
posix_syslog=yes
|
||||
fi
|
||||
|
||||
##########################################
|
||||
# check if we have sem_timedwait
|
||||
|
||||
sem_timedwait=no
|
||||
cat > $TMPC << EOF
|
||||
#include <semaphore.h>
|
||||
int main(void) { return sem_timedwait(0, 0); }
|
||||
EOF
|
||||
if compile_prog "" "" ; then
|
||||
sem_timedwait=yes
|
||||
fi
|
||||
|
||||
##########################################
|
||||
# check if trace backend exists
|
||||
|
||||
@@ -5034,16 +5063,34 @@ if test "$want_tools" = "yes" ; then
|
||||
fi
|
||||
fi
|
||||
if test "$softmmu" = yes ; then
|
||||
if test "$virtfs" != no ; then
|
||||
if test "$cap" = yes && test "$linux" = yes && test "$attr" = yes ; then
|
||||
if test "$linux" = yes; then
|
||||
if test "$virtfs" != no && test "$cap" = yes && test "$attr" = yes ; then
|
||||
virtfs=yes
|
||||
tools="$tools fsdev/virtfs-proxy-helper\$(EXESUF)"
|
||||
else
|
||||
if test "$virtfs" = yes; then
|
||||
error_exit "VirtFS is supported only on Linux and requires libcap devel and libattr devel"
|
||||
error_exit "VirtFS requires libcap devel and libattr devel"
|
||||
fi
|
||||
virtfs=no
|
||||
fi
|
||||
if test "$mpath" != no && test "$mpathpersist" = yes ; then
|
||||
mpath=yes
|
||||
else
|
||||
if test "$mpath" = yes; then
|
||||
error_exit "Multipath requires libmpathpersist devel"
|
||||
fi
|
||||
mpath=no
|
||||
fi
|
||||
tools="$tools scsi/qemu-pr-helper\$(EXESUF)"
|
||||
else
|
||||
if test "$virtfs" = yes; then
|
||||
error_exit "VirtFS is supported only on Linux"
|
||||
fi
|
||||
virtfs=no
|
||||
if test "$mpath" = yes; then
|
||||
error_exit "Multipath is supported only on Linux"
|
||||
fi
|
||||
mpath=no
|
||||
fi
|
||||
fi
|
||||
|
||||
@@ -5289,6 +5336,7 @@ echo "Audio drivers $audio_drv_list"
|
||||
echo "Block whitelist (rw) $block_drv_rw_whitelist"
|
||||
echo "Block whitelist (ro) $block_drv_ro_whitelist"
|
||||
echo "VirtFS support $virtfs"
|
||||
echo "Multipath support $mpath"
|
||||
echo "VNC support $vnc"
|
||||
if test "$vnc" = "yes" ; then
|
||||
echo "VNC SASL support $vnc_sasl"
|
||||
@@ -5499,6 +5547,7 @@ if test "$slirp" = "yes" ; then
|
||||
fi
|
||||
if test "$vde" = "yes" ; then
|
||||
echo "CONFIG_VDE=y" >> $config_host_mak
|
||||
echo "VDE_LIBS=$vde_libs" >> $config_host_mak
|
||||
fi
|
||||
if test "$netmap" = "yes" ; then
|
||||
echo "CONFIG_NETMAP=y" >> $config_host_mak
|
||||
@@ -5514,6 +5563,11 @@ for drv in $audio_drv_list; do
|
||||
def=CONFIG_$(echo $drv | LC_ALL=C tr '[a-z]' '[A-Z]')
|
||||
echo "$def=y" >> $config_host_mak
|
||||
done
|
||||
echo "ALSA_LIBS=$alsa_libs" >> $config_host_mak
|
||||
echo "PULSE_LIBS=$pulse_libs" >> $config_host_mak
|
||||
echo "COREAUDIO_LIBS=$coreaudio_libs" >> $config_host_mak
|
||||
echo "DSOUND_LIBS=$dsound_libs" >> $config_host_mak
|
||||
echo "OSS_LIBS=$oss_libs" >> $config_host_mak
|
||||
if test "$audio_pt_int" = "yes" ; then
|
||||
echo "CONFIG_AUDIO_PT_INT=y" >> $config_host_mak
|
||||
fi
|
||||
@@ -5558,6 +5612,7 @@ if test "$sdl" = "yes" ; then
|
||||
echo "CONFIG_SDL=y" >> $config_host_mak
|
||||
echo "CONFIG_SDLABI=$sdlabi" >> $config_host_mak
|
||||
echo "SDL_CFLAGS=$sdl_cflags" >> $config_host_mak
|
||||
echo "SDL_LIBS=$sdl_libs" >> $config_host_mak
|
||||
fi
|
||||
if test "$cocoa" = "yes" ; then
|
||||
echo "CONFIG_COCOA=y" >> $config_host_mak
|
||||
@@ -5634,6 +5689,9 @@ fi
|
||||
if test "$inotify1" = "yes" ; then
|
||||
echo "CONFIG_INOTIFY1=y" >> $config_host_mak
|
||||
fi
|
||||
if test "$sem_timedwait" = "yes" ; then
|
||||
echo "CONFIG_SEM_TIMEDWAIT=y" >> $config_host_mak
|
||||
fi
|
||||
if test "$byteswap_h" = "yes" ; then
|
||||
echo "CONFIG_BYTESWAP_H=y" >> $config_host_mak
|
||||
fi
|
||||
@@ -5647,6 +5705,7 @@ if test "$curl" = "yes" ; then
|
||||
fi
|
||||
if test "$brlapi" = "yes" ; then
|
||||
echo "CONFIG_BRLAPI=y" >> $config_host_mak
|
||||
echo "BRLAPI_LIBS=$brlapi_libs" >> $config_host_mak
|
||||
fi
|
||||
if test "$bluez" = "yes" ; then
|
||||
echo "CONFIG_BLUEZ=y" >> $config_host_mak
|
||||
@@ -5732,6 +5791,9 @@ fi
|
||||
if test "$virtfs" = "yes" ; then
|
||||
echo "CONFIG_VIRTFS=y" >> $config_host_mak
|
||||
fi
|
||||
if test "$mpath" = "yes" ; then
|
||||
echo "CONFIG_MPATH=y" >> $config_host_mak
|
||||
fi
|
||||
if test "$vhost_scsi" = "yes" ; then
|
||||
echo "CONFIG_VHOST_SCSI=y" >> $config_host_mak
|
||||
fi
|
||||
@@ -5781,14 +5843,20 @@ fi
|
||||
|
||||
if test "$smartcard" = "yes" ; then
|
||||
echo "CONFIG_SMARTCARD=y" >> $config_host_mak
|
||||
echo "SMARTCARD_CFLAGS=$libcacard_cflags" >> $config_host_mak
|
||||
echo "SMARTCARD_LIBS=$libcacard_libs" >> $config_host_mak
|
||||
fi
|
||||
|
||||
if test "$libusb" = "yes" ; then
|
||||
echo "CONFIG_USB_LIBUSB=y" >> $config_host_mak
|
||||
echo "LIBUSB_CFLAGS=$libusb_cflags" >> $config_host_mak
|
||||
echo "LIBUSB_LIBS=$libusb_libs" >> $config_host_mak
|
||||
fi
|
||||
|
||||
if test "$usb_redir" = "yes" ; then
|
||||
echo "CONFIG_USB_REDIR=y" >> $config_host_mak
|
||||
echo "USB_REDIR_CFLAGS=$usb_redir_cflags" >> $config_host_mak
|
||||
echo "USB_REDIR_LIBS=$usb_redir_libs" >> $config_host_mak
|
||||
fi
|
||||
|
||||
if test "$opengl" = "yes" ; then
|
||||
@@ -5984,6 +6052,7 @@ echo "CONFIG_TRACE_FILE=$trace_file" >> $config_host_mak
|
||||
|
||||
if test "$rdma" = "yes" ; then
|
||||
echo "CONFIG_RDMA=y" >> $config_host_mak
|
||||
echo "RDMA_LIBS=$rdma_libs" >> $config_host_mak
|
||||
fi
|
||||
|
||||
if test "$have_rtnetlink" = "yes" ; then
|
||||
@@ -6505,8 +6574,8 @@ if test "$ccache_cpp2" = "yes"; then
|
||||
fi
|
||||
|
||||
# build tree in object directory in case the source is not in the current directory
|
||||
DIRS="tests tests/tcg tests/tcg/cris tests/tcg/lm32 tests/libqos tests/qapi-schema tests/tcg/xtensa tests/qemu-iotests"
|
||||
DIRS="$DIRS docs docs/interop fsdev"
|
||||
DIRS="tests tests/tcg tests/tcg/cris tests/tcg/lm32 tests/libqos tests/qapi-schema tests/tcg/xtensa tests/qemu-iotests tests/vm"
|
||||
DIRS="$DIRS docs docs/interop fsdev scsi"
|
||||
DIRS="$DIRS pc-bios/optionrom pc-bios/spapr-rtas pc-bios/s390-ccw"
|
||||
DIRS="$DIRS roms/seabios roms/vgabios"
|
||||
DIRS="$DIRS qapi-generated"
|
||||
|
||||
5
cpus.c
5
cpus.c
@@ -1764,8 +1764,9 @@ void qemu_init_vcpu(CPUState *cpu)
|
||||
/* If the target cpu hasn't set up any address spaces itself,
|
||||
* give it the default one.
|
||||
*/
|
||||
AddressSpace *as = address_space_init_shareable(cpu->memory,
|
||||
"cpu-memory");
|
||||
AddressSpace *as = g_new0(AddressSpace, 1);
|
||||
|
||||
address_space_init(as, cpu->memory, "cpu-memory");
|
||||
cpu->num_ases = 1;
|
||||
cpu_address_space_init(cpu, as, 0);
|
||||
}
|
||||
|
||||
@@ -129,3 +129,4 @@ CONFIG_ACPI=y
|
||||
CONFIG_SMBIOS=y
|
||||
CONFIG_ASPEED_SOC=y
|
||||
CONFIG_GPIO_KEY=y
|
||||
CONFIG_MSF2=y
|
||||
|
||||
@@ -63,11 +63,23 @@ operations:
|
||||
typeof(*ptr) atomic_fetch_sub(ptr, val)
|
||||
typeof(*ptr) atomic_fetch_and(ptr, val)
|
||||
typeof(*ptr) atomic_fetch_or(ptr, val)
|
||||
typeof(*ptr) atomic_fetch_xor(ptr, val)
|
||||
typeof(*ptr) atomic_fetch_inc_nonzero(ptr)
|
||||
typeof(*ptr) atomic_xchg(ptr, val)
|
||||
typeof(*ptr) atomic_cmpxchg(ptr, old, new)
|
||||
|
||||
all of which return the old value of *ptr. These operations are
|
||||
polymorphic; they operate on any type that is as wide as an int.
|
||||
polymorphic; they operate on any type that is as wide as a pointer.
|
||||
|
||||
Similar operations return the new value of *ptr:
|
||||
|
||||
typeof(*ptr) atomic_inc_fetch(ptr)
|
||||
typeof(*ptr) atomic_dec_fetch(ptr)
|
||||
typeof(*ptr) atomic_add_fetch(ptr, val)
|
||||
typeof(*ptr) atomic_sub_fetch(ptr, val)
|
||||
typeof(*ptr) atomic_and_fetch(ptr, val)
|
||||
typeof(*ptr) atomic_or_fetch(ptr, val)
|
||||
typeof(*ptr) atomic_xor_fetch(ptr, val)
|
||||
|
||||
Sequentially consistent loads and stores can be done using:
|
||||
|
||||
|
||||
83
docs/interop/pr-helper.rst
Normal file
83
docs/interop/pr-helper.rst
Normal file
@@ -0,0 +1,83 @@
|
||||
..
|
||||
|
||||
======================================
|
||||
Persistent reservation helper protocol
|
||||
======================================
|
||||
|
||||
QEMU's SCSI passthrough devices, ``scsi-block`` and ``scsi-generic``,
|
||||
can delegate implementation of persistent reservations to an external
|
||||
(and typically privileged) program. Persistent Reservations allow
|
||||
restricting access to block devices to specific initiators in a shared
|
||||
storage setup.
|
||||
|
||||
For a more detailed reference please refer the the SCSI Primary
|
||||
Commands standard, specifically the section on Reservations and the
|
||||
"PERSISTENT RESERVE IN" and "PERSISTENT RESERVE OUT" commands.
|
||||
|
||||
This document describes the socket protocol used between QEMU's
|
||||
``pr-manager-helper`` object and the external program.
|
||||
|
||||
.. contents::
|
||||
|
||||
Connection and initialization
|
||||
-----------------------------
|
||||
|
||||
All data transmitted on the socket is big-endian.
|
||||
|
||||
After connecting to the helper program's socket, the helper starts a simple
|
||||
feature negotiation process by writing four bytes corresponding to
|
||||
the features it exposes (``supported_features``). QEMU reads it,
|
||||
then writes four bytes corresponding to the desired features of the
|
||||
helper program (``requested_features``).
|
||||
|
||||
If a bit is 1 in ``requested_features`` and 0 in ``supported_features``,
|
||||
the corresponding feature is not supported by the helper and the connection
|
||||
is closed. On the other hand, it is acceptable for a bit to be 0 in
|
||||
``requested_features`` and 1 in ``supported_features``; in this case,
|
||||
the helper will not enable the feature.
|
||||
|
||||
Right now no feature is defined, so the two parties always write four
|
||||
zero bytes.
|
||||
|
||||
Command format
|
||||
--------------
|
||||
|
||||
It is invalid to send multiple commands concurrently on the same
|
||||
socket. It is however possible to connect multiple sockets to the
|
||||
helper and send multiple commands to the helper for one or more
|
||||
file descriptors.
|
||||
|
||||
A command consists of a request and a response. A request consists
|
||||
of a 16-byte SCSI CDB. A file descriptor must be passed to the helper
|
||||
together with the SCSI CDB using ancillary data.
|
||||
|
||||
The CDB has the following limitations:
|
||||
|
||||
- the command (stored in the first byte) must be one of 0x5E
|
||||
(PERSISTENT RESERVE IN) or 0x5F (PERSISTENT RESERVE OUT).
|
||||
|
||||
- the allocation length (stored in bytes 7-8 of the CDB for PERSISTENT
|
||||
RESERVE IN) or parameter list length (stored in bytes 5-8 of the CDB
|
||||
for PERSISTENT RESERVE OUT) is limited to 8 KiB.
|
||||
|
||||
For PERSISTENT RESERVE OUT, the parameter list is sent right after the
|
||||
CDB. The length of the parameter list is taken from the CDB itself.
|
||||
|
||||
The helper's reply has the following structure:
|
||||
|
||||
- 4 bytes for the SCSI status
|
||||
|
||||
- 4 bytes for the payload size (nonzero only for PERSISTENT RESERVE IN
|
||||
and only if the SCSI status is 0x00, i.e. GOOD)
|
||||
|
||||
- 96 bytes for the SCSI sense data
|
||||
|
||||
- if the size is nonzero, the payload follows
|
||||
|
||||
The sense data is always sent to keep the protocol simple, even though
|
||||
it is only valid if the SCSI status is CHECK CONDITION (0x02).
|
||||
|
||||
The payload size is always less than or equal to the allocation length
|
||||
specified in the CDB for the PERSISTENT RESERVE IN command.
|
||||
|
||||
If the protocol is violated, the helper closes the socket.
|
||||
@@ -24,7 +24,7 @@ Where,
|
||||
|
||||
For example, the following command-line:
|
||||
|
||||
qemu [...] 1G,slots=3,maxmem=4G
|
||||
qemu [...] -m 1G,slots=3,maxmem=4G
|
||||
|
||||
Creates a guest with 1GB of memory and three hotpluggable memory slots.
|
||||
The hotpluggable memory slots are empty when the guest is booted, so all
|
||||
|
||||
111
docs/pr-manager.rst
Normal file
111
docs/pr-manager.rst
Normal file
@@ -0,0 +1,111 @@
|
||||
======================================
|
||||
Persistent reservation managers
|
||||
======================================
|
||||
|
||||
SCSI persistent Reservations allow restricting access to block devices
|
||||
to specific initiators in a shared storage setup. When implementing
|
||||
clustering of virtual machines, it is a common requirement for virtual
|
||||
machines to send persistent reservation SCSI commands. However,
|
||||
the operating system restricts sending these commands to unprivileged
|
||||
programs because incorrect usage can disrupt regular operation of the
|
||||
storage fabric.
|
||||
|
||||
For this reason, QEMU's SCSI passthrough devices, ``scsi-block``
|
||||
and ``scsi-generic`` (both are only available on Linux) can delegate
|
||||
implementation of persistent reservations to a separate object,
|
||||
the "persistent reservation manager". Only PERSISTENT RESERVE OUT and
|
||||
PERSISTENT RESERVE IN commands are passed to the persistent reservation
|
||||
manager object; other commands are processed by QEMU as usual.
|
||||
|
||||
-----------------------------------------
|
||||
Defining a persistent reservation manager
|
||||
-----------------------------------------
|
||||
|
||||
A persistent reservation manager is an instance of a subclass of the
|
||||
"pr-manager" QOM class.
|
||||
|
||||
Right now only one subclass is defined, ``pr-manager-helper``, which
|
||||
forwards the commands to an external privileged helper program
|
||||
over Unix sockets. The helper program only allows sending persistent
|
||||
reservation commands to devices for which QEMU has a file descriptor,
|
||||
so that QEMU will not be able to effect persistent reservations
|
||||
unless it has access to both the socket and the device.
|
||||
|
||||
``pr-manager-helper`` has a single string property, ``path``, which
|
||||
accepts the path to the helper program's Unix socket. For example,
|
||||
the following command line defines a ``pr-manager-helper`` object and
|
||||
attaches it to a SCSI passthrough device::
|
||||
|
||||
$ qemu-system-x86_64
|
||||
-device virtio-scsi \
|
||||
-object pr-manager-helper,id=helper0,path=/var/run/qemu-pr-helper.sock
|
||||
-drive if=none,id=hd,driver=raw,file.filename=/dev/sdb,file.pr-manager=helper0
|
||||
-device scsi-block,drive=hd
|
||||
|
||||
Alternatively, using ``-blockdev``::
|
||||
|
||||
$ qemu-system-x86_64
|
||||
-device virtio-scsi \
|
||||
-object pr-manager-helper,id=helper0,path=/var/run/qemu-pr-helper.sock
|
||||
-blockdev node-name=hd,driver=raw,file.driver=host_device,file.filename=/dev/sdb,file.pr-manager=helper0
|
||||
-device scsi-block,drive=hd
|
||||
|
||||
----------------------------------
|
||||
Invoking :program:`qemu-pr-helper`
|
||||
----------------------------------
|
||||
|
||||
QEMU provides an implementation of the persistent reservation helper,
|
||||
called :program:`qemu-pr-helper`. The helper should be started as a
|
||||
system service and supports the following option:
|
||||
|
||||
-d, --daemon run in the background
|
||||
-q, --quiet decrease verbosity
|
||||
-v, --verbose increase verbosity
|
||||
-f, --pidfile=path PID file when running as a daemon
|
||||
-k, --socket=path path to the socket
|
||||
-T, --trace=trace-opts tracing options
|
||||
|
||||
By default, the socket and PID file are placed in the runtime state
|
||||
directory, for example :file:`/var/run/qemu-pr-helper.sock` and
|
||||
:file:`/var/run/qemu-pr-helper.pid`. The PID file is not created
|
||||
unless :option:`-d` is passed too.
|
||||
|
||||
:program:`qemu-pr-helper` can also use the systemd socket activation
|
||||
protocol. In this case, the systemd socket unit should specify a
|
||||
Unix stream socket, like this::
|
||||
|
||||
[Socket]
|
||||
ListenStream=/var/run/qemu-pr-helper.sock
|
||||
|
||||
After connecting to the socket, :program:`qemu-pr-helper`` can optionally drop
|
||||
root privileges, except for those capabilities that are needed for
|
||||
its operation. To do this, add the following options:
|
||||
|
||||
-u, --user=user user to drop privileges to
|
||||
-g, --group=group group to drop privileges to
|
||||
|
||||
---------------------------------------------
|
||||
Multipath devices and persistent reservations
|
||||
---------------------------------------------
|
||||
|
||||
Proper support of persistent reservation for multipath devices requires
|
||||
communication with the multipath daemon, so that the reservation is
|
||||
registered and applied when a path is newly discovered or becomes online
|
||||
again. :command:`qemu-pr-helper` can do this if the ``libmpathpersist``
|
||||
library was available on the system at build time.
|
||||
|
||||
As of August 2017, a reservation key must be specified in ``multipath.conf``
|
||||
for ``multipathd`` to check for persistent reservation for newly
|
||||
discovered paths or reinstated paths. The attribute can be added
|
||||
to the ``defaults`` section or the ``multipaths`` section; for example::
|
||||
|
||||
multipaths {
|
||||
multipath {
|
||||
wwid XXXXXXXXXXXXXXXX
|
||||
alias yellow
|
||||
reservation_key 0x123abc
|
||||
}
|
||||
}
|
||||
|
||||
Linking :program:`qemu-pr-helper` to ``libmpathpersist`` does not impede
|
||||
its usage on regular SCSI devices.
|
||||
330
exec.c
330
exec.c
@@ -187,21 +187,18 @@ typedef struct PhysPageMap {
|
||||
} PhysPageMap;
|
||||
|
||||
struct AddressSpaceDispatch {
|
||||
struct rcu_head rcu;
|
||||
|
||||
MemoryRegionSection *mru_section;
|
||||
/* This is a multi-level map on the physical address space.
|
||||
* The bottom level has pointers to MemoryRegionSections.
|
||||
*/
|
||||
PhysPageEntry phys_map;
|
||||
PhysPageMap map;
|
||||
AddressSpace *as;
|
||||
};
|
||||
|
||||
#define SUBPAGE_IDX(addr) ((addr) & ~TARGET_PAGE_MASK)
|
||||
typedef struct subpage_t {
|
||||
MemoryRegion iomem;
|
||||
AddressSpace *as;
|
||||
FlatView *fv;
|
||||
hwaddr base;
|
||||
uint16_t sub_section[];
|
||||
} subpage_t;
|
||||
@@ -361,7 +358,7 @@ static void phys_page_compact(PhysPageEntry *lp, Node *nodes)
|
||||
}
|
||||
}
|
||||
|
||||
static void phys_page_compact_all(AddressSpaceDispatch *d, int nodes_nb)
|
||||
void address_space_dispatch_compact(AddressSpaceDispatch *d)
|
||||
{
|
||||
if (d->phys_map.skip) {
|
||||
phys_page_compact(&d->phys_map, d->map.nodes);
|
||||
@@ -471,12 +468,13 @@ address_space_translate_internal(AddressSpaceDispatch *d, hwaddr addr, hwaddr *x
|
||||
}
|
||||
|
||||
/* Called from RCU critical section */
|
||||
static MemoryRegionSection address_space_do_translate(AddressSpace *as,
|
||||
hwaddr addr,
|
||||
hwaddr *xlat,
|
||||
hwaddr *plen,
|
||||
bool is_write,
|
||||
bool is_mmio)
|
||||
static MemoryRegionSection flatview_do_translate(FlatView *fv,
|
||||
hwaddr addr,
|
||||
hwaddr *xlat,
|
||||
hwaddr *plen,
|
||||
bool is_write,
|
||||
bool is_mmio,
|
||||
AddressSpace **target_as)
|
||||
{
|
||||
IOMMUTLBEntry iotlb;
|
||||
MemoryRegionSection *section;
|
||||
@@ -484,8 +482,9 @@ static MemoryRegionSection address_space_do_translate(AddressSpace *as,
|
||||
IOMMUMemoryRegionClass *imrc;
|
||||
|
||||
for (;;) {
|
||||
AddressSpaceDispatch *d = atomic_rcu_read(&as->dispatch);
|
||||
section = address_space_translate_internal(d, addr, &addr, plen, is_mmio);
|
||||
section = address_space_translate_internal(
|
||||
flatview_to_dispatch(fv), addr, &addr,
|
||||
plen, is_mmio);
|
||||
|
||||
iommu_mr = memory_region_get_iommu(section->mr);
|
||||
if (!iommu_mr) {
|
||||
@@ -502,7 +501,8 @@ static MemoryRegionSection address_space_do_translate(AddressSpace *as,
|
||||
goto translate_fail;
|
||||
}
|
||||
|
||||
as = iotlb.target_as;
|
||||
fv = address_space_to_flatview(iotlb.target_as);
|
||||
*target_as = iotlb.target_as;
|
||||
}
|
||||
|
||||
*xlat = addr;
|
||||
@@ -524,8 +524,8 @@ IOMMUTLBEntry address_space_get_iotlb_entry(AddressSpace *as, hwaddr addr,
|
||||
plen = (hwaddr)-1;
|
||||
|
||||
/* This can never be MMIO. */
|
||||
section = address_space_do_translate(as, addr, &xlat, &plen,
|
||||
is_write, false);
|
||||
section = flatview_do_translate(address_space_to_flatview(as), addr,
|
||||
&xlat, &plen, is_write, false, &as);
|
||||
|
||||
/* Illegal translation */
|
||||
if (section.mr == &io_mem_unassigned) {
|
||||
@@ -548,7 +548,7 @@ IOMMUTLBEntry address_space_get_iotlb_entry(AddressSpace *as, hwaddr addr,
|
||||
plen -= 1;
|
||||
|
||||
return (IOMMUTLBEntry) {
|
||||
.target_as = section.address_space,
|
||||
.target_as = as,
|
||||
.iova = addr & ~plen,
|
||||
.translated_addr = xlat & ~plen,
|
||||
.addr_mask = plen,
|
||||
@@ -561,15 +561,15 @@ iotlb_fail:
|
||||
}
|
||||
|
||||
/* Called from RCU critical section */
|
||||
MemoryRegion *address_space_translate(AddressSpace *as, hwaddr addr,
|
||||
hwaddr *xlat, hwaddr *plen,
|
||||
bool is_write)
|
||||
MemoryRegion *flatview_translate(FlatView *fv, hwaddr addr, hwaddr *xlat,
|
||||
hwaddr *plen, bool is_write)
|
||||
{
|
||||
MemoryRegion *mr;
|
||||
MemoryRegionSection section;
|
||||
AddressSpace *as = NULL;
|
||||
|
||||
/* This can be MMIO, so setup MMIO bit. */
|
||||
section = address_space_do_translate(as, addr, xlat, plen, is_write, true);
|
||||
section = flatview_do_translate(fv, addr, xlat, plen, is_write, true, &as);
|
||||
mr = section.mr;
|
||||
|
||||
if (xen_enabled() && memory_access_is_direct(mr, is_write)) {
|
||||
@@ -1219,7 +1219,7 @@ hwaddr memory_region_section_get_iotlb(CPUState *cpu,
|
||||
} else {
|
||||
AddressSpaceDispatch *d;
|
||||
|
||||
d = atomic_rcu_read(§ion->address_space->dispatch);
|
||||
d = flatview_to_dispatch(section->fv);
|
||||
iotlb = section - d->map.sections;
|
||||
iotlb += xlat;
|
||||
}
|
||||
@@ -1245,7 +1245,7 @@ hwaddr memory_region_section_get_iotlb(CPUState *cpu,
|
||||
|
||||
static int subpage_register (subpage_t *mmio, uint32_t start, uint32_t end,
|
||||
uint16_t section);
|
||||
static subpage_t *subpage_init(AddressSpace *as, hwaddr base);
|
||||
static subpage_t *subpage_init(FlatView *fv, hwaddr base);
|
||||
|
||||
static void *(*phys_mem_alloc)(size_t size, uint64_t *align) =
|
||||
qemu_anon_ram_alloc;
|
||||
@@ -1302,8 +1302,9 @@ static void phys_sections_free(PhysPageMap *map)
|
||||
g_free(map->nodes);
|
||||
}
|
||||
|
||||
static void register_subpage(AddressSpaceDispatch *d, MemoryRegionSection *section)
|
||||
static void register_subpage(FlatView *fv, MemoryRegionSection *section)
|
||||
{
|
||||
AddressSpaceDispatch *d = flatview_to_dispatch(fv);
|
||||
subpage_t *subpage;
|
||||
hwaddr base = section->offset_within_address_space
|
||||
& TARGET_PAGE_MASK;
|
||||
@@ -1317,8 +1318,8 @@ static void register_subpage(AddressSpaceDispatch *d, MemoryRegionSection *secti
|
||||
assert(existing->mr->subpage || existing->mr == &io_mem_unassigned);
|
||||
|
||||
if (!(existing->mr->subpage)) {
|
||||
subpage = subpage_init(d->as, base);
|
||||
subsection.address_space = d->as;
|
||||
subpage = subpage_init(fv, base);
|
||||
subsection.fv = fv;
|
||||
subsection.mr = &subpage->iomem;
|
||||
phys_page_set(d, base >> TARGET_PAGE_BITS, 1,
|
||||
phys_section_add(&d->map, &subsection));
|
||||
@@ -1332,9 +1333,10 @@ static void register_subpage(AddressSpaceDispatch *d, MemoryRegionSection *secti
|
||||
}
|
||||
|
||||
|
||||
static void register_multipage(AddressSpaceDispatch *d,
|
||||
static void register_multipage(FlatView *fv,
|
||||
MemoryRegionSection *section)
|
||||
{
|
||||
AddressSpaceDispatch *d = flatview_to_dispatch(fv);
|
||||
hwaddr start_addr = section->offset_within_address_space;
|
||||
uint16_t section_index = phys_section_add(&d->map, section);
|
||||
uint64_t num_pages = int128_get64(int128_rshift(section->size,
|
||||
@@ -1344,10 +1346,8 @@ static void register_multipage(AddressSpaceDispatch *d,
|
||||
phys_page_set(d, start_addr >> TARGET_PAGE_BITS, num_pages, section_index);
|
||||
}
|
||||
|
||||
static void mem_add(MemoryListener *listener, MemoryRegionSection *section)
|
||||
void flatview_add_to_dispatch(FlatView *fv, MemoryRegionSection *section)
|
||||
{
|
||||
AddressSpace *as = container_of(listener, AddressSpace, dispatch_listener);
|
||||
AddressSpaceDispatch *d = as->next_dispatch;
|
||||
MemoryRegionSection now = *section, remain = *section;
|
||||
Int128 page_size = int128_make64(TARGET_PAGE_SIZE);
|
||||
|
||||
@@ -1356,7 +1356,7 @@ static void mem_add(MemoryListener *listener, MemoryRegionSection *section)
|
||||
- now.offset_within_address_space;
|
||||
|
||||
now.size = int128_min(int128_make64(left), now.size);
|
||||
register_subpage(d, &now);
|
||||
register_subpage(fv, &now);
|
||||
} else {
|
||||
now.size = int128_zero();
|
||||
}
|
||||
@@ -1366,13 +1366,13 @@ static void mem_add(MemoryListener *listener, MemoryRegionSection *section)
|
||||
remain.offset_within_region += int128_get64(now.size);
|
||||
now = remain;
|
||||
if (int128_lt(remain.size, page_size)) {
|
||||
register_subpage(d, &now);
|
||||
register_subpage(fv, &now);
|
||||
} else if (remain.offset_within_address_space & ~TARGET_PAGE_MASK) {
|
||||
now.size = page_size;
|
||||
register_subpage(d, &now);
|
||||
register_subpage(fv, &now);
|
||||
} else {
|
||||
now.size = int128_and(now.size, int128_neg(page_size));
|
||||
register_multipage(d, &now);
|
||||
register_multipage(fv, &now);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2500,6 +2500,11 @@ static const MemoryRegionOps watch_mem_ops = {
|
||||
.endianness = DEVICE_NATIVE_ENDIAN,
|
||||
};
|
||||
|
||||
static MemTxResult flatview_write(FlatView *fv, hwaddr addr, MemTxAttrs attrs,
|
||||
const uint8_t *buf, int len);
|
||||
static bool flatview_access_valid(FlatView *fv, hwaddr addr, int len,
|
||||
bool is_write);
|
||||
|
||||
static MemTxResult subpage_read(void *opaque, hwaddr addr, uint64_t *data,
|
||||
unsigned len, MemTxAttrs attrs)
|
||||
{
|
||||
@@ -2511,8 +2516,7 @@ static MemTxResult subpage_read(void *opaque, hwaddr addr, uint64_t *data,
|
||||
printf("%s: subpage %p len %u addr " TARGET_FMT_plx "\n", __func__,
|
||||
subpage, len, addr);
|
||||
#endif
|
||||
res = address_space_read(subpage->as, addr + subpage->base,
|
||||
attrs, buf, len);
|
||||
res = flatview_read(subpage->fv, addr + subpage->base, attrs, buf, len);
|
||||
if (res) {
|
||||
return res;
|
||||
}
|
||||
@@ -2561,8 +2565,7 @@ static MemTxResult subpage_write(void *opaque, hwaddr addr,
|
||||
default:
|
||||
abort();
|
||||
}
|
||||
return address_space_write(subpage->as, addr + subpage->base,
|
||||
attrs, buf, len);
|
||||
return flatview_write(subpage->fv, addr + subpage->base, attrs, buf, len);
|
||||
}
|
||||
|
||||
static bool subpage_accepts(void *opaque, hwaddr addr,
|
||||
@@ -2574,8 +2577,8 @@ static bool subpage_accepts(void *opaque, hwaddr addr,
|
||||
__func__, subpage, is_write ? 'w' : 'r', len, addr);
|
||||
#endif
|
||||
|
||||
return address_space_access_valid(subpage->as, addr + subpage->base,
|
||||
len, is_write);
|
||||
return flatview_access_valid(subpage->fv, addr + subpage->base,
|
||||
len, is_write);
|
||||
}
|
||||
|
||||
static const MemoryRegionOps subpage_ops = {
|
||||
@@ -2609,12 +2612,12 @@ static int subpage_register (subpage_t *mmio, uint32_t start, uint32_t end,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static subpage_t *subpage_init(AddressSpace *as, hwaddr base)
|
||||
static subpage_t *subpage_init(FlatView *fv, hwaddr base)
|
||||
{
|
||||
subpage_t *mmio;
|
||||
|
||||
mmio = g_malloc0(sizeof(subpage_t) + TARGET_PAGE_SIZE * sizeof(uint16_t));
|
||||
mmio->as = as;
|
||||
mmio->fv = fv;
|
||||
mmio->base = base;
|
||||
memory_region_init_io(&mmio->iomem, NULL, &subpage_ops, mmio,
|
||||
NULL, TARGET_PAGE_SIZE);
|
||||
@@ -2628,12 +2631,11 @@ static subpage_t *subpage_init(AddressSpace *as, hwaddr base)
|
||||
return mmio;
|
||||
}
|
||||
|
||||
static uint16_t dummy_section(PhysPageMap *map, AddressSpace *as,
|
||||
MemoryRegion *mr)
|
||||
static uint16_t dummy_section(PhysPageMap *map, FlatView *fv, MemoryRegion *mr)
|
||||
{
|
||||
assert(as);
|
||||
assert(fv);
|
||||
MemoryRegionSection section = {
|
||||
.address_space = as,
|
||||
.fv = fv,
|
||||
.mr = mr,
|
||||
.offset_within_address_space = 0,
|
||||
.offset_within_region = 0,
|
||||
@@ -2670,46 +2672,31 @@ static void io_mem_init(void)
|
||||
NULL, UINT64_MAX);
|
||||
}
|
||||
|
||||
static void mem_begin(MemoryListener *listener)
|
||||
AddressSpaceDispatch *address_space_dispatch_new(FlatView *fv)
|
||||
{
|
||||
AddressSpace *as = container_of(listener, AddressSpace, dispatch_listener);
|
||||
AddressSpaceDispatch *d = g_new0(AddressSpaceDispatch, 1);
|
||||
uint16_t n;
|
||||
|
||||
n = dummy_section(&d->map, as, &io_mem_unassigned);
|
||||
n = dummy_section(&d->map, fv, &io_mem_unassigned);
|
||||
assert(n == PHYS_SECTION_UNASSIGNED);
|
||||
n = dummy_section(&d->map, as, &io_mem_notdirty);
|
||||
n = dummy_section(&d->map, fv, &io_mem_notdirty);
|
||||
assert(n == PHYS_SECTION_NOTDIRTY);
|
||||
n = dummy_section(&d->map, as, &io_mem_rom);
|
||||
n = dummy_section(&d->map, fv, &io_mem_rom);
|
||||
assert(n == PHYS_SECTION_ROM);
|
||||
n = dummy_section(&d->map, as, &io_mem_watch);
|
||||
n = dummy_section(&d->map, fv, &io_mem_watch);
|
||||
assert(n == PHYS_SECTION_WATCH);
|
||||
|
||||
d->phys_map = (PhysPageEntry) { .ptr = PHYS_MAP_NODE_NIL, .skip = 1 };
|
||||
d->as = as;
|
||||
as->next_dispatch = d;
|
||||
|
||||
return d;
|
||||
}
|
||||
|
||||
static void address_space_dispatch_free(AddressSpaceDispatch *d)
|
||||
void address_space_dispatch_free(AddressSpaceDispatch *d)
|
||||
{
|
||||
phys_sections_free(&d->map);
|
||||
g_free(d);
|
||||
}
|
||||
|
||||
static void mem_commit(MemoryListener *listener)
|
||||
{
|
||||
AddressSpace *as = container_of(listener, AddressSpace, dispatch_listener);
|
||||
AddressSpaceDispatch *cur = as->dispatch;
|
||||
AddressSpaceDispatch *next = as->next_dispatch;
|
||||
|
||||
phys_page_compact_all(next, next->map.nodes_nb);
|
||||
|
||||
atomic_rcu_set(&as->dispatch, next);
|
||||
if (cur) {
|
||||
call_rcu(cur, address_space_dispatch_free, rcu);
|
||||
}
|
||||
}
|
||||
|
||||
static void tcg_commit(MemoryListener *listener)
|
||||
{
|
||||
CPUAddressSpace *cpuas;
|
||||
@@ -2723,39 +2710,11 @@ static void tcg_commit(MemoryListener *listener)
|
||||
* We reload the dispatch pointer now because cpu_reloading_memory_map()
|
||||
* may have split the RCU critical section.
|
||||
*/
|
||||
d = atomic_rcu_read(&cpuas->as->dispatch);
|
||||
d = address_space_to_dispatch(cpuas->as);
|
||||
atomic_rcu_set(&cpuas->memory_dispatch, d);
|
||||
tlb_flush(cpuas->cpu);
|
||||
}
|
||||
|
||||
void address_space_init_dispatch(AddressSpace *as)
|
||||
{
|
||||
as->dispatch = NULL;
|
||||
as->dispatch_listener = (MemoryListener) {
|
||||
.begin = mem_begin,
|
||||
.commit = mem_commit,
|
||||
.region_add = mem_add,
|
||||
.region_nop = mem_add,
|
||||
.priority = 0,
|
||||
};
|
||||
memory_listener_register(&as->dispatch_listener, as);
|
||||
}
|
||||
|
||||
void address_space_unregister(AddressSpace *as)
|
||||
{
|
||||
memory_listener_unregister(&as->dispatch_listener);
|
||||
}
|
||||
|
||||
void address_space_destroy_dispatch(AddressSpace *as)
|
||||
{
|
||||
AddressSpaceDispatch *d = as->dispatch;
|
||||
|
||||
atomic_rcu_set(&as->dispatch, NULL);
|
||||
if (d) {
|
||||
call_rcu(d, address_space_dispatch_free, rcu);
|
||||
}
|
||||
}
|
||||
|
||||
static void memory_map_init(void)
|
||||
{
|
||||
system_memory = g_malloc(sizeof(*system_memory));
|
||||
@@ -2899,11 +2858,11 @@ static bool prepare_mmio_access(MemoryRegion *mr)
|
||||
}
|
||||
|
||||
/* Called within RCU critical section. */
|
||||
static MemTxResult address_space_write_continue(AddressSpace *as, hwaddr addr,
|
||||
MemTxAttrs attrs,
|
||||
const uint8_t *buf,
|
||||
int len, hwaddr addr1,
|
||||
hwaddr l, MemoryRegion *mr)
|
||||
static MemTxResult flatview_write_continue(FlatView *fv, hwaddr addr,
|
||||
MemTxAttrs attrs,
|
||||
const uint8_t *buf,
|
||||
int len, hwaddr addr1,
|
||||
hwaddr l, MemoryRegion *mr)
|
||||
{
|
||||
uint8_t *ptr;
|
||||
uint64_t val;
|
||||
@@ -2965,14 +2924,14 @@ static MemTxResult address_space_write_continue(AddressSpace *as, hwaddr addr,
|
||||
}
|
||||
|
||||
l = len;
|
||||
mr = address_space_translate(as, addr, &addr1, &l, true);
|
||||
mr = flatview_translate(fv, addr, &addr1, &l, true);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
MemTxResult address_space_write(AddressSpace *as, hwaddr addr, MemTxAttrs attrs,
|
||||
const uint8_t *buf, int len)
|
||||
static MemTxResult flatview_write(FlatView *fv, hwaddr addr, MemTxAttrs attrs,
|
||||
const uint8_t *buf, int len)
|
||||
{
|
||||
hwaddr l;
|
||||
hwaddr addr1;
|
||||
@@ -2982,20 +2941,27 @@ MemTxResult address_space_write(AddressSpace *as, hwaddr addr, MemTxAttrs attrs,
|
||||
if (len > 0) {
|
||||
rcu_read_lock();
|
||||
l = len;
|
||||
mr = address_space_translate(as, addr, &addr1, &l, true);
|
||||
result = address_space_write_continue(as, addr, attrs, buf, len,
|
||||
addr1, l, mr);
|
||||
mr = flatview_translate(fv, addr, &addr1, &l, true);
|
||||
result = flatview_write_continue(fv, addr, attrs, buf, len,
|
||||
addr1, l, mr);
|
||||
rcu_read_unlock();
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
MemTxResult address_space_write(AddressSpace *as, hwaddr addr,
|
||||
MemTxAttrs attrs,
|
||||
const uint8_t *buf, int len)
|
||||
{
|
||||
return flatview_write(address_space_to_flatview(as), addr, attrs, buf, len);
|
||||
}
|
||||
|
||||
/* Called within RCU critical section. */
|
||||
MemTxResult address_space_read_continue(AddressSpace *as, hwaddr addr,
|
||||
MemTxAttrs attrs, uint8_t *buf,
|
||||
int len, hwaddr addr1, hwaddr l,
|
||||
MemoryRegion *mr)
|
||||
MemTxResult flatview_read_continue(FlatView *fv, hwaddr addr,
|
||||
MemTxAttrs attrs, uint8_t *buf,
|
||||
int len, hwaddr addr1, hwaddr l,
|
||||
MemoryRegion *mr)
|
||||
{
|
||||
uint8_t *ptr;
|
||||
uint64_t val;
|
||||
@@ -3055,14 +3021,14 @@ MemTxResult address_space_read_continue(AddressSpace *as, hwaddr addr,
|
||||
}
|
||||
|
||||
l = len;
|
||||
mr = address_space_translate(as, addr, &addr1, &l, false);
|
||||
mr = flatview_translate(fv, addr, &addr1, &l, false);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
MemTxResult address_space_read_full(AddressSpace *as, hwaddr addr,
|
||||
MemTxAttrs attrs, uint8_t *buf, int len)
|
||||
MemTxResult flatview_read_full(FlatView *fv, hwaddr addr,
|
||||
MemTxAttrs attrs, uint8_t *buf, int len)
|
||||
{
|
||||
hwaddr l;
|
||||
hwaddr addr1;
|
||||
@@ -3072,25 +3038,33 @@ MemTxResult address_space_read_full(AddressSpace *as, hwaddr addr,
|
||||
if (len > 0) {
|
||||
rcu_read_lock();
|
||||
l = len;
|
||||
mr = address_space_translate(as, addr, &addr1, &l, false);
|
||||
result = address_space_read_continue(as, addr, attrs, buf, len,
|
||||
addr1, l, mr);
|
||||
mr = flatview_translate(fv, addr, &addr1, &l, false);
|
||||
result = flatview_read_continue(fv, addr, attrs, buf, len,
|
||||
addr1, l, mr);
|
||||
rcu_read_unlock();
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
MemTxResult address_space_rw(AddressSpace *as, hwaddr addr, MemTxAttrs attrs,
|
||||
uint8_t *buf, int len, bool is_write)
|
||||
static MemTxResult flatview_rw(FlatView *fv, hwaddr addr, MemTxAttrs attrs,
|
||||
uint8_t *buf, int len, bool is_write)
|
||||
{
|
||||
if (is_write) {
|
||||
return address_space_write(as, addr, attrs, (uint8_t *)buf, len);
|
||||
return flatview_write(fv, addr, attrs, (uint8_t *)buf, len);
|
||||
} else {
|
||||
return address_space_read(as, addr, attrs, (uint8_t *)buf, len);
|
||||
return flatview_read(fv, addr, attrs, (uint8_t *)buf, len);
|
||||
}
|
||||
}
|
||||
|
||||
MemTxResult address_space_rw(AddressSpace *as, hwaddr addr,
|
||||
MemTxAttrs attrs, uint8_t *buf,
|
||||
int len, bool is_write)
|
||||
{
|
||||
return flatview_rw(address_space_to_flatview(as),
|
||||
addr, attrs, buf, len, is_write);
|
||||
}
|
||||
|
||||
void cpu_physical_memory_rw(hwaddr addr, uint8_t *buf,
|
||||
int len, int is_write)
|
||||
{
|
||||
@@ -3248,7 +3222,8 @@ static void cpu_notify_map_clients(void)
|
||||
qemu_mutex_unlock(&map_client_list_lock);
|
||||
}
|
||||
|
||||
bool address_space_access_valid(AddressSpace *as, hwaddr addr, int len, bool is_write)
|
||||
static bool flatview_access_valid(FlatView *fv, hwaddr addr, int len,
|
||||
bool is_write)
|
||||
{
|
||||
MemoryRegion *mr;
|
||||
hwaddr l, xlat;
|
||||
@@ -3256,7 +3231,7 @@ bool address_space_access_valid(AddressSpace *as, hwaddr addr, int len, bool is_
|
||||
rcu_read_lock();
|
||||
while (len > 0) {
|
||||
l = len;
|
||||
mr = address_space_translate(as, addr, &xlat, &l, is_write);
|
||||
mr = flatview_translate(fv, addr, &xlat, &l, is_write);
|
||||
if (!memory_access_is_direct(mr, is_write)) {
|
||||
l = memory_access_size(mr, l, addr);
|
||||
if (!memory_region_access_valid(mr, xlat, l, is_write)) {
|
||||
@@ -3272,8 +3247,16 @@ bool address_space_access_valid(AddressSpace *as, hwaddr addr, int len, bool is_
|
||||
return true;
|
||||
}
|
||||
|
||||
bool address_space_access_valid(AddressSpace *as, hwaddr addr,
|
||||
int len, bool is_write)
|
||||
{
|
||||
return flatview_access_valid(address_space_to_flatview(as),
|
||||
addr, len, is_write);
|
||||
}
|
||||
|
||||
static hwaddr
|
||||
address_space_extend_translation(AddressSpace *as, hwaddr addr, hwaddr target_len,
|
||||
flatview_extend_translation(FlatView *fv, hwaddr addr,
|
||||
hwaddr target_len,
|
||||
MemoryRegion *mr, hwaddr base, hwaddr len,
|
||||
bool is_write)
|
||||
{
|
||||
@@ -3290,7 +3273,8 @@ address_space_extend_translation(AddressSpace *as, hwaddr addr, hwaddr target_le
|
||||
}
|
||||
|
||||
len = target_len;
|
||||
this_mr = address_space_translate(as, addr, &xlat, &len, is_write);
|
||||
this_mr = flatview_translate(fv, addr, &xlat,
|
||||
&len, is_write);
|
||||
if (this_mr != mr || xlat != base + done) {
|
||||
return done;
|
||||
}
|
||||
@@ -3313,6 +3297,7 @@ void *address_space_map(AddressSpace *as,
|
||||
hwaddr l, xlat;
|
||||
MemoryRegion *mr;
|
||||
void *ptr;
|
||||
FlatView *fv = address_space_to_flatview(as);
|
||||
|
||||
if (len == 0) {
|
||||
return NULL;
|
||||
@@ -3320,7 +3305,7 @@ void *address_space_map(AddressSpace *as,
|
||||
|
||||
l = len;
|
||||
rcu_read_lock();
|
||||
mr = address_space_translate(as, addr, &xlat, &l, is_write);
|
||||
mr = flatview_translate(fv, addr, &xlat, &l, is_write);
|
||||
|
||||
if (!memory_access_is_direct(mr, is_write)) {
|
||||
if (atomic_xchg(&bounce.in_use, true)) {
|
||||
@@ -3336,7 +3321,7 @@ void *address_space_map(AddressSpace *as,
|
||||
memory_region_ref(mr);
|
||||
bounce.mr = mr;
|
||||
if (!is_write) {
|
||||
address_space_read(as, addr, MEMTXATTRS_UNSPECIFIED,
|
||||
flatview_read(fv, addr, MEMTXATTRS_UNSPECIFIED,
|
||||
bounce.buffer, l);
|
||||
}
|
||||
|
||||
@@ -3347,7 +3332,8 @@ void *address_space_map(AddressSpace *as,
|
||||
|
||||
|
||||
memory_region_ref(mr);
|
||||
*plen = address_space_extend_translation(as, addr, len, mr, xlat, l, is_write);
|
||||
*plen = flatview_extend_translation(fv, addr, len, mr, xlat,
|
||||
l, is_write);
|
||||
ptr = qemu_ram_ptr_length(mr->ram_block, xlat, plen, true);
|
||||
rcu_read_unlock();
|
||||
|
||||
@@ -3630,3 +3616,87 @@ void page_size_init(void)
|
||||
}
|
||||
qemu_host_page_mask = -(intptr_t)qemu_host_page_size;
|
||||
}
|
||||
|
||||
#if !defined(CONFIG_USER_ONLY)
|
||||
|
||||
static void mtree_print_phys_entries(fprintf_function mon, void *f,
|
||||
int start, int end, int skip, int ptr)
|
||||
{
|
||||
if (start == end - 1) {
|
||||
mon(f, "\t%3d ", start);
|
||||
} else {
|
||||
mon(f, "\t%3d..%-3d ", start, end - 1);
|
||||
}
|
||||
mon(f, " skip=%d ", skip);
|
||||
if (ptr == PHYS_MAP_NODE_NIL) {
|
||||
mon(f, " ptr=NIL");
|
||||
} else if (!skip) {
|
||||
mon(f, " ptr=#%d", ptr);
|
||||
} else {
|
||||
mon(f, " ptr=[%d]", ptr);
|
||||
}
|
||||
mon(f, "\n");
|
||||
}
|
||||
|
||||
#define MR_SIZE(size) (int128_nz(size) ? (hwaddr)int128_get64( \
|
||||
int128_sub((size), int128_one())) : 0)
|
||||
|
||||
void mtree_print_dispatch(fprintf_function mon, void *f,
|
||||
AddressSpaceDispatch *d, MemoryRegion *root)
|
||||
{
|
||||
int i;
|
||||
|
||||
mon(f, " Dispatch\n");
|
||||
mon(f, " Physical sections\n");
|
||||
|
||||
for (i = 0; i < d->map.sections_nb; ++i) {
|
||||
MemoryRegionSection *s = d->map.sections + i;
|
||||
const char *names[] = { " [unassigned]", " [not dirty]",
|
||||
" [ROM]", " [watch]" };
|
||||
|
||||
mon(f, " #%d @" TARGET_FMT_plx ".." TARGET_FMT_plx " %s%s%s%s%s",
|
||||
i,
|
||||
s->offset_within_address_space,
|
||||
s->offset_within_address_space + MR_SIZE(s->mr->size),
|
||||
s->mr->name ? s->mr->name : "(noname)",
|
||||
i < ARRAY_SIZE(names) ? names[i] : "",
|
||||
s->mr == root ? " [ROOT]" : "",
|
||||
s == d->mru_section ? " [MRU]" : "",
|
||||
s->mr->is_iommu ? " [iommu]" : "");
|
||||
|
||||
if (s->mr->alias) {
|
||||
mon(f, " alias=%s", s->mr->alias->name ?
|
||||
s->mr->alias->name : "noname");
|
||||
}
|
||||
mon(f, "\n");
|
||||
}
|
||||
|
||||
mon(f, " Nodes (%d bits per level, %d levels) ptr=[%d] skip=%d\n",
|
||||
P_L2_BITS, P_L2_LEVELS, d->phys_map.ptr, d->phys_map.skip);
|
||||
for (i = 0; i < d->map.nodes_nb; ++i) {
|
||||
int j, jprev;
|
||||
PhysPageEntry prev;
|
||||
Node *n = d->map.nodes + i;
|
||||
|
||||
mon(f, " [%d]\n", i);
|
||||
|
||||
for (j = 0, jprev = 0, prev = *n[0]; j < ARRAY_SIZE(*n); ++j) {
|
||||
PhysPageEntry *pe = *n + j;
|
||||
|
||||
if (pe->ptr == prev.ptr && pe->skip == prev.skip) {
|
||||
continue;
|
||||
}
|
||||
|
||||
mtree_print_phys_entries(mon, f, jprev, j, prev.skip, prev.ptr);
|
||||
|
||||
jprev = j;
|
||||
prev = *pe;
|
||||
}
|
||||
|
||||
if (jprev != ARRAY_SIZE(*n)) {
|
||||
mtree_print_phys_entries(mon, f, jprev, j, prev.skip, prev.ptr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@@ -250,9 +250,10 @@ ETEXI
|
||||
|
||||
{
|
||||
.name = "mtree",
|
||||
.args_type = "flatview:-f",
|
||||
.params = "[-f]",
|
||||
.help = "show memory tree (-f: dump flat view for address spaces)",
|
||||
.args_type = "flatview:-f,dispatch_tree:-d",
|
||||
.params = "[-f][-d]",
|
||||
.help = "show memory tree (-f: dump flat view for address spaces;"
|
||||
"-d: dump dispatch tree, valid with -f only)",
|
||||
.cmd = hmp_info_mtree,
|
||||
},
|
||||
|
||||
|
||||
14
hmp.c
14
hmp.c
@@ -336,6 +336,12 @@ void hmp_info_migrate_parameters(Monitor *mon, const QDict *qdict)
|
||||
monitor_printf(mon, "%s: %s\n",
|
||||
MigrationParameter_str(MIGRATION_PARAMETER_BLOCK_INCREMENTAL),
|
||||
params->block_incremental ? "on" : "off");
|
||||
monitor_printf(mon, "%s: %" PRId64 "\n",
|
||||
MigrationParameter_str(MIGRATION_PARAMETER_X_MULTIFD_CHANNELS),
|
||||
params->x_multifd_channels);
|
||||
monitor_printf(mon, "%s: %" PRId64 "\n",
|
||||
MigrationParameter_str(MIGRATION_PARAMETER_X_MULTIFD_PAGE_COUNT),
|
||||
params->x_multifd_page_count);
|
||||
}
|
||||
|
||||
qapi_free_MigrationParameters(params);
|
||||
@@ -1621,6 +1627,14 @@ void hmp_migrate_set_parameter(Monitor *mon, const QDict *qdict)
|
||||
p->has_block_incremental = true;
|
||||
visit_type_bool(v, param, &p->block_incremental, &err);
|
||||
break;
|
||||
case MIGRATION_PARAMETER_X_MULTIFD_CHANNELS:
|
||||
p->has_x_multifd_channels = true;
|
||||
visit_type_int(v, param, &p->x_multifd_channels, &err);
|
||||
break;
|
||||
case MIGRATION_PARAMETER_X_MULTIFD_PAGE_COUNT:
|
||||
p->has_x_multifd_page_count = true;
|
||||
visit_type_int(v, param, &p->x_multifd_page_count, &err);
|
||||
break;
|
||||
default:
|
||||
assert(0);
|
||||
}
|
||||
|
||||
@@ -19,3 +19,4 @@ obj-$(CONFIG_FSL_IMX31) += fsl-imx31.o kzm.o
|
||||
obj-$(CONFIG_FSL_IMX6) += fsl-imx6.o sabrelite.o
|
||||
obj-$(CONFIG_ASPEED_SOC) += aspeed_soc.o aspeed.o
|
||||
obj-$(CONFIG_MPS2) += mps2.o
|
||||
obj-$(CONFIG_MSF2) += msf2-soc.o msf2-som.o
|
||||
|
||||
@@ -41,7 +41,7 @@ static MemTxResult bitband_read(void *opaque, hwaddr offset,
|
||||
|
||||
/* Find address in underlying memory and round down to multiple of size */
|
||||
addr = bitband_addr(s, offset) & (-size);
|
||||
res = address_space_read(s->source_as, addr, attrs, buf, size);
|
||||
res = address_space_read(&s->source_as, addr, attrs, buf, size);
|
||||
if (res) {
|
||||
return res;
|
||||
}
|
||||
@@ -66,7 +66,7 @@ static MemTxResult bitband_write(void *opaque, hwaddr offset, uint64_t value,
|
||||
|
||||
/* Find address in underlying memory and round down to multiple of size */
|
||||
addr = bitband_addr(s, offset) & (-size);
|
||||
res = address_space_read(s->source_as, addr, attrs, buf, size);
|
||||
res = address_space_read(&s->source_as, addr, attrs, buf, size);
|
||||
if (res) {
|
||||
return res;
|
||||
}
|
||||
@@ -79,7 +79,7 @@ static MemTxResult bitband_write(void *opaque, hwaddr offset, uint64_t value,
|
||||
} else {
|
||||
buf[bitpos >> 3] &= ~bit;
|
||||
}
|
||||
return address_space_write(s->source_as, addr, attrs, buf, size);
|
||||
return address_space_write(&s->source_as, addr, attrs, buf, size);
|
||||
}
|
||||
|
||||
static const MemoryRegionOps bitband_ops = {
|
||||
@@ -111,8 +111,7 @@ static void bitband_realize(DeviceState *dev, Error **errp)
|
||||
return;
|
||||
}
|
||||
|
||||
s->source_as = address_space_init_shareable(s->source_memory,
|
||||
"bitband-source");
|
||||
address_space_init(&s->source_as, s->source_memory, "bitband-source");
|
||||
}
|
||||
|
||||
/* Board init. */
|
||||
|
||||
238
hw/arm/msf2-soc.c
Normal file
238
hw/arm/msf2-soc.c
Normal file
@@ -0,0 +1,238 @@
|
||||
/*
|
||||
* SmartFusion2 SoC emulation.
|
||||
*
|
||||
* Copyright (c) 2017 Subbaraya Sundeep <sundeep.lkml@gmail.com>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "qapi/error.h"
|
||||
#include "qemu-common.h"
|
||||
#include "hw/arm/arm.h"
|
||||
#include "exec/address-spaces.h"
|
||||
#include "hw/char/serial.h"
|
||||
#include "hw/boards.h"
|
||||
#include "sysemu/block-backend.h"
|
||||
#include "qemu/cutils.h"
|
||||
#include "hw/arm/msf2-soc.h"
|
||||
#include "hw/misc/unimp.h"
|
||||
|
||||
#define MSF2_TIMER_BASE 0x40004000
|
||||
#define MSF2_SYSREG_BASE 0x40038000
|
||||
|
||||
#define ENVM_BASE_ADDRESS 0x60000000
|
||||
|
||||
#define SRAM_BASE_ADDRESS 0x20000000
|
||||
|
||||
#define MSF2_ENVM_MAX_SIZE (512 * K_BYTE)
|
||||
|
||||
/*
|
||||
* eSRAM max size is 80k without SECDED(Single error correction and
|
||||
* dual error detection) feature and 64k with SECDED.
|
||||
* We do not support SECDED now.
|
||||
*/
|
||||
#define MSF2_ESRAM_MAX_SIZE (80 * K_BYTE)
|
||||
|
||||
static const uint32_t spi_addr[MSF2_NUM_SPIS] = { 0x40001000 , 0x40011000 };
|
||||
static const uint32_t uart_addr[MSF2_NUM_UARTS] = { 0x40000000 , 0x40010000 };
|
||||
|
||||
static const int spi_irq[MSF2_NUM_SPIS] = { 2, 3 };
|
||||
static const int uart_irq[MSF2_NUM_UARTS] = { 10, 11 };
|
||||
static const int timer_irq[MSF2_NUM_TIMERS] = { 14, 15 };
|
||||
|
||||
static void m2sxxx_soc_initfn(Object *obj)
|
||||
{
|
||||
MSF2State *s = MSF2_SOC(obj);
|
||||
int i;
|
||||
|
||||
object_initialize(&s->armv7m, sizeof(s->armv7m), TYPE_ARMV7M);
|
||||
qdev_set_parent_bus(DEVICE(&s->armv7m), sysbus_get_default());
|
||||
|
||||
object_initialize(&s->sysreg, sizeof(s->sysreg), TYPE_MSF2_SYSREG);
|
||||
qdev_set_parent_bus(DEVICE(&s->sysreg), sysbus_get_default());
|
||||
|
||||
object_initialize(&s->timer, sizeof(s->timer), TYPE_MSS_TIMER);
|
||||
qdev_set_parent_bus(DEVICE(&s->timer), sysbus_get_default());
|
||||
|
||||
for (i = 0; i < MSF2_NUM_SPIS; i++) {
|
||||
object_initialize(&s->spi[i], sizeof(s->spi[i]),
|
||||
TYPE_MSS_SPI);
|
||||
qdev_set_parent_bus(DEVICE(&s->spi[i]), sysbus_get_default());
|
||||
}
|
||||
}
|
||||
|
||||
static void m2sxxx_soc_realize(DeviceState *dev_soc, Error **errp)
|
||||
{
|
||||
MSF2State *s = MSF2_SOC(dev_soc);
|
||||
DeviceState *dev, *armv7m;
|
||||
SysBusDevice *busdev;
|
||||
Error *err = NULL;
|
||||
int i;
|
||||
|
||||
MemoryRegion *system_memory = get_system_memory();
|
||||
MemoryRegion *nvm = g_new(MemoryRegion, 1);
|
||||
MemoryRegion *nvm_alias = g_new(MemoryRegion, 1);
|
||||
MemoryRegion *sram = g_new(MemoryRegion, 1);
|
||||
|
||||
memory_region_init_rom(nvm, NULL, "MSF2.eNVM", s->envm_size,
|
||||
&error_fatal);
|
||||
/*
|
||||
* On power-on, the eNVM region 0x60000000 is automatically
|
||||
* remapped to the Cortex-M3 processor executable region
|
||||
* start address (0x0). We do not support remapping other eNVM,
|
||||
* eSRAM and DDR regions by guest(via Sysreg) currently.
|
||||
*/
|
||||
memory_region_init_alias(nvm_alias, NULL, "MSF2.eNVM",
|
||||
nvm, 0, s->envm_size);
|
||||
|
||||
memory_region_add_subregion(system_memory, ENVM_BASE_ADDRESS, nvm);
|
||||
memory_region_add_subregion(system_memory, 0, nvm_alias);
|
||||
|
||||
memory_region_init_ram(sram, NULL, "MSF2.eSRAM", s->esram_size,
|
||||
&error_fatal);
|
||||
memory_region_add_subregion(system_memory, SRAM_BASE_ADDRESS, sram);
|
||||
|
||||
armv7m = DEVICE(&s->armv7m);
|
||||
qdev_prop_set_uint32(armv7m, "num-irq", 81);
|
||||
qdev_prop_set_string(armv7m, "cpu-type", s->cpu_type);
|
||||
object_property_set_link(OBJECT(&s->armv7m), OBJECT(get_system_memory()),
|
||||
"memory", &error_abort);
|
||||
object_property_set_bool(OBJECT(&s->armv7m), true, "realized", &err);
|
||||
if (err != NULL) {
|
||||
error_propagate(errp, err);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!s->m3clk) {
|
||||
error_setg(errp, "Invalid m3clk value");
|
||||
error_append_hint(errp, "m3clk can not be zero\n");
|
||||
return;
|
||||
}
|
||||
system_clock_scale = NANOSECONDS_PER_SECOND / s->m3clk;
|
||||
|
||||
for (i = 0; i < MSF2_NUM_UARTS; i++) {
|
||||
if (serial_hds[i]) {
|
||||
serial_mm_init(get_system_memory(), uart_addr[i], 2,
|
||||
qdev_get_gpio_in(armv7m, uart_irq[i]),
|
||||
115200, serial_hds[i], DEVICE_NATIVE_ENDIAN);
|
||||
}
|
||||
}
|
||||
|
||||
dev = DEVICE(&s->timer);
|
||||
/* APB0 clock is the timer input clock */
|
||||
qdev_prop_set_uint32(dev, "clock-frequency", s->m3clk / s->apb0div);
|
||||
object_property_set_bool(OBJECT(&s->timer), true, "realized", &err);
|
||||
if (err != NULL) {
|
||||
error_propagate(errp, err);
|
||||
return;
|
||||
}
|
||||
busdev = SYS_BUS_DEVICE(dev);
|
||||
sysbus_mmio_map(busdev, 0, MSF2_TIMER_BASE);
|
||||
sysbus_connect_irq(busdev, 0,
|
||||
qdev_get_gpio_in(armv7m, timer_irq[0]));
|
||||
sysbus_connect_irq(busdev, 1,
|
||||
qdev_get_gpio_in(armv7m, timer_irq[1]));
|
||||
|
||||
dev = DEVICE(&s->sysreg);
|
||||
qdev_prop_set_uint32(dev, "apb0divisor", s->apb0div);
|
||||
qdev_prop_set_uint32(dev, "apb1divisor", s->apb1div);
|
||||
object_property_set_bool(OBJECT(&s->sysreg), true, "realized", &err);
|
||||
if (err != NULL) {
|
||||
error_propagate(errp, err);
|
||||
return;
|
||||
}
|
||||
busdev = SYS_BUS_DEVICE(dev);
|
||||
sysbus_mmio_map(busdev, 0, MSF2_SYSREG_BASE);
|
||||
|
||||
for (i = 0; i < MSF2_NUM_SPIS; i++) {
|
||||
gchar *bus_name;
|
||||
|
||||
object_property_set_bool(OBJECT(&s->spi[i]), true, "realized", &err);
|
||||
if (err != NULL) {
|
||||
error_propagate(errp, err);
|
||||
return;
|
||||
}
|
||||
|
||||
sysbus_mmio_map(SYS_BUS_DEVICE(&s->spi[i]), 0, spi_addr[i]);
|
||||
sysbus_connect_irq(SYS_BUS_DEVICE(&s->spi[i]), 0,
|
||||
qdev_get_gpio_in(armv7m, spi_irq[i]));
|
||||
|
||||
/* Alias controller SPI bus to the SoC itself */
|
||||
bus_name = g_strdup_printf("spi%d", i);
|
||||
object_property_add_alias(OBJECT(s), bus_name,
|
||||
OBJECT(&s->spi[i]), "spi",
|
||||
&error_abort);
|
||||
g_free(bus_name);
|
||||
}
|
||||
|
||||
/* Below devices are not modelled yet. */
|
||||
create_unimplemented_device("i2c_0", 0x40002000, 0x1000);
|
||||
create_unimplemented_device("dma", 0x40003000, 0x1000);
|
||||
create_unimplemented_device("watchdog", 0x40005000, 0x1000);
|
||||
create_unimplemented_device("i2c_1", 0x40012000, 0x1000);
|
||||
create_unimplemented_device("gpio", 0x40013000, 0x1000);
|
||||
create_unimplemented_device("hs-dma", 0x40014000, 0x1000);
|
||||
create_unimplemented_device("can", 0x40015000, 0x1000);
|
||||
create_unimplemented_device("rtc", 0x40017000, 0x1000);
|
||||
create_unimplemented_device("apb_config", 0x40020000, 0x10000);
|
||||
create_unimplemented_device("emac", 0x40041000, 0x1000);
|
||||
create_unimplemented_device("usb", 0x40043000, 0x1000);
|
||||
}
|
||||
|
||||
static Property m2sxxx_soc_properties[] = {
|
||||
/*
|
||||
* part name specifies the type of SmartFusion2 device variant(this
|
||||
* property is for information purpose only.
|
||||
*/
|
||||
DEFINE_PROP_STRING("cpu-type", MSF2State, cpu_type),
|
||||
DEFINE_PROP_STRING("part-name", MSF2State, part_name),
|
||||
DEFINE_PROP_UINT64("eNVM-size", MSF2State, envm_size, MSF2_ENVM_MAX_SIZE),
|
||||
DEFINE_PROP_UINT64("eSRAM-size", MSF2State, esram_size,
|
||||
MSF2_ESRAM_MAX_SIZE),
|
||||
/* Libero GUI shows 100Mhz as default for clocks */
|
||||
DEFINE_PROP_UINT32("m3clk", MSF2State, m3clk, 100 * 1000000),
|
||||
/* default divisors in Libero GUI */
|
||||
DEFINE_PROP_UINT8("apb0div", MSF2State, apb0div, 2),
|
||||
DEFINE_PROP_UINT8("apb1div", MSF2State, apb1div, 2),
|
||||
DEFINE_PROP_END_OF_LIST(),
|
||||
};
|
||||
|
||||
static void m2sxxx_soc_class_init(ObjectClass *klass, void *data)
|
||||
{
|
||||
DeviceClass *dc = DEVICE_CLASS(klass);
|
||||
|
||||
dc->realize = m2sxxx_soc_realize;
|
||||
dc->props = m2sxxx_soc_properties;
|
||||
}
|
||||
|
||||
static const TypeInfo m2sxxx_soc_info = {
|
||||
.name = TYPE_MSF2_SOC,
|
||||
.parent = TYPE_SYS_BUS_DEVICE,
|
||||
.instance_size = sizeof(MSF2State),
|
||||
.instance_init = m2sxxx_soc_initfn,
|
||||
.class_init = m2sxxx_soc_class_init,
|
||||
};
|
||||
|
||||
static void m2sxxx_soc_types(void)
|
||||
{
|
||||
type_register_static(&m2sxxx_soc_info);
|
||||
}
|
||||
|
||||
type_init(m2sxxx_soc_types)
|
||||
105
hw/arm/msf2-som.c
Normal file
105
hw/arm/msf2-som.c
Normal file
@@ -0,0 +1,105 @@
|
||||
/*
|
||||
* SmartFusion2 SOM starter kit(from Emcraft) emulation.
|
||||
*
|
||||
* Copyright (c) 2017 Subbaraya Sundeep <sundeep.lkml@gmail.com>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "qapi/error.h"
|
||||
#include "qemu/error-report.h"
|
||||
#include "hw/boards.h"
|
||||
#include "hw/arm/arm.h"
|
||||
#include "exec/address-spaces.h"
|
||||
#include "qemu/cutils.h"
|
||||
#include "hw/arm/msf2-soc.h"
|
||||
#include "cpu.h"
|
||||
|
||||
#define DDR_BASE_ADDRESS 0xA0000000
|
||||
#define DDR_SIZE (64 * M_BYTE)
|
||||
|
||||
#define M2S010_ENVM_SIZE (256 * K_BYTE)
|
||||
#define M2S010_ESRAM_SIZE (64 * K_BYTE)
|
||||
|
||||
static void emcraft_sf2_s2s010_init(MachineState *machine)
|
||||
{
|
||||
DeviceState *dev;
|
||||
DeviceState *spi_flash;
|
||||
MSF2State *soc;
|
||||
MachineClass *mc = MACHINE_GET_CLASS(machine);
|
||||
DriveInfo *dinfo = drive_get_next(IF_MTD);
|
||||
qemu_irq cs_line;
|
||||
SSIBus *spi_bus;
|
||||
MemoryRegion *sysmem = get_system_memory();
|
||||
MemoryRegion *ddr = g_new(MemoryRegion, 1);
|
||||
|
||||
if (strcmp(machine->cpu_type, mc->default_cpu_type) != 0) {
|
||||
error_report("This board can only be used with CPU %s",
|
||||
mc->default_cpu_type);
|
||||
}
|
||||
|
||||
memory_region_init_ram(ddr, NULL, "ddr-ram", DDR_SIZE,
|
||||
&error_fatal);
|
||||
memory_region_add_subregion(sysmem, DDR_BASE_ADDRESS, ddr);
|
||||
|
||||
dev = qdev_create(NULL, TYPE_MSF2_SOC);
|
||||
qdev_prop_set_string(dev, "part-name", "M2S010");
|
||||
qdev_prop_set_string(dev, "cpu-type", mc->default_cpu_type);
|
||||
|
||||
qdev_prop_set_uint64(dev, "eNVM-size", M2S010_ENVM_SIZE);
|
||||
qdev_prop_set_uint64(dev, "eSRAM-size", M2S010_ESRAM_SIZE);
|
||||
|
||||
/*
|
||||
* CPU clock and peripheral clocks(APB0, APB1)are configurable
|
||||
* in Libero. CPU clock is divided by APB0 and APB1 divisors for
|
||||
* peripherals. Emcraft's SoM kit comes with these settings by default.
|
||||
*/
|
||||
qdev_prop_set_uint32(dev, "m3clk", 142 * 1000000);
|
||||
qdev_prop_set_uint32(dev, "apb0div", 2);
|
||||
qdev_prop_set_uint32(dev, "apb1div", 2);
|
||||
|
||||
object_property_set_bool(OBJECT(dev), true, "realized", &error_fatal);
|
||||
|
||||
soc = MSF2_SOC(dev);
|
||||
|
||||
/* Attach SPI flash to SPI0 controller */
|
||||
spi_bus = (SSIBus *)qdev_get_child_bus(dev, "spi0");
|
||||
spi_flash = ssi_create_slave_no_init(spi_bus, "s25sl12801");
|
||||
qdev_prop_set_uint8(spi_flash, "spansion-cr2nv", 1);
|
||||
if (dinfo) {
|
||||
qdev_prop_set_drive(spi_flash, "drive", blk_by_legacy_dinfo(dinfo),
|
||||
&error_fatal);
|
||||
}
|
||||
qdev_init_nofail(spi_flash);
|
||||
cs_line = qdev_get_gpio_in_named(spi_flash, SSI_GPIO_CS, 0);
|
||||
sysbus_connect_irq(SYS_BUS_DEVICE(&soc->spi[0]), 1, cs_line);
|
||||
|
||||
armv7m_load_kernel(ARM_CPU(first_cpu), machine->kernel_filename,
|
||||
soc->envm_size);
|
||||
}
|
||||
|
||||
static void emcraft_sf2_machine_init(MachineClass *mc)
|
||||
{
|
||||
mc->desc = "SmartFusion2 SOM kit from Emcraft (M2S010)";
|
||||
mc->init = emcraft_sf2_s2s010_init;
|
||||
mc->default_cpu_type = ARM_CPU_TYPE_NAME("cortex-m3");
|
||||
}
|
||||
|
||||
DEFINE_MACHINE("emcraft-sf2", emcraft_sf2_machine_init)
|
||||
@@ -2087,19 +2087,44 @@ static void omap_sysctl_write(void *opaque, hwaddr addr,
|
||||
}
|
||||
}
|
||||
|
||||
static uint64_t omap_sysctl_readfn(void *opaque, hwaddr addr,
|
||||
unsigned size)
|
||||
{
|
||||
switch (size) {
|
||||
case 1:
|
||||
return omap_sysctl_read8(opaque, addr);
|
||||
case 2:
|
||||
return omap_badwidth_read32(opaque, addr); /* TODO */
|
||||
case 4:
|
||||
return omap_sysctl_read(opaque, addr);
|
||||
default:
|
||||
g_assert_not_reached();
|
||||
}
|
||||
}
|
||||
|
||||
static void omap_sysctl_writefn(void *opaque, hwaddr addr,
|
||||
uint64_t value, unsigned size)
|
||||
{
|
||||
switch (size) {
|
||||
case 1:
|
||||
omap_sysctl_write8(opaque, addr, value);
|
||||
break;
|
||||
case 2:
|
||||
omap_badwidth_write32(opaque, addr, value); /* TODO */
|
||||
break;
|
||||
case 4:
|
||||
omap_sysctl_write(opaque, addr, value);
|
||||
break;
|
||||
default:
|
||||
g_assert_not_reached();
|
||||
}
|
||||
}
|
||||
|
||||
static const MemoryRegionOps omap_sysctl_ops = {
|
||||
.old_mmio = {
|
||||
.read = {
|
||||
omap_sysctl_read8,
|
||||
omap_badwidth_read32, /* TODO */
|
||||
omap_sysctl_read,
|
||||
},
|
||||
.write = {
|
||||
omap_sysctl_write8,
|
||||
omap_badwidth_write32, /* TODO */
|
||||
omap_sysctl_write,
|
||||
},
|
||||
},
|
||||
.read = omap_sysctl_readfn,
|
||||
.write = omap_sysctl_writefn,
|
||||
.valid.min_access_size = 1,
|
||||
.valid.max_access_size = 4,
|
||||
.endianness = DEVICE_NATIVE_ENDIAN,
|
||||
};
|
||||
|
||||
|
||||
@@ -31,26 +31,16 @@
|
||||
#include "exec/address-spaces.h"
|
||||
#include "cpu.h"
|
||||
|
||||
static uint32_t static_readb(void *opaque, hwaddr offset)
|
||||
static uint64_t static_read(void *opaque, hwaddr offset, unsigned size)
|
||||
{
|
||||
uint32_t *val = (uint32_t *) opaque;
|
||||
return *val >> ((offset & 3) << 3);
|
||||
uint32_t *val = (uint32_t *)opaque;
|
||||
uint32_t sizemask = 7 >> size;
|
||||
|
||||
return *val >> ((offset & sizemask) << 3);
|
||||
}
|
||||
|
||||
static uint32_t static_readh(void *opaque, hwaddr offset)
|
||||
{
|
||||
uint32_t *val = (uint32_t *) opaque;
|
||||
return *val >> ((offset & 1) << 3);
|
||||
}
|
||||
|
||||
static uint32_t static_readw(void *opaque, hwaddr offset)
|
||||
{
|
||||
uint32_t *val = (uint32_t *) opaque;
|
||||
return *val >> ((offset & 0) << 3);
|
||||
}
|
||||
|
||||
static void static_write(void *opaque, hwaddr offset,
|
||||
uint32_t value)
|
||||
static void static_write(void *opaque, hwaddr offset, uint64_t value,
|
||||
unsigned size)
|
||||
{
|
||||
#ifdef SPY
|
||||
printf("%s: value %08lx written at " PA_FMT "\n",
|
||||
@@ -59,10 +49,10 @@ static void static_write(void *opaque, hwaddr offset,
|
||||
}
|
||||
|
||||
static const MemoryRegionOps static_ops = {
|
||||
.old_mmio = {
|
||||
.read = { static_readb, static_readh, static_readw, },
|
||||
.write = { static_write, static_write, static_write, },
|
||||
},
|
||||
.read = static_read,
|
||||
.write = static_write,
|
||||
.valid.min_access_size = 1,
|
||||
.valid.max_access_size = 4,
|
||||
.endianness = DEVICE_NATIVE_ENDIAN,
|
||||
};
|
||||
|
||||
|
||||
@@ -187,6 +187,26 @@ static int chr_be_change(void *opaque)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void virtconsole_enable_backend(VirtIOSerialPort *port, bool enable)
|
||||
{
|
||||
VirtConsole *vcon = VIRTIO_CONSOLE(port);
|
||||
|
||||
if (!qemu_chr_fe_backend_connected(&vcon->chr)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (enable) {
|
||||
VirtIOSerialPortClass *k = VIRTIO_SERIAL_PORT_GET_CLASS(port);
|
||||
|
||||
qemu_chr_fe_set_handlers(&vcon->chr, chr_can_read, chr_read,
|
||||
k->is_console ? NULL : chr_event,
|
||||
chr_be_change, vcon, NULL, false);
|
||||
} else {
|
||||
qemu_chr_fe_set_handlers(&vcon->chr, NULL, NULL, NULL,
|
||||
NULL, NULL, NULL, false);
|
||||
}
|
||||
}
|
||||
|
||||
static void virtconsole_realize(DeviceState *dev, Error **errp)
|
||||
{
|
||||
VirtIOSerialPort *port = VIRTIO_SERIAL_PORT(dev);
|
||||
@@ -258,6 +278,7 @@ static void virtserialport_class_init(ObjectClass *klass, void *data)
|
||||
k->unrealize = virtconsole_unrealize;
|
||||
k->have_data = flush_buf;
|
||||
k->set_guest_connected = set_guest_connected;
|
||||
k->enable_backend = virtconsole_enable_backend;
|
||||
k->guest_writable = guest_writable;
|
||||
dc->props = virtserialport_properties;
|
||||
}
|
||||
|
||||
@@ -637,6 +637,13 @@ static void set_status(VirtIODevice *vdev, uint8_t status)
|
||||
if (!(status & VIRTIO_CONFIG_S_DRIVER_OK)) {
|
||||
guest_reset(vser);
|
||||
}
|
||||
|
||||
QTAILQ_FOREACH(port, &vser->ports, next) {
|
||||
VirtIOSerialPortClass *vsc = VIRTIO_SERIAL_PORT_GET_CLASS(port);
|
||||
if (vsc->enable_backend) {
|
||||
vsc->enable_backend(port, vdev->vm_running);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void vser_reset(VirtIODevice *vdev)
|
||||
|
||||
@@ -6,6 +6,7 @@ jazz_led_write(uint64_t addr, uint8_t new) "write addr=0x%"PRIx64": 0x%x"
|
||||
|
||||
# hw/display/xenfb.c
|
||||
xenfb_mouse_event(void *opaque, int dx, int dy, int dz, int button_state, int abs_pointer_wanted) "%p x %d y %d z %d bs 0x%x abs %d"
|
||||
xenfb_key_event(void *opaque, int scancode, int button_state) "%p scancode %d bs 0x%x"
|
||||
xenfb_input_connected(void *xendev, int abs_pointer_wanted) "%p abs %d"
|
||||
|
||||
# hw/display/g364fb.c
|
||||
|
||||
@@ -1321,6 +1321,7 @@ static void virtio_gpu_class_init(ObjectClass *klass, void *data)
|
||||
|
||||
vdc->reset = virtio_gpu_reset;
|
||||
|
||||
set_bit(DEVICE_CATEGORY_DISPLAY, dc->categories);
|
||||
dc->props = virtio_gpu_properties;
|
||||
dc->vmsd = &vmstate_virtio_gpu;
|
||||
dc->hotpluggable = false;
|
||||
|
||||
@@ -290,6 +290,7 @@ static void xenfb_key_event(void *opaque, int scancode)
|
||||
scancode |= 0x80;
|
||||
xenfb->extended = 0;
|
||||
}
|
||||
trace_xenfb_key_event(opaque, scancode2linux[scancode], down);
|
||||
xenfb_send_key(xenfb, down, scancode2linux[scancode]);
|
||||
}
|
||||
|
||||
|
||||
@@ -525,17 +525,23 @@ static void omap2_gpio_module_write(void *opaque, hwaddr addr,
|
||||
}
|
||||
}
|
||||
|
||||
static uint32_t omap2_gpio_module_readp(void *opaque, hwaddr addr)
|
||||
static uint64_t omap2_gpio_module_readp(void *opaque, hwaddr addr,
|
||||
unsigned size)
|
||||
{
|
||||
return omap2_gpio_module_read(opaque, addr & ~3) >> ((addr & 3) << 3);
|
||||
}
|
||||
|
||||
static void omap2_gpio_module_writep(void *opaque, hwaddr addr,
|
||||
uint32_t value)
|
||||
uint64_t value, unsigned size)
|
||||
{
|
||||
uint32_t cur = 0;
|
||||
uint32_t mask = 0xffff;
|
||||
|
||||
if (size == 4) {
|
||||
omap2_gpio_module_write(opaque, addr, value);
|
||||
return;
|
||||
}
|
||||
|
||||
switch (addr & ~3) {
|
||||
case 0x00: /* GPIO_REVISION */
|
||||
case 0x14: /* GPIO_SYSSTATUS */
|
||||
@@ -581,18 +587,10 @@ static void omap2_gpio_module_writep(void *opaque, hwaddr addr,
|
||||
}
|
||||
|
||||
static const MemoryRegionOps omap2_gpio_module_ops = {
|
||||
.old_mmio = {
|
||||
.read = {
|
||||
omap2_gpio_module_readp,
|
||||
omap2_gpio_module_readp,
|
||||
omap2_gpio_module_read,
|
||||
},
|
||||
.write = {
|
||||
omap2_gpio_module_writep,
|
||||
omap2_gpio_module_writep,
|
||||
omap2_gpio_module_write,
|
||||
},
|
||||
},
|
||||
.read = omap2_gpio_module_readp,
|
||||
.write = omap2_gpio_module_writep,
|
||||
.valid.min_access_size = 1,
|
||||
.valid.max_access_size = 4,
|
||||
.endianness = DEVICE_NATIVE_ENDIAN,
|
||||
};
|
||||
|
||||
|
||||
@@ -430,19 +430,39 @@ static void omap_i2c_writeb(void *opaque, hwaddr addr,
|
||||
}
|
||||
}
|
||||
|
||||
static uint64_t omap_i2c_readfn(void *opaque, hwaddr addr,
|
||||
unsigned size)
|
||||
{
|
||||
switch (size) {
|
||||
case 2:
|
||||
return omap_i2c_read(opaque, addr);
|
||||
default:
|
||||
return omap_badwidth_read16(opaque, addr);
|
||||
}
|
||||
}
|
||||
|
||||
static void omap_i2c_writefn(void *opaque, hwaddr addr,
|
||||
uint64_t value, unsigned size)
|
||||
{
|
||||
switch (size) {
|
||||
case 1:
|
||||
/* Only the last fifo write can be 8 bit. */
|
||||
omap_i2c_writeb(opaque, addr, value);
|
||||
break;
|
||||
case 2:
|
||||
omap_i2c_write(opaque, addr, value);
|
||||
break;
|
||||
default:
|
||||
omap_badwidth_write16(opaque, addr, value);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static const MemoryRegionOps omap_i2c_ops = {
|
||||
.old_mmio = {
|
||||
.read = {
|
||||
omap_badwidth_read16,
|
||||
omap_i2c_read,
|
||||
omap_badwidth_read16,
|
||||
},
|
||||
.write = {
|
||||
omap_i2c_writeb, /* Only the last fifo write can be 8 bit. */
|
||||
omap_i2c_write,
|
||||
omap_badwidth_write16,
|
||||
},
|
||||
},
|
||||
.read = omap_i2c_readfn,
|
||||
.write = omap_i2c_writefn,
|
||||
.valid.min_access_size = 1,
|
||||
.valid.max_access_size = 4,
|
||||
.endianness = DEVICE_NATIVE_ENDIAN,
|
||||
};
|
||||
|
||||
|
||||
@@ -184,7 +184,7 @@ static void ahci_check_irq(AHCIState *s)
|
||||
static void ahci_trigger_irq(AHCIState *s, AHCIDevice *d,
|
||||
enum AHCIPortIRQ irqbit)
|
||||
{
|
||||
g_assert(irqbit >= 0 && irqbit < 32);
|
||||
g_assert((unsigned)irqbit < 32);
|
||||
uint32_t irq = 1U << irqbit;
|
||||
uint32_t irqstat = d->port_regs.irq_stat | irq;
|
||||
|
||||
|
||||
@@ -68,7 +68,7 @@ const char *IDE_DMA_CMD_lookup[IDE_DMA__COUNT] = {
|
||||
|
||||
static const char *IDE_DMA_CMD_str(enum ide_dma_cmd enval)
|
||||
{
|
||||
if (enval >= IDE_DMA__BEGIN && enval < IDE_DMA__COUNT) {
|
||||
if ((unsigned)enval < IDE_DMA__COUNT) {
|
||||
return IDE_DMA_CMD_lookup[enval];
|
||||
}
|
||||
return "DMA UNKNOWN CMD";
|
||||
|
||||
208
hw/ide/macio.c
208
hw/ide/macio.c
@@ -255,114 +255,100 @@ static void pmac_ide_flush(DBDMA_io *io)
|
||||
}
|
||||
|
||||
/* PowerMac IDE memory IO */
|
||||
static void pmac_ide_writeb (void *opaque,
|
||||
hwaddr addr, uint32_t val)
|
||||
static uint64_t pmac_ide_read(void *opaque, hwaddr addr, unsigned size)
|
||||
{
|
||||
MACIOIDEState *d = opaque;
|
||||
uint64_t retval = 0xffffffff;
|
||||
int reg = addr >> 4;
|
||||
|
||||
addr = (addr & 0xFFF) >> 4;
|
||||
switch (addr) {
|
||||
case 1 ... 7:
|
||||
ide_ioport_write(&d->bus, addr, val);
|
||||
switch (reg) {
|
||||
case 0x0:
|
||||
if (size == 2) {
|
||||
retval = ide_data_readw(&d->bus, 0);
|
||||
} else if (size == 4) {
|
||||
retval = ide_data_readl(&d->bus, 0);
|
||||
}
|
||||
break;
|
||||
case 8:
|
||||
case 22:
|
||||
ide_cmd_write(&d->bus, 0, val);
|
||||
case 0x1 ... 0x7:
|
||||
if (size == 1) {
|
||||
retval = ide_ioport_read(&d->bus, reg);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
case 0x8:
|
||||
case 0x16:
|
||||
if (size == 1) {
|
||||
retval = ide_status_read(&d->bus, 0);
|
||||
}
|
||||
break;
|
||||
case 0x20:
|
||||
if (size == 4) {
|
||||
retval = d->timing_reg;
|
||||
}
|
||||
break;
|
||||
case 0x30:
|
||||
/* This is an interrupt state register that only exists
|
||||
* in the KeyLargo and later variants. Bit 0x8000_0000
|
||||
* latches the DMA interrupt and has to be written to
|
||||
* clear. Bit 0x4000_0000 is an image of the disk
|
||||
* interrupt. MacOS X relies on this and will hang if
|
||||
* we don't provide at least the disk interrupt
|
||||
*/
|
||||
if (size == 4) {
|
||||
retval = d->irq_reg;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static uint32_t pmac_ide_readb (void *opaque,hwaddr addr)
|
||||
{
|
||||
uint8_t retval;
|
||||
MACIOIDEState *d = opaque;
|
||||
|
||||
addr = (addr & 0xFFF) >> 4;
|
||||
switch (addr) {
|
||||
case 1 ... 7:
|
||||
retval = ide_ioport_read(&d->bus, addr);
|
||||
break;
|
||||
case 8:
|
||||
case 22:
|
||||
retval = ide_status_read(&d->bus, 0);
|
||||
break;
|
||||
default:
|
||||
retval = 0xFF;
|
||||
break;
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
|
||||
static void pmac_ide_writew (void *opaque,
|
||||
hwaddr addr, uint32_t val)
|
||||
|
||||
static void pmac_ide_write(void *opaque, hwaddr addr, uint64_t val,
|
||||
unsigned size)
|
||||
{
|
||||
MACIOIDEState *d = opaque;
|
||||
int reg = addr >> 4;
|
||||
|
||||
addr = (addr & 0xFFF) >> 4;
|
||||
val = bswap16(val);
|
||||
if (addr == 0) {
|
||||
ide_data_writew(&d->bus, 0, val);
|
||||
switch (reg) {
|
||||
case 0x0:
|
||||
if (size == 2) {
|
||||
ide_data_writew(&d->bus, 0, val);
|
||||
} else if (size == 4) {
|
||||
ide_data_writel(&d->bus, 0, val);
|
||||
}
|
||||
break;
|
||||
case 0x1 ... 0x7:
|
||||
if (size == 1) {
|
||||
ide_ioport_write(&d->bus, reg, val);
|
||||
}
|
||||
break;
|
||||
case 0x8:
|
||||
case 0x16:
|
||||
if (size == 1) {
|
||||
ide_cmd_write(&d->bus, 0, val);
|
||||
}
|
||||
break;
|
||||
case 0x20:
|
||||
if (size == 4) {
|
||||
d->timing_reg = val;
|
||||
}
|
||||
break;
|
||||
case 0x30:
|
||||
if (size == 4) {
|
||||
if (val & 0x80000000u) {
|
||||
d->irq_reg &= 0x7fffffff;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static uint32_t pmac_ide_readw (void *opaque,hwaddr addr)
|
||||
{
|
||||
uint16_t retval;
|
||||
MACIOIDEState *d = opaque;
|
||||
|
||||
addr = (addr & 0xFFF) >> 4;
|
||||
if (addr == 0) {
|
||||
retval = ide_data_readw(&d->bus, 0);
|
||||
} else {
|
||||
retval = 0xFFFF;
|
||||
}
|
||||
retval = bswap16(retval);
|
||||
return retval;
|
||||
}
|
||||
|
||||
static void pmac_ide_writel (void *opaque,
|
||||
hwaddr addr, uint32_t val)
|
||||
{
|
||||
MACIOIDEState *d = opaque;
|
||||
|
||||
addr = (addr & 0xFFF) >> 4;
|
||||
val = bswap32(val);
|
||||
if (addr == 0) {
|
||||
ide_data_writel(&d->bus, 0, val);
|
||||
}
|
||||
}
|
||||
|
||||
static uint32_t pmac_ide_readl (void *opaque,hwaddr addr)
|
||||
{
|
||||
uint32_t retval;
|
||||
MACIOIDEState *d = opaque;
|
||||
|
||||
addr = (addr & 0xFFF) >> 4;
|
||||
if (addr == 0) {
|
||||
retval = ide_data_readl(&d->bus, 0);
|
||||
} else {
|
||||
retval = 0xFFFFFFFF;
|
||||
}
|
||||
retval = bswap32(retval);
|
||||
return retval;
|
||||
}
|
||||
|
||||
static const MemoryRegionOps pmac_ide_ops = {
|
||||
.old_mmio = {
|
||||
.write = {
|
||||
pmac_ide_writeb,
|
||||
pmac_ide_writew,
|
||||
pmac_ide_writel,
|
||||
},
|
||||
.read = {
|
||||
pmac_ide_readb,
|
||||
pmac_ide_readw,
|
||||
pmac_ide_readl,
|
||||
},
|
||||
},
|
||||
.endianness = DEVICE_NATIVE_ENDIAN,
|
||||
.read = pmac_ide_read,
|
||||
.write = pmac_ide_write,
|
||||
.valid.min_access_size = 1,
|
||||
.valid.max_access_size = 4,
|
||||
.endianness = DEVICE_LITTLE_ENDIAN,
|
||||
};
|
||||
|
||||
static const VMStateDescription vmstate_pmac = {
|
||||
@@ -426,13 +412,32 @@ static void macio_ide_realizefn(DeviceState *dev, Error **errp)
|
||||
{
|
||||
MACIOIDEState *s = MACIO_IDE(dev);
|
||||
|
||||
ide_init2(&s->bus, s->irq);
|
||||
ide_init2(&s->bus, s->ide_irq);
|
||||
|
||||
/* Register DMA callbacks */
|
||||
s->dma.ops = &dbdma_ops;
|
||||
s->bus.dma = &s->dma;
|
||||
}
|
||||
|
||||
static void pmac_ide_irq(void *opaque, int n, int level)
|
||||
{
|
||||
MACIOIDEState *s = opaque;
|
||||
uint32_t mask = 0x80000000u >> n;
|
||||
|
||||
/* We need to reflect the IRQ state in the irq register */
|
||||
if (level) {
|
||||
s->irq_reg |= mask;
|
||||
} else {
|
||||
s->irq_reg &= ~mask;
|
||||
}
|
||||
|
||||
if (n) {
|
||||
qemu_set_irq(s->real_ide_irq, level);
|
||||
} else {
|
||||
qemu_set_irq(s->real_dma_irq, level);
|
||||
}
|
||||
}
|
||||
|
||||
static void macio_ide_initfn(Object *obj)
|
||||
{
|
||||
SysBusDevice *d = SYS_BUS_DEVICE(obj);
|
||||
@@ -441,16 +446,28 @@ static void macio_ide_initfn(Object *obj)
|
||||
ide_bus_new(&s->bus, sizeof(s->bus), DEVICE(obj), 0, 2);
|
||||
memory_region_init_io(&s->mem, obj, &pmac_ide_ops, s, "pmac-ide", 0x1000);
|
||||
sysbus_init_mmio(d, &s->mem);
|
||||
sysbus_init_irq(d, &s->irq);
|
||||
sysbus_init_irq(d, &s->dma_irq);
|
||||
sysbus_init_irq(d, &s->real_ide_irq);
|
||||
sysbus_init_irq(d, &s->real_dma_irq);
|
||||
s->dma_irq = qemu_allocate_irq(pmac_ide_irq, s, 0);
|
||||
s->ide_irq = qemu_allocate_irq(pmac_ide_irq, s, 1);
|
||||
|
||||
object_property_add_link(obj, "dbdma", TYPE_MAC_DBDMA,
|
||||
(Object **) &s->dbdma,
|
||||
qdev_prop_allow_set_link_before_realize, 0, NULL);
|
||||
}
|
||||
|
||||
static Property macio_ide_properties[] = {
|
||||
DEFINE_PROP_UINT32("channel", MACIOIDEState, channel, 0),
|
||||
DEFINE_PROP_END_OF_LIST(),
|
||||
};
|
||||
|
||||
static void macio_ide_class_init(ObjectClass *oc, void *data)
|
||||
{
|
||||
DeviceClass *dc = DEVICE_CLASS(oc);
|
||||
|
||||
dc->realize = macio_ide_realizefn;
|
||||
dc->reset = macio_ide_reset;
|
||||
dc->props = macio_ide_properties;
|
||||
dc->vmsd = &vmstate_pmac;
|
||||
set_bit(DEVICE_CATEGORY_STORAGE, dc->categories);
|
||||
}
|
||||
@@ -480,10 +497,9 @@ void macio_ide_init_drives(MACIOIDEState *s, DriveInfo **hd_table)
|
||||
}
|
||||
}
|
||||
|
||||
void macio_ide_register_dma(MACIOIDEState *s, void *dbdma, int channel)
|
||||
void macio_ide_register_dma(MACIOIDEState *s)
|
||||
{
|
||||
s->dbdma = dbdma;
|
||||
DBDMA_register_channel(dbdma, channel, s->dma_irq,
|
||||
DBDMA_register_channel(s->dbdma, s->channel, s->dma_irq,
|
||||
pmac_ide_transfer, pmac_ide_flush, s);
|
||||
}
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -92,6 +92,16 @@ static int get_current_cpu(void);
|
||||
#define RAVEN_MAX_TMR OPENPIC_MAX_TMR
|
||||
#define RAVEN_MAX_IPI OPENPIC_MAX_IPI
|
||||
|
||||
/* KeyLargo */
|
||||
#define KEYLARGO_MAX_CPU 4
|
||||
#define KEYLARGO_MAX_EXT 64
|
||||
#define KEYLARGO_MAX_IPI 4
|
||||
#define KEYLARGO_MAX_IRQ (64 + KEYLARGO_MAX_IPI)
|
||||
#define KEYLARGO_MAX_TMR 0
|
||||
#define KEYLARGO_IPI_IRQ (KEYLARGO_MAX_EXT) /* First IPI IRQ */
|
||||
/* Timers don't exist but this makes the code happy... */
|
||||
#define KEYLARGO_TMR_IRQ (KEYLARGO_IPI_IRQ + KEYLARGO_MAX_IPI)
|
||||
|
||||
/* Interrupt definitions */
|
||||
#define RAVEN_FE_IRQ (RAVEN_MAX_EXT) /* Internal functional IRQ */
|
||||
#define RAVEN_ERR_IRQ (RAVEN_MAX_EXT + 1) /* Error IRQ */
|
||||
@@ -120,6 +130,7 @@ static FslMpicInfo fsl_mpic_42 = {
|
||||
#define VID_REVISION_1_3 3
|
||||
|
||||
#define VIR_GENERIC 0x00000000 /* Generic Vendor ID */
|
||||
#define VIR_MPIC2A 0x00004614 /* IBM MPIC-2A */
|
||||
|
||||
#define GCR_RESET 0x80000000
|
||||
#define GCR_MODE_PASS 0x00000000
|
||||
@@ -329,6 +340,8 @@ typedef struct OpenPICState {
|
||||
uint32_t nb_cpus;
|
||||
/* Timer registers */
|
||||
OpenPICTimer timers[OPENPIC_MAX_TMR];
|
||||
uint32_t max_tmr;
|
||||
|
||||
/* Shared MSI registers */
|
||||
OpenPICMSI msi[MAX_MSI];
|
||||
uint32_t max_irq;
|
||||
@@ -1715,6 +1728,28 @@ static void openpic_realize(DeviceState *dev, Error **errp)
|
||||
return;
|
||||
}
|
||||
|
||||
map_list(opp, list_le, &list_count);
|
||||
break;
|
||||
|
||||
case OPENPIC_MODEL_KEYLARGO:
|
||||
opp->nb_irqs = KEYLARGO_MAX_EXT;
|
||||
opp->vid = VID_REVISION_1_2;
|
||||
opp->vir = VIR_GENERIC;
|
||||
opp->vector_mask = 0xFF;
|
||||
opp->tfrr_reset = 4160000;
|
||||
opp->ivpr_reset = IVPR_MASK_MASK | IVPR_MODE_MASK;
|
||||
opp->idr_reset = 0;
|
||||
opp->max_irq = KEYLARGO_MAX_IRQ;
|
||||
opp->irq_ipi0 = KEYLARGO_IPI_IRQ;
|
||||
opp->irq_tim0 = KEYLARGO_TMR_IRQ;
|
||||
opp->brr1 = -1;
|
||||
opp->mpic_mode_mask = GCR_MODE_MIXED;
|
||||
|
||||
if (opp->nb_cpus != 1) {
|
||||
error_setg(errp, "Only UP supported today");
|
||||
return;
|
||||
}
|
||||
|
||||
map_list(opp, list_le, &list_count);
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -124,7 +124,7 @@ static void kvm_openpic_region_add(MemoryListener *listener,
|
||||
uint64_t reg_base;
|
||||
int ret;
|
||||
|
||||
if (section->address_space != &address_space_memory) {
|
||||
if (section->fv != address_space_to_flatview(&address_space_memory)) {
|
||||
abort();
|
||||
}
|
||||
|
||||
|
||||
@@ -167,16 +167,17 @@ gicv3_redist_set_irq(uint32_t cpu, int irq, int level) "GICv3 redistributor 0x%x
|
||||
gicv3_redist_send_sgi(uint32_t cpu, int irq) "GICv3 redistributor 0x%x pending SGI %d"
|
||||
|
||||
# hw/intc/armv7m_nvic.c
|
||||
nvic_recompute_state(int vectpending, int exception_prio) "NVIC state recomputed: vectpending %d exception_prio %d"
|
||||
nvic_set_prio(int irq, uint8_t prio) "NVIC set irq %d priority %d"
|
||||
nvic_recompute_state(int vectpending, int vectpending_prio, int exception_prio) "NVIC state recomputed: vectpending %d vectpending_prio %d exception_prio %d"
|
||||
nvic_recompute_state_secure(int vectpending, bool vectpending_is_s_banked, int vectpending_prio, int exception_prio) "NVIC state recomputed: vectpending %d is_s_banked %d vectpending_prio %d exception_prio %d"
|
||||
nvic_set_prio(int irq, bool secure, uint8_t prio) "NVIC set irq %d secure-bank %d priority %d"
|
||||
nvic_irq_update(int vectpending, int pendprio, int exception_prio, int level) "NVIC vectpending %d pending prio %d exception_prio %d: setting irq line to %d"
|
||||
nvic_escalate_prio(int irq, int irqprio, int runprio) "NVIC escalating irq %d to HardFault: insufficient priority %d >= %d"
|
||||
nvic_escalate_disabled(int irq) "NVIC escalating irq %d to HardFault: disabled"
|
||||
nvic_set_pending(int irq, int en, int prio) "NVIC set pending irq %d (enabled: %d priority %d)"
|
||||
nvic_clear_pending(int irq, int en, int prio) "NVIC clear pending irq %d (enabled: %d priority %d)"
|
||||
nvic_set_pending(int irq, bool secure, int en, int prio) "NVIC set pending irq %d secure-bank %d (enabled: %d priority %d)"
|
||||
nvic_clear_pending(int irq, bool secure, int en, int prio) "NVIC clear pending irq %d secure-bank %d (enabled: %d priority %d)"
|
||||
nvic_set_pending_level(int irq) "NVIC set pending: irq %d higher prio than vectpending: setting irq line to 1"
|
||||
nvic_acknowledge_irq(int irq, int prio) "NVIC acknowledge IRQ: %d now active (prio %d)"
|
||||
nvic_complete_irq(int irq) "NVIC complete IRQ %d"
|
||||
nvic_acknowledge_irq(int irq, int prio, bool targets_secure) "NVIC acknowledge IRQ: %d now active (prio %d targets_secure %d)"
|
||||
nvic_complete_irq(int irq, bool secure) "NVIC complete IRQ %d (secure %d)"
|
||||
nvic_set_irq_level(int irq, int level) "NVIC external irq %d level set to %d"
|
||||
nvic_sysreg_read(uint64_t addr, uint32_t value, unsigned size) "NVIC sysreg read addr 0x%" PRIx64 " data 0x%" PRIx32 " size %u"
|
||||
nvic_sysreg_write(uint64_t addr, uint32_t value, unsigned size) "NVIC sysreg write addr 0x%" PRIx64 " data 0x%" PRIx32 " size %u"
|
||||
|
||||
@@ -386,6 +386,8 @@ static void pc87312_class_init(ObjectClass *klass, void *data)
|
||||
dc->reset = pc87312_reset;
|
||||
dc->vmsd = &vmstate_pc87312;
|
||||
dc->props = pc87312_properties;
|
||||
/* Reason: Uses parallel_hds[0] in realize(), so it can't be used twice */
|
||||
dc->user_creatable = false;
|
||||
}
|
||||
|
||||
static const TypeInfo pc87312_type_info = {
|
||||
|
||||
@@ -59,3 +59,4 @@ obj-$(CONFIG_HYPERV_TESTDEV) += hyperv_testdev.o
|
||||
obj-$(CONFIG_AUX) += auxbus.o
|
||||
obj-$(CONFIG_ASPEED_SOC) += aspeed_scu.o aspeed_sdmc.o
|
||||
obj-y += mmio_interface.o
|
||||
obj-$(CONFIG_MSF2) += msf2-sysreg.o
|
||||
|
||||
@@ -210,6 +210,16 @@ struct AUXTOI2CState {
|
||||
I2CBus *i2c_bus;
|
||||
};
|
||||
|
||||
static void aux_bridge_class_init(ObjectClass *oc, void *data)
|
||||
{
|
||||
DeviceClass *dc = DEVICE_CLASS(oc);
|
||||
|
||||
/* This device is private and is created only once for each
|
||||
* aux-bus in aux_init_bus(..). So don't allow the user to add one.
|
||||
*/
|
||||
dc->user_creatable = false;
|
||||
}
|
||||
|
||||
static void aux_bridge_init(Object *obj)
|
||||
{
|
||||
AUXTOI2CState *s = AUXTOI2C(obj);
|
||||
@@ -225,6 +235,7 @@ static inline I2CBus *aux_bridge_get_i2c_bus(AUXTOI2CState *bridge)
|
||||
static const TypeInfo aux_to_i2c_type_info = {
|
||||
.name = TYPE_AUXTOI2C,
|
||||
.parent = TYPE_DEVICE,
|
||||
.class_init = aux_bridge_class_init,
|
||||
.instance_size = sizeof(AUXTOI2CState),
|
||||
.instance_init = aux_bridge_init
|
||||
};
|
||||
|
||||
@@ -96,9 +96,8 @@ static void dbdma_cmdptr_load(DBDMA_channel *ch)
|
||||
|
||||
static void dbdma_cmdptr_save(DBDMA_channel *ch)
|
||||
{
|
||||
DBDMA_DPRINTFCH(ch, "dbdma_cmdptr_save 0x%08x\n",
|
||||
ch->regs[DBDMA_CMDPTR_LO]);
|
||||
DBDMA_DPRINTFCH(ch, "xfer_status 0x%08x res_count 0x%04x\n",
|
||||
DBDMA_DPRINTFCH(ch, "-> update 0x%08x stat=0x%08x, res=0x%04x\n",
|
||||
ch->regs[DBDMA_CMDPTR_LO],
|
||||
le16_to_cpu(ch->current.xfer_status),
|
||||
le16_to_cpu(ch->current.res_count));
|
||||
dma_memory_write(&address_space_memory, ch->regs[DBDMA_CMDPTR_LO],
|
||||
@@ -166,15 +165,14 @@ static int conditional_wait(DBDMA_channel *ch)
|
||||
uint16_t sel_mask, sel_value;
|
||||
uint32_t status;
|
||||
int cond;
|
||||
|
||||
DBDMA_DPRINTFCH(ch, "conditional_wait\n");
|
||||
int res = 0;
|
||||
|
||||
wait = le16_to_cpu(current->command) & WAIT_MASK;
|
||||
|
||||
switch(wait) {
|
||||
case WAIT_NEVER: /* don't wait */
|
||||
return 0;
|
||||
case WAIT_ALWAYS: /* always wait */
|
||||
DBDMA_DPRINTFCH(ch, " [WAIT_ALWAYS]\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -187,15 +185,19 @@ static int conditional_wait(DBDMA_channel *ch)
|
||||
|
||||
switch(wait) {
|
||||
case WAIT_IFSET: /* wait if condition bit is 1 */
|
||||
if (cond)
|
||||
return 1;
|
||||
return 0;
|
||||
if (cond) {
|
||||
res = 1;
|
||||
}
|
||||
DBDMA_DPRINTFCH(ch, " [WAIT_IFSET=%d]\n", res);
|
||||
break;
|
||||
case WAIT_IFCLR: /* wait if condition bit is 0 */
|
||||
if (!cond)
|
||||
return 1;
|
||||
return 0;
|
||||
if (!cond) {
|
||||
res = 1;
|
||||
}
|
||||
DBDMA_DPRINTFCH(ch, " [WAIT_IFCLR=%d]\n", res);
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
return res;
|
||||
}
|
||||
|
||||
static void next(DBDMA_channel *ch)
|
||||
@@ -226,8 +228,6 @@ static void conditional_branch(DBDMA_channel *ch)
|
||||
uint32_t status;
|
||||
int cond;
|
||||
|
||||
DBDMA_DPRINTFCH(ch, "conditional_branch\n");
|
||||
|
||||
/* check if we must branch */
|
||||
|
||||
br = le16_to_cpu(current->command) & BR_MASK;
|
||||
@@ -237,6 +237,7 @@ static void conditional_branch(DBDMA_channel *ch)
|
||||
next(ch);
|
||||
return;
|
||||
case BR_ALWAYS: /* always branch */
|
||||
DBDMA_DPRINTFCH(ch, " [BR_ALWAYS]\n");
|
||||
branch(ch);
|
||||
return;
|
||||
}
|
||||
@@ -250,16 +251,22 @@ static void conditional_branch(DBDMA_channel *ch)
|
||||
|
||||
switch(br) {
|
||||
case BR_IFSET: /* branch if condition bit is 1 */
|
||||
if (cond)
|
||||
if (cond) {
|
||||
DBDMA_DPRINTFCH(ch, " [BR_IFSET = 1]\n");
|
||||
branch(ch);
|
||||
else
|
||||
} else {
|
||||
DBDMA_DPRINTFCH(ch, " [BR_IFSET = 0]\n");
|
||||
next(ch);
|
||||
}
|
||||
return;
|
||||
case BR_IFCLR: /* branch if condition bit is 0 */
|
||||
if (!cond)
|
||||
if (!cond) {
|
||||
DBDMA_DPRINTFCH(ch, " [BR_IFCLR = 1]\n");
|
||||
branch(ch);
|
||||
else
|
||||
} else {
|
||||
DBDMA_DPRINTFCH(ch, " [BR_IFCLR = 0]\n");
|
||||
next(ch);
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -428,7 +435,7 @@ wait:
|
||||
|
||||
static void stop(DBDMA_channel *ch)
|
||||
{
|
||||
ch->regs[DBDMA_STATUS] &= ~(ACTIVE|DEAD|FLUSH);
|
||||
ch->regs[DBDMA_STATUS] &= ~(ACTIVE);
|
||||
|
||||
/* the stop command does not increment command pointer */
|
||||
}
|
||||
@@ -471,18 +478,22 @@ static void channel_run(DBDMA_channel *ch)
|
||||
|
||||
switch (cmd) {
|
||||
case OUTPUT_MORE:
|
||||
DBDMA_DPRINTFCH(ch, "* OUTPUT_MORE *\n");
|
||||
start_output(ch, key, phy_addr, req_count, 0);
|
||||
return;
|
||||
|
||||
case OUTPUT_LAST:
|
||||
DBDMA_DPRINTFCH(ch, "* OUTPUT_LAST *\n");
|
||||
start_output(ch, key, phy_addr, req_count, 1);
|
||||
return;
|
||||
|
||||
case INPUT_MORE:
|
||||
DBDMA_DPRINTFCH(ch, "* INPUT_MORE *\n");
|
||||
start_input(ch, key, phy_addr, req_count, 0);
|
||||
return;
|
||||
|
||||
case INPUT_LAST:
|
||||
DBDMA_DPRINTFCH(ch, "* INPUT_LAST *\n");
|
||||
start_input(ch, key, phy_addr, req_count, 1);
|
||||
return;
|
||||
}
|
||||
@@ -508,10 +519,12 @@ static void channel_run(DBDMA_channel *ch)
|
||||
|
||||
switch (cmd) {
|
||||
case LOAD_WORD:
|
||||
DBDMA_DPRINTFCH(ch, "* LOAD_WORD *\n");
|
||||
load_word(ch, key, phy_addr, req_count);
|
||||
return;
|
||||
|
||||
case STORE_WORD:
|
||||
DBDMA_DPRINTFCH(ch, "* STORE_WORD *\n");
|
||||
store_word(ch, key, phy_addr, req_count);
|
||||
return;
|
||||
}
|
||||
@@ -562,43 +575,117 @@ void DBDMA_register_channel(void *dbdma, int nchan, qemu_irq irq,
|
||||
ch->io.opaque = opaque;
|
||||
}
|
||||
|
||||
static void
|
||||
dbdma_control_write(DBDMA_channel *ch)
|
||||
static void dbdma_control_write(DBDMA_channel *ch)
|
||||
{
|
||||
uint16_t mask, value;
|
||||
uint32_t status;
|
||||
bool do_flush = false;
|
||||
|
||||
mask = (ch->regs[DBDMA_CONTROL] >> 16) & 0xffff;
|
||||
value = ch->regs[DBDMA_CONTROL] & 0xffff;
|
||||
|
||||
value &= (RUN | PAUSE | FLUSH | WAKE | DEVSTAT);
|
||||
|
||||
/* This is the status register which we'll update
|
||||
* appropriately and store back
|
||||
*/
|
||||
status = ch->regs[DBDMA_STATUS];
|
||||
|
||||
status = (value & mask) | (status & ~mask);
|
||||
/* RUN and PAUSE are bits under SW control only
|
||||
* FLUSH and WAKE are set by SW and cleared by HW
|
||||
* DEAD, ACTIVE and BT are only under HW control
|
||||
*
|
||||
* We handle ACTIVE separately at the end of the
|
||||
* logic to ensure all cases are covered.
|
||||
*/
|
||||
|
||||
if (status & WAKE)
|
||||
status |= ACTIVE;
|
||||
if (status & RUN) {
|
||||
status |= ACTIVE;
|
||||
status &= ~DEAD;
|
||||
/* Setting RUN will tentatively activate the channel
|
||||
*/
|
||||
if ((mask & RUN) && (value & RUN)) {
|
||||
status |= RUN;
|
||||
DBDMA_DPRINTFCH(ch, " Setting RUN !\n");
|
||||
}
|
||||
if (status & PAUSE)
|
||||
|
||||
/* Clearing RUN 1->0 will stop the channel */
|
||||
if ((mask & RUN) && !(value & RUN)) {
|
||||
/* This has the side effect of clearing the DEAD bit */
|
||||
status &= ~(DEAD | RUN);
|
||||
DBDMA_DPRINTFCH(ch, " Clearing RUN !\n");
|
||||
}
|
||||
|
||||
/* Setting WAKE wakes up an idle channel if it's running
|
||||
*
|
||||
* Note: The doc doesn't say so but assume that only works
|
||||
* on a channel whose RUN bit is set.
|
||||
*
|
||||
* We set WAKE in status, it's not terribly useful as it will
|
||||
* be cleared on the next command fetch but it seems to mimmic
|
||||
* the HW behaviour and is useful for the way we handle
|
||||
* ACTIVE further down.
|
||||
*/
|
||||
if ((mask & WAKE) && (value & WAKE) && (status & RUN)) {
|
||||
status |= WAKE;
|
||||
DBDMA_DPRINTFCH(ch, " Setting WAKE !\n");
|
||||
}
|
||||
|
||||
/* PAUSE being set will deactivate (or prevent activation)
|
||||
* of the channel. We just copy it over for now, ACTIVE will
|
||||
* be re-evaluated later.
|
||||
*/
|
||||
if (mask & PAUSE) {
|
||||
status = (status & ~PAUSE) | (value & PAUSE);
|
||||
DBDMA_DPRINTFCH(ch, " %sing PAUSE !\n",
|
||||
(value & PAUSE) ? "sett" : "clear");
|
||||
}
|
||||
|
||||
/* FLUSH is its own thing */
|
||||
if ((mask & FLUSH) && (value & FLUSH)) {
|
||||
DBDMA_DPRINTFCH(ch, " Setting FLUSH !\n");
|
||||
/* We set flush directly in the status register, we do *NOT*
|
||||
* set it in "status" so that it gets naturally cleared when
|
||||
* we update the status register further down. That way it
|
||||
* will be set only during the HW flush operation so it is
|
||||
* visible to any completions happening during that time.
|
||||
*/
|
||||
ch->regs[DBDMA_STATUS] |= FLUSH;
|
||||
do_flush = true;
|
||||
}
|
||||
|
||||
/* If either RUN or PAUSE is clear, so should ACTIVE be,
|
||||
* otherwise, ACTIVE will be set if we modified RUN, PAUSE or
|
||||
* set WAKE. That means that PAUSE was just cleared, RUN was
|
||||
* just set or WAKE was just set.
|
||||
*/
|
||||
if ((status & PAUSE) || !(status & RUN)) {
|
||||
status &= ~ACTIVE;
|
||||
if ((ch->regs[DBDMA_STATUS] & RUN) && !(status & RUN)) {
|
||||
/* RUN is cleared */
|
||||
status &= ~(ACTIVE|DEAD);
|
||||
DBDMA_DPRINTFCH(ch, " -> ACTIVE down !\n");
|
||||
|
||||
/* We stopped processing, we want the underlying HW command
|
||||
* to complete *before* we clear the ACTIVE bit. Otherwise
|
||||
* we can get into a situation where the command status will
|
||||
* have RUN or ACTIVE not set which is going to confuse the
|
||||
* MacOS driver.
|
||||
*/
|
||||
do_flush = true;
|
||||
} else if (mask & (RUN | PAUSE)) {
|
||||
status |= ACTIVE;
|
||||
DBDMA_DPRINTFCH(ch, " -> ACTIVE up !\n");
|
||||
} else if ((mask & WAKE) && (value & WAKE)) {
|
||||
status |= ACTIVE;
|
||||
DBDMA_DPRINTFCH(ch, " -> ACTIVE up !\n");
|
||||
}
|
||||
|
||||
if ((status & FLUSH) && ch->flush) {
|
||||
DBDMA_DPRINTFCH(ch, " new status=0x%08x\n", status);
|
||||
|
||||
/* If we need to flush the underlying HW, do it now, this happens
|
||||
* both on FLUSH commands and when stopping the channel for safety.
|
||||
*/
|
||||
if (do_flush && ch->flush) {
|
||||
ch->flush(&ch->io);
|
||||
status &= ~FLUSH;
|
||||
}
|
||||
|
||||
DBDMA_DPRINTFCH(ch, " status 0x%08x\n", status);
|
||||
|
||||
/* Finally update the status register image */
|
||||
ch->regs[DBDMA_STATUS] = status;
|
||||
|
||||
/* If active, make sure the BH gets to run */
|
||||
if (status & ACTIVE) {
|
||||
DBDMA_kick(dbdma_from_ch(ch));
|
||||
}
|
||||
@@ -666,13 +753,9 @@ static uint64_t dbdma_read(void *opaque, hwaddr addr,
|
||||
|
||||
value = ch->regs[reg];
|
||||
|
||||
DBDMA_DPRINTFCH(ch, "readl 0x" TARGET_FMT_plx " => 0x%08x\n", addr, value);
|
||||
DBDMA_DPRINTFCH(ch, "channel 0x%x reg 0x%x\n",
|
||||
(uint32_t)addr >> DBDMA_CHANNEL_SHIFT, reg);
|
||||
|
||||
switch(reg) {
|
||||
case DBDMA_CONTROL:
|
||||
value = 0;
|
||||
value = ch->regs[DBDMA_STATUS];
|
||||
break;
|
||||
case DBDMA_STATUS:
|
||||
case DBDMA_CMDPTR_LO:
|
||||
@@ -698,6 +781,10 @@ static uint64_t dbdma_read(void *opaque, hwaddr addr,
|
||||
break;
|
||||
}
|
||||
|
||||
DBDMA_DPRINTFCH(ch, "readl 0x" TARGET_FMT_plx " => 0x%08x\n", addr, value);
|
||||
DBDMA_DPRINTFCH(ch, "channel 0x%x reg 0x%x\n",
|
||||
(uint32_t)addr >> DBDMA_CHANNEL_SHIFT, reg);
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
@@ -764,51 +851,49 @@ static const VMStateDescription vmstate_dbdma = {
|
||||
}
|
||||
};
|
||||
|
||||
static void dbdma_reset(void *opaque)
|
||||
static void mac_dbdma_reset(DeviceState *d)
|
||||
{
|
||||
DBDMAState *s = opaque;
|
||||
DBDMAState *s = MAC_DBDMA(d);
|
||||
int i;
|
||||
|
||||
for (i = 0; i < DBDMA_CHANNELS; i++)
|
||||
for (i = 0; i < DBDMA_CHANNELS; i++) {
|
||||
memset(s->channels[i].regs, 0, DBDMA_SIZE);
|
||||
}
|
||||
}
|
||||
|
||||
static void dbdma_unassigned_rw(DBDMA_io *io)
|
||||
{
|
||||
DBDMA_channel *ch = io->channel;
|
||||
qemu_log_mask(LOG_GUEST_ERROR, "%s: use of unassigned channel %d\n",
|
||||
__func__, ch->channel);
|
||||
ch->io.processing = false;
|
||||
}
|
||||
|
||||
static void dbdma_unassigned_flush(DBDMA_io *io)
|
||||
{
|
||||
DBDMA_channel *ch = io->channel;
|
||||
dbdma_cmd *current = &ch->current;
|
||||
uint16_t cmd;
|
||||
qemu_log_mask(LOG_GUEST_ERROR, "%s: use of unassigned channel %d\n",
|
||||
__func__, ch->channel);
|
||||
ch->io.processing = false;
|
||||
|
||||
cmd = le16_to_cpu(current->command) & COMMAND_MASK;
|
||||
if (cmd == OUTPUT_MORE || cmd == OUTPUT_LAST ||
|
||||
cmd == INPUT_MORE || cmd == INPUT_LAST) {
|
||||
current->xfer_status = cpu_to_le16(ch->regs[DBDMA_STATUS] | FLUSH);
|
||||
current->xfer_status = cpu_to_le16(ch->regs[DBDMA_STATUS]);
|
||||
current->res_count = cpu_to_le16(io->len);
|
||||
dbdma_cmdptr_save(ch);
|
||||
}
|
||||
}
|
||||
|
||||
void* DBDMA_init (MemoryRegion **dbdma_mem)
|
||||
static void dbdma_unassigned_flush(DBDMA_io *io)
|
||||
{
|
||||
DBDMAState *s;
|
||||
DBDMA_channel *ch = io->channel;
|
||||
qemu_log_mask(LOG_GUEST_ERROR, "%s: use of unassigned channel %d\n",
|
||||
__func__, ch->channel);
|
||||
}
|
||||
|
||||
static void mac_dbdma_init(Object *obj)
|
||||
{
|
||||
SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
|
||||
DBDMAState *s = MAC_DBDMA(obj);
|
||||
int i;
|
||||
|
||||
s = g_malloc0(sizeof(DBDMAState));
|
||||
|
||||
for (i = 0; i < DBDMA_CHANNELS; i++) {
|
||||
DBDMA_io *io = &s->channels[i].io;
|
||||
DBDMA_channel *ch = &s->channels[i];
|
||||
qemu_iovec_init(&io->iov, 1);
|
||||
|
||||
ch->rw = dbdma_unassigned_rw;
|
||||
ch->flush = dbdma_unassigned_flush;
|
||||
@@ -816,12 +901,37 @@ void* DBDMA_init (MemoryRegion **dbdma_mem)
|
||||
ch->io.channel = ch;
|
||||
}
|
||||
|
||||
memory_region_init_io(&s->mem, NULL, &dbdma_ops, s, "dbdma", 0x1000);
|
||||
*dbdma_mem = &s->mem;
|
||||
vmstate_register(NULL, -1, &vmstate_dbdma, s);
|
||||
qemu_register_reset(dbdma_reset, s);
|
||||
memory_region_init_io(&s->mem, obj, &dbdma_ops, s, "dbdma", 0x1000);
|
||||
sysbus_init_mmio(sbd, &s->mem);
|
||||
}
|
||||
|
||||
static void mac_dbdma_realize(DeviceState *dev, Error **errp)
|
||||
{
|
||||
DBDMAState *s = MAC_DBDMA(dev);
|
||||
|
||||
s->bh = qemu_bh_new(DBDMA_run_bh, s);
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
static void mac_dbdma_class_init(ObjectClass *oc, void *data)
|
||||
{
|
||||
DeviceClass *dc = DEVICE_CLASS(oc);
|
||||
|
||||
dc->realize = mac_dbdma_realize;
|
||||
dc->reset = mac_dbdma_reset;
|
||||
dc->vmsd = &vmstate_dbdma;
|
||||
}
|
||||
|
||||
static const TypeInfo mac_dbdma_type_info = {
|
||||
.name = TYPE_MAC_DBDMA,
|
||||
.parent = TYPE_SYS_BUS_DEVICE,
|
||||
.instance_size = sizeof(DBDMAState),
|
||||
.instance_init = mac_dbdma_init,
|
||||
.class_init = mac_dbdma_class_init
|
||||
};
|
||||
|
||||
static void mac_dbdma_register_types(void)
|
||||
{
|
||||
type_register_static(&mac_dbdma_type_info);
|
||||
}
|
||||
|
||||
type_init(mac_dbdma_register_types)
|
||||
|
||||
@@ -41,7 +41,7 @@ typedef struct MacIOState
|
||||
|
||||
MemoryRegion bar;
|
||||
CUDAState cuda;
|
||||
void *dbdma;
|
||||
DBDMAState *dbdma;
|
||||
MemoryRegion *pic_mem;
|
||||
MemoryRegion *escc_mem;
|
||||
uint64_t frequency;
|
||||
@@ -127,10 +127,15 @@ static void macio_common_realize(PCIDevice *d, Error **errp)
|
||||
MacIOState *s = MACIO(d);
|
||||
SysBusDevice *sysbus_dev;
|
||||
Error *err = NULL;
|
||||
MemoryRegion *dbdma_mem;
|
||||
|
||||
s->dbdma = DBDMA_init(&dbdma_mem);
|
||||
memory_region_add_subregion(&s->bar, 0x08000, dbdma_mem);
|
||||
object_property_set_bool(OBJECT(s->dbdma), true, "realized", &err);
|
||||
if (err) {
|
||||
error_propagate(errp, err);
|
||||
return;
|
||||
}
|
||||
sysbus_dev = SYS_BUS_DEVICE(s->dbdma);
|
||||
memory_region_add_subregion(&s->bar, 0x08000,
|
||||
sysbus_mmio_get_region(sysbus_dev, 0));
|
||||
|
||||
object_property_set_bool(OBJECT(&s->cuda), true, "realized", &err);
|
||||
if (err) {
|
||||
@@ -154,7 +159,10 @@ static void macio_realize_ide(MacIOState *s, MACIOIDEState *ide,
|
||||
sysbus_dev = SYS_BUS_DEVICE(ide);
|
||||
sysbus_connect_irq(sysbus_dev, 0, irq0);
|
||||
sysbus_connect_irq(sysbus_dev, 1, irq1);
|
||||
macio_ide_register_dma(ide, s->dbdma, dmaid);
|
||||
qdev_prop_set_uint32(DEVICE(ide), "channel", dmaid);
|
||||
object_property_set_link(OBJECT(ide), OBJECT(s->dbdma), "dbdma", errp);
|
||||
macio_ide_register_dma(ide);
|
||||
|
||||
object_property_set_bool(OBJECT(ide), true, "realized", errp);
|
||||
}
|
||||
|
||||
@@ -334,6 +342,9 @@ static void macio_instance_init(Object *obj)
|
||||
object_initialize(&s->cuda, sizeof(s->cuda), TYPE_CUDA);
|
||||
qdev_set_parent_bus(DEVICE(&s->cuda), sysbus_get_default());
|
||||
object_property_add_child(obj, "cuda", OBJECT(&s->cuda), NULL);
|
||||
|
||||
s->dbdma = MAC_DBDMA(object_new(TYPE_MAC_DBDMA));
|
||||
object_property_add_child(obj, "dbdma", OBJECT(s->dbdma), NULL);
|
||||
}
|
||||
|
||||
static const VMStateDescription vmstate_macio_oldworld = {
|
||||
|
||||
160
hw/misc/msf2-sysreg.c
Normal file
160
hw/misc/msf2-sysreg.c
Normal file
@@ -0,0 +1,160 @@
|
||||
/*
|
||||
* System Register block model of Microsemi SmartFusion2.
|
||||
*
|
||||
* Copyright (c) 2017 Subbaraya Sundeep <sundeep.lkml@gmail.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version
|
||||
* 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "qapi/error.h"
|
||||
#include "qemu/log.h"
|
||||
#include "hw/misc/msf2-sysreg.h"
|
||||
#include "qemu/error-report.h"
|
||||
#include "trace.h"
|
||||
|
||||
static inline int msf2_divbits(uint32_t div)
|
||||
{
|
||||
int r = ctz32(div);
|
||||
|
||||
return (div < 8) ? r : r + 1;
|
||||
}
|
||||
|
||||
static void msf2_sysreg_reset(DeviceState *d)
|
||||
{
|
||||
MSF2SysregState *s = MSF2_SYSREG(d);
|
||||
|
||||
s->regs[MSSDDR_PLL_STATUS_LOW_CR] = 0x021A2358;
|
||||
s->regs[MSSDDR_PLL_STATUS] = 0x3;
|
||||
s->regs[MSSDDR_FACC1_CR] = msf2_divbits(s->apb0div) << 5 |
|
||||
msf2_divbits(s->apb1div) << 2;
|
||||
}
|
||||
|
||||
static uint64_t msf2_sysreg_read(void *opaque, hwaddr offset,
|
||||
unsigned size)
|
||||
{
|
||||
MSF2SysregState *s = opaque;
|
||||
uint32_t ret = 0;
|
||||
|
||||
offset >>= 2;
|
||||
if (offset < ARRAY_SIZE(s->regs)) {
|
||||
ret = s->regs[offset];
|
||||
trace_msf2_sysreg_read(offset << 2, ret);
|
||||
} else {
|
||||
qemu_log_mask(LOG_GUEST_ERROR,
|
||||
"%s: Bad offset 0x%08" HWADDR_PRIx "\n", __func__,
|
||||
offset << 2);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void msf2_sysreg_write(void *opaque, hwaddr offset,
|
||||
uint64_t val, unsigned size)
|
||||
{
|
||||
MSF2SysregState *s = opaque;
|
||||
uint32_t newval = val;
|
||||
|
||||
offset >>= 2;
|
||||
|
||||
switch (offset) {
|
||||
case MSSDDR_PLL_STATUS:
|
||||
trace_msf2_sysreg_write_pll_status();
|
||||
break;
|
||||
|
||||
case ESRAM_CR:
|
||||
case DDR_CR:
|
||||
case ENVM_REMAP_BASE_CR:
|
||||
if (newval != s->regs[offset]) {
|
||||
qemu_log_mask(LOG_UNIMP,
|
||||
TYPE_MSF2_SYSREG": remapping not supported\n");
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
if (offset < ARRAY_SIZE(s->regs)) {
|
||||
trace_msf2_sysreg_write(offset << 2, newval, s->regs[offset]);
|
||||
s->regs[offset] = newval;
|
||||
} else {
|
||||
qemu_log_mask(LOG_GUEST_ERROR,
|
||||
"%s: Bad offset 0x%08" HWADDR_PRIx "\n", __func__,
|
||||
offset << 2);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static const MemoryRegionOps sysreg_ops = {
|
||||
.read = msf2_sysreg_read,
|
||||
.write = msf2_sysreg_write,
|
||||
.endianness = DEVICE_NATIVE_ENDIAN,
|
||||
};
|
||||
|
||||
static void msf2_sysreg_init(Object *obj)
|
||||
{
|
||||
MSF2SysregState *s = MSF2_SYSREG(obj);
|
||||
|
||||
memory_region_init_io(&s->iomem, obj, &sysreg_ops, s, TYPE_MSF2_SYSREG,
|
||||
MSF2_SYSREG_MMIO_SIZE);
|
||||
sysbus_init_mmio(SYS_BUS_DEVICE(obj), &s->iomem);
|
||||
}
|
||||
|
||||
static const VMStateDescription vmstate_msf2_sysreg = {
|
||||
.name = TYPE_MSF2_SYSREG,
|
||||
.version_id = 1,
|
||||
.minimum_version_id = 1,
|
||||
.fields = (VMStateField[]) {
|
||||
VMSTATE_UINT32_ARRAY(regs, MSF2SysregState, MSF2_SYSREG_MMIO_SIZE / 4),
|
||||
VMSTATE_END_OF_LIST()
|
||||
}
|
||||
};
|
||||
|
||||
static Property msf2_sysreg_properties[] = {
|
||||
/* default divisors in Libero GUI */
|
||||
DEFINE_PROP_UINT8("apb0divisor", MSF2SysregState, apb0div, 2),
|
||||
DEFINE_PROP_UINT8("apb1divisor", MSF2SysregState, apb1div, 2),
|
||||
DEFINE_PROP_END_OF_LIST(),
|
||||
};
|
||||
|
||||
static void msf2_sysreg_realize(DeviceState *dev, Error **errp)
|
||||
{
|
||||
MSF2SysregState *s = MSF2_SYSREG(dev);
|
||||
|
||||
if ((s->apb0div > 32 || !is_power_of_2(s->apb0div))
|
||||
|| (s->apb1div > 32 || !is_power_of_2(s->apb1div))) {
|
||||
error_setg(errp, "Invalid apb divisor value");
|
||||
error_append_hint(errp, "apb divisor must be a power of 2"
|
||||
" and maximum value is 32\n");
|
||||
}
|
||||
}
|
||||
|
||||
static void msf2_sysreg_class_init(ObjectClass *klass, void *data)
|
||||
{
|
||||
DeviceClass *dc = DEVICE_CLASS(klass);
|
||||
|
||||
dc->vmsd = &vmstate_msf2_sysreg;
|
||||
dc->reset = msf2_sysreg_reset;
|
||||
dc->props = msf2_sysreg_properties;
|
||||
dc->realize = msf2_sysreg_realize;
|
||||
}
|
||||
|
||||
static const TypeInfo msf2_sysreg_info = {
|
||||
.name = TYPE_MSF2_SYSREG,
|
||||
.parent = TYPE_SYS_BUS_DEVICE,
|
||||
.class_init = msf2_sysreg_class_init,
|
||||
.instance_size = sizeof(MSF2SysregState),
|
||||
.instance_init = msf2_sysreg_init,
|
||||
};
|
||||
|
||||
static void msf2_sysreg_register_types(void)
|
||||
{
|
||||
type_register_static(&msf2_sysreg_info);
|
||||
}
|
||||
|
||||
type_init(msf2_sysreg_register_types)
|
||||
@@ -61,3 +61,8 @@ mps2_scc_reset(void) "MPS2 SCC: reset"
|
||||
mps2_scc_leds(char led7, char led6, char led5, char led4, char led3, char led2, char led1, char led0) "MPS2 SCC LEDs: %c%c%c%c%c%c%c%c"
|
||||
mps2_scc_cfg_write(unsigned function, unsigned device, uint32_t value) "MPS2 SCC config write: function %d device %d data 0x%" PRIx32
|
||||
mps2_scc_cfg_read(unsigned function, unsigned device, uint32_t value) "MPS2 SCC config read: function %d device %d data 0x%" PRIx32
|
||||
|
||||
# hw/misc/msf2-sysreg.c
|
||||
msf2_sysreg_write(uint64_t offset, uint32_t val, uint32_t prev) "msf2-sysreg write: addr 0x%08" HWADDR_PRIx " data 0x%" PRIx32 " prev 0x%" PRIx32
|
||||
msf2_sysreg_read(uint64_t offset, uint32_t val) "msf2-sysreg read: addr 0x%08" HWADDR_PRIx " data 0x%08" PRIx32
|
||||
msf2_sysreg_write_pll_status(void) "Invalid write to read only PLL status register"
|
||||
|
||||
10
hw/ppc/mac.h
10
hw/ppc/mac.h
@@ -131,8 +131,10 @@ typedef struct MACIOIDEState {
|
||||
/*< private >*/
|
||||
SysBusDevice parent_obj;
|
||||
/*< public >*/
|
||||
|
||||
qemu_irq irq;
|
||||
uint32_t channel;
|
||||
qemu_irq real_ide_irq;
|
||||
qemu_irq real_dma_irq;
|
||||
qemu_irq ide_irq;
|
||||
qemu_irq dma_irq;
|
||||
|
||||
MemoryRegion mem;
|
||||
@@ -140,10 +142,12 @@ typedef struct MACIOIDEState {
|
||||
IDEDMA dma;
|
||||
void *dbdma;
|
||||
bool dma_active;
|
||||
uint32_t timing_reg;
|
||||
uint32_t irq_reg;
|
||||
} MACIOIDEState;
|
||||
|
||||
void macio_ide_init_drives(MACIOIDEState *ide, DriveInfo **hd_table);
|
||||
void macio_ide_register_dma(MACIOIDEState *ide, void *dbdma, int channel);
|
||||
void macio_ide_register_dma(MACIOIDEState *ide);
|
||||
|
||||
void macio_init(PCIDevice *dev,
|
||||
MemoryRegion *pic_mem,
|
||||
|
||||
@@ -77,7 +77,7 @@
|
||||
#define MAX_IDE_BUS 2
|
||||
#define CFG_ADDR 0xf0000510
|
||||
#define TBFREQ (100UL * 1000UL * 1000UL)
|
||||
#define CLOCKFREQ (266UL * 1000UL * 1000UL)
|
||||
#define CLOCKFREQ (900UL * 1000UL * 1000UL)
|
||||
#define BUSFREQ (100UL * 1000UL * 1000UL)
|
||||
|
||||
#define NDRV_VGA_FILENAME "qemu_vga.ndrv"
|
||||
@@ -124,11 +124,6 @@ static uint64_t translate_kernel_address(void *opaque, uint64_t addr)
|
||||
return (addr & 0x0fffffff) + KERNEL_LOAD_ADDR;
|
||||
}
|
||||
|
||||
static hwaddr round_page(hwaddr addr)
|
||||
{
|
||||
return (addr + TARGET_PAGE_SIZE - 1) & TARGET_PAGE_MASK;
|
||||
}
|
||||
|
||||
static void ppc_core99_reset(void *opaque)
|
||||
{
|
||||
PowerPCCPU *cpu = opaque;
|
||||
@@ -252,7 +247,7 @@ static void ppc_core99_init(MachineState *machine)
|
||||
}
|
||||
/* load initrd */
|
||||
if (initrd_filename) {
|
||||
initrd_base = round_page(kernel_base + kernel_size + KERNEL_GAP);
|
||||
initrd_base = TARGET_PAGE_ALIGN(kernel_base + kernel_size + KERNEL_GAP);
|
||||
initrd_size = load_image_targphys(initrd_filename, initrd_base,
|
||||
ram_size - initrd_base);
|
||||
if (initrd_size < 0) {
|
||||
@@ -260,11 +255,11 @@ static void ppc_core99_init(MachineState *machine)
|
||||
initrd_filename);
|
||||
exit(1);
|
||||
}
|
||||
cmdline_base = round_page(initrd_base + initrd_size);
|
||||
cmdline_base = TARGET_PAGE_ALIGN(initrd_base + initrd_size);
|
||||
} else {
|
||||
initrd_base = 0;
|
||||
initrd_size = 0;
|
||||
cmdline_base = round_page(kernel_base + kernel_size + KERNEL_GAP);
|
||||
cmdline_base = TARGET_PAGE_ALIGN(kernel_base + kernel_size + KERNEL_GAP);
|
||||
}
|
||||
ppc_boot_device = 'm';
|
||||
} else {
|
||||
@@ -347,7 +342,7 @@ static void ppc_core99_init(MachineState *machine)
|
||||
pic = g_new0(qemu_irq, 64);
|
||||
|
||||
dev = qdev_create(NULL, TYPE_OPENPIC);
|
||||
qdev_prop_set_uint32(dev, "model", OPENPIC_MODEL_RAVEN);
|
||||
qdev_prop_set_uint32(dev, "model", OPENPIC_MODEL_KEYLARGO);
|
||||
qdev_init_nofail(dev);
|
||||
s = SYS_BUS_DEVICE(dev);
|
||||
pic_mem = s->mmio[0].memory;
|
||||
|
||||
@@ -66,11 +66,6 @@ static uint64_t translate_kernel_address(void *opaque, uint64_t addr)
|
||||
return (addr & 0x0fffffff) + KERNEL_LOAD_ADDR;
|
||||
}
|
||||
|
||||
static hwaddr round_page(hwaddr addr)
|
||||
{
|
||||
return (addr + TARGET_PAGE_SIZE - 1) & TARGET_PAGE_MASK;
|
||||
}
|
||||
|
||||
static void ppc_heathrow_reset(void *opaque)
|
||||
{
|
||||
PowerPCCPU *cpu = opaque;
|
||||
@@ -187,7 +182,7 @@ static void ppc_heathrow_init(MachineState *machine)
|
||||
}
|
||||
/* load initrd */
|
||||
if (initrd_filename) {
|
||||
initrd_base = round_page(kernel_base + kernel_size + KERNEL_GAP);
|
||||
initrd_base = TARGET_PAGE_ALIGN(kernel_base + kernel_size + KERNEL_GAP);
|
||||
initrd_size = load_image_targphys(initrd_filename, initrd_base,
|
||||
ram_size - initrd_base);
|
||||
if (initrd_size < 0) {
|
||||
@@ -195,11 +190,11 @@ static void ppc_heathrow_init(MachineState *machine)
|
||||
initrd_filename);
|
||||
exit(1);
|
||||
}
|
||||
cmdline_base = round_page(initrd_base + initrd_size);
|
||||
cmdline_base = TARGET_PAGE_ALIGN(initrd_base + initrd_size);
|
||||
} else {
|
||||
initrd_base = 0;
|
||||
initrd_size = 0;
|
||||
cmdline_base = round_page(kernel_base + kernel_size + KERNEL_GAP);
|
||||
cmdline_base = TARGET_PAGE_ALIGN(kernel_base + kernel_size + KERNEL_GAP);
|
||||
}
|
||||
ppc_boot_device = 'm';
|
||||
} else {
|
||||
@@ -376,8 +371,10 @@ static int heathrow_kvm_type(const char *arg)
|
||||
return 2;
|
||||
}
|
||||
|
||||
static void heathrow_machine_init(MachineClass *mc)
|
||||
static void heathrow_class_init(ObjectClass *oc, void *data)
|
||||
{
|
||||
MachineClass *mc = MACHINE_CLASS(oc);
|
||||
|
||||
mc->desc = "Heathrow based PowerMAC";
|
||||
mc->init = ppc_heathrow_init;
|
||||
mc->block_default_type = IF_IDE;
|
||||
@@ -390,4 +387,15 @@ static void heathrow_machine_init(MachineClass *mc)
|
||||
mc->kvm_type = heathrow_kvm_type;
|
||||
}
|
||||
|
||||
DEFINE_MACHINE("g3beige", heathrow_machine_init)
|
||||
static const TypeInfo ppc_heathrow_machine_info = {
|
||||
.name = MACHINE_TYPE_NAME("g3beige"),
|
||||
.parent = TYPE_MACHINE,
|
||||
.class_init = heathrow_class_init
|
||||
};
|
||||
|
||||
static void ppc_heathrow_register_types(void)
|
||||
{
|
||||
type_register_static(&ppc_heathrow_machine_info);
|
||||
}
|
||||
|
||||
type_init(ppc_heathrow_register_types);
|
||||
|
||||
@@ -570,10 +570,14 @@ static void ppc_powernv_init(MachineState *machine)
|
||||
}
|
||||
|
||||
fw_filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, bios_name);
|
||||
if (!fw_filename) {
|
||||
error_report("Could not find OPAL firmware '%s'", bios_name);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
fw_size = load_image_targphys(fw_filename, FW_LOAD_ADDR, FW_MAX_SIZE);
|
||||
if (fw_size < 0) {
|
||||
error_report("Could not load OPAL '%s'", fw_filename);
|
||||
error_report("Could not load OPAL firmware '%s'", fw_filename);
|
||||
exit(1);
|
||||
}
|
||||
g_free(fw_filename);
|
||||
|
||||
@@ -105,9 +105,12 @@ ram_addr_t ppc405_set_bootinfo (CPUPPCState *env, ppc4xx_bd_info_t *bd,
|
||||
/*****************************************************************************/
|
||||
/* Peripheral local bus arbitrer */
|
||||
enum {
|
||||
PLB0_BESR = 0x084,
|
||||
PLB0_BEAR = 0x086,
|
||||
PLB0_ACR = 0x087,
|
||||
PLB3A0_ACR = 0x077,
|
||||
PLB4A0_ACR = 0x081,
|
||||
PLB0_BESR = 0x084,
|
||||
PLB0_BEAR = 0x086,
|
||||
PLB0_ACR = 0x087,
|
||||
PLB4A1_ACR = 0x089,
|
||||
};
|
||||
|
||||
typedef struct ppc4xx_plb_t ppc4xx_plb_t;
|
||||
@@ -179,9 +182,12 @@ void ppc4xx_plb_init(CPUPPCState *env)
|
||||
ppc4xx_plb_t *plb;
|
||||
|
||||
plb = g_malloc0(sizeof(ppc4xx_plb_t));
|
||||
ppc_dcr_register(env, PLB3A0_ACR, plb, &dcr_read_plb, &dcr_write_plb);
|
||||
ppc_dcr_register(env, PLB4A0_ACR, plb, &dcr_read_plb, &dcr_write_plb);
|
||||
ppc_dcr_register(env, PLB0_ACR, plb, &dcr_read_plb, &dcr_write_plb);
|
||||
ppc_dcr_register(env, PLB0_BEAR, plb, &dcr_read_plb, &dcr_write_plb);
|
||||
ppc_dcr_register(env, PLB0_BESR, plb, &dcr_read_plb, &dcr_write_plb);
|
||||
ppc_dcr_register(env, PLB4A1_ACR, plb, &dcr_read_plb, &dcr_write_plb);
|
||||
qemu_register_reset(ppc4xx_plb_reset, plb);
|
||||
}
|
||||
|
||||
|
||||
@@ -1211,14 +1211,15 @@ static uint64_t spapr_get_patbe(PPCVirtualHypervisor *vhyp)
|
||||
*/
|
||||
static int get_htab_fd(sPAPRMachineState *spapr)
|
||||
{
|
||||
Error *local_err = NULL;
|
||||
|
||||
if (spapr->htab_fd >= 0) {
|
||||
return spapr->htab_fd;
|
||||
}
|
||||
|
||||
spapr->htab_fd = kvmppc_get_htab_fd(false);
|
||||
spapr->htab_fd = kvmppc_get_htab_fd(false, 0, &local_err);
|
||||
if (spapr->htab_fd < 0) {
|
||||
error_report("Unable to open fd for reading hash table from KVM: %s",
|
||||
strerror(errno));
|
||||
error_report_err(local_err);
|
||||
}
|
||||
|
||||
return spapr->htab_fd;
|
||||
@@ -1239,6 +1240,19 @@ static hwaddr spapr_hpt_mask(PPCVirtualHypervisor *vhyp)
|
||||
return HTAB_SIZE(spapr) / HASH_PTEG_SIZE_64 - 1;
|
||||
}
|
||||
|
||||
static target_ulong spapr_encode_hpt_for_kvm_pr(PPCVirtualHypervisor *vhyp)
|
||||
{
|
||||
sPAPRMachineState *spapr = SPAPR_MACHINE(vhyp);
|
||||
|
||||
assert(kvm_enabled());
|
||||
|
||||
if (!spapr->htab) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return (target_ulong)(uintptr_t)spapr->htab | (spapr->htab_shift - 18);
|
||||
}
|
||||
|
||||
static const ppc_hash_pte64_t *spapr_map_hptes(PPCVirtualHypervisor *vhyp,
|
||||
hwaddr ptex, int n)
|
||||
{
|
||||
@@ -1708,6 +1722,23 @@ static int htab_save_setup(QEMUFile *f, void *opaque)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void htab_save_chunk(QEMUFile *f, sPAPRMachineState *spapr,
|
||||
int chunkstart, int n_valid, int n_invalid)
|
||||
{
|
||||
qemu_put_be32(f, chunkstart);
|
||||
qemu_put_be16(f, n_valid);
|
||||
qemu_put_be16(f, n_invalid);
|
||||
qemu_put_buffer(f, HPTE(spapr->htab, chunkstart),
|
||||
HASH_PTE_SIZE_64 * n_valid);
|
||||
}
|
||||
|
||||
static void htab_save_end_marker(QEMUFile *f)
|
||||
{
|
||||
qemu_put_be32(f, 0);
|
||||
qemu_put_be16(f, 0);
|
||||
qemu_put_be16(f, 0);
|
||||
}
|
||||
|
||||
static void htab_save_first_pass(QEMUFile *f, sPAPRMachineState *spapr,
|
||||
int64_t max_ns)
|
||||
{
|
||||
@@ -1739,11 +1770,7 @@ static void htab_save_first_pass(QEMUFile *f, sPAPRMachineState *spapr,
|
||||
if (index > chunkstart) {
|
||||
int n_valid = index - chunkstart;
|
||||
|
||||
qemu_put_be32(f, chunkstart);
|
||||
qemu_put_be16(f, n_valid);
|
||||
qemu_put_be16(f, 0);
|
||||
qemu_put_buffer(f, HPTE(spapr->htab, chunkstart),
|
||||
HASH_PTE_SIZE_64 * n_valid);
|
||||
htab_save_chunk(f, spapr, chunkstart, n_valid, 0);
|
||||
|
||||
if (has_timeout &&
|
||||
(qemu_clock_get_ns(QEMU_CLOCK_REALTIME) - starttime) > max_ns) {
|
||||
@@ -1805,11 +1832,7 @@ static int htab_save_later_pass(QEMUFile *f, sPAPRMachineState *spapr,
|
||||
int n_valid = invalidstart - chunkstart;
|
||||
int n_invalid = index - invalidstart;
|
||||
|
||||
qemu_put_be32(f, chunkstart);
|
||||
qemu_put_be16(f, n_valid);
|
||||
qemu_put_be16(f, n_invalid);
|
||||
qemu_put_buffer(f, HPTE(spapr->htab, chunkstart),
|
||||
HASH_PTE_SIZE_64 * n_valid);
|
||||
htab_save_chunk(f, spapr, chunkstart, n_valid, n_invalid);
|
||||
sent += index - chunkstart;
|
||||
|
||||
if (!final && (qemu_clock_get_ns(QEMU_CLOCK_REALTIME) - starttime) > max_ns) {
|
||||
@@ -1872,10 +1895,7 @@ static int htab_save_iterate(QEMUFile *f, void *opaque)
|
||||
rc = htab_save_later_pass(f, spapr, MAX_ITERATION_NS);
|
||||
}
|
||||
|
||||
/* End marker */
|
||||
qemu_put_be32(f, 0);
|
||||
qemu_put_be16(f, 0);
|
||||
qemu_put_be16(f, 0);
|
||||
htab_save_end_marker(f);
|
||||
|
||||
return rc;
|
||||
}
|
||||
@@ -1915,9 +1935,7 @@ static int htab_save_complete(QEMUFile *f, void *opaque)
|
||||
}
|
||||
|
||||
/* End marker */
|
||||
qemu_put_be32(f, 0);
|
||||
qemu_put_be16(f, 0);
|
||||
qemu_put_be16(f, 0);
|
||||
htab_save_end_marker(f);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -1927,6 +1945,7 @@ static int htab_load(QEMUFile *f, void *opaque, int version_id)
|
||||
sPAPRMachineState *spapr = opaque;
|
||||
uint32_t section_hdr;
|
||||
int fd = -1;
|
||||
Error *local_err = NULL;
|
||||
|
||||
if (version_id < 1 || version_id > 1) {
|
||||
error_report("htab_load() bad version");
|
||||
@@ -1941,8 +1960,6 @@ static int htab_load(QEMUFile *f, void *opaque, int version_id)
|
||||
}
|
||||
|
||||
if (section_hdr) {
|
||||
Error *local_err = NULL;
|
||||
|
||||
/* First section gives the htab size */
|
||||
spapr_reallocate_hpt(spapr, section_hdr, &local_err);
|
||||
if (local_err) {
|
||||
@@ -1955,10 +1972,10 @@ static int htab_load(QEMUFile *f, void *opaque, int version_id)
|
||||
if (!spapr->htab) {
|
||||
assert(kvm_enabled());
|
||||
|
||||
fd = kvmppc_get_htab_fd(true);
|
||||
fd = kvmppc_get_htab_fd(true, 0, &local_err);
|
||||
if (fd < 0) {
|
||||
error_report("Unable to open fd to restore KVM hash table: %s",
|
||||
strerror(errno));
|
||||
error_report_err(local_err);
|
||||
return fd;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3600,6 +3617,7 @@ static void spapr_machine_class_init(ObjectClass *oc, void *data)
|
||||
vhc->unmap_hptes = spapr_unmap_hptes;
|
||||
vhc->store_hpte = spapr_store_hpte;
|
||||
vhc->get_patbe = spapr_get_patbe;
|
||||
vhc->encode_hpt_for_kvm_pr = spapr_encode_hpt_for_kvm_pr;
|
||||
xic->ics_get = spapr_ics_get;
|
||||
xic->ics_resend = spapr_ics_resend;
|
||||
xic->icp_get = spapr_icp_get;
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
#include "hw/ppc/ppc.h"
|
||||
#include "target/ppc/mmu-hash64.h"
|
||||
#include "sysemu/numa.h"
|
||||
#include "sysemu/hw_accel.h"
|
||||
#include "qemu/error-report.h"
|
||||
|
||||
void spapr_cpu_parse_features(sPAPRMachineState *spapr)
|
||||
@@ -73,7 +74,6 @@ void spapr_cpu_parse_features(sPAPRMachineState *spapr)
|
||||
|
||||
static void spapr_cpu_reset(void *opaque)
|
||||
{
|
||||
sPAPRMachineState *spapr = SPAPR_MACHINE(qdev_get_machine());
|
||||
PowerPCCPU *cpu = opaque;
|
||||
CPUState *cs = CPU(cpu);
|
||||
CPUPPCState *env = &cpu->env;
|
||||
@@ -86,20 +86,6 @@ static void spapr_cpu_reset(void *opaque)
|
||||
cs->halted = 1;
|
||||
|
||||
env->spr[SPR_HIOR] = 0;
|
||||
|
||||
/*
|
||||
* This is a hack for the benefit of KVM PR - it abuses the SDR1
|
||||
* slot in kvm_sregs to communicate the userspace address of the
|
||||
* HPT
|
||||
*/
|
||||
if (kvm_enabled()) {
|
||||
env->spr[SPR_SDR1] = (target_ulong)(uintptr_t)spapr->htab
|
||||
| (spapr->htab_shift - 18);
|
||||
if (kvmppc_put_books_sregs(cpu) < 0) {
|
||||
error_report("Unable to update SDR1 in KVM");
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void spapr_cpu_destroy(PowerPCCPU *cpu)
|
||||
|
||||
@@ -686,6 +686,37 @@ static int rehash_hpt(PowerPCCPU *cpu,
|
||||
return H_SUCCESS;
|
||||
}
|
||||
|
||||
static void do_push_sregs_to_kvm_pr(CPUState *cs, run_on_cpu_data data)
|
||||
{
|
||||
int ret;
|
||||
|
||||
cpu_synchronize_state(cs);
|
||||
|
||||
ret = kvmppc_put_books_sregs(POWERPC_CPU(cs));
|
||||
if (ret < 0) {
|
||||
error_report("failed to push sregs to KVM: %s", strerror(-ret));
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
static void push_sregs_to_kvm_pr(sPAPRMachineState *spapr)
|
||||
{
|
||||
CPUState *cs;
|
||||
|
||||
/*
|
||||
* This is a hack for the benefit of KVM PR - it abuses the SDR1
|
||||
* slot in kvm_sregs to communicate the userspace address of the
|
||||
* HPT
|
||||
*/
|
||||
if (!kvm_enabled() || !spapr->htab) {
|
||||
return;
|
||||
}
|
||||
|
||||
CPU_FOREACH(cs) {
|
||||
run_on_cpu(cs, do_push_sregs_to_kvm_pr, RUN_ON_CPU_NULL);
|
||||
}
|
||||
}
|
||||
|
||||
static target_ulong h_resize_hpt_commit(PowerPCCPU *cpu,
|
||||
sPAPRMachineState *spapr,
|
||||
target_ulong opcode,
|
||||
@@ -733,12 +764,7 @@ static target_ulong h_resize_hpt_commit(PowerPCCPU *cpu,
|
||||
spapr->htab = pending->hpt;
|
||||
spapr->htab_shift = pending->shift;
|
||||
|
||||
if (kvm_enabled()) {
|
||||
/* For KVM PR, update the HPT pointer */
|
||||
target_ulong sdr1 = (target_ulong)(uintptr_t)spapr->htab
|
||||
| (spapr->htab_shift - 18);
|
||||
kvmppc_update_sdr1(sdr1);
|
||||
}
|
||||
push_sregs_to_kvm_pr(spapr);
|
||||
|
||||
pending->hpt = NULL; /* so it's not free()d */
|
||||
}
|
||||
@@ -1564,12 +1590,7 @@ static target_ulong h_client_architecture_support(PowerPCCPU *cpu,
|
||||
* the point this is called, nothing should have been
|
||||
* entered into the existing HPT */
|
||||
spapr_reallocate_hpt(spapr, maxshift, &error_fatal);
|
||||
if (kvm_enabled()) {
|
||||
/* For KVM PR, update the HPT pointer */
|
||||
target_ulong sdr1 = (target_ulong)(uintptr_t)spapr->htab
|
||||
| (spapr->htab_shift - 18);
|
||||
kvmppc_update_sdr1(sdr1);
|
||||
}
|
||||
push_sregs_to_kvm_pr(spapr);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1523,16 +1523,6 @@ static void spapr_phb_realize(DeviceState *dev, Error **errp)
|
||||
sPAPRMachineClass *smc = SPAPR_MACHINE_GET_CLASS(spapr);
|
||||
Error *local_err = NULL;
|
||||
|
||||
if ((sphb->buid != (uint64_t)-1) || (sphb->dma_liobn[0] != (uint32_t)-1)
|
||||
|| (sphb->dma_liobn[1] != (uint32_t)-1 && windows_supported == 2)
|
||||
|| (sphb->mem_win_addr != (hwaddr)-1)
|
||||
|| (sphb->mem64_win_addr != (hwaddr)-1)
|
||||
|| (sphb->io_win_addr != (hwaddr)-1)) {
|
||||
error_setg(errp, "Either \"index\" or other parameters must"
|
||||
" be specified for PAPR PHB, not both");
|
||||
return;
|
||||
}
|
||||
|
||||
smc->phb_placement(spapr, sphb->index,
|
||||
&sphb->buid, &sphb->io_win_addr,
|
||||
&sphb->mem_win_addr, &sphb->mem64_win_addr,
|
||||
@@ -1541,46 +1531,20 @@ static void spapr_phb_realize(DeviceState *dev, Error **errp)
|
||||
error_propagate(errp, local_err);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (sphb->buid == (uint64_t)-1) {
|
||||
error_setg(errp, "BUID not specified for PHB");
|
||||
return;
|
||||
}
|
||||
|
||||
if ((sphb->dma_liobn[0] == (uint32_t)-1) ||
|
||||
((sphb->dma_liobn[1] == (uint32_t)-1) && (windows_supported > 1))) {
|
||||
error_setg(errp, "LIOBN(s) not specified for PHB");
|
||||
return;
|
||||
}
|
||||
|
||||
if (sphb->mem_win_addr == (hwaddr)-1) {
|
||||
error_setg(errp, "Memory window address not specified for PHB");
|
||||
return;
|
||||
}
|
||||
|
||||
if (sphb->io_win_addr == (hwaddr)-1) {
|
||||
error_setg(errp, "IO window address not specified for PHB");
|
||||
} else {
|
||||
error_setg(errp, "\"index\" for PAPR PHB is mandatory");
|
||||
return;
|
||||
}
|
||||
|
||||
if (sphb->mem64_win_size != 0) {
|
||||
if (sphb->mem64_win_addr == (hwaddr)-1) {
|
||||
error_setg(errp,
|
||||
"64-bit memory window address not specified for PHB");
|
||||
return;
|
||||
}
|
||||
|
||||
if (sphb->mem_win_size > SPAPR_PCI_MEM32_WIN_SIZE) {
|
||||
error_setg(errp, "32-bit memory window of size 0x%"HWADDR_PRIx
|
||||
" (max 2 GiB)", sphb->mem_win_size);
|
||||
return;
|
||||
}
|
||||
|
||||
if (sphb->mem64_win_pciaddr == (hwaddr)-1) {
|
||||
/* 64-bit window defaults to identity mapping */
|
||||
sphb->mem64_win_pciaddr = sphb->mem64_win_addr;
|
||||
}
|
||||
/* 64-bit window defaults to identity mapping */
|
||||
sphb->mem64_win_pciaddr = sphb->mem64_win_addr;
|
||||
} else if (sphb->mem_win_size > SPAPR_PCI_MEM32_WIN_SIZE) {
|
||||
/*
|
||||
* For compatibility with old configuration, if no 64-bit MMIO
|
||||
@@ -1622,18 +1586,16 @@ static void spapr_phb_realize(DeviceState *dev, Error **errp)
|
||||
memory_region_add_subregion(get_system_memory(), sphb->mem_win_addr,
|
||||
&sphb->mem32window);
|
||||
|
||||
if (sphb->mem64_win_pciaddr != (hwaddr)-1) {
|
||||
if (sphb->mem64_win_size != 0) {
|
||||
namebuf = g_strdup_printf("%s.mmio64-alias", sphb->dtbusname);
|
||||
memory_region_init_alias(&sphb->mem64window, OBJECT(sphb),
|
||||
namebuf, &sphb->memspace,
|
||||
sphb->mem64_win_pciaddr, sphb->mem64_win_size);
|
||||
g_free(namebuf);
|
||||
|
||||
if (sphb->mem64_win_addr != (hwaddr)-1) {
|
||||
memory_region_add_subregion(get_system_memory(),
|
||||
sphb->mem64_win_addr,
|
||||
&sphb->mem64window);
|
||||
}
|
||||
memory_region_add_subregion(get_system_memory(),
|
||||
sphb->mem64_win_addr,
|
||||
&sphb->mem64window);
|
||||
}
|
||||
|
||||
/* Initialize IO regions */
|
||||
@@ -1789,18 +1751,10 @@ static void spapr_phb_reset(DeviceState *qdev)
|
||||
|
||||
static Property spapr_phb_properties[] = {
|
||||
DEFINE_PROP_UINT32("index", sPAPRPHBState, index, -1),
|
||||
DEFINE_PROP_UINT64("buid", sPAPRPHBState, buid, -1),
|
||||
DEFINE_PROP_UINT32("liobn", sPAPRPHBState, dma_liobn[0], -1),
|
||||
DEFINE_PROP_UINT32("liobn64", sPAPRPHBState, dma_liobn[1], -1),
|
||||
DEFINE_PROP_UINT64("mem_win_addr", sPAPRPHBState, mem_win_addr, -1),
|
||||
DEFINE_PROP_UINT64("mem_win_size", sPAPRPHBState, mem_win_size,
|
||||
SPAPR_PCI_MEM32_WIN_SIZE),
|
||||
DEFINE_PROP_UINT64("mem64_win_addr", sPAPRPHBState, mem64_win_addr, -1),
|
||||
DEFINE_PROP_UINT64("mem64_win_size", sPAPRPHBState, mem64_win_size,
|
||||
SPAPR_PCI_MEM64_WIN_SIZE),
|
||||
DEFINE_PROP_UINT64("mem64_win_pciaddr", sPAPRPHBState, mem64_win_pciaddr,
|
||||
-1),
|
||||
DEFINE_PROP_UINT64("io_win_addr", sPAPRPHBState, io_win_addr, -1),
|
||||
DEFINE_PROP_UINT64("io_win_size", sPAPRPHBState, io_win_size,
|
||||
SPAPR_PCI_IO_WIN_SIZE),
|
||||
DEFINE_PROP_BOOL("dynamic-reconfiguration", sPAPRPHBState, dr_enabled,
|
||||
|
||||
@@ -4,6 +4,7 @@ common-obj-$(CONFIG_XILINX_SPI) += xilinx_spi.o
|
||||
common-obj-$(CONFIG_XILINX_SPIPS) += xilinx_spips.o
|
||||
common-obj-$(CONFIG_ASPEED_SOC) += aspeed_smc.o
|
||||
common-obj-$(CONFIG_STM32F2XX_SPI) += stm32f2xx_spi.o
|
||||
common-obj-$(CONFIG_MSF2) += mss-spi.o
|
||||
|
||||
obj-$(CONFIG_OMAP) += omap_spi.o
|
||||
obj-$(CONFIG_IMX) += imx_spi.o
|
||||
|
||||
404
hw/ssi/mss-spi.c
Normal file
404
hw/ssi/mss-spi.c
Normal file
@@ -0,0 +1,404 @@
|
||||
/*
|
||||
* Block model of SPI controller present in
|
||||
* Microsemi's SmartFusion2 and SmartFusion SoCs.
|
||||
*
|
||||
* Copyright (C) 2017 Subbaraya Sundeep <sundeep.lkml@gmail.com>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "hw/ssi/mss-spi.h"
|
||||
#include "qemu/log.h"
|
||||
|
||||
#ifndef MSS_SPI_ERR_DEBUG
|
||||
#define MSS_SPI_ERR_DEBUG 0
|
||||
#endif
|
||||
|
||||
#define DB_PRINT_L(lvl, fmt, args...) do { \
|
||||
if (MSS_SPI_ERR_DEBUG >= lvl) { \
|
||||
qemu_log("%s: " fmt "\n", __func__, ## args); \
|
||||
} \
|
||||
} while (0);
|
||||
|
||||
#define DB_PRINT(fmt, args...) DB_PRINT_L(1, fmt, ## args)
|
||||
|
||||
#define FIFO_CAPACITY 32
|
||||
|
||||
#define R_SPI_CONTROL 0
|
||||
#define R_SPI_DFSIZE 1
|
||||
#define R_SPI_STATUS 2
|
||||
#define R_SPI_INTCLR 3
|
||||
#define R_SPI_RX 4
|
||||
#define R_SPI_TX 5
|
||||
#define R_SPI_CLKGEN 6
|
||||
#define R_SPI_SS 7
|
||||
#define R_SPI_MIS 8
|
||||
#define R_SPI_RIS 9
|
||||
|
||||
#define S_TXDONE (1 << 0)
|
||||
#define S_RXRDY (1 << 1)
|
||||
#define S_RXCHOVRF (1 << 2)
|
||||
#define S_RXFIFOFUL (1 << 4)
|
||||
#define S_RXFIFOFULNXT (1 << 5)
|
||||
#define S_RXFIFOEMP (1 << 6)
|
||||
#define S_RXFIFOEMPNXT (1 << 7)
|
||||
#define S_TXFIFOFUL (1 << 8)
|
||||
#define S_TXFIFOFULNXT (1 << 9)
|
||||
#define S_TXFIFOEMP (1 << 10)
|
||||
#define S_TXFIFOEMPNXT (1 << 11)
|
||||
#define S_FRAMESTART (1 << 12)
|
||||
#define S_SSEL (1 << 13)
|
||||
#define S_ACTIVE (1 << 14)
|
||||
|
||||
#define C_ENABLE (1 << 0)
|
||||
#define C_MODE (1 << 1)
|
||||
#define C_INTRXDATA (1 << 4)
|
||||
#define C_INTTXDATA (1 << 5)
|
||||
#define C_INTRXOVRFLO (1 << 6)
|
||||
#define C_SPS (1 << 26)
|
||||
#define C_BIGFIFO (1 << 29)
|
||||
#define C_RESET (1 << 31)
|
||||
|
||||
#define FRAMESZ_MASK 0x1F
|
||||
#define FMCOUNT_MASK 0x00FFFF00
|
||||
#define FMCOUNT_SHIFT 8
|
||||
|
||||
static void txfifo_reset(MSSSpiState *s)
|
||||
{
|
||||
fifo32_reset(&s->tx_fifo);
|
||||
|
||||
s->regs[R_SPI_STATUS] &= ~S_TXFIFOFUL;
|
||||
s->regs[R_SPI_STATUS] |= S_TXFIFOEMP;
|
||||
}
|
||||
|
||||
static void rxfifo_reset(MSSSpiState *s)
|
||||
{
|
||||
fifo32_reset(&s->rx_fifo);
|
||||
|
||||
s->regs[R_SPI_STATUS] &= ~S_RXFIFOFUL;
|
||||
s->regs[R_SPI_STATUS] |= S_RXFIFOEMP;
|
||||
}
|
||||
|
||||
static void set_fifodepth(MSSSpiState *s)
|
||||
{
|
||||
unsigned int size = s->regs[R_SPI_DFSIZE] & FRAMESZ_MASK;
|
||||
|
||||
if (size <= 8) {
|
||||
s->fifo_depth = 32;
|
||||
} else if (size <= 16) {
|
||||
s->fifo_depth = 16;
|
||||
} else if (size <= 32) {
|
||||
s->fifo_depth = 8;
|
||||
} else {
|
||||
s->fifo_depth = 4;
|
||||
}
|
||||
}
|
||||
|
||||
static void update_mis(MSSSpiState *s)
|
||||
{
|
||||
uint32_t reg = s->regs[R_SPI_CONTROL];
|
||||
uint32_t tmp;
|
||||
|
||||
/*
|
||||
* form the Control register interrupt enable bits
|
||||
* same as RIS, MIS and Interrupt clear registers for simplicity
|
||||
*/
|
||||
tmp = ((reg & C_INTRXOVRFLO) >> 4) | ((reg & C_INTRXDATA) >> 3) |
|
||||
((reg & C_INTTXDATA) >> 5);
|
||||
s->regs[R_SPI_MIS] |= tmp & s->regs[R_SPI_RIS];
|
||||
}
|
||||
|
||||
static void spi_update_irq(MSSSpiState *s)
|
||||
{
|
||||
int irq;
|
||||
|
||||
update_mis(s);
|
||||
irq = !!(s->regs[R_SPI_MIS]);
|
||||
|
||||
qemu_set_irq(s->irq, irq);
|
||||
}
|
||||
|
||||
static void mss_spi_reset(DeviceState *d)
|
||||
{
|
||||
MSSSpiState *s = MSS_SPI(d);
|
||||
|
||||
memset(s->regs, 0, sizeof s->regs);
|
||||
s->regs[R_SPI_CONTROL] = 0x80000102;
|
||||
s->regs[R_SPI_DFSIZE] = 0x4;
|
||||
s->regs[R_SPI_STATUS] = S_SSEL | S_TXFIFOEMP | S_RXFIFOEMP;
|
||||
s->regs[R_SPI_CLKGEN] = 0x7;
|
||||
s->regs[R_SPI_RIS] = 0x0;
|
||||
|
||||
s->fifo_depth = 4;
|
||||
s->frame_count = 1;
|
||||
s->enabled = false;
|
||||
|
||||
rxfifo_reset(s);
|
||||
txfifo_reset(s);
|
||||
}
|
||||
|
||||
static uint64_t
|
||||
spi_read(void *opaque, hwaddr addr, unsigned int size)
|
||||
{
|
||||
MSSSpiState *s = opaque;
|
||||
uint32_t ret = 0;
|
||||
|
||||
addr >>= 2;
|
||||
switch (addr) {
|
||||
case R_SPI_RX:
|
||||
s->regs[R_SPI_STATUS] &= ~S_RXFIFOFUL;
|
||||
s->regs[R_SPI_STATUS] &= ~S_RXCHOVRF;
|
||||
ret = fifo32_pop(&s->rx_fifo);
|
||||
if (fifo32_is_empty(&s->rx_fifo)) {
|
||||
s->regs[R_SPI_STATUS] |= S_RXFIFOEMP;
|
||||
}
|
||||
break;
|
||||
|
||||
case R_SPI_MIS:
|
||||
update_mis(s);
|
||||
ret = s->regs[R_SPI_MIS];
|
||||
break;
|
||||
|
||||
default:
|
||||
if (addr < ARRAY_SIZE(s->regs)) {
|
||||
ret = s->regs[addr];
|
||||
} else {
|
||||
qemu_log_mask(LOG_GUEST_ERROR,
|
||||
"%s: Bad offset 0x%" HWADDR_PRIx "\n", __func__,
|
||||
addr * 4);
|
||||
return ret;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
DB_PRINT("addr=0x%" HWADDR_PRIx " = 0x%" PRIx32, addr * 4, ret);
|
||||
spi_update_irq(s);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void assert_cs(MSSSpiState *s)
|
||||
{
|
||||
qemu_set_irq(s->cs_line, 0);
|
||||
}
|
||||
|
||||
static void deassert_cs(MSSSpiState *s)
|
||||
{
|
||||
qemu_set_irq(s->cs_line, 1);
|
||||
}
|
||||
|
||||
static void spi_flush_txfifo(MSSSpiState *s)
|
||||
{
|
||||
uint32_t tx;
|
||||
uint32_t rx;
|
||||
bool sps = !!(s->regs[R_SPI_CONTROL] & C_SPS);
|
||||
|
||||
/*
|
||||
* Chip Select(CS) is automatically controlled by this controller.
|
||||
* If SPS bit is set in Control register then CS is asserted
|
||||
* until all the frames set in frame count of Control register are
|
||||
* transferred. If SPS is not set then CS pulses between frames.
|
||||
* Note that Slave Select register specifies which of the CS line
|
||||
* has to be controlled automatically by controller. Bits SS[7:1] are for
|
||||
* masters in FPGA fabric since we model only Microcontroller subsystem
|
||||
* of Smartfusion2 we control only one CS(SS[0]) line.
|
||||
*/
|
||||
while (!fifo32_is_empty(&s->tx_fifo) && s->frame_count) {
|
||||
assert_cs(s);
|
||||
|
||||
s->regs[R_SPI_STATUS] &= ~(S_TXDONE | S_RXRDY);
|
||||
|
||||
tx = fifo32_pop(&s->tx_fifo);
|
||||
DB_PRINT("data tx:0x%" PRIx32, tx);
|
||||
rx = ssi_transfer(s->spi, tx);
|
||||
DB_PRINT("data rx:0x%" PRIx32, rx);
|
||||
|
||||
if (fifo32_num_used(&s->rx_fifo) == s->fifo_depth) {
|
||||
s->regs[R_SPI_STATUS] |= S_RXCHOVRF;
|
||||
s->regs[R_SPI_RIS] |= S_RXCHOVRF;
|
||||
} else {
|
||||
fifo32_push(&s->rx_fifo, rx);
|
||||
s->regs[R_SPI_STATUS] &= ~S_RXFIFOEMP;
|
||||
if (fifo32_num_used(&s->rx_fifo) == (s->fifo_depth - 1)) {
|
||||
s->regs[R_SPI_STATUS] |= S_RXFIFOFULNXT;
|
||||
} else if (fifo32_num_used(&s->rx_fifo) == s->fifo_depth) {
|
||||
s->regs[R_SPI_STATUS] |= S_RXFIFOFUL;
|
||||
}
|
||||
}
|
||||
s->frame_count--;
|
||||
if (!sps) {
|
||||
deassert_cs(s);
|
||||
}
|
||||
}
|
||||
|
||||
if (!s->frame_count) {
|
||||
s->frame_count = (s->regs[R_SPI_CONTROL] & FMCOUNT_MASK) >>
|
||||
FMCOUNT_SHIFT;
|
||||
deassert_cs(s);
|
||||
s->regs[R_SPI_RIS] |= S_TXDONE | S_RXRDY;
|
||||
s->regs[R_SPI_STATUS] |= S_TXDONE | S_RXRDY;
|
||||
}
|
||||
}
|
||||
|
||||
static void spi_write(void *opaque, hwaddr addr,
|
||||
uint64_t val64, unsigned int size)
|
||||
{
|
||||
MSSSpiState *s = opaque;
|
||||
uint32_t value = val64;
|
||||
|
||||
DB_PRINT("addr=0x%" HWADDR_PRIx " =0x%" PRIx32, addr, value);
|
||||
addr >>= 2;
|
||||
|
||||
switch (addr) {
|
||||
case R_SPI_TX:
|
||||
/* adding to already full FIFO */
|
||||
if (fifo32_num_used(&s->tx_fifo) == s->fifo_depth) {
|
||||
break;
|
||||
}
|
||||
s->regs[R_SPI_STATUS] &= ~S_TXFIFOEMP;
|
||||
fifo32_push(&s->tx_fifo, value);
|
||||
if (fifo32_num_used(&s->tx_fifo) == (s->fifo_depth - 1)) {
|
||||
s->regs[R_SPI_STATUS] |= S_TXFIFOFULNXT;
|
||||
} else if (fifo32_num_used(&s->tx_fifo) == s->fifo_depth) {
|
||||
s->regs[R_SPI_STATUS] |= S_TXFIFOFUL;
|
||||
}
|
||||
if (s->enabled) {
|
||||
spi_flush_txfifo(s);
|
||||
}
|
||||
break;
|
||||
|
||||
case R_SPI_CONTROL:
|
||||
s->regs[R_SPI_CONTROL] = value;
|
||||
if (value & C_BIGFIFO) {
|
||||
set_fifodepth(s);
|
||||
} else {
|
||||
s->fifo_depth = 4;
|
||||
}
|
||||
s->enabled = value & C_ENABLE;
|
||||
s->frame_count = (value & FMCOUNT_MASK) >> FMCOUNT_SHIFT;
|
||||
if (value & C_RESET) {
|
||||
mss_spi_reset(DEVICE(s));
|
||||
}
|
||||
break;
|
||||
|
||||
case R_SPI_DFSIZE:
|
||||
if (s->enabled) {
|
||||
break;
|
||||
}
|
||||
s->regs[R_SPI_DFSIZE] = value;
|
||||
break;
|
||||
|
||||
case R_SPI_INTCLR:
|
||||
s->regs[R_SPI_INTCLR] = value;
|
||||
if (value & S_TXDONE) {
|
||||
s->regs[R_SPI_RIS] &= ~S_TXDONE;
|
||||
}
|
||||
if (value & S_RXRDY) {
|
||||
s->regs[R_SPI_RIS] &= ~S_RXRDY;
|
||||
}
|
||||
if (value & S_RXCHOVRF) {
|
||||
s->regs[R_SPI_RIS] &= ~S_RXCHOVRF;
|
||||
}
|
||||
break;
|
||||
|
||||
case R_SPI_MIS:
|
||||
case R_SPI_STATUS:
|
||||
case R_SPI_RIS:
|
||||
qemu_log_mask(LOG_GUEST_ERROR,
|
||||
"%s: Write to read only register 0x%" HWADDR_PRIx "\n",
|
||||
__func__, addr * 4);
|
||||
break;
|
||||
|
||||
default:
|
||||
if (addr < ARRAY_SIZE(s->regs)) {
|
||||
s->regs[addr] = value;
|
||||
} else {
|
||||
qemu_log_mask(LOG_GUEST_ERROR,
|
||||
"%s: Bad offset 0x%" HWADDR_PRIx "\n", __func__,
|
||||
addr * 4);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
spi_update_irq(s);
|
||||
}
|
||||
|
||||
static const MemoryRegionOps spi_ops = {
|
||||
.read = spi_read,
|
||||
.write = spi_write,
|
||||
.endianness = DEVICE_NATIVE_ENDIAN,
|
||||
.valid = {
|
||||
.min_access_size = 1,
|
||||
.max_access_size = 4
|
||||
}
|
||||
};
|
||||
|
||||
static void mss_spi_realize(DeviceState *dev, Error **errp)
|
||||
{
|
||||
MSSSpiState *s = MSS_SPI(dev);
|
||||
SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
|
||||
|
||||
s->spi = ssi_create_bus(dev, "spi");
|
||||
|
||||
sysbus_init_irq(sbd, &s->irq);
|
||||
ssi_auto_connect_slaves(dev, &s->cs_line, s->spi);
|
||||
sysbus_init_irq(sbd, &s->cs_line);
|
||||
|
||||
memory_region_init_io(&s->mmio, OBJECT(s), &spi_ops, s,
|
||||
TYPE_MSS_SPI, R_SPI_MAX * 4);
|
||||
sysbus_init_mmio(sbd, &s->mmio);
|
||||
|
||||
fifo32_create(&s->tx_fifo, FIFO_CAPACITY);
|
||||
fifo32_create(&s->rx_fifo, FIFO_CAPACITY);
|
||||
}
|
||||
|
||||
static const VMStateDescription vmstate_mss_spi = {
|
||||
.name = TYPE_MSS_SPI,
|
||||
.version_id = 1,
|
||||
.minimum_version_id = 1,
|
||||
.fields = (VMStateField[]) {
|
||||
VMSTATE_FIFO32(tx_fifo, MSSSpiState),
|
||||
VMSTATE_FIFO32(rx_fifo, MSSSpiState),
|
||||
VMSTATE_UINT32_ARRAY(regs, MSSSpiState, R_SPI_MAX),
|
||||
VMSTATE_END_OF_LIST()
|
||||
}
|
||||
};
|
||||
|
||||
static void mss_spi_class_init(ObjectClass *klass, void *data)
|
||||
{
|
||||
DeviceClass *dc = DEVICE_CLASS(klass);
|
||||
|
||||
dc->realize = mss_spi_realize;
|
||||
dc->reset = mss_spi_reset;
|
||||
dc->vmsd = &vmstate_mss_spi;
|
||||
}
|
||||
|
||||
static const TypeInfo mss_spi_info = {
|
||||
.name = TYPE_MSS_SPI,
|
||||
.parent = TYPE_SYS_BUS_DEVICE,
|
||||
.instance_size = sizeof(MSSSpiState),
|
||||
.class_init = mss_spi_class_init,
|
||||
};
|
||||
|
||||
static void mss_spi_register_types(void)
|
||||
{
|
||||
type_register_static(&mss_spi_info);
|
||||
}
|
||||
|
||||
type_init(mss_spi_register_types)
|
||||
@@ -42,3 +42,4 @@ common-obj-$(CONFIG_ASPEED_SOC) += aspeed_timer.o
|
||||
|
||||
common-obj-$(CONFIG_SUN4V_RTC) += sun4v-rtc.o
|
||||
common-obj-$(CONFIG_CMSDK_APB_TIMER) += cmsdk-apb-timer.o
|
||||
common-obj-$(CONFIG_MSF2) += mss-timer.o
|
||||
|
||||
289
hw/timer/mss-timer.c
Normal file
289
hw/timer/mss-timer.c
Normal file
@@ -0,0 +1,289 @@
|
||||
/*
|
||||
* Block model of System timer present in
|
||||
* Microsemi's SmartFusion2 and SmartFusion SoCs.
|
||||
*
|
||||
* Copyright (c) 2017 Subbaraya Sundeep <sundeep.lkml@gmail.com>.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "qemu/main-loop.h"
|
||||
#include "qemu/log.h"
|
||||
#include "hw/timer/mss-timer.h"
|
||||
|
||||
#ifndef MSS_TIMER_ERR_DEBUG
|
||||
#define MSS_TIMER_ERR_DEBUG 0
|
||||
#endif
|
||||
|
||||
#define DB_PRINT_L(lvl, fmt, args...) do { \
|
||||
if (MSS_TIMER_ERR_DEBUG >= lvl) { \
|
||||
qemu_log("%s: " fmt "\n", __func__, ## args); \
|
||||
} \
|
||||
} while (0);
|
||||
|
||||
#define DB_PRINT(fmt, args...) DB_PRINT_L(1, fmt, ## args)
|
||||
|
||||
#define R_TIM_VAL 0
|
||||
#define R_TIM_LOADVAL 1
|
||||
#define R_TIM_BGLOADVAL 2
|
||||
#define R_TIM_CTRL 3
|
||||
#define R_TIM_RIS 4
|
||||
#define R_TIM_MIS 5
|
||||
|
||||
#define TIMER_CTRL_ENBL (1 << 0)
|
||||
#define TIMER_CTRL_ONESHOT (1 << 1)
|
||||
#define TIMER_CTRL_INTR (1 << 2)
|
||||
#define TIMER_RIS_ACK (1 << 0)
|
||||
#define TIMER_RST_CLR (1 << 6)
|
||||
#define TIMER_MODE (1 << 0)
|
||||
|
||||
static void timer_update_irq(struct Msf2Timer *st)
|
||||
{
|
||||
bool isr, ier;
|
||||
|
||||
isr = !!(st->regs[R_TIM_RIS] & TIMER_RIS_ACK);
|
||||
ier = !!(st->regs[R_TIM_CTRL] & TIMER_CTRL_INTR);
|
||||
qemu_set_irq(st->irq, (ier && isr));
|
||||
}
|
||||
|
||||
static void timer_update(struct Msf2Timer *st)
|
||||
{
|
||||
uint64_t count;
|
||||
|
||||
if (!(st->regs[R_TIM_CTRL] & TIMER_CTRL_ENBL)) {
|
||||
ptimer_stop(st->ptimer);
|
||||
return;
|
||||
}
|
||||
|
||||
count = st->regs[R_TIM_LOADVAL];
|
||||
ptimer_set_limit(st->ptimer, count, 1);
|
||||
ptimer_run(st->ptimer, 1);
|
||||
}
|
||||
|
||||
static uint64_t
|
||||
timer_read(void *opaque, hwaddr offset, unsigned int size)
|
||||
{
|
||||
MSSTimerState *t = opaque;
|
||||
hwaddr addr;
|
||||
struct Msf2Timer *st;
|
||||
uint32_t ret = 0;
|
||||
int timer = 0;
|
||||
int isr;
|
||||
int ier;
|
||||
|
||||
addr = offset >> 2;
|
||||
/*
|
||||
* Two independent timers has same base address.
|
||||
* Based on address passed figure out which timer is being used.
|
||||
*/
|
||||
if ((addr >= R_TIM1_MAX) && (addr < NUM_TIMERS * R_TIM1_MAX)) {
|
||||
timer = 1;
|
||||
addr -= R_TIM1_MAX;
|
||||
}
|
||||
|
||||
st = &t->timers[timer];
|
||||
|
||||
switch (addr) {
|
||||
case R_TIM_VAL:
|
||||
ret = ptimer_get_count(st->ptimer);
|
||||
break;
|
||||
|
||||
case R_TIM_MIS:
|
||||
isr = !!(st->regs[R_TIM_RIS] & TIMER_RIS_ACK);
|
||||
ier = !!(st->regs[R_TIM_CTRL] & TIMER_CTRL_INTR);
|
||||
ret = ier & isr;
|
||||
break;
|
||||
|
||||
default:
|
||||
if (addr < R_TIM1_MAX) {
|
||||
ret = st->regs[addr];
|
||||
} else {
|
||||
qemu_log_mask(LOG_GUEST_ERROR,
|
||||
TYPE_MSS_TIMER": 64-bit mode not supported\n");
|
||||
return ret;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
DB_PRINT("timer=%d 0x%" HWADDR_PRIx "=0x%" PRIx32, timer, offset,
|
||||
ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void
|
||||
timer_write(void *opaque, hwaddr offset,
|
||||
uint64_t val64, unsigned int size)
|
||||
{
|
||||
MSSTimerState *t = opaque;
|
||||
hwaddr addr;
|
||||
struct Msf2Timer *st;
|
||||
int timer = 0;
|
||||
uint32_t value = val64;
|
||||
|
||||
addr = offset >> 2;
|
||||
/*
|
||||
* Two independent timers has same base address.
|
||||
* Based on addr passed figure out which timer is being used.
|
||||
*/
|
||||
if ((addr >= R_TIM1_MAX) && (addr < NUM_TIMERS * R_TIM1_MAX)) {
|
||||
timer = 1;
|
||||
addr -= R_TIM1_MAX;
|
||||
}
|
||||
|
||||
st = &t->timers[timer];
|
||||
|
||||
DB_PRINT("addr=0x%" HWADDR_PRIx " val=0x%" PRIx32 " (timer=%d)", offset,
|
||||
value, timer);
|
||||
|
||||
switch (addr) {
|
||||
case R_TIM_CTRL:
|
||||
st->regs[R_TIM_CTRL] = value;
|
||||
timer_update(st);
|
||||
break;
|
||||
|
||||
case R_TIM_RIS:
|
||||
if (value & TIMER_RIS_ACK) {
|
||||
st->regs[R_TIM_RIS] &= ~TIMER_RIS_ACK;
|
||||
}
|
||||
break;
|
||||
|
||||
case R_TIM_LOADVAL:
|
||||
st->regs[R_TIM_LOADVAL] = value;
|
||||
if (st->regs[R_TIM_CTRL] & TIMER_CTRL_ENBL) {
|
||||
timer_update(st);
|
||||
}
|
||||
break;
|
||||
|
||||
case R_TIM_BGLOADVAL:
|
||||
st->regs[R_TIM_BGLOADVAL] = value;
|
||||
st->regs[R_TIM_LOADVAL] = value;
|
||||
break;
|
||||
|
||||
case R_TIM_VAL:
|
||||
case R_TIM_MIS:
|
||||
break;
|
||||
|
||||
default:
|
||||
if (addr < R_TIM1_MAX) {
|
||||
st->regs[addr] = value;
|
||||
} else {
|
||||
qemu_log_mask(LOG_GUEST_ERROR,
|
||||
TYPE_MSS_TIMER": 64-bit mode not supported\n");
|
||||
return;
|
||||
}
|
||||
break;
|
||||
}
|
||||
timer_update_irq(st);
|
||||
}
|
||||
|
||||
static const MemoryRegionOps timer_ops = {
|
||||
.read = timer_read,
|
||||
.write = timer_write,
|
||||
.endianness = DEVICE_NATIVE_ENDIAN,
|
||||
.valid = {
|
||||
.min_access_size = 1,
|
||||
.max_access_size = 4
|
||||
}
|
||||
};
|
||||
|
||||
static void timer_hit(void *opaque)
|
||||
{
|
||||
struct Msf2Timer *st = opaque;
|
||||
|
||||
st->regs[R_TIM_RIS] |= TIMER_RIS_ACK;
|
||||
|
||||
if (!(st->regs[R_TIM_CTRL] & TIMER_CTRL_ONESHOT)) {
|
||||
timer_update(st);
|
||||
}
|
||||
timer_update_irq(st);
|
||||
}
|
||||
|
||||
static void mss_timer_init(Object *obj)
|
||||
{
|
||||
MSSTimerState *t = MSS_TIMER(obj);
|
||||
int i;
|
||||
|
||||
/* Init all the ptimers. */
|
||||
for (i = 0; i < NUM_TIMERS; i++) {
|
||||
struct Msf2Timer *st = &t->timers[i];
|
||||
|
||||
st->bh = qemu_bh_new(timer_hit, st);
|
||||
st->ptimer = ptimer_init(st->bh, PTIMER_POLICY_DEFAULT);
|
||||
ptimer_set_freq(st->ptimer, t->freq_hz);
|
||||
sysbus_init_irq(SYS_BUS_DEVICE(obj), &st->irq);
|
||||
}
|
||||
|
||||
memory_region_init_io(&t->mmio, OBJECT(t), &timer_ops, t, TYPE_MSS_TIMER,
|
||||
NUM_TIMERS * R_TIM1_MAX * 4);
|
||||
sysbus_init_mmio(SYS_BUS_DEVICE(obj), &t->mmio);
|
||||
}
|
||||
|
||||
static const VMStateDescription vmstate_timers = {
|
||||
.name = "mss-timer-block",
|
||||
.version_id = 1,
|
||||
.minimum_version_id = 1,
|
||||
.fields = (VMStateField[]) {
|
||||
VMSTATE_PTIMER(ptimer, struct Msf2Timer),
|
||||
VMSTATE_UINT32_ARRAY(regs, struct Msf2Timer, R_TIM1_MAX),
|
||||
VMSTATE_END_OF_LIST()
|
||||
}
|
||||
};
|
||||
|
||||
static const VMStateDescription vmstate_mss_timer = {
|
||||
.name = TYPE_MSS_TIMER,
|
||||
.version_id = 1,
|
||||
.minimum_version_id = 1,
|
||||
.fields = (VMStateField[]) {
|
||||
VMSTATE_UINT32(freq_hz, MSSTimerState),
|
||||
VMSTATE_STRUCT_ARRAY(timers, MSSTimerState, NUM_TIMERS, 0,
|
||||
vmstate_timers, struct Msf2Timer),
|
||||
VMSTATE_END_OF_LIST()
|
||||
}
|
||||
};
|
||||
|
||||
static Property mss_timer_properties[] = {
|
||||
/* Libero GUI shows 100Mhz as default for clocks */
|
||||
DEFINE_PROP_UINT32("clock-frequency", MSSTimerState, freq_hz,
|
||||
100 * 1000000),
|
||||
DEFINE_PROP_END_OF_LIST(),
|
||||
};
|
||||
|
||||
static void mss_timer_class_init(ObjectClass *klass, void *data)
|
||||
{
|
||||
DeviceClass *dc = DEVICE_CLASS(klass);
|
||||
|
||||
dc->props = mss_timer_properties;
|
||||
dc->vmsd = &vmstate_mss_timer;
|
||||
}
|
||||
|
||||
static const TypeInfo mss_timer_info = {
|
||||
.name = TYPE_MSS_TIMER,
|
||||
.parent = TYPE_SYS_BUS_DEVICE,
|
||||
.instance_size = sizeof(MSSTimerState),
|
||||
.instance_init = mss_timer_init,
|
||||
.class_init = mss_timer_class_init,
|
||||
};
|
||||
|
||||
static void mss_timer_register_types(void)
|
||||
{
|
||||
type_register_static(&mss_timer_info);
|
||||
}
|
||||
|
||||
type_init(mss_timer_register_types)
|
||||
@@ -450,19 +450,44 @@ static void omap_gp_timer_writeh(void *opaque, hwaddr addr,
|
||||
s->writeh = (uint16_t) value;
|
||||
}
|
||||
|
||||
static uint64_t omap_gp_timer_readfn(void *opaque, hwaddr addr,
|
||||
unsigned size)
|
||||
{
|
||||
switch (size) {
|
||||
case 1:
|
||||
return omap_badwidth_read32(opaque, addr);
|
||||
case 2:
|
||||
return omap_gp_timer_readh(opaque, addr);
|
||||
case 4:
|
||||
return omap_gp_timer_readw(opaque, addr);
|
||||
default:
|
||||
g_assert_not_reached();
|
||||
}
|
||||
}
|
||||
|
||||
static void omap_gp_timer_writefn(void *opaque, hwaddr addr,
|
||||
uint64_t value, unsigned size)
|
||||
{
|
||||
switch (size) {
|
||||
case 1:
|
||||
omap_badwidth_write32(opaque, addr, value);
|
||||
break;
|
||||
case 2:
|
||||
omap_gp_timer_writeh(opaque, addr, value);
|
||||
break;
|
||||
case 4:
|
||||
omap_gp_timer_write(opaque, addr, value);
|
||||
break;
|
||||
default:
|
||||
g_assert_not_reached();
|
||||
}
|
||||
}
|
||||
|
||||
static const MemoryRegionOps omap_gp_timer_ops = {
|
||||
.old_mmio = {
|
||||
.read = {
|
||||
omap_badwidth_read32,
|
||||
omap_gp_timer_readh,
|
||||
omap_gp_timer_readw,
|
||||
},
|
||||
.write = {
|
||||
omap_badwidth_write32,
|
||||
omap_gp_timer_writeh,
|
||||
omap_gp_timer_write,
|
||||
},
|
||||
},
|
||||
.read = omap_gp_timer_readfn,
|
||||
.write = omap_gp_timer_writefn,
|
||||
.valid.min_access_size = 1,
|
||||
.valid.max_access_size = 4,
|
||||
.endianness = DEVICE_NATIVE_ENDIAN,
|
||||
};
|
||||
|
||||
|
||||
@@ -68,25 +68,32 @@ static uint32_t omap_synctimer_readh(void *opaque, hwaddr addr)
|
||||
}
|
||||
}
|
||||
|
||||
static void omap_synctimer_write(void *opaque, hwaddr addr,
|
||||
uint32_t value)
|
||||
static uint64_t omap_synctimer_readfn(void *opaque, hwaddr addr,
|
||||
unsigned size)
|
||||
{
|
||||
switch (size) {
|
||||
case 1:
|
||||
return omap_badwidth_read32(opaque, addr);
|
||||
case 2:
|
||||
return omap_synctimer_readh(opaque, addr);
|
||||
case 4:
|
||||
return omap_synctimer_readw(opaque, addr);
|
||||
default:
|
||||
g_assert_not_reached();
|
||||
}
|
||||
}
|
||||
|
||||
static void omap_synctimer_writefn(void *opaque, hwaddr addr,
|
||||
uint64_t value, unsigned size)
|
||||
{
|
||||
OMAP_BAD_REG(addr);
|
||||
}
|
||||
|
||||
static const MemoryRegionOps omap_synctimer_ops = {
|
||||
.old_mmio = {
|
||||
.read = {
|
||||
omap_badwidth_read32,
|
||||
omap_synctimer_readh,
|
||||
omap_synctimer_readw,
|
||||
},
|
||||
.write = {
|
||||
omap_badwidth_write32,
|
||||
omap_synctimer_write,
|
||||
omap_synctimer_write,
|
||||
},
|
||||
},
|
||||
.read = omap_synctimer_readfn,
|
||||
.write = omap_synctimer_writefn,
|
||||
.valid.min_access_size = 1,
|
||||
.valid.max_access_size = 4,
|
||||
.endianness = DEVICE_NATIVE_ENDIAN,
|
||||
};
|
||||
|
||||
|
||||
@@ -26,8 +26,10 @@ common-obj-$(CONFIG_USB_BLUETOOTH) += dev-bluetooth.o
|
||||
|
||||
ifeq ($(CONFIG_USB_SMARTCARD),y)
|
||||
common-obj-y += dev-smartcard-reader.o
|
||||
common-obj-$(CONFIG_SMARTCARD) += ccid-card-passthru.o
|
||||
common-obj-$(CONFIG_SMARTCARD) += ccid-card-emulated.o
|
||||
common-obj-$(CONFIG_SMARTCARD) += smartcard.mo
|
||||
smartcard.mo-objs := ccid-card-passthru.o ccid-card-emulated.o
|
||||
smartcard.mo-cflags := $(SMARTCARD_CFLAGS)
|
||||
smartcard.mo-libs := $(SMARTCARD_LIBS)
|
||||
endif
|
||||
|
||||
ifeq ($(CONFIG_POSIX),y)
|
||||
@@ -36,6 +38,8 @@ endif
|
||||
|
||||
# usb redirection
|
||||
common-obj-$(CONFIG_USB_REDIR) += redirect.o quirks.o
|
||||
redirect.o-cflags = $(USB_REDIR_CFLAGS)
|
||||
redirect.o-libs = $(USB_REDIR_LIBS)
|
||||
|
||||
# usb pass-through
|
||||
ifeq ($(CONFIG_LIBUSB)$(CONFIG_USB),yy)
|
||||
@@ -44,6 +48,11 @@ else
|
||||
common-obj-y += host-stub.o
|
||||
endif
|
||||
|
||||
host-libusb.o-cflags := $(LIBUSB_CFLAGS)
|
||||
host-libusb.o-libs := $(LIBUSB_LIBS)
|
||||
|
||||
ifeq ($(CONFIG_USB_LIBUSB),y)
|
||||
common-obj-$(CONFIG_XEN) += xen-usb.o
|
||||
xen-usb.o-cflags := $(LIBUSB_CFLAGS)
|
||||
xen-usb.o-libs := $(LIBUSB_LIBS)
|
||||
endif
|
||||
|
||||
@@ -142,6 +142,30 @@ static const TypeInfo ehci_tegra2_type_info = {
|
||||
.class_init = ehci_tegra2_class_init,
|
||||
};
|
||||
|
||||
static void ehci_ppc4xx_init(Object *o)
|
||||
{
|
||||
EHCISysBusState *s = SYS_BUS_EHCI(o);
|
||||
|
||||
s->ehci.companion_enable = true;
|
||||
}
|
||||
|
||||
static void ehci_ppc4xx_class_init(ObjectClass *oc, void *data)
|
||||
{
|
||||
SysBusEHCIClass *sec = SYS_BUS_EHCI_CLASS(oc);
|
||||
DeviceClass *dc = DEVICE_CLASS(oc);
|
||||
|
||||
sec->capsbase = 0x0;
|
||||
sec->opregbase = 0x10;
|
||||
set_bit(DEVICE_CATEGORY_USB, dc->categories);
|
||||
}
|
||||
|
||||
static const TypeInfo ehci_ppc4xx_type_info = {
|
||||
.name = TYPE_PPC4xx_EHCI,
|
||||
.parent = TYPE_SYS_BUS_EHCI,
|
||||
.class_init = ehci_ppc4xx_class_init,
|
||||
.instance_init = ehci_ppc4xx_init,
|
||||
};
|
||||
|
||||
/*
|
||||
* Faraday FUSBH200 USB 2.0 EHCI
|
||||
*/
|
||||
@@ -224,6 +248,7 @@ static void ehci_sysbus_register_types(void)
|
||||
type_register_static(&ehci_xlnx_type_info);
|
||||
type_register_static(&ehci_exynos4210_type_info);
|
||||
type_register_static(&ehci_tegra2_type_info);
|
||||
type_register_static(&ehci_ppc4xx_type_info);
|
||||
type_register_static(&ehci_fusbh200_type_info);
|
||||
}
|
||||
|
||||
|
||||
@@ -344,6 +344,7 @@ typedef struct EHCIPCIState {
|
||||
#define TYPE_SYS_BUS_EHCI "sysbus-ehci-usb"
|
||||
#define TYPE_EXYNOS4210_EHCI "exynos4210-ehci-usb"
|
||||
#define TYPE_TEGRA2_EHCI "tegra2-ehci-usb"
|
||||
#define TYPE_PPC4xx_EHCI "ppc4xx-ehci-usb"
|
||||
#define TYPE_FUSBH200_EHCI "fusbh200-ehci-usb"
|
||||
|
||||
#define SYS_BUS_EHCI(obj) \
|
||||
|
||||
@@ -1999,7 +1999,9 @@ typedef struct {
|
||||
/*< public >*/
|
||||
|
||||
OHCIState ohci;
|
||||
char *masterbus;
|
||||
uint32_t num_ports;
|
||||
uint32_t firstport;
|
||||
dma_addr_t dma_offset;
|
||||
} OHCISysBusState;
|
||||
|
||||
@@ -2007,10 +2009,15 @@ static void ohci_realize_pxa(DeviceState *dev, Error **errp)
|
||||
{
|
||||
OHCISysBusState *s = SYSBUS_OHCI(dev);
|
||||
SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
|
||||
Error *err = NULL;
|
||||
|
||||
/* Cannot fail as we pass NULL for masterbus */
|
||||
usb_ohci_init(&s->ohci, dev, s->num_ports, s->dma_offset, NULL, 0,
|
||||
&address_space_memory, &error_abort);
|
||||
usb_ohci_init(&s->ohci, dev, s->num_ports, s->dma_offset,
|
||||
s->masterbus, s->firstport,
|
||||
&address_space_memory, &err);
|
||||
if (err) {
|
||||
error_propagate(errp, err);
|
||||
return;
|
||||
}
|
||||
sysbus_init_irq(sbd, &s->ohci.irq);
|
||||
sysbus_init_mmio(sbd, &s->ohci.mem);
|
||||
}
|
||||
@@ -2142,7 +2149,9 @@ static const TypeInfo ohci_pci_info = {
|
||||
};
|
||||
|
||||
static Property ohci_sysbus_properties[] = {
|
||||
DEFINE_PROP_STRING("masterbus", OHCISysBusState, masterbus),
|
||||
DEFINE_PROP_UINT32("num-ports", OHCISysBusState, num_ports, 3),
|
||||
DEFINE_PROP_UINT32("firstport", OHCISysBusState, firstport, 0),
|
||||
DEFINE_PROP_DMAADDR("dma-offset", OHCISysBusState, dma_offset, 0),
|
||||
DEFINE_PROP_END_OF_LIST(),
|
||||
};
|
||||
|
||||
@@ -55,6 +55,7 @@ struct Chardev {
|
||||
int logfd;
|
||||
int be_open;
|
||||
GSource *gsource;
|
||||
GMainContext *gcontext;
|
||||
DECLARE_BITMAP(features, QEMU_CHAR_FEATURE_LAST);
|
||||
};
|
||||
|
||||
@@ -168,6 +169,16 @@ void qemu_chr_be_write(Chardev *s, uint8_t *buf, int len);
|
||||
*/
|
||||
void qemu_chr_be_write_impl(Chardev *s, uint8_t *buf, int len);
|
||||
|
||||
/**
|
||||
* @qemu_chr_be_update_read_handlers:
|
||||
*
|
||||
* Invoked when frontend read handlers are setup
|
||||
*
|
||||
* @context the gcontext that will be used to attach the watch sources
|
||||
*/
|
||||
void qemu_chr_be_update_read_handlers(Chardev *s,
|
||||
GMainContext *context);
|
||||
|
||||
/**
|
||||
* @qemu_chr_be_event:
|
||||
*
|
||||
@@ -227,7 +238,7 @@ typedef struct ChardevClass {
|
||||
int (*chr_write)(Chardev *s, const uint8_t *buf, int len);
|
||||
int (*chr_sync_read)(Chardev *s, const uint8_t *buf, int len);
|
||||
GSource *(*chr_add_watch)(Chardev *s, GIOCondition cond);
|
||||
void (*chr_update_read_handler)(Chardev *s, GMainContext *context);
|
||||
void (*chr_update_read_handler)(Chardev *s);
|
||||
int (*chr_ioctl)(Chardev *s, int cmd, void *arg);
|
||||
int (*get_msgfds)(Chardev *s, int* fds, int num);
|
||||
int (*set_msgfds)(Chardev *s, int *fds, int num);
|
||||
|
||||
@@ -22,14 +22,22 @@
|
||||
#ifndef CONFIG_USER_ONLY
|
||||
typedef struct AddressSpaceDispatch AddressSpaceDispatch;
|
||||
|
||||
void address_space_init_dispatch(AddressSpace *as);
|
||||
void address_space_unregister(AddressSpace *as);
|
||||
void address_space_destroy_dispatch(AddressSpace *as);
|
||||
|
||||
extern const MemoryRegionOps unassigned_mem_ops;
|
||||
|
||||
bool memory_region_access_valid(MemoryRegion *mr, hwaddr addr,
|
||||
unsigned size, bool is_write);
|
||||
|
||||
void flatview_add_to_dispatch(FlatView *fv, MemoryRegionSection *section);
|
||||
AddressSpaceDispatch *address_space_dispatch_new(FlatView *fv);
|
||||
void address_space_dispatch_compact(AddressSpaceDispatch *d);
|
||||
|
||||
AddressSpaceDispatch *address_space_to_dispatch(AddressSpace *as);
|
||||
AddressSpaceDispatch *flatview_to_dispatch(FlatView *fv);
|
||||
void address_space_dispatch_free(AddressSpaceDispatch *d);
|
||||
|
||||
void mtree_print_dispatch(fprintf_function mon, void *f,
|
||||
struct AddressSpaceDispatch *d,
|
||||
MemoryRegion *root);
|
||||
|
||||
#endif
|
||||
#endif
|
||||
|
||||
@@ -308,21 +308,18 @@ struct AddressSpace {
|
||||
struct rcu_head rcu;
|
||||
char *name;
|
||||
MemoryRegion *root;
|
||||
int ref_count;
|
||||
bool malloced;
|
||||
|
||||
/* Accessed via RCU. */
|
||||
struct FlatView *current_map;
|
||||
|
||||
int ioeventfd_nb;
|
||||
struct MemoryRegionIoeventfd *ioeventfds;
|
||||
struct AddressSpaceDispatch *dispatch;
|
||||
struct AddressSpaceDispatch *next_dispatch;
|
||||
MemoryListener dispatch_listener;
|
||||
QTAILQ_HEAD(memory_listeners_as, MemoryListener) listeners;
|
||||
QTAILQ_ENTRY(AddressSpace) address_spaces_link;
|
||||
};
|
||||
|
||||
FlatView *address_space_to_flatview(AddressSpace *as);
|
||||
|
||||
/**
|
||||
* MemoryRegionSection: describes a fragment of a #MemoryRegion
|
||||
*
|
||||
@@ -336,7 +333,7 @@ struct AddressSpace {
|
||||
*/
|
||||
struct MemoryRegionSection {
|
||||
MemoryRegion *mr;
|
||||
AddressSpace *address_space;
|
||||
FlatView *fv;
|
||||
hwaddr offset_within_region;
|
||||
Int128 size;
|
||||
hwaddr offset_within_address_space;
|
||||
@@ -1515,7 +1512,8 @@ void memory_global_dirty_log_start(void);
|
||||
*/
|
||||
void memory_global_dirty_log_stop(void);
|
||||
|
||||
void mtree_info(fprintf_function mon_printf, void *f, bool flatview);
|
||||
void mtree_info(fprintf_function mon_printf, void *f, bool flatview,
|
||||
bool dispatch_tree);
|
||||
|
||||
/**
|
||||
* memory_region_request_mmio_ptr: request a pointer to an mmio
|
||||
@@ -1584,23 +1582,6 @@ MemTxResult memory_region_dispatch_write(MemoryRegion *mr,
|
||||
*/
|
||||
void address_space_init(AddressSpace *as, MemoryRegion *root, const char *name);
|
||||
|
||||
/**
|
||||
* address_space_init_shareable: return an address space for a memory region,
|
||||
* creating it if it does not already exist
|
||||
*
|
||||
* @root: a #MemoryRegion that routes addresses for the address space
|
||||
* @name: an address space name. The name is only used for debugging
|
||||
* output.
|
||||
*
|
||||
* This function will return a pointer to an existing AddressSpace
|
||||
* which was initialized with the specified MemoryRegion, or it will
|
||||
* create and initialize one if it does not already exist. The ASes
|
||||
* are reference-counted, so the memory will be freed automatically
|
||||
* when the AddressSpace is destroyed via address_space_destroy.
|
||||
*/
|
||||
AddressSpace *address_space_init_shareable(MemoryRegion *root,
|
||||
const char *name);
|
||||
|
||||
/**
|
||||
* address_space_destroy: destroy an address space
|
||||
*
|
||||
@@ -1845,9 +1826,17 @@ IOMMUTLBEntry address_space_get_iotlb_entry(AddressSpace *as, hwaddr addr,
|
||||
* @len: pointer to length
|
||||
* @is_write: indicates the transfer direction
|
||||
*/
|
||||
MemoryRegion *address_space_translate(AddressSpace *as, hwaddr addr,
|
||||
hwaddr *xlat, hwaddr *len,
|
||||
bool is_write);
|
||||
MemoryRegion *flatview_translate(FlatView *fv,
|
||||
hwaddr addr, hwaddr *xlat,
|
||||
hwaddr *len, bool is_write);
|
||||
|
||||
static inline MemoryRegion *address_space_translate(AddressSpace *as,
|
||||
hwaddr addr, hwaddr *xlat,
|
||||
hwaddr *len, bool is_write)
|
||||
{
|
||||
return flatview_translate(address_space_to_flatview(as),
|
||||
addr, xlat, len, is_write);
|
||||
}
|
||||
|
||||
/* address_space_access_valid: check for validity of accessing an address
|
||||
* space range
|
||||
@@ -1898,12 +1887,13 @@ void address_space_unmap(AddressSpace *as, void *buffer, hwaddr len,
|
||||
|
||||
|
||||
/* Internal functions, part of the implementation of address_space_read. */
|
||||
MemTxResult address_space_read_continue(AddressSpace *as, hwaddr addr,
|
||||
MemTxAttrs attrs, uint8_t *buf,
|
||||
int len, hwaddr addr1, hwaddr l,
|
||||
MemoryRegion *mr);
|
||||
MemTxResult address_space_read_full(AddressSpace *as, hwaddr addr,
|
||||
MemTxAttrs attrs, uint8_t *buf, int len);
|
||||
MemTxResult flatview_read_continue(FlatView *fv, hwaddr addr,
|
||||
MemTxAttrs attrs, uint8_t *buf,
|
||||
int len, hwaddr addr1, hwaddr l,
|
||||
MemoryRegion *mr);
|
||||
|
||||
MemTxResult flatview_read_full(FlatView *fv, hwaddr addr,
|
||||
MemTxAttrs attrs, uint8_t *buf, int len);
|
||||
void *qemu_map_ram_ptr(RAMBlock *ram_block, ram_addr_t addr);
|
||||
|
||||
static inline bool memory_access_is_direct(MemoryRegion *mr, bool is_write)
|
||||
@@ -1930,8 +1920,8 @@ static inline bool memory_access_is_direct(MemoryRegion *mr, bool is_write)
|
||||
* @buf: buffer with the data transferred
|
||||
*/
|
||||
static inline __attribute__((__always_inline__))
|
||||
MemTxResult address_space_read(AddressSpace *as, hwaddr addr, MemTxAttrs attrs,
|
||||
uint8_t *buf, int len)
|
||||
MemTxResult flatview_read(FlatView *fv, hwaddr addr, MemTxAttrs attrs,
|
||||
uint8_t *buf, int len)
|
||||
{
|
||||
MemTxResult result = MEMTX_OK;
|
||||
hwaddr l, addr1;
|
||||
@@ -1942,22 +1932,29 @@ MemTxResult address_space_read(AddressSpace *as, hwaddr addr, MemTxAttrs attrs,
|
||||
if (len) {
|
||||
rcu_read_lock();
|
||||
l = len;
|
||||
mr = address_space_translate(as, addr, &addr1, &l, false);
|
||||
mr = flatview_translate(fv, addr, &addr1, &l, false);
|
||||
if (len == l && memory_access_is_direct(mr, false)) {
|
||||
ptr = qemu_map_ram_ptr(mr->ram_block, addr1);
|
||||
memcpy(buf, ptr, len);
|
||||
} else {
|
||||
result = address_space_read_continue(as, addr, attrs, buf, len,
|
||||
addr1, l, mr);
|
||||
result = flatview_read_continue(fv, addr, attrs, buf, len,
|
||||
addr1, l, mr);
|
||||
}
|
||||
rcu_read_unlock();
|
||||
}
|
||||
} else {
|
||||
result = address_space_read_full(as, addr, attrs, buf, len);
|
||||
result = flatview_read_full(fv, addr, attrs, buf, len);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
static inline MemTxResult address_space_read(AddressSpace *as, hwaddr addr,
|
||||
MemTxAttrs attrs, uint8_t *buf,
|
||||
int len)
|
||||
{
|
||||
return flatview_read(address_space_to_flatview(as), addr, attrs, buf, len);
|
||||
}
|
||||
|
||||
/**
|
||||
* address_space_read_cached: read from a cached RAM region
|
||||
*
|
||||
|
||||
@@ -223,6 +223,8 @@ static inline gboolean g_hash_table_contains(GHashTable *hash_table,
|
||||
{
|
||||
return g_hash_table_lookup_extended(hash_table, key, NULL, NULL);
|
||||
}
|
||||
#define G_SOURCE_CONTINUE TRUE
|
||||
#define G_SOURCE_REMOVE FALSE
|
||||
#endif
|
||||
|
||||
#ifndef g_assert_true
|
||||
|
||||
@@ -21,7 +21,7 @@ typedef struct {
|
||||
SysBusDevice parent_obj;
|
||||
/*< public >*/
|
||||
|
||||
AddressSpace *source_as;
|
||||
AddressSpace source_as;
|
||||
MemoryRegion iomem;
|
||||
uint32_t base;
|
||||
MemoryRegion *source_memory;
|
||||
|
||||
67
include/hw/arm/msf2-soc.h
Normal file
67
include/hw/arm/msf2-soc.h
Normal file
@@ -0,0 +1,67 @@
|
||||
/*
|
||||
* Microsemi Smartfusion2 SoC
|
||||
*
|
||||
* Copyright (c) 2017 Subbaraya Sundeep <sundeep.lkml@gmail.com>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef HW_ARM_MSF2_SOC_H
|
||||
#define HW_ARM_MSF2_SOC_H
|
||||
|
||||
#include "hw/arm/armv7m.h"
|
||||
#include "hw/timer/mss-timer.h"
|
||||
#include "hw/misc/msf2-sysreg.h"
|
||||
#include "hw/ssi/mss-spi.h"
|
||||
|
||||
#define TYPE_MSF2_SOC "msf2-soc"
|
||||
#define MSF2_SOC(obj) OBJECT_CHECK(MSF2State, (obj), TYPE_MSF2_SOC)
|
||||
|
||||
#define MSF2_NUM_SPIS 2
|
||||
#define MSF2_NUM_UARTS 2
|
||||
|
||||
/*
|
||||
* System timer consists of two programmable 32-bit
|
||||
* decrementing counters that generate individual interrupts to
|
||||
* the Cortex-M3 processor
|
||||
*/
|
||||
#define MSF2_NUM_TIMERS 2
|
||||
|
||||
typedef struct MSF2State {
|
||||
/*< private >*/
|
||||
SysBusDevice parent_obj;
|
||||
/*< public >*/
|
||||
|
||||
ARMv7MState armv7m;
|
||||
|
||||
char *cpu_type;
|
||||
char *part_name;
|
||||
uint64_t envm_size;
|
||||
uint64_t esram_size;
|
||||
|
||||
uint32_t m3clk;
|
||||
uint8_t apb0div;
|
||||
uint8_t apb1div;
|
||||
|
||||
MSF2SysregState sysreg;
|
||||
MSSTimerState timer;
|
||||
MSSSpiState spi[MSF2_NUM_SPIS];
|
||||
} MSF2State;
|
||||
|
||||
#endif
|
||||
@@ -333,8 +333,7 @@ struct unreported_events {
|
||||
};
|
||||
|
||||
enum ide_dma_cmd {
|
||||
IDE_DMA__BEGIN = 0,
|
||||
IDE_DMA_READ = IDE_DMA__BEGIN,
|
||||
IDE_DMA_READ = 0,
|
||||
IDE_DMA_WRITE,
|
||||
IDE_DMA_TRIM,
|
||||
IDE_DMA_ATAPI,
|
||||
|
||||
@@ -21,6 +21,8 @@
|
||||
|
||||
/* Highest permitted number of exceptions (architectural limit) */
|
||||
#define NVIC_MAX_VECTORS 512
|
||||
/* Number of internal exceptions */
|
||||
#define NVIC_INTERNAL_VECTORS 16
|
||||
|
||||
typedef struct VecInfo {
|
||||
/* Exception priorities can range from -3 to 255; only the unmodifiable
|
||||
@@ -41,13 +43,38 @@ typedef struct NVICState {
|
||||
ARMCPU *cpu;
|
||||
|
||||
VecInfo vectors[NVIC_MAX_VECTORS];
|
||||
uint32_t prigroup;
|
||||
/* If the v8M security extension is implemented, some of the internal
|
||||
* exceptions are banked between security states (ie there exists both
|
||||
* a Secure and a NonSecure version of the exception and its state):
|
||||
* HardFault, MemManage, UsageFault, SVCall, PendSV, SysTick (R_PJHV)
|
||||
* The rest (including all the external exceptions) are not banked, though
|
||||
* they may be configurable to target either Secure or NonSecure state.
|
||||
* We store the secure exception state in sec_vectors[] for the banked
|
||||
* exceptions, and otherwise use only vectors[] (including for exceptions
|
||||
* like SecureFault that unconditionally target Secure state).
|
||||
* Entries in sec_vectors[] for non-banked exception numbers are unused.
|
||||
*/
|
||||
VecInfo sec_vectors[NVIC_INTERNAL_VECTORS];
|
||||
/* The PRIGROUP field in AIRCR is banked */
|
||||
uint32_t prigroup[M_REG_NUM_BANKS];
|
||||
|
||||
/* vectpending and exception_prio are both cached state that can
|
||||
* be recalculated from the vectors[] array and the prigroup field.
|
||||
/* v8M NVIC_ITNS state (stored as a bool per bit) */
|
||||
bool itns[NVIC_MAX_VECTORS];
|
||||
|
||||
/* The following fields are all cached state that can be recalculated
|
||||
* from the vectors[] and sec_vectors[] arrays and the prigroup field:
|
||||
* - vectpending
|
||||
* - vectpending_is_secure
|
||||
* - exception_prio
|
||||
* - vectpending_prio
|
||||
*/
|
||||
unsigned int vectpending; /* highest prio pending enabled exception */
|
||||
/* true if vectpending is a banked secure exception, ie it is in
|
||||
* sec_vectors[] rather than vectors[]
|
||||
*/
|
||||
bool vectpending_is_s_banked;
|
||||
int exception_prio; /* group prio of the highest prio active exception */
|
||||
int vectpending_prio; /* group prio of the exeception in vectpending */
|
||||
|
||||
MemoryRegion sysregmem;
|
||||
MemoryRegion sysreg_ns_mem;
|
||||
|
||||
77
include/hw/misc/msf2-sysreg.h
Normal file
77
include/hw/misc/msf2-sysreg.h
Normal file
@@ -0,0 +1,77 @@
|
||||
/*
|
||||
* Microsemi SmartFusion2 SYSREG
|
||||
*
|
||||
* Copyright (c) 2017 Subbaraya Sundeep <sundeep.lkml@gmail.com>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef HW_MSF2_SYSREG_H
|
||||
#define HW_MSF2_SYSREG_H
|
||||
|
||||
#include "hw/sysbus.h"
|
||||
|
||||
enum {
|
||||
ESRAM_CR = 0x00 / 4,
|
||||
ESRAM_MAX_LAT,
|
||||
DDR_CR,
|
||||
ENVM_CR,
|
||||
ENVM_REMAP_BASE_CR,
|
||||
ENVM_REMAP_FAB_CR,
|
||||
CC_CR,
|
||||
CC_REGION_CR,
|
||||
CC_LOCK_BASE_ADDR_CR,
|
||||
CC_FLUSH_INDX_CR,
|
||||
DDRB_BUF_TIMER_CR,
|
||||
DDRB_NB_ADDR_CR,
|
||||
DDRB_NB_SIZE_CR,
|
||||
DDRB_CR,
|
||||
|
||||
SOFT_RESET_CR = 0x48 / 4,
|
||||
M3_CR,
|
||||
|
||||
GPIO_SYSRESET_SEL_CR = 0x58 / 4,
|
||||
|
||||
MDDR_CR = 0x60 / 4,
|
||||
|
||||
MSSDDR_PLL_STATUS_LOW_CR = 0x90 / 4,
|
||||
MSSDDR_PLL_STATUS_HIGH_CR,
|
||||
MSSDDR_FACC1_CR,
|
||||
MSSDDR_FACC2_CR,
|
||||
|
||||
MSSDDR_PLL_STATUS = 0x150 / 4,
|
||||
};
|
||||
|
||||
#define MSF2_SYSREG_MMIO_SIZE 0x300
|
||||
|
||||
#define TYPE_MSF2_SYSREG "msf2-sysreg"
|
||||
#define MSF2_SYSREG(obj) OBJECT_CHECK(MSF2SysregState, (obj), TYPE_MSF2_SYSREG)
|
||||
|
||||
typedef struct MSF2SysregState {
|
||||
SysBusDevice parent_obj;
|
||||
|
||||
MemoryRegion iomem;
|
||||
|
||||
uint8_t apb0div;
|
||||
uint8_t apb1div;
|
||||
|
||||
uint32_t regs[MSF2_SYSREG_MMIO_SIZE / 4];
|
||||
} MSF2SysregState;
|
||||
|
||||
#endif /* HW_MSF2_SYSREG_H */
|
||||
@@ -26,6 +26,7 @@
|
||||
#include "exec/memory.h"
|
||||
#include "qemu/iov.h"
|
||||
#include "sysemu/dma.h"
|
||||
#include "hw/sysbus.h"
|
||||
|
||||
typedef struct DBDMA_io DBDMA_io;
|
||||
|
||||
@@ -42,10 +43,6 @@ struct DBDMA_io {
|
||||
DBDMA_end dma_end;
|
||||
/* DMA is in progress, don't start another one */
|
||||
bool processing;
|
||||
/* unaligned last sector of a request */
|
||||
uint8_t head_remainder[0x200];
|
||||
uint8_t tail_remainder[0x200];
|
||||
QEMUIOVector iov;
|
||||
/* DMA request */
|
||||
void *dma_mem;
|
||||
dma_addr_t dma_len;
|
||||
@@ -164,6 +161,8 @@ typedef struct DBDMA_channel {
|
||||
} DBDMA_channel;
|
||||
|
||||
typedef struct {
|
||||
SysBusDevice parent_obj;
|
||||
|
||||
MemoryRegion mem;
|
||||
DBDMA_channel channels[DBDMA_CHANNELS];
|
||||
QEMUBH *bh;
|
||||
@@ -175,6 +174,8 @@ void DBDMA_register_channel(void *dbdma, int nchan, qemu_irq irq,
|
||||
DBDMA_rw rw, DBDMA_flush flush,
|
||||
void *opaque);
|
||||
void DBDMA_kick(DBDMAState *dbdma);
|
||||
void* DBDMA_init (MemoryRegion **dbdma_mem);
|
||||
|
||||
#define TYPE_MAC_DBDMA "mac-dbdma"
|
||||
#define MAC_DBDMA(obj) OBJECT_CHECK(DBDMAState, (obj), TYPE_MAC_DBDMA)
|
||||
|
||||
#endif
|
||||
|
||||
@@ -20,6 +20,7 @@ enum {
|
||||
#define OPENPIC_MODEL_RAVEN 0
|
||||
#define OPENPIC_MODEL_FSL_MPIC_20 1
|
||||
#define OPENPIC_MODEL_FSL_MPIC_42 2
|
||||
#define OPENPIC_MODEL_KEYLARGO 3
|
||||
|
||||
#define OPENPIC_MAX_SRC 256
|
||||
#define OPENPIC_MAX_TMR 4
|
||||
|
||||
@@ -54,7 +54,7 @@ typedef struct PnvXScomInterfaceClass {
|
||||
* PCB SLAVE 0x110Fxxxx
|
||||
*/
|
||||
|
||||
#define PNV_XSCOM_EX_CORE_BASE(base, i) (base | (((uint64_t)i) << 24))
|
||||
#define PNV_XSCOM_EX_CORE_BASE(base, i) ((base) | ((uint64_t)(i) << 24))
|
||||
#define PNV_XSCOM_EX_CORE_SIZE 0x100000
|
||||
|
||||
#define PNV_XSCOM_LPC_BASE 0xb0020
|
||||
|
||||
58
include/hw/ssi/mss-spi.h
Normal file
58
include/hw/ssi/mss-spi.h
Normal file
@@ -0,0 +1,58 @@
|
||||
/*
|
||||
* Microsemi SmartFusion2 SPI
|
||||
*
|
||||
* Copyright (c) 2017 Subbaraya Sundeep <sundeep.lkml@gmail.com>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef HW_MSS_SPI_H
|
||||
#define HW_MSS_SPI_H
|
||||
|
||||
#include "hw/sysbus.h"
|
||||
#include "hw/ssi/ssi.h"
|
||||
#include "qemu/fifo32.h"
|
||||
|
||||
#define TYPE_MSS_SPI "mss-spi"
|
||||
#define MSS_SPI(obj) OBJECT_CHECK(MSSSpiState, (obj), TYPE_MSS_SPI)
|
||||
|
||||
#define R_SPI_MAX 16
|
||||
|
||||
typedef struct MSSSpiState {
|
||||
SysBusDevice parent_obj;
|
||||
|
||||
MemoryRegion mmio;
|
||||
|
||||
qemu_irq irq;
|
||||
|
||||
qemu_irq cs_line;
|
||||
|
||||
SSIBus *spi;
|
||||
|
||||
Fifo32 rx_fifo;
|
||||
Fifo32 tx_fifo;
|
||||
|
||||
int fifo_depth;
|
||||
uint32_t frame_count;
|
||||
bool enabled;
|
||||
|
||||
uint32_t regs[R_SPI_MAX];
|
||||
} MSSSpiState;
|
||||
|
||||
#endif /* HW_MSS_SPI_H */
|
||||
64
include/hw/timer/mss-timer.h
Normal file
64
include/hw/timer/mss-timer.h
Normal file
@@ -0,0 +1,64 @@
|
||||
/*
|
||||
* Microsemi SmartFusion2 Timer.
|
||||
*
|
||||
* Copyright (c) 2017 Subbaraya Sundeep <sundeep.lkml@gmail.com>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef HW_MSS_TIMER_H
|
||||
#define HW_MSS_TIMER_H
|
||||
|
||||
#include "hw/sysbus.h"
|
||||
#include "hw/ptimer.h"
|
||||
|
||||
#define TYPE_MSS_TIMER "mss-timer"
|
||||
#define MSS_TIMER(obj) OBJECT_CHECK(MSSTimerState, \
|
||||
(obj), TYPE_MSS_TIMER)
|
||||
|
||||
/*
|
||||
* There are two 32-bit down counting timers.
|
||||
* Timers 1 and 2 can be concatenated into a single 64-bit Timer
|
||||
* that operates either in Periodic mode or in One-shot mode.
|
||||
* Writing 1 to the TIM64_MODE register bit 0 sets the Timers in 64-bit mode.
|
||||
* In 64-bit mode, writing to the 32-bit registers has no effect.
|
||||
* Similarly, in 32-bit mode, writing to the 64-bit mode registers
|
||||
* has no effect. Only two 32-bit timers are supported currently.
|
||||
*/
|
||||
#define NUM_TIMERS 2
|
||||
|
||||
#define R_TIM1_MAX 6
|
||||
|
||||
struct Msf2Timer {
|
||||
QEMUBH *bh;
|
||||
ptimer_state *ptimer;
|
||||
|
||||
uint32_t regs[R_TIM1_MAX];
|
||||
qemu_irq irq;
|
||||
};
|
||||
|
||||
typedef struct MSSTimerState {
|
||||
SysBusDevice parent_obj;
|
||||
|
||||
MemoryRegion mmio;
|
||||
uint32_t freq_hz;
|
||||
struct Msf2Timer timers[NUM_TIMERS];
|
||||
} MSSTimerState;
|
||||
|
||||
#endif /* HW_MSS_TIMER_H */
|
||||
@@ -58,6 +58,9 @@ typedef struct VirtIOSerialPortClass {
|
||||
/* Guest opened/closed device. */
|
||||
void (*set_guest_connected)(VirtIOSerialPort *port, int guest_connected);
|
||||
|
||||
/* Enable/disable backend for virtio serial port */
|
||||
void (*enable_backend)(VirtIOSerialPort *port, bool enable);
|
||||
|
||||
/* Guest is now ready to accept data (virtqueues set up). */
|
||||
void (*guest_ready)(VirtIOSerialPort *port);
|
||||
|
||||
|
||||
@@ -24,6 +24,7 @@ typedef struct SaveVMHandlers {
|
||||
|
||||
/* This runs both outside and inside the iothread lock. */
|
||||
bool (*is_active)(void *opaque);
|
||||
bool (*has_postcopy)(void *opaque);
|
||||
|
||||
/* This runs outside the iothread lock in the migration case, and
|
||||
* within the lock in the savevm case. The callback had better only
|
||||
|
||||
@@ -442,4 +442,12 @@
|
||||
} while(0)
|
||||
#endif
|
||||
|
||||
#define atomic_fetch_inc_nonzero(ptr) ({ \
|
||||
typeof_strip_qual(*ptr) _oldn = atomic_read(ptr); \
|
||||
while (_oldn && atomic_cmpxchg(ptr, _oldn, _oldn + 1) != _oldn) { \
|
||||
_oldn = atomic_read(ptr); \
|
||||
} \
|
||||
_oldn; \
|
||||
})
|
||||
|
||||
#endif /* QEMU_ATOMIC_H */
|
||||
|
||||
@@ -39,6 +39,8 @@
|
||||
* bitmap_clear(dst, pos, nbits) Clear specified bit area
|
||||
* bitmap_test_and_clear_atomic(dst, pos, nbits) Test and clear area
|
||||
* bitmap_find_next_zero_area(buf, len, pos, n, mask) Find bit free area
|
||||
* bitmap_to_le(dst, src, nbits) Convert bitmap to little endian
|
||||
* bitmap_from_le(dst, src, nbits) Convert bitmap from little endian
|
||||
*/
|
||||
|
||||
/*
|
||||
@@ -82,6 +84,7 @@ int slow_bitmap_andnot(unsigned long *dst, const unsigned long *bitmap1,
|
||||
const unsigned long *bitmap2, long bits);
|
||||
int slow_bitmap_intersects(const unsigned long *bitmap1,
|
||||
const unsigned long *bitmap2, long bits);
|
||||
long slow_bitmap_count_one(const unsigned long *bitmap, long nbits);
|
||||
|
||||
static inline unsigned long *bitmap_try_new(long nbits)
|
||||
{
|
||||
@@ -216,6 +219,15 @@ static inline int bitmap_intersects(const unsigned long *src1,
|
||||
}
|
||||
}
|
||||
|
||||
static inline long bitmap_count_one(const unsigned long *bitmap, long nbits)
|
||||
{
|
||||
if (small_nbits(nbits)) {
|
||||
return ctpopl(*bitmap & BITMAP_LAST_WORD_MASK(nbits));
|
||||
} else {
|
||||
return slow_bitmap_count_one(bitmap, nbits);
|
||||
}
|
||||
}
|
||||
|
||||
void bitmap_set(unsigned long *map, long i, long len);
|
||||
void bitmap_set_atomic(unsigned long *map, long i, long len);
|
||||
void bitmap_clear(unsigned long *map, long start, long nr);
|
||||
@@ -237,4 +249,9 @@ static inline unsigned long *bitmap_zero_extend(unsigned long *old,
|
||||
return new;
|
||||
}
|
||||
|
||||
void bitmap_to_le(unsigned long *dst, const unsigned long *src,
|
||||
long nbits);
|
||||
void bitmap_from_le(unsigned long *dst, const unsigned long *src,
|
||||
long nbits);
|
||||
|
||||
#endif /* BITMAP_H */
|
||||
|
||||
@@ -205,13 +205,13 @@ extern int daemon(int, int);
|
||||
|
||||
/* Round number up to multiple. Requires that d be a power of 2 (see
|
||||
* QEMU_ALIGN_UP for a safer but slower version on arbitrary
|
||||
* numbers) */
|
||||
* numbers); works even if d is a smaller type than n. */
|
||||
#ifndef ROUND_UP
|
||||
#define ROUND_UP(n,d) (((n) + (d) - 1) & -(d))
|
||||
#define ROUND_UP(n, d) (((n) + (d) - 1) & -(0 ? (n) : (d)))
|
||||
#endif
|
||||
|
||||
#ifndef DIV_ROUND_UP
|
||||
#define DIV_ROUND_UP(n,d) (((n) + (d) - 1) / (d))
|
||||
#define DIV_ROUND_UP(n, d) (((n) + (d) - 1) / (d))
|
||||
#endif
|
||||
|
||||
/*
|
||||
|
||||
@@ -21,7 +21,7 @@ struct QemuCond {
|
||||
};
|
||||
|
||||
struct QemuSemaphore {
|
||||
#if defined(__APPLE__) || defined(__NetBSD__)
|
||||
#ifndef CONFIG_SEM_TIMEDWAIT
|
||||
pthread_mutex_t lock;
|
||||
pthread_cond_t cond;
|
||||
unsigned int count;
|
||||
|
||||
@@ -30,6 +30,7 @@ typedef struct DisplaySurface DisplaySurface;
|
||||
typedef struct DriveInfo DriveInfo;
|
||||
typedef struct Error Error;
|
||||
typedef struct EventNotifier EventNotifier;
|
||||
typedef struct FlatView FlatView;
|
||||
typedef struct FWCfgEntry FWCfgEntry;
|
||||
typedef struct FWCfgIoState FWCfgIoState;
|
||||
typedef struct FWCfgMemState FWCfgMemState;
|
||||
|
||||
56
include/scsi/pr-manager.h
Normal file
56
include/scsi/pr-manager.h
Normal file
@@ -0,0 +1,56 @@
|
||||
#ifndef PR_MANAGER_H
|
||||
#define PR_MANAGER_H
|
||||
|
||||
#include "qom/object.h"
|
||||
#include "qapi/qmp/qdict.h"
|
||||
#include "qapi/visitor.h"
|
||||
#include "qom/object_interfaces.h"
|
||||
#include "block/aio.h"
|
||||
|
||||
#define TYPE_PR_MANAGER "pr-manager"
|
||||
|
||||
#define PR_MANAGER_CLASS(klass) \
|
||||
OBJECT_CLASS_CHECK(PRManagerClass, (klass), TYPE_PR_MANAGER)
|
||||
#define PR_MANAGER_GET_CLASS(obj) \
|
||||
OBJECT_GET_CLASS(PRManagerClass, (obj), TYPE_PR_MANAGER)
|
||||
#define PR_MANAGER(obj) \
|
||||
OBJECT_CHECK(PRManager, (obj), TYPE_PR_MANAGER)
|
||||
|
||||
struct sg_io_hdr;
|
||||
|
||||
typedef struct PRManager {
|
||||
/* <private> */
|
||||
Object parent;
|
||||
} PRManager;
|
||||
|
||||
/**
|
||||
* PRManagerClass:
|
||||
* @parent_class: the base class
|
||||
* @run: callback invoked in thread pool context
|
||||
*/
|
||||
typedef struct PRManagerClass {
|
||||
/* <private> */
|
||||
ObjectClass parent_class;
|
||||
|
||||
/* <public> */
|
||||
int (*run)(PRManager *pr_mgr, int fd, struct sg_io_hdr *hdr);
|
||||
} PRManagerClass;
|
||||
|
||||
BlockAIOCB *pr_manager_execute(PRManager *pr_mgr,
|
||||
AioContext *ctx, int fd,
|
||||
struct sg_io_hdr *hdr,
|
||||
BlockCompletionFunc *complete,
|
||||
void *opaque);
|
||||
|
||||
#ifdef CONFIG_LINUX
|
||||
PRManager *pr_manager_lookup(const char *id, Error **errp);
|
||||
#else
|
||||
static inline PRManager *pr_manager_lookup(const char *id, Error **errp)
|
||||
{
|
||||
/* The classes do not exist at all! */
|
||||
error_setg(errp, "No persistent reservation manager with id '%s'", id);
|
||||
return NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -72,10 +72,14 @@ extern const struct SCSISense sense_code_IO_ERROR;
|
||||
extern const struct SCSISense sense_code_I_T_NEXUS_LOSS;
|
||||
/* Command aborted, Logical Unit failure */
|
||||
extern const struct SCSISense sense_code_LUN_FAILURE;
|
||||
/* Command aborted, LUN Communication failure */
|
||||
extern const struct SCSISense sense_code_LUN_COMM_FAILURE;
|
||||
/* Command aborted, Overlapped Commands Attempted */
|
||||
extern const struct SCSISense sense_code_OVERLAPPED_COMMANDS;
|
||||
/* LUN not ready, Capacity data has changed */
|
||||
extern const struct SCSISense sense_code_CAPACITY_CHANGED;
|
||||
/* Unit attention, SCSI bus reset */
|
||||
extern const struct SCSISense sense_code_SCSI_BUS_RESET;
|
||||
/* LUN not ready, Medium not present */
|
||||
extern const struct SCSISense sense_code_UNIT_ATTENTION_NO_MEDIUM;
|
||||
/* Unit attention, Power on, reset or bus device reset occurred */
|
||||
|
||||
@@ -21,7 +21,5 @@
|
||||
#define QEMU_SECCOMP_SET_SPAWN (1 << 3)
|
||||
#define QEMU_SECCOMP_SET_RESOURCECTL (1 << 4)
|
||||
|
||||
#include <seccomp.h>
|
||||
|
||||
int seccomp_start(uint32_t seccomp_opts);
|
||||
#endif
|
||||
|
||||
382
memory.c
382
memory.c
@@ -47,6 +47,8 @@ static QTAILQ_HEAD(memory_listeners, MemoryListener) memory_listeners
|
||||
static QTAILQ_HEAD(, AddressSpace) address_spaces
|
||||
= QTAILQ_HEAD_INITIALIZER(address_spaces);
|
||||
|
||||
static GHashTable *flat_views;
|
||||
|
||||
typedef struct AddrRange AddrRange;
|
||||
|
||||
/*
|
||||
@@ -154,7 +156,8 @@ enum ListenerDirection { Forward, Reverse };
|
||||
/* No need to ref/unref .mr, the FlatRange keeps it alive. */
|
||||
#define MEMORY_LISTENER_UPDATE_REGION(fr, as, dir, callback, _args...) \
|
||||
do { \
|
||||
MemoryRegionSection mrs = section_from_flat_range(fr, as); \
|
||||
MemoryRegionSection mrs = section_from_flat_range(fr, \
|
||||
address_space_to_flatview(as)); \
|
||||
MEMORY_LISTENER_CALL(as, callback, dir, &mrs, ##_args); \
|
||||
} while(0)
|
||||
|
||||
@@ -208,7 +211,6 @@ static bool memory_region_ioeventfd_equal(MemoryRegionIoeventfd a,
|
||||
}
|
||||
|
||||
typedef struct FlatRange FlatRange;
|
||||
typedef struct FlatView FlatView;
|
||||
|
||||
/* Range of memory in the global map. Addresses are absolute. */
|
||||
struct FlatRange {
|
||||
@@ -229,6 +231,8 @@ struct FlatView {
|
||||
FlatRange *ranges;
|
||||
unsigned nr;
|
||||
unsigned nr_allocated;
|
||||
struct AddressSpaceDispatch *dispatch;
|
||||
MemoryRegion *root;
|
||||
};
|
||||
|
||||
typedef struct AddressSpaceOps AddressSpaceOps;
|
||||
@@ -237,11 +241,11 @@ typedef struct AddressSpaceOps AddressSpaceOps;
|
||||
for (var = (view)->ranges; var < (view)->ranges + (view)->nr; ++var)
|
||||
|
||||
static inline MemoryRegionSection
|
||||
section_from_flat_range(FlatRange *fr, AddressSpace *as)
|
||||
section_from_flat_range(FlatRange *fr, FlatView *fv)
|
||||
{
|
||||
return (MemoryRegionSection) {
|
||||
.mr = fr->mr,
|
||||
.address_space = as,
|
||||
.fv = fv,
|
||||
.offset_within_region = fr->offset_in_region,
|
||||
.size = fr->addr.size,
|
||||
.offset_within_address_space = int128_get64(fr->addr.start),
|
||||
@@ -258,12 +262,17 @@ static bool flatrange_equal(FlatRange *a, FlatRange *b)
|
||||
&& a->readonly == b->readonly;
|
||||
}
|
||||
|
||||
static void flatview_init(FlatView *view)
|
||||
static FlatView *flatview_new(MemoryRegion *mr_root)
|
||||
{
|
||||
FlatView *view;
|
||||
|
||||
view = g_new0(FlatView, 1);
|
||||
view->ref = 1;
|
||||
view->ranges = NULL;
|
||||
view->nr = 0;
|
||||
view->nr_allocated = 0;
|
||||
view->root = mr_root;
|
||||
memory_region_ref(mr_root);
|
||||
trace_flatview_new(view, mr_root);
|
||||
|
||||
return view;
|
||||
}
|
||||
|
||||
/* Insert a range into a given position. Caller is responsible for maintaining
|
||||
@@ -287,25 +296,47 @@ static void flatview_destroy(FlatView *view)
|
||||
{
|
||||
int i;
|
||||
|
||||
trace_flatview_destroy(view, view->root);
|
||||
if (view->dispatch) {
|
||||
address_space_dispatch_free(view->dispatch);
|
||||
}
|
||||
for (i = 0; i < view->nr; i++) {
|
||||
memory_region_unref(view->ranges[i].mr);
|
||||
}
|
||||
g_free(view->ranges);
|
||||
memory_region_unref(view->root);
|
||||
g_free(view);
|
||||
}
|
||||
|
||||
static void flatview_ref(FlatView *view)
|
||||
static bool flatview_ref(FlatView *view)
|
||||
{
|
||||
atomic_inc(&view->ref);
|
||||
return atomic_fetch_inc_nonzero(&view->ref) > 0;
|
||||
}
|
||||
|
||||
static void flatview_unref(FlatView *view)
|
||||
{
|
||||
if (atomic_fetch_dec(&view->ref) == 1) {
|
||||
flatview_destroy(view);
|
||||
trace_flatview_destroy_rcu(view, view->root);
|
||||
assert(view->root);
|
||||
call_rcu(view, flatview_destroy, rcu);
|
||||
}
|
||||
}
|
||||
|
||||
FlatView *address_space_to_flatview(AddressSpace *as)
|
||||
{
|
||||
return atomic_rcu_read(&as->current_map);
|
||||
}
|
||||
|
||||
AddressSpaceDispatch *flatview_to_dispatch(FlatView *fv)
|
||||
{
|
||||
return fv->dispatch;
|
||||
}
|
||||
|
||||
AddressSpaceDispatch *address_space_to_dispatch(AddressSpace *as)
|
||||
{
|
||||
return flatview_to_dispatch(address_space_to_flatview(as));
|
||||
}
|
||||
|
||||
static bool can_merge(FlatRange *r1, FlatRange *r2)
|
||||
{
|
||||
return int128_eq(addrrange_end(r1->addr), r2->addr.start)
|
||||
@@ -560,13 +591,14 @@ static MemTxResult access_with_adjusted_size(hwaddr addr,
|
||||
unsigned size,
|
||||
unsigned access_size_min,
|
||||
unsigned access_size_max,
|
||||
MemTxResult (*access)(MemoryRegion *mr,
|
||||
hwaddr addr,
|
||||
uint64_t *value,
|
||||
unsigned size,
|
||||
unsigned shift,
|
||||
uint64_t mask,
|
||||
MemTxAttrs attrs),
|
||||
MemTxResult (*access_fn)
|
||||
(MemoryRegion *mr,
|
||||
hwaddr addr,
|
||||
uint64_t *value,
|
||||
unsigned size,
|
||||
unsigned shift,
|
||||
uint64_t mask,
|
||||
MemTxAttrs attrs),
|
||||
MemoryRegion *mr,
|
||||
MemTxAttrs attrs)
|
||||
{
|
||||
@@ -587,12 +619,12 @@ static MemTxResult access_with_adjusted_size(hwaddr addr,
|
||||
access_mask = -1ULL >> (64 - access_size * 8);
|
||||
if (memory_region_big_endian(mr)) {
|
||||
for (i = 0; i < size; i += access_size) {
|
||||
r |= access(mr, addr + i, value, access_size,
|
||||
r |= access_fn(mr, addr + i, value, access_size,
|
||||
(size - access_size - i) * 8, access_mask, attrs);
|
||||
}
|
||||
} else {
|
||||
for (i = 0; i < size; i += access_size) {
|
||||
r |= access(mr, addr + i, value, access_size, i * 8,
|
||||
r |= access_fn(mr, addr + i, value, access_size, i * 8,
|
||||
access_mask, attrs);
|
||||
}
|
||||
}
|
||||
@@ -701,13 +733,57 @@ static void render_memory_region(FlatView *view,
|
||||
}
|
||||
}
|
||||
|
||||
static MemoryRegion *memory_region_get_flatview_root(MemoryRegion *mr)
|
||||
{
|
||||
while (mr->enabled) {
|
||||
if (mr->alias) {
|
||||
if (!mr->alias_offset && int128_ge(mr->size, mr->alias->size)) {
|
||||
/* The alias is included in its entirety. Use it as
|
||||
* the "real" root, so that we can share more FlatViews.
|
||||
*/
|
||||
mr = mr->alias;
|
||||
continue;
|
||||
}
|
||||
} else if (!mr->terminates) {
|
||||
unsigned int found = 0;
|
||||
MemoryRegion *child, *next = NULL;
|
||||
QTAILQ_FOREACH(child, &mr->subregions, subregions_link) {
|
||||
if (child->enabled) {
|
||||
if (++found > 1) {
|
||||
next = NULL;
|
||||
break;
|
||||
}
|
||||
if (!child->addr && int128_ge(mr->size, child->size)) {
|
||||
/* A child is included in its entirety. If it's the only
|
||||
* enabled one, use it in the hope of finding an alias down the
|
||||
* way. This will also let us share FlatViews.
|
||||
*/
|
||||
next = child;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (found == 0) {
|
||||
return NULL;
|
||||
}
|
||||
if (next) {
|
||||
mr = next;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
return mr;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Render a memory topology into a list of disjoint absolute ranges. */
|
||||
static FlatView *generate_memory_topology(MemoryRegion *mr)
|
||||
{
|
||||
int i;
|
||||
FlatView *view;
|
||||
|
||||
view = g_new(FlatView, 1);
|
||||
flatview_init(view);
|
||||
view = flatview_new(mr);
|
||||
|
||||
if (mr) {
|
||||
render_memory_region(view, mr, int128_zero(),
|
||||
@@ -715,6 +791,15 @@ static FlatView *generate_memory_topology(MemoryRegion *mr)
|
||||
}
|
||||
flatview_simplify(view);
|
||||
|
||||
view->dispatch = address_space_dispatch_new(view);
|
||||
for (i = 0; i < view->nr; i++) {
|
||||
MemoryRegionSection mrs =
|
||||
section_from_flat_range(&view->ranges[i], view);
|
||||
flatview_add_to_dispatch(view, &mrs);
|
||||
}
|
||||
address_space_dispatch_compact(view->dispatch);
|
||||
g_hash_table_replace(flat_views, mr, view);
|
||||
|
||||
return view;
|
||||
}
|
||||
|
||||
@@ -740,7 +825,7 @@ static void address_space_add_del_ioeventfds(AddressSpace *as,
|
||||
fds_new[inew]))) {
|
||||
fd = &fds_old[iold];
|
||||
section = (MemoryRegionSection) {
|
||||
.address_space = as,
|
||||
.fv = address_space_to_flatview(as),
|
||||
.offset_within_address_space = int128_get64(fd->addr.start),
|
||||
.size = fd->addr.size,
|
||||
};
|
||||
@@ -753,7 +838,7 @@ static void address_space_add_del_ioeventfds(AddressSpace *as,
|
||||
fds_old[iold]))) {
|
||||
fd = &fds_new[inew];
|
||||
section = (MemoryRegionSection) {
|
||||
.address_space = as,
|
||||
.fv = address_space_to_flatview(as),
|
||||
.offset_within_address_space = int128_get64(fd->addr.start),
|
||||
.size = fd->addr.size,
|
||||
};
|
||||
@@ -772,8 +857,12 @@ static FlatView *address_space_get_flatview(AddressSpace *as)
|
||||
FlatView *view;
|
||||
|
||||
rcu_read_lock();
|
||||
view = atomic_rcu_read(&as->current_map);
|
||||
flatview_ref(view);
|
||||
do {
|
||||
view = address_space_to_flatview(as);
|
||||
/* If somebody has replaced as->current_map concurrently,
|
||||
* flatview_ref returns false.
|
||||
*/
|
||||
} while (!flatview_ref(view));
|
||||
rcu_read_unlock();
|
||||
return view;
|
||||
}
|
||||
@@ -879,18 +968,81 @@ static void address_space_update_topology_pass(AddressSpace *as,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void address_space_update_topology(AddressSpace *as)
|
||||
static void flatviews_init(void)
|
||||
{
|
||||
FlatView *old_view = address_space_get_flatview(as);
|
||||
FlatView *new_view = generate_memory_topology(as->root);
|
||||
static FlatView *empty_view;
|
||||
|
||||
address_space_update_topology_pass(as, old_view, new_view, false);
|
||||
address_space_update_topology_pass(as, old_view, new_view, true);
|
||||
if (flat_views) {
|
||||
return;
|
||||
}
|
||||
|
||||
flat_views = g_hash_table_new_full(g_direct_hash, g_direct_equal, NULL,
|
||||
(GDestroyNotify) flatview_unref);
|
||||
if (!empty_view) {
|
||||
empty_view = generate_memory_topology(NULL);
|
||||
/* We keep it alive forever in the global variable. */
|
||||
flatview_ref(empty_view);
|
||||
} else {
|
||||
g_hash_table_replace(flat_views, NULL, empty_view);
|
||||
flatview_ref(empty_view);
|
||||
}
|
||||
}
|
||||
|
||||
static void flatviews_reset(void)
|
||||
{
|
||||
AddressSpace *as;
|
||||
|
||||
if (flat_views) {
|
||||
g_hash_table_unref(flat_views);
|
||||
flat_views = NULL;
|
||||
}
|
||||
flatviews_init();
|
||||
|
||||
/* Render unique FVs */
|
||||
QTAILQ_FOREACH(as, &address_spaces, address_spaces_link) {
|
||||
MemoryRegion *physmr = memory_region_get_flatview_root(as->root);
|
||||
|
||||
if (g_hash_table_lookup(flat_views, physmr)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
generate_memory_topology(physmr);
|
||||
}
|
||||
}
|
||||
|
||||
static void address_space_set_flatview(AddressSpace *as)
|
||||
{
|
||||
FlatView *old_view = address_space_to_flatview(as);
|
||||
MemoryRegion *physmr = memory_region_get_flatview_root(as->root);
|
||||
FlatView *new_view = g_hash_table_lookup(flat_views, physmr);
|
||||
|
||||
assert(new_view);
|
||||
|
||||
if (old_view == new_view) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (old_view) {
|
||||
flatview_ref(old_view);
|
||||
}
|
||||
|
||||
flatview_ref(new_view);
|
||||
|
||||
if (!QTAILQ_EMPTY(&as->listeners)) {
|
||||
FlatView tmpview = { .nr = 0 }, *old_view2 = old_view;
|
||||
|
||||
if (!old_view2) {
|
||||
old_view2 = &tmpview;
|
||||
}
|
||||
address_space_update_topology_pass(as, old_view2, new_view, false);
|
||||
address_space_update_topology_pass(as, old_view2, new_view, true);
|
||||
}
|
||||
|
||||
/* Writes are protected by the BQL. */
|
||||
atomic_rcu_set(&as->current_map, new_view);
|
||||
call_rcu(old_view, flatview_unref, rcu);
|
||||
if (old_view) {
|
||||
flatview_unref(old_view);
|
||||
}
|
||||
|
||||
/* Note that all the old MemoryRegions are still alive up to this
|
||||
* point. This relieves most MemoryListeners from the need to
|
||||
@@ -898,9 +1050,20 @@ static void address_space_update_topology(AddressSpace *as)
|
||||
* outside the iothread mutex, in which case precise reference
|
||||
* counting is necessary.
|
||||
*/
|
||||
flatview_unref(old_view);
|
||||
if (old_view) {
|
||||
flatview_unref(old_view);
|
||||
}
|
||||
}
|
||||
|
||||
address_space_update_ioeventfds(as);
|
||||
static void address_space_update_topology(AddressSpace *as)
|
||||
{
|
||||
MemoryRegion *physmr = memory_region_get_flatview_root(as->root);
|
||||
|
||||
flatviews_init();
|
||||
if (!g_hash_table_lookup(flat_views, physmr)) {
|
||||
generate_memory_topology(physmr);
|
||||
}
|
||||
address_space_set_flatview(as);
|
||||
}
|
||||
|
||||
void memory_region_transaction_begin(void)
|
||||
@@ -919,10 +1082,13 @@ void memory_region_transaction_commit(void)
|
||||
--memory_region_transaction_depth;
|
||||
if (!memory_region_transaction_depth) {
|
||||
if (memory_region_update_pending) {
|
||||
flatviews_reset();
|
||||
|
||||
MEMORY_LISTENER_CALL_GLOBAL(begin, Forward);
|
||||
|
||||
QTAILQ_FOREACH(as, &address_spaces, address_spaces_link) {
|
||||
address_space_update_topology(as);
|
||||
address_space_set_flatview(as);
|
||||
address_space_update_ioeventfds(as);
|
||||
}
|
||||
memory_region_update_pending = false;
|
||||
MEMORY_LISTENER_CALL_GLOBAL(commit, Forward);
|
||||
@@ -1835,7 +2001,7 @@ void memory_region_sync_dirty_bitmap(MemoryRegion *mr)
|
||||
view = address_space_get_flatview(as);
|
||||
FOR_EACH_FLAT_RANGE(fr, view) {
|
||||
if (fr->mr == mr) {
|
||||
MemoryRegionSection mrs = section_from_flat_range(fr, as);
|
||||
MemoryRegionSection mrs = section_from_flat_range(fr, view);
|
||||
listener->log_sync(listener, &mrs);
|
||||
}
|
||||
}
|
||||
@@ -1938,7 +2104,7 @@ static void memory_region_update_coalesced_range_as(MemoryRegion *mr, AddressSpa
|
||||
FOR_EACH_FLAT_RANGE(fr, view) {
|
||||
if (fr->mr == mr) {
|
||||
section = (MemoryRegionSection) {
|
||||
.address_space = as,
|
||||
.fv = view,
|
||||
.offset_within_address_space = int128_get64(fr->addr.start),
|
||||
.size = fr->addr.size,
|
||||
};
|
||||
@@ -2289,7 +2455,7 @@ static MemoryRegionSection memory_region_find_rcu(MemoryRegion *mr,
|
||||
}
|
||||
range = addrrange_make(int128_make64(addr), int128_make64(size));
|
||||
|
||||
view = atomic_rcu_read(&as->current_map);
|
||||
view = address_space_to_flatview(as);
|
||||
fr = flatview_lookup(view, range);
|
||||
if (!fr) {
|
||||
return ret;
|
||||
@@ -2300,7 +2466,7 @@ static MemoryRegionSection memory_region_find_rcu(MemoryRegion *mr,
|
||||
}
|
||||
|
||||
ret.mr = fr->mr;
|
||||
ret.address_space = as;
|
||||
ret.fv = view;
|
||||
range = addrrange_intersection(range, fr->addr);
|
||||
ret.offset_within_region = fr->offset_in_region;
|
||||
ret.offset_within_region += int128_get64(int128_sub(range.start,
|
||||
@@ -2349,7 +2515,8 @@ void memory_global_dirty_log_sync(void)
|
||||
view = address_space_get_flatview(as);
|
||||
FOR_EACH_FLAT_RANGE(fr, view) {
|
||||
if (fr->dirty_log_mask) {
|
||||
MemoryRegionSection mrs = section_from_flat_range(fr, as);
|
||||
MemoryRegionSection mrs = section_from_flat_range(fr, view);
|
||||
|
||||
listener->log_sync(listener, &mrs);
|
||||
}
|
||||
}
|
||||
@@ -2434,7 +2601,7 @@ static void listener_add_address_space(MemoryListener *listener,
|
||||
FOR_EACH_FLAT_RANGE(fr, view) {
|
||||
MemoryRegionSection section = {
|
||||
.mr = fr->mr,
|
||||
.address_space = as,
|
||||
.fv = view,
|
||||
.offset_within_region = fr->offset_in_region,
|
||||
.size = fr->addr.size,
|
||||
.offset_within_address_space = int128_get64(fr->addr.start),
|
||||
@@ -2610,69 +2777,36 @@ void memory_region_invalidate_mmio_ptr(MemoryRegion *mr, hwaddr offset,
|
||||
void address_space_init(AddressSpace *as, MemoryRegion *root, const char *name)
|
||||
{
|
||||
memory_region_ref(root);
|
||||
memory_region_transaction_begin();
|
||||
as->ref_count = 1;
|
||||
as->root = root;
|
||||
as->malloced = false;
|
||||
as->current_map = g_new(FlatView, 1);
|
||||
flatview_init(as->current_map);
|
||||
as->current_map = NULL;
|
||||
as->ioeventfd_nb = 0;
|
||||
as->ioeventfds = NULL;
|
||||
QTAILQ_INIT(&as->listeners);
|
||||
QTAILQ_INSERT_TAIL(&address_spaces, as, address_spaces_link);
|
||||
as->name = g_strdup(name ? name : "anonymous");
|
||||
address_space_init_dispatch(as);
|
||||
memory_region_update_pending |= root->enabled;
|
||||
memory_region_transaction_commit();
|
||||
address_space_update_topology(as);
|
||||
address_space_update_ioeventfds(as);
|
||||
}
|
||||
|
||||
static void do_address_space_destroy(AddressSpace *as)
|
||||
{
|
||||
bool do_free = as->malloced;
|
||||
|
||||
address_space_destroy_dispatch(as);
|
||||
assert(QTAILQ_EMPTY(&as->listeners));
|
||||
|
||||
flatview_unref(as->current_map);
|
||||
g_free(as->name);
|
||||
g_free(as->ioeventfds);
|
||||
memory_region_unref(as->root);
|
||||
if (do_free) {
|
||||
g_free(as);
|
||||
}
|
||||
}
|
||||
|
||||
AddressSpace *address_space_init_shareable(MemoryRegion *root, const char *name)
|
||||
{
|
||||
AddressSpace *as;
|
||||
|
||||
QTAILQ_FOREACH(as, &address_spaces, address_spaces_link) {
|
||||
if (root == as->root && as->malloced) {
|
||||
as->ref_count++;
|
||||
return as;
|
||||
}
|
||||
}
|
||||
|
||||
as = g_malloc0(sizeof *as);
|
||||
address_space_init(as, root, name);
|
||||
as->malloced = true;
|
||||
return as;
|
||||
}
|
||||
|
||||
void address_space_destroy(AddressSpace *as)
|
||||
{
|
||||
MemoryRegion *root = as->root;
|
||||
|
||||
as->ref_count--;
|
||||
if (as->ref_count) {
|
||||
return;
|
||||
}
|
||||
/* Flush out anything from MemoryListeners listening in on this */
|
||||
memory_region_transaction_begin();
|
||||
as->root = NULL;
|
||||
memory_region_transaction_commit();
|
||||
QTAILQ_REMOVE(&address_spaces, as, address_spaces_link);
|
||||
address_space_unregister(as);
|
||||
|
||||
/* At this point, as->dispatch and as->current_map are dummy
|
||||
* entries that the guest should never use. Wait for the old
|
||||
@@ -2807,18 +2941,44 @@ static void mtree_print_mr(fprintf_function mon_printf, void *f,
|
||||
}
|
||||
}
|
||||
|
||||
static void mtree_print_flatview(fprintf_function p, void *f,
|
||||
AddressSpace *as)
|
||||
struct FlatViewInfo {
|
||||
fprintf_function mon_printf;
|
||||
void *f;
|
||||
int counter;
|
||||
bool dispatch_tree;
|
||||
};
|
||||
|
||||
static void mtree_print_flatview(gpointer key, gpointer value,
|
||||
gpointer user_data)
|
||||
{
|
||||
FlatView *view = address_space_get_flatview(as);
|
||||
FlatView *view = key;
|
||||
GArray *fv_address_spaces = value;
|
||||
struct FlatViewInfo *fvi = user_data;
|
||||
fprintf_function p = fvi->mon_printf;
|
||||
void *f = fvi->f;
|
||||
FlatRange *range = &view->ranges[0];
|
||||
MemoryRegion *mr;
|
||||
int n = view->nr;
|
||||
int i;
|
||||
AddressSpace *as;
|
||||
|
||||
p(f, "FlatView #%d\n", fvi->counter);
|
||||
++fvi->counter;
|
||||
|
||||
for (i = 0; i < fv_address_spaces->len; ++i) {
|
||||
as = g_array_index(fv_address_spaces, AddressSpace*, i);
|
||||
p(f, " AS \"%s\", root: %s", as->name, memory_region_name(as->root));
|
||||
if (as->root->alias) {
|
||||
p(f, ", alias %s", memory_region_name(as->root->alias));
|
||||
}
|
||||
p(f, "\n");
|
||||
}
|
||||
|
||||
p(f, " Root memory region: %s\n",
|
||||
view->root ? memory_region_name(view->root) : "(none)");
|
||||
|
||||
if (n <= 0) {
|
||||
p(f, MTREE_INDENT "No rendered FlatView for "
|
||||
"address space '%s'\n", as->name);
|
||||
flatview_unref(view);
|
||||
p(f, MTREE_INDENT "No rendered FlatView\n\n");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -2845,21 +3005,65 @@ static void mtree_print_flatview(fprintf_function p, void *f,
|
||||
range++;
|
||||
}
|
||||
|
||||
flatview_unref(view);
|
||||
#if !defined(CONFIG_USER_ONLY)
|
||||
if (fvi->dispatch_tree && view->root) {
|
||||
mtree_print_dispatch(p, f, view->dispatch, view->root);
|
||||
}
|
||||
#endif
|
||||
|
||||
p(f, "\n");
|
||||
}
|
||||
|
||||
void mtree_info(fprintf_function mon_printf, void *f, bool flatview)
|
||||
static gboolean mtree_info_flatview_free(gpointer key, gpointer value,
|
||||
gpointer user_data)
|
||||
{
|
||||
FlatView *view = key;
|
||||
GArray *fv_address_spaces = value;
|
||||
|
||||
g_array_unref(fv_address_spaces);
|
||||
flatview_unref(view);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void mtree_info(fprintf_function mon_printf, void *f, bool flatview,
|
||||
bool dispatch_tree)
|
||||
{
|
||||
MemoryRegionListHead ml_head;
|
||||
MemoryRegionList *ml, *ml2;
|
||||
AddressSpace *as;
|
||||
|
||||
if (flatview) {
|
||||
FlatView *view;
|
||||
struct FlatViewInfo fvi = {
|
||||
.mon_printf = mon_printf,
|
||||
.f = f,
|
||||
.counter = 0,
|
||||
.dispatch_tree = dispatch_tree
|
||||
};
|
||||
GArray *fv_address_spaces;
|
||||
GHashTable *views = g_hash_table_new(g_direct_hash, g_direct_equal);
|
||||
|
||||
/* Gather all FVs in one table */
|
||||
QTAILQ_FOREACH(as, &address_spaces, address_spaces_link) {
|
||||
mon_printf(f, "address-space (flat view): %s\n", as->name);
|
||||
mtree_print_flatview(mon_printf, f, as);
|
||||
mon_printf(f, "\n");
|
||||
view = address_space_get_flatview(as);
|
||||
|
||||
fv_address_spaces = g_hash_table_lookup(views, view);
|
||||
if (!fv_address_spaces) {
|
||||
fv_address_spaces = g_array_new(false, false, sizeof(as));
|
||||
g_hash_table_insert(views, view, fv_address_spaces);
|
||||
}
|
||||
|
||||
g_array_append_val(fv_address_spaces, as);
|
||||
}
|
||||
|
||||
/* Print */
|
||||
g_hash_table_foreach(views, mtree_print_flatview, &fvi);
|
||||
|
||||
/* Free */
|
||||
g_hash_table_foreach_remove(views, mtree_info_flatview_free, 0);
|
||||
g_hash_table_unref(views);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -11,3 +11,4 @@ common-obj-$(CONFIG_RDMA) += rdma.o
|
||||
|
||||
common-obj-$(CONFIG_LIVE_BLOCK_MIGRATION) += block.o
|
||||
|
||||
rdma.o-libs := $(RDMA_LIBS)
|
||||
|
||||
@@ -19,6 +19,14 @@
|
||||
#include "qapi/error.h"
|
||||
#include "io/channel-tls.h"
|
||||
|
||||
/**
|
||||
* @migration_channel_process_incoming - Create new incoming migration channel
|
||||
*
|
||||
* Notice that TLS is special. For it we listen in a listener socket,
|
||||
* and then create a new client socket from the TLS library.
|
||||
*
|
||||
* @ioc: Channel to which we are connecting
|
||||
*/
|
||||
void migration_channel_process_incoming(QIOChannel *ioc)
|
||||
{
|
||||
MigrationState *s = migrate_get_current();
|
||||
@@ -36,12 +44,18 @@ void migration_channel_process_incoming(QIOChannel *ioc)
|
||||
error_report_err(local_err);
|
||||
}
|
||||
} else {
|
||||
QEMUFile *f = qemu_fopen_channel_input(ioc);
|
||||
migration_fd_process_incoming(f);
|
||||
migration_ioc_process_incoming(ioc);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @migration_channel_connect - Create new outgoing migration channel
|
||||
*
|
||||
* @s: Current migration state
|
||||
* @ioc: Channel to which we are connecting
|
||||
* @hostname: Where we want to connect
|
||||
*/
|
||||
void migration_channel_connect(MigrationState *s,
|
||||
QIOChannel *ioc,
|
||||
const char *hostname)
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user