Compare commits
372 Commits
vfio-pci-f
...
pull-input
Author | SHA1 | Date | |
---|---|---|---|
|
dbb2a1326a | ||
|
c3aa84b68f | ||
|
f53f3d0a00 | ||
|
d7c698af8a | ||
|
6570025e53 | ||
|
80aaa0741f | ||
|
6fc0303b95 | ||
|
bb2b045034 | ||
|
c3f8d28e45 | ||
|
4089f7c6a0 | ||
|
2c02f88780 | ||
|
4c288acbd6 | ||
|
9c83ffd859 | ||
|
eb909c7f72 | ||
|
c75203c8d3 | ||
|
c6e0bd9b70 | ||
|
8ae8e904fc | ||
|
d5546c5e77 | ||
|
7dc74db88b | ||
|
464d9f641d | ||
|
078896a9ee | ||
|
cd5d031e75 | ||
|
50c75136be | ||
|
90ce8a061b | ||
|
47ea2de2d6 | ||
|
f47c3f5a80 | ||
|
2fa4c042bc | ||
|
64bb01aa35 | ||
|
b1f7d84fd2 | ||
|
85c09bc016 | ||
|
47c03744b3 | ||
|
6f90f3d786 | ||
|
5643706a09 | ||
|
5c07d00f1b | ||
|
70b52f62b8 | ||
|
e842c68d44 | ||
|
a8dfb1c34f | ||
|
4a33f45e2e | ||
|
4798648e32 | ||
|
2d0755d21c | ||
|
16b0ecd168 | ||
|
faecd955ce | ||
|
c43ce5512f | ||
|
21bae11a39 | ||
|
2e08c665cc | ||
|
c751a74afe | ||
|
f100db385d | ||
|
14768eba46 | ||
|
3ab193e662 | ||
|
192f81bfce | ||
|
edd85a3d9e | ||
|
502c8db5b4 | ||
|
d3535431e8 | ||
|
43579403a3 | ||
|
cd10032888 | ||
|
de8f580b23 | ||
|
8d447d10b7 | ||
|
a25f545d68 | ||
|
af98ba92ac | ||
|
d2a9260335 | ||
|
9784e57930 | ||
|
6567147588 | ||
|
c8b405b679 | ||
|
8b6b0c59a6 | ||
|
bbd1b1cc25 | ||
|
031fa96439 | ||
|
7ad95ff76c | ||
|
d4c8533755 | ||
|
7e7494627f | ||
|
0f20ba62c3 | ||
|
0ce470cd4c | ||
|
a0fcac9c21 | ||
|
c138593380 | ||
|
3f94170be3 | ||
|
7c43bca004 | ||
|
f3c75d42ad | ||
|
3707cd62db | ||
|
7dff9abe63 | ||
|
3c3b0ddefa | ||
|
e5d7d2b0f5 | ||
|
0a61f3b478 | ||
|
ac174549b7 | ||
|
57354f8f12 | ||
|
557d52fa69 | ||
|
e8f7b27b99 | ||
|
b8476fc7c6 | ||
|
f1064f612c | ||
|
6f3dab41fb | ||
|
4d82038e41 | ||
|
b41da4ebb2 | ||
|
2fdf78e649 | ||
|
818692ff95 | ||
|
e0ffe77f27 | ||
|
4430e07663 | ||
|
024215b242 | ||
|
8203e31b54 | ||
|
e13500b3c3 | ||
|
f293f04ab5 | ||
|
953f0f5842 | ||
|
63be09365a | ||
|
aa9e930c88 | ||
|
56eabc7508 | ||
|
111c5f54a1 | ||
|
a737d3ebc8 | ||
|
50f5fc0cf2 | ||
|
5dffff5a47 | ||
|
9b47bb490c | ||
|
bb5275338d | ||
|
32ea54ab5f | ||
|
27b95bfe62 | ||
|
9c294d5ab3 | ||
|
84cab1e2f5 | ||
|
e0498daab5 | ||
|
71a8c019c4 | ||
|
38a853375e | ||
|
52a4984d97 | ||
|
60511041d6 | ||
|
94840e0700 | ||
|
f5bc1bfa35 | ||
|
3f34cf910c | ||
|
61de36761b | ||
|
5736245c80 | ||
|
3b66da82ce | ||
|
18674b2678 | ||
|
6a2331d12e | ||
|
133e70ee88 | ||
|
eb1e7c3e51 | ||
|
b36f100e17 | ||
|
0658aa9cba | ||
|
69b31b907b | ||
|
66c3e32841 | ||
|
ce8ca30b39 | ||
|
6d41d146c9 | ||
|
da29cb7bc7 | ||
|
29a0e4e9a1 | ||
|
c73860803f | ||
|
28288b48a8 | ||
|
fab7fe426f | ||
|
1b0bd0029f | ||
|
587c51f74b | ||
|
5c77a786e2 | ||
|
1fa6c53304 | ||
|
a98eb9e99d | ||
|
6a4fda3358 | ||
|
e44259b6d4 | ||
|
98d1eb2748 | ||
|
a824bc191a | ||
|
86ba37edcb | ||
|
7ee19fb9d6 | ||
|
3d1140bf3e | ||
|
097ec5d850 | ||
|
f5c0f7f981 | ||
|
67a33f3727 | ||
|
74698350ca | ||
|
f53f81e08b | ||
|
968e76bcab | ||
|
cea4e57473 | ||
|
2c0c52ae62 | ||
|
b24d0b472b | ||
|
ab9408a2d1 | ||
|
3fd0aadfc1 | ||
|
e16a626b82 | ||
|
f026da7830 | ||
|
cac7f0ba4a | ||
|
e072fe796e | ||
|
dbcc48fa8f | ||
|
88e33d08c9 | ||
|
5177d2ca93 | ||
|
ed8ac5686a | ||
|
354a6decf1 | ||
|
959e9c9d1e | ||
|
4f17e9c738 | ||
|
595c6eefb7 | ||
|
5cb151acb1 | ||
|
bc80838f86 | ||
|
d3f9df8fb8 | ||
|
d32404fe42 | ||
|
2009227fbe | ||
|
4b98eeef50 | ||
|
5e591d8812 | ||
|
ee6e02c0ac | ||
|
3c3cbbdc84 | ||
|
59800ec8e5 | ||
|
4e38181979 | ||
|
3052f0d594 | ||
|
09aa9a526a | ||
|
6cd8712c5f | ||
|
7a7c05d77d | ||
|
363248e8c9 | ||
|
0dc083fe10 | ||
|
ca480de664 | ||
|
135a129a1c | ||
|
9c06a1f79f | ||
|
88ccd23a0c | ||
|
401949176c | ||
|
0bfe9299da | ||
|
81d2fb4dfd | ||
|
6475c9f05c | ||
|
a5100e752b | ||
|
f55ea6297c | ||
|
ac458e121c | ||
|
e00ef747f0 | ||
|
4a29420ea1 | ||
|
4fd42afe61 | ||
|
c2cb92f9ea | ||
|
739aa555b8 | ||
|
d47e95c0c8 | ||
|
57f45b6207 | ||
|
993c91a0e9 | ||
|
4fa4ce7107 | ||
|
fae0864573 | ||
|
75b7931ec6 | ||
|
b774539743 | ||
|
25a7017555 | ||
|
949ceeb31b | ||
|
56bed4135f | ||
|
a105acbce3 | ||
|
678e48a2e4 | ||
|
2fc0043283 | ||
|
7ad993b480 | ||
|
aabbd472a0 | ||
|
2c38b60010 | ||
|
c2216a8a7a | ||
|
ab22ad96ce | ||
|
357765fed5 | ||
|
25254a7191 | ||
|
cae8a9289b | ||
|
67d065c3db | ||
|
777872e5c6 | ||
|
cc99c6f5ff | ||
|
aa830cdc28 | ||
|
7edd9ddc97 | ||
|
8ead601883 | ||
|
c5d3c49896 | ||
|
55e7c29e46 | ||
|
0064aceb29 | ||
|
de580dafad | ||
|
1c884abede | ||
|
de92f3f86a | ||
|
ffe9fe3a25 | ||
|
4864512389 | ||
|
3eba13ec25 | ||
|
9147d019f3 | ||
|
69bef7931e | ||
|
4b350f1de1 | ||
|
0c762736df | ||
|
a9e6a0cbe2 | ||
|
adccfbcd60 | ||
|
1b37b3442f | ||
|
9a05feabd5 | ||
|
7d6dc7f30c | ||
|
4ab23a9182 | ||
|
b53ccc30c4 | ||
|
d12f57ec66 | ||
|
64cfba6a47 | ||
|
d0686c7291 | ||
|
298f116827 | ||
|
7aad248d35 | ||
|
607dacd0a0 | ||
|
4835ef7784 | ||
|
5d31babe5c | ||
|
fda053875e | ||
|
6a519918b3 | ||
|
b5ba1cc626 | ||
|
cb48da7f81 | ||
|
4e47e39ab0 | ||
|
d2fe51bda8 | ||
|
fbb0621a0f | ||
|
cd159d0954 | ||
|
d844a7b656 | ||
|
9fbee91a13 | ||
|
73795cea96 | ||
|
af87bf290f | ||
|
9eb08a435a | ||
|
ead4cf04f8 | ||
|
f9681f116c | ||
|
7f00eb30fe | ||
|
1eecf41b3e | ||
|
04c2b5168e | ||
|
f7d3e46676 | ||
|
49f5c9e98a | ||
|
0ca3611221 | ||
|
5d739a4787 | ||
|
d1028f1b5b | ||
|
c804c2a717 | ||
|
6fbef18a4c | ||
|
477a72a1ef | ||
|
65e526c24e | ||
|
e8803d93df | ||
|
6e25280216 | ||
|
a0fa2cb8cc | ||
|
9da45bb217 | ||
|
77319f2263 | ||
|
f2c55d1735 | ||
|
0788082a4b | ||
|
819bd3091e | ||
|
3a553fc658 | ||
|
216db403d0 | ||
|
2ce5868ca1 | ||
|
6f6831f61a | ||
|
bc3fbad816 | ||
|
28c05edff5 | ||
|
c04018e933 | ||
|
a5ae7e3984 | ||
|
432a0a130e | ||
|
1c8be73d4e | ||
|
c3143ba877 | ||
|
024c6e2ea5 | ||
|
63a31905cb | ||
|
eb0ecd5ad9 | ||
|
0956ff5a4e | ||
|
1f79ee32b5 | ||
|
34222fb810 | ||
|
9cfa0b4e4c | ||
|
4cc35614a0 | ||
|
1ed69e82b8 | ||
|
d9ea7d290b | ||
|
cd5c11b84b | ||
|
0b45451e58 | ||
|
e60cef860f | ||
|
a7adc4b779 | ||
|
4b7fff2fab | ||
|
327ed10fa2 | ||
|
a505d7fe5f | ||
|
cb2e37dffa | ||
|
5ebafdf31a | ||
|
b0fe242751 | ||
|
91e240698f | ||
|
168aa23bb0 | ||
|
8af35c37d2 | ||
|
cd4da63177 | ||
|
0eef9d9833 | ||
|
7da845b0f4 | ||
|
67ed771ded | ||
|
855011be05 | ||
|
1da41cc1c6 | ||
|
0a6a7ccaae | ||
|
d6032e06d1 | ||
|
876074c228 | ||
|
6453fa998a | ||
|
c10f7fc3d1 | ||
|
cf143ad350 | ||
|
fce0a82608 | ||
|
775fda92a1 | ||
|
cba933b225 | ||
|
106a73b6d2 | ||
|
ec1efab957 | ||
|
d77f7779b4 | ||
|
ad37bb3b00 | ||
|
e3e48565c1 | ||
|
d6085e3ace | ||
|
41310c6878 | ||
|
6d3cb1f970 | ||
|
24a370ef23 | ||
|
aded6539d9 | ||
|
0a985b3727 | ||
|
f6c65bfb93 | ||
|
3bac80d31a | ||
|
cf528b8958 | ||
|
2e753bcc7d | ||
|
1f55ac4586 | ||
|
e96dfd110e | ||
|
6e50d18847 | ||
|
cd6c88305f | ||
|
d9738fd246 | ||
|
64cc22841e | ||
|
24d3bd67ac | ||
|
837c390137 | ||
|
7ef8cf9a08 | ||
|
703dd81aca | ||
|
c5f52875b9 | ||
|
521f438e36 |
@@ -726,7 +726,7 @@ F: vl.c
|
|||||||
|
|
||||||
Human Monitor (HMP)
|
Human Monitor (HMP)
|
||||||
M: Luiz Capitulino <lcapitulino@redhat.com>
|
M: Luiz Capitulino <lcapitulino@redhat.com>
|
||||||
S: Supported
|
S: Maintained
|
||||||
F: monitor.c
|
F: monitor.c
|
||||||
F: hmp.c
|
F: hmp.c
|
||||||
F: hmp-commands.hx
|
F: hmp-commands.hx
|
||||||
@@ -758,7 +758,7 @@ T: git git://github.com/bonzini/qemu.git nbd-next
|
|||||||
QAPI
|
QAPI
|
||||||
M: Luiz Capitulino <lcapitulino@redhat.com>
|
M: Luiz Capitulino <lcapitulino@redhat.com>
|
||||||
M: Michael Roth <mdroth@linux.vnet.ibm.com>
|
M: Michael Roth <mdroth@linux.vnet.ibm.com>
|
||||||
S: Supported
|
S: Maintained
|
||||||
F: qapi/
|
F: qapi/
|
||||||
T: git git://repo.or.cz/qemu/qmp-unstable.git queue/qmp
|
T: git git://repo.or.cz/qemu/qmp-unstable.git queue/qmp
|
||||||
|
|
||||||
@@ -772,7 +772,7 @@ T: git git://repo.or.cz/qemu/qmp-unstable.git queue/qmp
|
|||||||
|
|
||||||
QMP
|
QMP
|
||||||
M: Luiz Capitulino <lcapitulino@redhat.com>
|
M: Luiz Capitulino <lcapitulino@redhat.com>
|
||||||
S: Supported
|
S: Maintained
|
||||||
F: qmp.c
|
F: qmp.c
|
||||||
F: monitor.c
|
F: monitor.c
|
||||||
F: qmp-commands.hx
|
F: qmp-commands.hx
|
||||||
|
5
Makefile
5
Makefile
@@ -159,6 +159,7 @@ qemu-options.def: $(SRC_PATH)/qemu-options.hx
|
|||||||
SUBDIR_RULES=$(patsubst %,subdir-%, $(TARGET_DIRS))
|
SUBDIR_RULES=$(patsubst %,subdir-%, $(TARGET_DIRS))
|
||||||
SOFTMMU_SUBDIR_RULES=$(filter %-softmmu,$(SUBDIR_RULES))
|
SOFTMMU_SUBDIR_RULES=$(filter %-softmmu,$(SUBDIR_RULES))
|
||||||
|
|
||||||
|
$(SOFTMMU_SUBDIR_RULES): $(block-obj-y)
|
||||||
$(SOFTMMU_SUBDIR_RULES): config-all-devices.mak
|
$(SOFTMMU_SUBDIR_RULES): config-all-devices.mak
|
||||||
|
|
||||||
subdir-%:
|
subdir-%:
|
||||||
@@ -319,7 +320,7 @@ ifdef INSTALL_BLOBS
|
|||||||
BLOBS=bios.bin bios-256k.bin sgabios.bin vgabios.bin vgabios-cirrus.bin \
|
BLOBS=bios.bin bios-256k.bin sgabios.bin vgabios.bin vgabios-cirrus.bin \
|
||||||
vgabios-stdvga.bin vgabios-vmware.bin vgabios-qxl.bin \
|
vgabios-stdvga.bin vgabios-vmware.bin vgabios-qxl.bin \
|
||||||
acpi-dsdt.aml q35-acpi-dsdt.aml \
|
acpi-dsdt.aml q35-acpi-dsdt.aml \
|
||||||
ppc_rom.bin openbios-sparc32 openbios-sparc64 openbios-ppc QEMU,tcx.bin \
|
ppc_rom.bin openbios-sparc32 openbios-sparc64 openbios-ppc QEMU,tcx.bin QEMU,cgthree.bin \
|
||||||
pxe-e1000.rom pxe-eepro100.rom pxe-ne2k_pci.rom \
|
pxe-e1000.rom pxe-eepro100.rom pxe-ne2k_pci.rom \
|
||||||
pxe-pcnet.rom pxe-rtl8139.rom pxe-virtio.rom \
|
pxe-pcnet.rom pxe-rtl8139.rom pxe-virtio.rom \
|
||||||
efi-e1000.rom efi-eepro100.rom efi-ne2k_pci.rom \
|
efi-e1000.rom efi-eepro100.rom efi-ne2k_pci.rom \
|
||||||
@@ -398,7 +399,7 @@ endif
|
|||||||
$(INSTALL_DATA) $(SRC_PATH)/pc-bios/keymaps/$$x "$(DESTDIR)$(qemu_datadir)/keymaps"; \
|
$(INSTALL_DATA) $(SRC_PATH)/pc-bios/keymaps/$$x "$(DESTDIR)$(qemu_datadir)/keymaps"; \
|
||||||
done
|
done
|
||||||
for d in $(TARGET_DIRS); do \
|
for d in $(TARGET_DIRS); do \
|
||||||
$(MAKE) -C $$d $@ || exit 1 ; \
|
$(MAKE) $(SUBDIR_MAKEFLAGS) TARGET_DIR=$$d/ -C $$d $@ || exit 1 ; \
|
||||||
done
|
done
|
||||||
|
|
||||||
# various test targets
|
# various test targets
|
||||||
|
@@ -21,11 +21,6 @@ block-obj-y += coroutine-$(CONFIG_COROUTINE_BACKEND).o
|
|||||||
|
|
||||||
block-obj-m = block/
|
block-obj-m = block/
|
||||||
|
|
||||||
ifeq ($(CONFIG_VIRTIO)$(CONFIG_VIRTFS)$(CONFIG_PCI),yyy)
|
|
||||||
# Lots of the fsdev/9pcode is pulled in by vl.c via qemu_fsdev_add.
|
|
||||||
# only pull in the actual virtio-9p device if we also enabled virtio.
|
|
||||||
CONFIG_REALLY_VIRTFS=y
|
|
||||||
endif
|
|
||||||
|
|
||||||
######################################################################
|
######################################################################
|
||||||
# smartcard
|
# smartcard
|
||||||
|
64
arch_init.c
64
arch_init.c
@@ -122,7 +122,6 @@ static void check_guest_throttling(void);
|
|||||||
#define RAM_SAVE_FLAG_XBZRLE 0x40
|
#define RAM_SAVE_FLAG_XBZRLE 0x40
|
||||||
/* 0x80 is reserved in migration.h start with 0x100 next */
|
/* 0x80 is reserved in migration.h start with 0x100 next */
|
||||||
|
|
||||||
|
|
||||||
static struct defconfig_file {
|
static struct defconfig_file {
|
||||||
const char *filename;
|
const char *filename;
|
||||||
/* Indicates it is an user config file (disabled by -no-user-config) */
|
/* Indicates it is an user config file (disabled by -no-user-config) */
|
||||||
@@ -133,6 +132,7 @@ static struct defconfig_file {
|
|||||||
{ NULL }, /* end of list */
|
{ NULL }, /* end of list */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static const uint8_t ZERO_TARGET_PAGE[TARGET_PAGE_SIZE];
|
||||||
|
|
||||||
int qemu_read_default_config_files(bool userconfig)
|
int qemu_read_default_config_files(bool userconfig)
|
||||||
{
|
{
|
||||||
@@ -273,6 +273,34 @@ static size_t save_block_hdr(QEMUFile *f, RAMBlock *block, ram_addr_t offset,
|
|||||||
return size;
|
return size;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* This is the last block that we have visited serching for dirty pages
|
||||||
|
*/
|
||||||
|
static RAMBlock *last_seen_block;
|
||||||
|
/* This is the last block from where we have sent data */
|
||||||
|
static RAMBlock *last_sent_block;
|
||||||
|
static ram_addr_t last_offset;
|
||||||
|
static unsigned long *migration_bitmap;
|
||||||
|
static uint64_t migration_dirty_pages;
|
||||||
|
static uint32_t last_version;
|
||||||
|
static bool ram_bulk_stage;
|
||||||
|
|
||||||
|
/* Update the xbzrle cache to reflect a page that's been sent as all 0.
|
||||||
|
* The important thing is that a stale (not-yet-0'd) page be replaced
|
||||||
|
* by the new data.
|
||||||
|
* As a bonus, if the page wasn't in the cache it gets added so that
|
||||||
|
* when a small write is made into the 0'd page it gets XBZRLE sent
|
||||||
|
*/
|
||||||
|
static void xbzrle_cache_zero_page(ram_addr_t current_addr)
|
||||||
|
{
|
||||||
|
if (ram_bulk_stage || !migrate_use_xbzrle()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* We don't care if this fails to allocate a new cache page
|
||||||
|
* as long as it updated an old one */
|
||||||
|
cache_insert(XBZRLE.cache, current_addr, ZERO_TARGET_PAGE);
|
||||||
|
}
|
||||||
|
|
||||||
#define ENCODING_FLAG_XBZRLE 0x1
|
#define ENCODING_FLAG_XBZRLE 0x1
|
||||||
|
|
||||||
static int save_xbzrle_page(QEMUFile *f, uint8_t *current_data,
|
static int save_xbzrle_page(QEMUFile *f, uint8_t *current_data,
|
||||||
@@ -329,18 +357,6 @@ static int save_xbzrle_page(QEMUFile *f, uint8_t *current_data,
|
|||||||
return bytes_sent;
|
return bytes_sent;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* This is the last block that we have visited serching for dirty pages
|
|
||||||
*/
|
|
||||||
static RAMBlock *last_seen_block;
|
|
||||||
/* This is the last block from where we have sent data */
|
|
||||||
static RAMBlock *last_sent_block;
|
|
||||||
static ram_addr_t last_offset;
|
|
||||||
static unsigned long *migration_bitmap;
|
|
||||||
static uint64_t migration_dirty_pages;
|
|
||||||
static uint32_t last_version;
|
|
||||||
static bool ram_bulk_stage;
|
|
||||||
|
|
||||||
static inline
|
static inline
|
||||||
ram_addr_t migration_bitmap_find_and_reset_dirty(MemoryRegion *mr,
|
ram_addr_t migration_bitmap_find_and_reset_dirty(MemoryRegion *mr,
|
||||||
ram_addr_t start)
|
ram_addr_t start)
|
||||||
@@ -512,6 +528,7 @@ static int ram_save_block(QEMUFile *f, bool last_stage)
|
|||||||
} else {
|
} else {
|
||||||
int ret;
|
int ret;
|
||||||
uint8_t *p;
|
uint8_t *p;
|
||||||
|
bool send_async = true;
|
||||||
int cont = (block == last_sent_block) ?
|
int cont = (block == last_sent_block) ?
|
||||||
RAM_SAVE_FLAG_CONTINUE : 0;
|
RAM_SAVE_FLAG_CONTINUE : 0;
|
||||||
|
|
||||||
@@ -522,6 +539,7 @@ static int ram_save_block(QEMUFile *f, bool last_stage)
|
|||||||
ret = ram_control_save_page(f, block->offset,
|
ret = ram_control_save_page(f, block->offset,
|
||||||
offset, TARGET_PAGE_SIZE, &bytes_sent);
|
offset, TARGET_PAGE_SIZE, &bytes_sent);
|
||||||
|
|
||||||
|
current_addr = block->offset + offset;
|
||||||
if (ret != RAM_SAVE_CONTROL_NOT_SUPP) {
|
if (ret != RAM_SAVE_CONTROL_NOT_SUPP) {
|
||||||
if (ret != RAM_SAVE_CONTROL_DELAYED) {
|
if (ret != RAM_SAVE_CONTROL_DELAYED) {
|
||||||
if (bytes_sent > 0) {
|
if (bytes_sent > 0) {
|
||||||
@@ -536,19 +554,35 @@ static int ram_save_block(QEMUFile *f, bool last_stage)
|
|||||||
RAM_SAVE_FLAG_COMPRESS);
|
RAM_SAVE_FLAG_COMPRESS);
|
||||||
qemu_put_byte(f, 0);
|
qemu_put_byte(f, 0);
|
||||||
bytes_sent++;
|
bytes_sent++;
|
||||||
|
/* Must let xbzrle know, otherwise a previous (now 0'd) cached
|
||||||
|
* page would be stale
|
||||||
|
*/
|
||||||
|
xbzrle_cache_zero_page(current_addr);
|
||||||
} else if (!ram_bulk_stage && migrate_use_xbzrle()) {
|
} else if (!ram_bulk_stage && migrate_use_xbzrle()) {
|
||||||
current_addr = block->offset + offset;
|
|
||||||
bytes_sent = save_xbzrle_page(f, p, current_addr, block,
|
bytes_sent = save_xbzrle_page(f, p, current_addr, block,
|
||||||
offset, cont, last_stage);
|
offset, cont, last_stage);
|
||||||
if (!last_stage) {
|
if (!last_stage) {
|
||||||
|
/* We must send exactly what's in the xbzrle cache
|
||||||
|
* even if the page wasn't xbzrle compressed, so that
|
||||||
|
* it's right next time.
|
||||||
|
*/
|
||||||
p = get_cached_data(XBZRLE.cache, current_addr);
|
p = get_cached_data(XBZRLE.cache, current_addr);
|
||||||
|
|
||||||
|
/* Can't send this cached data async, since the cache page
|
||||||
|
* might get updated before it gets to the wire
|
||||||
|
*/
|
||||||
|
send_async = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* XBZRLE overflow or normal page */
|
/* XBZRLE overflow or normal page */
|
||||||
if (bytes_sent == -1) {
|
if (bytes_sent == -1) {
|
||||||
bytes_sent = save_block_hdr(f, block, offset, cont, RAM_SAVE_FLAG_PAGE);
|
bytes_sent = save_block_hdr(f, block, offset, cont, RAM_SAVE_FLAG_PAGE);
|
||||||
qemu_put_buffer_async(f, p, TARGET_PAGE_SIZE);
|
if (send_async) {
|
||||||
|
qemu_put_buffer_async(f, p, TARGET_PAGE_SIZE);
|
||||||
|
} else {
|
||||||
|
qemu_put_buffer(f, p, TARGET_PAGE_SIZE);
|
||||||
|
}
|
||||||
bytes_sent += TARGET_PAGE_SIZE;
|
bytes_sent += TARGET_PAGE_SIZE;
|
||||||
acct_info.norm_pages++;
|
acct_info.norm_pages++;
|
||||||
}
|
}
|
||||||
|
@@ -566,7 +566,7 @@ CharDriverState *chr_baum_init(void)
|
|||||||
BaumDriverState *baum;
|
BaumDriverState *baum;
|
||||||
CharDriverState *chr;
|
CharDriverState *chr;
|
||||||
brlapi_handle_t *handle;
|
brlapi_handle_t *handle;
|
||||||
#ifdef CONFIG_SDL
|
#if defined(CONFIG_SDL) && SDL_COMPILEDVERSION < SDL_VERSIONNUM(2, 0, 0)
|
||||||
SDL_SysWMinfo info;
|
SDL_SysWMinfo info;
|
||||||
#endif
|
#endif
|
||||||
int tty;
|
int tty;
|
||||||
@@ -595,7 +595,7 @@ CharDriverState *chr_baum_init(void)
|
|||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef CONFIG_SDL
|
#if defined(CONFIG_SDL) && SDL_COMPILEDVERSION < SDL_VERSIONNUM(2, 0, 0)
|
||||||
memset(&info, 0, sizeof(info));
|
memset(&info, 0, sizeof(info));
|
||||||
SDL_VERSION(&info.version);
|
SDL_VERSION(&info.version);
|
||||||
if (SDL_GetWMInfo(&info))
|
if (SDL_GetWMInfo(&info))
|
||||||
|
39
block.c
39
block.c
@@ -547,8 +547,9 @@ int get_tmp_filename(char *filename, int size)
|
|||||||
int fd;
|
int fd;
|
||||||
const char *tmpdir;
|
const char *tmpdir;
|
||||||
tmpdir = getenv("TMPDIR");
|
tmpdir = getenv("TMPDIR");
|
||||||
if (!tmpdir)
|
if (!tmpdir) {
|
||||||
tmpdir = "/tmp";
|
tmpdir = "/var/tmp";
|
||||||
|
}
|
||||||
if (snprintf(filename, size, "%s/vl.XXXXXX", tmpdir) >= size) {
|
if (snprintf(filename, size, "%s/vl.XXXXXX", tmpdir) >= size) {
|
||||||
return -EOVERFLOW;
|
return -EOVERFLOW;
|
||||||
}
|
}
|
||||||
@@ -934,7 +935,7 @@ static int bdrv_open_common(BlockDriverState *bs, BlockDriverState *file,
|
|||||||
|
|
||||||
bdrv_refresh_limits(bs);
|
bdrv_refresh_limits(bs);
|
||||||
assert(bdrv_opt_mem_align(bs) != 0);
|
assert(bdrv_opt_mem_align(bs) != 0);
|
||||||
assert(bs->request_alignment != 0);
|
assert((bs->request_alignment != 0) || bs->sg);
|
||||||
|
|
||||||
#ifndef _WIN32
|
#ifndef _WIN32
|
||||||
if (bs->is_temporary) {
|
if (bs->is_temporary) {
|
||||||
@@ -1016,7 +1017,12 @@ static int bdrv_file_open(BlockDriverState *bs, const char *filename,
|
|||||||
ret = -EINVAL;
|
ret = -EINVAL;
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
qdict_del(*options, "filename");
|
|
||||||
|
if (!drv->bdrv_needs_filename) {
|
||||||
|
qdict_del(*options, "filename");
|
||||||
|
} else {
|
||||||
|
filename = qdict_get_str(*options, "filename");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!drv->bdrv_file_open) {
|
if (!drv->bdrv_file_open) {
|
||||||
@@ -1228,6 +1234,7 @@ int bdrv_open(BlockDriverState **pbs, const char *filename,
|
|||||||
ret = bdrv_file_open(bs, filename, &options, flags & ~BDRV_O_PROTOCOL,
|
ret = bdrv_file_open(bs, filename, &options, flags & ~BDRV_O_PROTOCOL,
|
||||||
&local_err);
|
&local_err);
|
||||||
if (!ret) {
|
if (!ret) {
|
||||||
|
drv = bs->drv;
|
||||||
goto done;
|
goto done;
|
||||||
} else if (bs->drv) {
|
} else if (bs->drv) {
|
||||||
goto close_and_fail;
|
goto close_and_fail;
|
||||||
@@ -1846,11 +1853,6 @@ static void bdrv_move_feature_fields(BlockDriverState *bs_dest,
|
|||||||
pstrcpy(bs_dest->device_name, sizeof(bs_dest->device_name),
|
pstrcpy(bs_dest->device_name, sizeof(bs_dest->device_name),
|
||||||
bs_src->device_name);
|
bs_src->device_name);
|
||||||
bs_dest->device_list = bs_src->device_list;
|
bs_dest->device_list = bs_src->device_list;
|
||||||
|
|
||||||
/* keep the same entry in graph_bdrv_states
|
|
||||||
* We do want to swap name but don't want to swap linked list entries
|
|
||||||
*/
|
|
||||||
bs_dest->node_list = bs_src->node_list;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -1869,6 +1871,17 @@ void bdrv_swap(BlockDriverState *bs_new, BlockDriverState *bs_old)
|
|||||||
{
|
{
|
||||||
BlockDriverState tmp;
|
BlockDriverState tmp;
|
||||||
|
|
||||||
|
/* The code needs to swap the node_name but simply swapping node_list won't
|
||||||
|
* work so first remove the nodes from the graph list, do the swap then
|
||||||
|
* insert them back if needed.
|
||||||
|
*/
|
||||||
|
if (bs_new->node_name[0] != '\0') {
|
||||||
|
QTAILQ_REMOVE(&graph_bdrv_states, bs_new, node_list);
|
||||||
|
}
|
||||||
|
if (bs_old->node_name[0] != '\0') {
|
||||||
|
QTAILQ_REMOVE(&graph_bdrv_states, bs_old, node_list);
|
||||||
|
}
|
||||||
|
|
||||||
/* bs_new must be anonymous and shouldn't have anything fancy enabled */
|
/* bs_new must be anonymous and shouldn't have anything fancy enabled */
|
||||||
assert(bs_new->device_name[0] == '\0');
|
assert(bs_new->device_name[0] == '\0');
|
||||||
assert(QLIST_EMPTY(&bs_new->dirty_bitmaps));
|
assert(QLIST_EMPTY(&bs_new->dirty_bitmaps));
|
||||||
@@ -1897,6 +1910,14 @@ void bdrv_swap(BlockDriverState *bs_new, BlockDriverState *bs_old)
|
|||||||
assert(bs_new->io_limits_enabled == false);
|
assert(bs_new->io_limits_enabled == false);
|
||||||
assert(!throttle_have_timer(&bs_new->throttle_state));
|
assert(!throttle_have_timer(&bs_new->throttle_state));
|
||||||
|
|
||||||
|
/* insert the nodes back into the graph node list if needed */
|
||||||
|
if (bs_new->node_name[0] != '\0') {
|
||||||
|
QTAILQ_INSERT_TAIL(&graph_bdrv_states, bs_new, node_list);
|
||||||
|
}
|
||||||
|
if (bs_old->node_name[0] != '\0') {
|
||||||
|
QTAILQ_INSERT_TAIL(&graph_bdrv_states, bs_old, node_list);
|
||||||
|
}
|
||||||
|
|
||||||
bdrv_rebind(bs_new);
|
bdrv_rebind(bs_new);
|
||||||
bdrv_rebind(bs_old);
|
bdrv_rebind(bs_old);
|
||||||
}
|
}
|
||||||
|
159
block/gluster.c
159
block/gluster.c
@@ -3,21 +3,12 @@
|
|||||||
*
|
*
|
||||||
* Copyright (C) 2012 Bharata B Rao <bharata@linux.vnet.ibm.com>
|
* Copyright (C) 2012 Bharata B Rao <bharata@linux.vnet.ibm.com>
|
||||||
*
|
*
|
||||||
* Pipe handling mechanism in AIO implementation is derived from
|
* This work is licensed under the terms of the GNU GPL, version 2 or later.
|
||||||
* block/rbd.c. Hence,
|
* See the COPYING file in the top-level directory.
|
||||||
*
|
*
|
||||||
* Copyright (C) 2010-2011 Christian Brunner <chb@muc.de>,
|
|
||||||
* Josh Durgin <josh.durgin@dreamhost.com>
|
|
||||||
*
|
|
||||||
* This work is licensed under the terms of the GNU GPL, version 2. See
|
|
||||||
* the COPYING file in the top-level directory.
|
|
||||||
*
|
|
||||||
* Contributions after 2012-01-13 are licensed under the terms of the
|
|
||||||
* GNU GPL, version 2 or (at your option) any later version.
|
|
||||||
*/
|
*/
|
||||||
#include <glusterfs/api/glfs.h>
|
#include <glusterfs/api/glfs.h>
|
||||||
#include "block/block_int.h"
|
#include "block/block_int.h"
|
||||||
#include "qemu/sockets.h"
|
|
||||||
#include "qemu/uri.h"
|
#include "qemu/uri.h"
|
||||||
|
|
||||||
typedef struct GlusterAIOCB {
|
typedef struct GlusterAIOCB {
|
||||||
@@ -32,9 +23,6 @@ typedef struct BDRVGlusterState {
|
|||||||
struct glfs_fd *fd;
|
struct glfs_fd *fd;
|
||||||
} BDRVGlusterState;
|
} BDRVGlusterState;
|
||||||
|
|
||||||
#define GLUSTER_FD_READ 0
|
|
||||||
#define GLUSTER_FD_WRITE 1
|
|
||||||
|
|
||||||
typedef struct GlusterConf {
|
typedef struct GlusterConf {
|
||||||
char *server;
|
char *server;
|
||||||
int port;
|
int port;
|
||||||
@@ -45,11 +33,13 @@ typedef struct GlusterConf {
|
|||||||
|
|
||||||
static void qemu_gluster_gconf_free(GlusterConf *gconf)
|
static void qemu_gluster_gconf_free(GlusterConf *gconf)
|
||||||
{
|
{
|
||||||
g_free(gconf->server);
|
if (gconf) {
|
||||||
g_free(gconf->volname);
|
g_free(gconf->server);
|
||||||
g_free(gconf->image);
|
g_free(gconf->volname);
|
||||||
g_free(gconf->transport);
|
g_free(gconf->image);
|
||||||
g_free(gconf);
|
g_free(gconf->transport);
|
||||||
|
g_free(gconf);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static int parse_volume_options(GlusterConf *gconf, char *path)
|
static int parse_volume_options(GlusterConf *gconf, char *path)
|
||||||
@@ -272,11 +262,28 @@ static QemuOptsList runtime_opts = {
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static void qemu_gluster_parse_flags(int bdrv_flags, int *open_flags)
|
||||||
|
{
|
||||||
|
assert(open_flags != NULL);
|
||||||
|
|
||||||
|
*open_flags |= O_BINARY;
|
||||||
|
|
||||||
|
if (bdrv_flags & BDRV_O_RDWR) {
|
||||||
|
*open_flags |= O_RDWR;
|
||||||
|
} else {
|
||||||
|
*open_flags |= O_RDONLY;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((bdrv_flags & BDRV_O_NOCACHE)) {
|
||||||
|
*open_flags |= O_DIRECT;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static int qemu_gluster_open(BlockDriverState *bs, QDict *options,
|
static int qemu_gluster_open(BlockDriverState *bs, QDict *options,
|
||||||
int bdrv_flags, Error **errp)
|
int bdrv_flags, Error **errp)
|
||||||
{
|
{
|
||||||
BDRVGlusterState *s = bs->opaque;
|
BDRVGlusterState *s = bs->opaque;
|
||||||
int open_flags = O_BINARY;
|
int open_flags = 0;
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
GlusterConf *gconf = g_malloc0(sizeof(GlusterConf));
|
GlusterConf *gconf = g_malloc0(sizeof(GlusterConf));
|
||||||
QemuOpts *opts;
|
QemuOpts *opts;
|
||||||
@@ -299,15 +306,7 @@ static int qemu_gluster_open(BlockDriverState *bs, QDict *options,
|
|||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (bdrv_flags & BDRV_O_RDWR) {
|
qemu_gluster_parse_flags(bdrv_flags, &open_flags);
|
||||||
open_flags |= O_RDWR;
|
|
||||||
} else {
|
|
||||||
open_flags |= O_RDONLY;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((bdrv_flags & BDRV_O_NOCACHE)) {
|
|
||||||
open_flags |= O_DIRECT;
|
|
||||||
}
|
|
||||||
|
|
||||||
s->fd = glfs_open(s->glfs, gconf->image, open_flags);
|
s->fd = glfs_open(s->glfs, gconf->image, open_flags);
|
||||||
if (!s->fd) {
|
if (!s->fd) {
|
||||||
@@ -329,6 +328,96 @@ out:
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
typedef struct BDRVGlusterReopenState {
|
||||||
|
struct glfs *glfs;
|
||||||
|
struct glfs_fd *fd;
|
||||||
|
} BDRVGlusterReopenState;
|
||||||
|
|
||||||
|
|
||||||
|
static int qemu_gluster_reopen_prepare(BDRVReopenState *state,
|
||||||
|
BlockReopenQueue *queue, Error **errp)
|
||||||
|
{
|
||||||
|
int ret = 0;
|
||||||
|
BDRVGlusterReopenState *reop_s;
|
||||||
|
GlusterConf *gconf = NULL;
|
||||||
|
int open_flags = 0;
|
||||||
|
|
||||||
|
assert(state != NULL);
|
||||||
|
assert(state->bs != NULL);
|
||||||
|
|
||||||
|
state->opaque = g_malloc0(sizeof(BDRVGlusterReopenState));
|
||||||
|
reop_s = state->opaque;
|
||||||
|
|
||||||
|
qemu_gluster_parse_flags(state->flags, &open_flags);
|
||||||
|
|
||||||
|
gconf = g_malloc0(sizeof(GlusterConf));
|
||||||
|
|
||||||
|
reop_s->glfs = qemu_gluster_init(gconf, state->bs->filename, errp);
|
||||||
|
if (reop_s->glfs == NULL) {
|
||||||
|
ret = -errno;
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
reop_s->fd = glfs_open(reop_s->glfs, gconf->image, open_flags);
|
||||||
|
if (reop_s->fd == NULL) {
|
||||||
|
/* reops->glfs will be cleaned up in _abort */
|
||||||
|
ret = -errno;
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
exit:
|
||||||
|
/* state->opaque will be freed in either the _abort or _commit */
|
||||||
|
qemu_gluster_gconf_free(gconf);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void qemu_gluster_reopen_commit(BDRVReopenState *state)
|
||||||
|
{
|
||||||
|
BDRVGlusterReopenState *reop_s = state->opaque;
|
||||||
|
BDRVGlusterState *s = state->bs->opaque;
|
||||||
|
|
||||||
|
|
||||||
|
/* close the old */
|
||||||
|
if (s->fd) {
|
||||||
|
glfs_close(s->fd);
|
||||||
|
}
|
||||||
|
if (s->glfs) {
|
||||||
|
glfs_fini(s->glfs);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* use the newly opened image / connection */
|
||||||
|
s->fd = reop_s->fd;
|
||||||
|
s->glfs = reop_s->glfs;
|
||||||
|
|
||||||
|
g_free(state->opaque);
|
||||||
|
state->opaque = NULL;
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void qemu_gluster_reopen_abort(BDRVReopenState *state)
|
||||||
|
{
|
||||||
|
BDRVGlusterReopenState *reop_s = state->opaque;
|
||||||
|
|
||||||
|
if (reop_s == NULL) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (reop_s->fd) {
|
||||||
|
glfs_close(reop_s->fd);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (reop_s->glfs) {
|
||||||
|
glfs_fini(reop_s->glfs);
|
||||||
|
}
|
||||||
|
|
||||||
|
g_free(state->opaque);
|
||||||
|
state->opaque = NULL;
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
#ifdef CONFIG_GLUSTERFS_ZEROFILL
|
#ifdef CONFIG_GLUSTERFS_ZEROFILL
|
||||||
static coroutine_fn int qemu_gluster_co_write_zeroes(BlockDriverState *bs,
|
static coroutine_fn int qemu_gluster_co_write_zeroes(BlockDriverState *bs,
|
||||||
int64_t sector_num, int nb_sectors, BdrvRequestFlags flags)
|
int64_t sector_num, int nb_sectors, BdrvRequestFlags flags)
|
||||||
@@ -619,6 +708,9 @@ static BlockDriver bdrv_gluster = {
|
|||||||
.instance_size = sizeof(BDRVGlusterState),
|
.instance_size = sizeof(BDRVGlusterState),
|
||||||
.bdrv_needs_filename = true,
|
.bdrv_needs_filename = true,
|
||||||
.bdrv_file_open = qemu_gluster_open,
|
.bdrv_file_open = qemu_gluster_open,
|
||||||
|
.bdrv_reopen_prepare = qemu_gluster_reopen_prepare,
|
||||||
|
.bdrv_reopen_commit = qemu_gluster_reopen_commit,
|
||||||
|
.bdrv_reopen_abort = qemu_gluster_reopen_abort,
|
||||||
.bdrv_close = qemu_gluster_close,
|
.bdrv_close = qemu_gluster_close,
|
||||||
.bdrv_create = qemu_gluster_create,
|
.bdrv_create = qemu_gluster_create,
|
||||||
.bdrv_getlength = qemu_gluster_getlength,
|
.bdrv_getlength = qemu_gluster_getlength,
|
||||||
@@ -643,6 +735,9 @@ static BlockDriver bdrv_gluster_tcp = {
|
|||||||
.instance_size = sizeof(BDRVGlusterState),
|
.instance_size = sizeof(BDRVGlusterState),
|
||||||
.bdrv_needs_filename = true,
|
.bdrv_needs_filename = true,
|
||||||
.bdrv_file_open = qemu_gluster_open,
|
.bdrv_file_open = qemu_gluster_open,
|
||||||
|
.bdrv_reopen_prepare = qemu_gluster_reopen_prepare,
|
||||||
|
.bdrv_reopen_commit = qemu_gluster_reopen_commit,
|
||||||
|
.bdrv_reopen_abort = qemu_gluster_reopen_abort,
|
||||||
.bdrv_close = qemu_gluster_close,
|
.bdrv_close = qemu_gluster_close,
|
||||||
.bdrv_create = qemu_gluster_create,
|
.bdrv_create = qemu_gluster_create,
|
||||||
.bdrv_getlength = qemu_gluster_getlength,
|
.bdrv_getlength = qemu_gluster_getlength,
|
||||||
@@ -667,6 +762,9 @@ static BlockDriver bdrv_gluster_unix = {
|
|||||||
.instance_size = sizeof(BDRVGlusterState),
|
.instance_size = sizeof(BDRVGlusterState),
|
||||||
.bdrv_needs_filename = true,
|
.bdrv_needs_filename = true,
|
||||||
.bdrv_file_open = qemu_gluster_open,
|
.bdrv_file_open = qemu_gluster_open,
|
||||||
|
.bdrv_reopen_prepare = qemu_gluster_reopen_prepare,
|
||||||
|
.bdrv_reopen_commit = qemu_gluster_reopen_commit,
|
||||||
|
.bdrv_reopen_abort = qemu_gluster_reopen_abort,
|
||||||
.bdrv_close = qemu_gluster_close,
|
.bdrv_close = qemu_gluster_close,
|
||||||
.bdrv_create = qemu_gluster_create,
|
.bdrv_create = qemu_gluster_create,
|
||||||
.bdrv_getlength = qemu_gluster_getlength,
|
.bdrv_getlength = qemu_gluster_getlength,
|
||||||
@@ -691,6 +789,9 @@ static BlockDriver bdrv_gluster_rdma = {
|
|||||||
.instance_size = sizeof(BDRVGlusterState),
|
.instance_size = sizeof(BDRVGlusterState),
|
||||||
.bdrv_needs_filename = true,
|
.bdrv_needs_filename = true,
|
||||||
.bdrv_file_open = qemu_gluster_open,
|
.bdrv_file_open = qemu_gluster_open,
|
||||||
|
.bdrv_reopen_prepare = qemu_gluster_reopen_prepare,
|
||||||
|
.bdrv_reopen_commit = qemu_gluster_reopen_commit,
|
||||||
|
.bdrv_reopen_abort = qemu_gluster_reopen_abort,
|
||||||
.bdrv_close = qemu_gluster_close,
|
.bdrv_close = qemu_gluster_close,
|
||||||
.bdrv_create = qemu_gluster_create,
|
.bdrv_create = qemu_gluster_create,
|
||||||
.bdrv_getlength = qemu_gluster_getlength,
|
.bdrv_getlength = qemu_gluster_getlength,
|
||||||
|
150
block/iscsi.c
150
block/iscsi.c
@@ -145,12 +145,13 @@ iscsi_co_generic_cb(struct iscsi_context *iscsi, int status,
|
|||||||
|
|
||||||
if (iTask->retries-- > 0 && status == SCSI_STATUS_CHECK_CONDITION
|
if (iTask->retries-- > 0 && status == SCSI_STATUS_CHECK_CONDITION
|
||||||
&& task->sense.key == SCSI_SENSE_UNIT_ATTENTION) {
|
&& task->sense.key == SCSI_SENSE_UNIT_ATTENTION) {
|
||||||
|
error_report("iSCSI CheckCondition: %s", iscsi_get_error(iscsi));
|
||||||
iTask->do_retry = 1;
|
iTask->do_retry = 1;
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (status != SCSI_STATUS_GOOD) {
|
if (status != SCSI_STATUS_GOOD) {
|
||||||
error_report("iSCSI: Failure. %s", iscsi_get_error(iscsi));
|
error_report("iSCSI Failure: %s", iscsi_get_error(iscsi));
|
||||||
}
|
}
|
||||||
|
|
||||||
out:
|
out:
|
||||||
@@ -325,6 +326,7 @@ retry:
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (iTask.do_retry) {
|
if (iTask.do_retry) {
|
||||||
|
iTask.complete = 0;
|
||||||
goto retry;
|
goto retry;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -399,6 +401,7 @@ retry:
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (iTask.do_retry) {
|
if (iTask.do_retry) {
|
||||||
|
iTask.complete = 0;
|
||||||
goto retry;
|
goto retry;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -433,6 +436,7 @@ retry:
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (iTask.do_retry) {
|
if (iTask.do_retry) {
|
||||||
|
iTask.complete = 0;
|
||||||
goto retry;
|
goto retry;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -683,6 +687,7 @@ retry:
|
|||||||
scsi_free_scsi_task(iTask.task);
|
scsi_free_scsi_task(iTask.task);
|
||||||
iTask.task = NULL;
|
iTask.task = NULL;
|
||||||
}
|
}
|
||||||
|
iTask.complete = 0;
|
||||||
goto retry;
|
goto retry;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -767,6 +772,7 @@ retry:
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (iTask.do_retry) {
|
if (iTask.do_retry) {
|
||||||
|
iTask.complete = 0;
|
||||||
goto retry;
|
goto retry;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -830,24 +836,26 @@ retry:
|
|||||||
qemu_coroutine_yield();
|
qemu_coroutine_yield();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (iTask.status == SCSI_STATUS_CHECK_CONDITION &&
|
||||||
|
iTask.task->sense.key == SCSI_SENSE_ILLEGAL_REQUEST &&
|
||||||
|
iTask.task->sense.ascq == SCSI_SENSE_ASCQ_INVALID_OPERATION_CODE) {
|
||||||
|
/* WRITE SAME is not supported by the target */
|
||||||
|
iscsilun->has_write_same = false;
|
||||||
|
scsi_free_scsi_task(iTask.task);
|
||||||
|
return -ENOTSUP;
|
||||||
|
}
|
||||||
|
|
||||||
if (iTask.task != NULL) {
|
if (iTask.task != NULL) {
|
||||||
scsi_free_scsi_task(iTask.task);
|
scsi_free_scsi_task(iTask.task);
|
||||||
iTask.task = NULL;
|
iTask.task = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (iTask.do_retry) {
|
if (iTask.do_retry) {
|
||||||
|
iTask.complete = 0;
|
||||||
goto retry;
|
goto retry;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (iTask.status != SCSI_STATUS_GOOD) {
|
if (iTask.status != SCSI_STATUS_GOOD) {
|
||||||
if (iTask.status == SCSI_STATUS_CHECK_CONDITION &&
|
|
||||||
iTask.task->sense.key == SCSI_SENSE_ILLEGAL_REQUEST &&
|
|
||||||
iTask.task->sense.ascq == SCSI_SENSE_ASCQ_INVALID_OPERATION_CODE) {
|
|
||||||
/* WRITE SAME is not supported by the target */
|
|
||||||
iscsilun->has_write_same = false;
|
|
||||||
return -ENOTSUP;
|
|
||||||
}
|
|
||||||
|
|
||||||
return -EIO;
|
return -EIO;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1060,7 +1068,7 @@ static QemuOptsList runtime_opts = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
static struct scsi_task *iscsi_do_inquiry(struct iscsi_context *iscsi, int lun,
|
static struct scsi_task *iscsi_do_inquiry(struct iscsi_context *iscsi, int lun,
|
||||||
int evpd, int pc, Error **errp)
|
int evpd, int pc, void **inq, Error **errp)
|
||||||
{
|
{
|
||||||
int full_size;
|
int full_size;
|
||||||
struct scsi_task *task = NULL;
|
struct scsi_task *task = NULL;
|
||||||
@@ -1079,14 +1087,19 @@ static struct scsi_task *iscsi_do_inquiry(struct iscsi_context *iscsi, int lun,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
*inq = scsi_datain_unmarshall(task);
|
||||||
|
if (*inq == NULL) {
|
||||||
|
error_setg(errp, "iSCSI: failed to unmarshall inquiry datain blob");
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
return task;
|
return task;
|
||||||
|
|
||||||
fail:
|
fail:
|
||||||
error_setg(errp, "iSCSI: Inquiry command failed : %s",
|
error_setg(errp, "iSCSI: Inquiry command failed : %s",
|
||||||
iscsi_get_error(iscsi));
|
iscsi_get_error(iscsi));
|
||||||
if (task) {
|
if (task != NULL) {
|
||||||
scsi_free_scsi_task(task);
|
scsi_free_scsi_task(task);
|
||||||
return NULL;
|
|
||||||
}
|
}
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
@@ -1107,11 +1120,12 @@ static int iscsi_open(BlockDriverState *bs, QDict *options, int flags,
|
|||||||
struct iscsi_url *iscsi_url = NULL;
|
struct iscsi_url *iscsi_url = NULL;
|
||||||
struct scsi_task *task = NULL;
|
struct scsi_task *task = NULL;
|
||||||
struct scsi_inquiry_standard *inq = NULL;
|
struct scsi_inquiry_standard *inq = NULL;
|
||||||
|
struct scsi_inquiry_supported_pages *inq_vpd;
|
||||||
char *initiator_name = NULL;
|
char *initiator_name = NULL;
|
||||||
QemuOpts *opts;
|
QemuOpts *opts;
|
||||||
Error *local_err = NULL;
|
Error *local_err = NULL;
|
||||||
const char *filename;
|
const char *filename;
|
||||||
int ret;
|
int i, ret;
|
||||||
|
|
||||||
if ((BDRV_SECTOR_SIZE % 512) != 0) {
|
if ((BDRV_SECTOR_SIZE % 512) != 0) {
|
||||||
error_setg(errp, "iSCSI: Invalid BDRV_SECTOR_SIZE. "
|
error_setg(errp, "iSCSI: Invalid BDRV_SECTOR_SIZE. "
|
||||||
@@ -1197,25 +1211,18 @@ static int iscsi_open(BlockDriverState *bs, QDict *options, int flags,
|
|||||||
|
|
||||||
iscsilun->iscsi = iscsi;
|
iscsilun->iscsi = iscsi;
|
||||||
iscsilun->lun = iscsi_url->lun;
|
iscsilun->lun = iscsi_url->lun;
|
||||||
|
|
||||||
task = iscsi_inquiry_sync(iscsi, iscsilun->lun, 0, 0, 36);
|
|
||||||
|
|
||||||
if (task == NULL || task->status != SCSI_STATUS_GOOD) {
|
|
||||||
error_setg(errp, "iSCSI: failed to send inquiry command.");
|
|
||||||
ret = -EINVAL;
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
|
|
||||||
inq = scsi_datain_unmarshall(task);
|
|
||||||
if (inq == NULL) {
|
|
||||||
error_setg(errp, "iSCSI: Failed to unmarshall inquiry data.");
|
|
||||||
ret = -EINVAL;
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
|
|
||||||
iscsilun->type = inq->periperal_device_type;
|
|
||||||
iscsilun->has_write_same = true;
|
iscsilun->has_write_same = true;
|
||||||
|
|
||||||
|
task = iscsi_do_inquiry(iscsilun->iscsi, iscsilun->lun, 0, 0,
|
||||||
|
(void **) &inq, errp);
|
||||||
|
if (task == NULL) {
|
||||||
|
ret = -EINVAL;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
iscsilun->type = inq->periperal_device_type;
|
||||||
|
scsi_free_scsi_task(task);
|
||||||
|
task = NULL;
|
||||||
|
|
||||||
iscsi_readcapacity_sync(iscsilun, &local_err);
|
iscsi_readcapacity_sync(iscsilun, &local_err);
|
||||||
if (local_err != NULL) {
|
if (local_err != NULL) {
|
||||||
error_propagate(errp, local_err);
|
error_propagate(errp, local_err);
|
||||||
@@ -1224,55 +1231,56 @@ static int iscsi_open(BlockDriverState *bs, QDict *options, int flags,
|
|||||||
bs->total_sectors = sector_lun2qemu(iscsilun->num_blocks, iscsilun);
|
bs->total_sectors = sector_lun2qemu(iscsilun->num_blocks, iscsilun);
|
||||||
bs->request_alignment = iscsilun->block_size;
|
bs->request_alignment = iscsilun->block_size;
|
||||||
|
|
||||||
/* Medium changer or tape. We dont have any emulation for this so this must
|
/* We don't have any emulation for devices other than disks and CD-ROMs, so
|
||||||
* be sg ioctl compatible. We force it to be sg, otherwise qemu will try
|
* this must be sg ioctl compatible. We force it to be sg, otherwise qemu
|
||||||
* to read from the device to guess the image format.
|
* will try to read from the device to guess the image format.
|
||||||
*/
|
*/
|
||||||
if (iscsilun->type == TYPE_MEDIUM_CHANGER ||
|
if (iscsilun->type != TYPE_DISK && iscsilun->type != TYPE_ROM) {
|
||||||
iscsilun->type == TYPE_TAPE) {
|
|
||||||
bs->sg = 1;
|
bs->sg = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (iscsilun->lbpme) {
|
task = iscsi_do_inquiry(iscsilun->iscsi, iscsilun->lun, 1,
|
||||||
|
SCSI_INQUIRY_PAGECODE_SUPPORTED_VPD_PAGES,
|
||||||
|
(void **) &inq_vpd, errp);
|
||||||
|
if (task == NULL) {
|
||||||
|
ret = -EINVAL;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
for (i = 0; i < inq_vpd->num_pages; i++) {
|
||||||
|
struct scsi_task *inq_task;
|
||||||
struct scsi_inquiry_logical_block_provisioning *inq_lbp;
|
struct scsi_inquiry_logical_block_provisioning *inq_lbp;
|
||||||
task = iscsi_do_inquiry(iscsilun->iscsi, iscsilun->lun, 1,
|
|
||||||
SCSI_INQUIRY_PAGECODE_LOGICAL_BLOCK_PROVISIONING,
|
|
||||||
errp);
|
|
||||||
if (task == NULL) {
|
|
||||||
ret = -EINVAL;
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
inq_lbp = scsi_datain_unmarshall(task);
|
|
||||||
if (inq_lbp == NULL) {
|
|
||||||
error_setg(errp, "iSCSI: failed to unmarshall inquiry datain blob");
|
|
||||||
ret = -EINVAL;
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
memcpy(&iscsilun->lbp, inq_lbp,
|
|
||||||
sizeof(struct scsi_inquiry_logical_block_provisioning));
|
|
||||||
scsi_free_scsi_task(task);
|
|
||||||
task = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (iscsilun->lbp.lbpu || iscsilun->lbp.lbpws) {
|
|
||||||
struct scsi_inquiry_block_limits *inq_bl;
|
struct scsi_inquiry_block_limits *inq_bl;
|
||||||
task = iscsi_do_inquiry(iscsilun->iscsi, iscsilun->lun, 1,
|
switch (inq_vpd->pages[i]) {
|
||||||
SCSI_INQUIRY_PAGECODE_BLOCK_LIMITS, errp);
|
case SCSI_INQUIRY_PAGECODE_LOGICAL_BLOCK_PROVISIONING:
|
||||||
if (task == NULL) {
|
inq_task = iscsi_do_inquiry(iscsilun->iscsi, iscsilun->lun, 1,
|
||||||
ret = -EINVAL;
|
SCSI_INQUIRY_PAGECODE_LOGICAL_BLOCK_PROVISIONING,
|
||||||
goto out;
|
(void **) &inq_lbp, errp);
|
||||||
|
if (inq_task == NULL) {
|
||||||
|
ret = -EINVAL;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
memcpy(&iscsilun->lbp, inq_lbp,
|
||||||
|
sizeof(struct scsi_inquiry_logical_block_provisioning));
|
||||||
|
scsi_free_scsi_task(inq_task);
|
||||||
|
break;
|
||||||
|
case SCSI_INQUIRY_PAGECODE_BLOCK_LIMITS:
|
||||||
|
inq_task = iscsi_do_inquiry(iscsilun->iscsi, iscsilun->lun, 1,
|
||||||
|
SCSI_INQUIRY_PAGECODE_BLOCK_LIMITS,
|
||||||
|
(void **) &inq_bl, errp);
|
||||||
|
if (inq_task == NULL) {
|
||||||
|
ret = -EINVAL;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
memcpy(&iscsilun->bl, inq_bl,
|
||||||
|
sizeof(struct scsi_inquiry_block_limits));
|
||||||
|
scsi_free_scsi_task(inq_task);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
inq_bl = scsi_datain_unmarshall(task);
|
|
||||||
if (inq_bl == NULL) {
|
|
||||||
error_setg(errp, "iSCSI: failed to unmarshall inquiry datain blob");
|
|
||||||
ret = -EINVAL;
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
memcpy(&iscsilun->bl, inq_bl,
|
|
||||||
sizeof(struct scsi_inquiry_block_limits));
|
|
||||||
scsi_free_scsi_task(task);
|
|
||||||
task = NULL;
|
|
||||||
}
|
}
|
||||||
|
scsi_free_scsi_task(task);
|
||||||
|
task = NULL;
|
||||||
|
|
||||||
#if defined(LIBISCSI_FEATURE_NOP_COUNTER)
|
#if defined(LIBISCSI_FEATURE_NOP_COUNTER)
|
||||||
/* Set up a timer for sending out iSCSI NOPs */
|
/* Set up a timer for sending out iSCSI NOPs */
|
||||||
|
@@ -520,9 +520,6 @@ static void mirror_complete(BlockJob *job, Error **errp)
|
|||||||
|
|
||||||
ret = bdrv_open_backing_file(s->target, NULL, &local_err);
|
ret = bdrv_open_backing_file(s->target, NULL, &local_err);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
char backing_filename[PATH_MAX];
|
|
||||||
bdrv_get_full_backing_filename(s->target, backing_filename,
|
|
||||||
sizeof(backing_filename));
|
|
||||||
error_propagate(errp, local_err);
|
error_propagate(errp, local_err);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@@ -200,11 +200,14 @@ static void quorum_report_bad(QuorumAIOCB *acb, char *node_name, int ret)
|
|||||||
{
|
{
|
||||||
QObject *data;
|
QObject *data;
|
||||||
assert(node_name);
|
assert(node_name);
|
||||||
data = qobject_from_jsonf("{ 'ret': %d"
|
data = qobject_from_jsonf("{ 'node-name': %s"
|
||||||
", 'node-name': %s"
|
|
||||||
", 'sector-num': %" PRId64
|
", 'sector-num': %" PRId64
|
||||||
", 'sectors-count': %d }",
|
", 'sectors-count': %d }",
|
||||||
ret, node_name, acb->sector_num, acb->nb_sectors);
|
node_name, acb->sector_num, acb->nb_sectors);
|
||||||
|
if (ret < 0) {
|
||||||
|
QDict *dict = qobject_to_qdict(data);
|
||||||
|
qdict_put(dict, "error", qstring_from_str(strerror(-ret)));
|
||||||
|
}
|
||||||
monitor_protocol_event(QEVENT_QUORUM_REPORT_BAD, data);
|
monitor_protocol_event(QEVENT_QUORUM_REPORT_BAD, data);
|
||||||
qobject_decref(data);
|
qobject_decref(data);
|
||||||
}
|
}
|
||||||
|
@@ -336,6 +336,17 @@ error:
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
static void raw_parse_filename(const char *filename, QDict *options,
|
||||||
|
Error **errp)
|
||||||
|
{
|
||||||
|
/* The filename does not have to be prefixed by the protocol name, since
|
||||||
|
* "file" is the default protocol; therefore, the return value of this
|
||||||
|
* function call can be ignored. */
|
||||||
|
strstart(filename, "file:", &filename);
|
||||||
|
|
||||||
|
qdict_put_obj(options, "filename", QOBJECT(qstring_from_str(filename)));
|
||||||
|
}
|
||||||
|
|
||||||
static QemuOptsList raw_runtime_opts = {
|
static QemuOptsList raw_runtime_opts = {
|
||||||
.name = "raw",
|
.name = "raw",
|
||||||
.head = QTAILQ_HEAD_INITIALIZER(raw_runtime_opts.head),
|
.head = QTAILQ_HEAD_INITIALIZER(raw_runtime_opts.head),
|
||||||
@@ -1230,6 +1241,8 @@ static int raw_create(const char *filename, QEMUOptionParameter *options,
|
|||||||
int result = 0;
|
int result = 0;
|
||||||
int64_t total_size = 0;
|
int64_t total_size = 0;
|
||||||
|
|
||||||
|
strstart(filename, "file:", &filename);
|
||||||
|
|
||||||
/* Read out options */
|
/* Read out options */
|
||||||
while (options && options->name) {
|
while (options && options->name) {
|
||||||
if (!strcmp(options->name, BLOCK_OPT_SIZE)) {
|
if (!strcmp(options->name, BLOCK_OPT_SIZE)) {
|
||||||
@@ -1412,6 +1425,7 @@ static BlockDriver bdrv_file = {
|
|||||||
.instance_size = sizeof(BDRVRawState),
|
.instance_size = sizeof(BDRVRawState),
|
||||||
.bdrv_needs_filename = true,
|
.bdrv_needs_filename = true,
|
||||||
.bdrv_probe = NULL, /* no probe for protocols */
|
.bdrv_probe = NULL, /* no probe for protocols */
|
||||||
|
.bdrv_parse_filename = raw_parse_filename,
|
||||||
.bdrv_file_open = raw_open,
|
.bdrv_file_open = raw_open,
|
||||||
.bdrv_reopen_prepare = raw_reopen_prepare,
|
.bdrv_reopen_prepare = raw_reopen_prepare,
|
||||||
.bdrv_reopen_commit = raw_reopen_commit,
|
.bdrv_reopen_commit = raw_reopen_commit,
|
||||||
|
@@ -251,6 +251,17 @@ static void raw_parse_flags(int flags, int *access_flags, DWORD *overlapped)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void raw_parse_filename(const char *filename, QDict *options,
|
||||||
|
Error **errp)
|
||||||
|
{
|
||||||
|
/* The filename does not have to be prefixed by the protocol name, since
|
||||||
|
* "file" is the default protocol; therefore, the return value of this
|
||||||
|
* function call can be ignored. */
|
||||||
|
strstart(filename, "file:", &filename);
|
||||||
|
|
||||||
|
qdict_put_obj(options, "filename", QOBJECT(qstring_from_str(filename)));
|
||||||
|
}
|
||||||
|
|
||||||
static QemuOptsList raw_runtime_opts = {
|
static QemuOptsList raw_runtime_opts = {
|
||||||
.name = "raw",
|
.name = "raw",
|
||||||
.head = QTAILQ_HEAD_INITIALIZER(raw_runtime_opts.head),
|
.head = QTAILQ_HEAD_INITIALIZER(raw_runtime_opts.head),
|
||||||
@@ -470,6 +481,8 @@ static int raw_create(const char *filename, QEMUOptionParameter *options,
|
|||||||
int fd;
|
int fd;
|
||||||
int64_t total_size = 0;
|
int64_t total_size = 0;
|
||||||
|
|
||||||
|
strstart(filename, "file:", &filename);
|
||||||
|
|
||||||
/* Read out options */
|
/* Read out options */
|
||||||
while (options && options->name) {
|
while (options && options->name) {
|
||||||
if (!strcmp(options->name, BLOCK_OPT_SIZE)) {
|
if (!strcmp(options->name, BLOCK_OPT_SIZE)) {
|
||||||
@@ -504,6 +517,7 @@ static BlockDriver bdrv_file = {
|
|||||||
.protocol_name = "file",
|
.protocol_name = "file",
|
||||||
.instance_size = sizeof(BDRVRawState),
|
.instance_size = sizeof(BDRVRawState),
|
||||||
.bdrv_needs_filename = true,
|
.bdrv_needs_filename = true,
|
||||||
|
.bdrv_parse_filename = raw_parse_filename,
|
||||||
.bdrv_file_open = raw_open,
|
.bdrv_file_open = raw_open,
|
||||||
.bdrv_close = raw_close,
|
.bdrv_close = raw_close,
|
||||||
.bdrv_create = raw_create,
|
.bdrv_create = raw_create,
|
||||||
|
@@ -1184,7 +1184,7 @@ static int64_t coroutine_fn vmdk_co_get_block_status(BlockDriverState *bs,
|
|||||||
break;
|
break;
|
||||||
case VMDK_OK:
|
case VMDK_OK:
|
||||||
ret = BDRV_BLOCK_DATA;
|
ret = BDRV_BLOCK_DATA;
|
||||||
if (extent->file == bs->file) {
|
if (extent->file == bs->file && !extent->compressed) {
|
||||||
ret |= BDRV_BLOCK_OFFSET_VALID | offset;
|
ret |= BDRV_BLOCK_OFFSET_VALID | offset;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
15
blockdev.c
15
blockdev.c
@@ -2266,6 +2266,7 @@ void qmp_block_job_complete(const char *device, Error **errp)
|
|||||||
void qmp_blockdev_add(BlockdevOptions *options, Error **errp)
|
void qmp_blockdev_add(BlockdevOptions *options, Error **errp)
|
||||||
{
|
{
|
||||||
QmpOutputVisitor *ov = qmp_output_visitor_new();
|
QmpOutputVisitor *ov = qmp_output_visitor_new();
|
||||||
|
DriveInfo *dinfo;
|
||||||
QObject *obj;
|
QObject *obj;
|
||||||
QDict *qdict;
|
QDict *qdict;
|
||||||
Error *local_err = NULL;
|
Error *local_err = NULL;
|
||||||
@@ -2282,8 +2283,10 @@ void qmp_blockdev_add(BlockdevOptions *options, Error **errp)
|
|||||||
*
|
*
|
||||||
* For now, simply forbidding the combination for all drivers will do. */
|
* For now, simply forbidding the combination for all drivers will do. */
|
||||||
if (options->has_aio && options->aio == BLOCKDEV_AIO_OPTIONS_NATIVE) {
|
if (options->has_aio && options->aio == BLOCKDEV_AIO_OPTIONS_NATIVE) {
|
||||||
bool direct = options->cache->has_direct && options->cache->direct;
|
bool direct = options->has_cache &&
|
||||||
if (!options->has_cache && !direct) {
|
options->cache->has_direct &&
|
||||||
|
options->cache->direct;
|
||||||
|
if (!direct) {
|
||||||
error_setg(errp, "aio=native requires cache.direct=true");
|
error_setg(errp, "aio=native requires cache.direct=true");
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
@@ -2301,12 +2304,18 @@ void qmp_blockdev_add(BlockdevOptions *options, Error **errp)
|
|||||||
|
|
||||||
qdict_flatten(qdict);
|
qdict_flatten(qdict);
|
||||||
|
|
||||||
blockdev_init(NULL, qdict, &local_err);
|
dinfo = blockdev_init(NULL, qdict, &local_err);
|
||||||
if (local_err) {
|
if (local_err) {
|
||||||
error_propagate(errp, local_err);
|
error_propagate(errp, local_err);
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (bdrv_key_required(dinfo->bdrv)) {
|
||||||
|
drive_uninit(dinfo);
|
||||||
|
error_setg(errp, "blockdev-add doesn't support encrypted devices");
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
fail:
|
fail:
|
||||||
qmp_output_visitor_cleanup(ov);
|
qmp_output_visitor_cleanup(ov);
|
||||||
}
|
}
|
||||||
|
166
configure
vendored
166
configure
vendored
@@ -14,13 +14,14 @@ fi
|
|||||||
TMPC="${TMPDIR1}/qemu-conf-${RANDOM}-$$-${RANDOM}.c"
|
TMPC="${TMPDIR1}/qemu-conf-${RANDOM}-$$-${RANDOM}.c"
|
||||||
TMPB="qemu-conf-${RANDOM}-$$-${RANDOM}"
|
TMPB="qemu-conf-${RANDOM}-$$-${RANDOM}"
|
||||||
TMPO="${TMPDIR1}/${TMPB}.o"
|
TMPO="${TMPDIR1}/${TMPB}.o"
|
||||||
|
TMPCXX="${TMPDIR1}/${TMPB}.cxx"
|
||||||
TMPL="${TMPDIR1}/${TMPB}.lo"
|
TMPL="${TMPDIR1}/${TMPB}.lo"
|
||||||
TMPA="${TMPDIR1}/lib${TMPB}.la"
|
TMPA="${TMPDIR1}/lib${TMPB}.la"
|
||||||
TMPE="${TMPDIR1}/qemu-conf-${RANDOM}-$$-${RANDOM}.exe"
|
TMPE="${TMPDIR1}/qemu-conf-${RANDOM}-$$-${RANDOM}.exe"
|
||||||
|
|
||||||
# NB: do not call "exit" in the trap handler; this is buggy with some shells;
|
# NB: do not call "exit" in the trap handler; this is buggy with some shells;
|
||||||
# see <1285349658-3122-1-git-send-email-loic.minier@linaro.org>
|
# see <1285349658-3122-1-git-send-email-loic.minier@linaro.org>
|
||||||
trap "rm -f $TMPC $TMPO $TMPE" EXIT INT QUIT TERM
|
trap "rm -f $TMPC $TMPO $TMPCXX $TMPE" EXIT INT QUIT TERM
|
||||||
rm -f config.log
|
rm -f config.log
|
||||||
|
|
||||||
# Print a helpful header at the top of config.log
|
# Print a helpful header at the top of config.log
|
||||||
@@ -54,10 +55,13 @@ error_exit() {
|
|||||||
exit 1
|
exit 1
|
||||||
}
|
}
|
||||||
|
|
||||||
do_cc() {
|
do_compiler() {
|
||||||
# Run the compiler, capturing its output to the log.
|
# Run the compiler, capturing its output to the log. First argument
|
||||||
echo $cc "$@" >> config.log
|
# is compiler binary to execute.
|
||||||
$cc "$@" >> config.log 2>&1 || return $?
|
local compiler="$1"
|
||||||
|
shift
|
||||||
|
echo $compiler "$@" >> config.log
|
||||||
|
$compiler "$@" >> config.log 2>&1 || return $?
|
||||||
# Test passed. If this is an --enable-werror build, rerun
|
# Test passed. If this is an --enable-werror build, rerun
|
||||||
# the test with -Werror and bail out if it fails. This
|
# the test with -Werror and bail out if it fails. This
|
||||||
# makes warning-generating-errors in configure test code
|
# makes warning-generating-errors in configure test code
|
||||||
@@ -71,14 +75,39 @@ do_cc() {
|
|||||||
return 0
|
return 0
|
||||||
;;
|
;;
|
||||||
esac
|
esac
|
||||||
echo $cc -Werror "$@" >> config.log
|
echo $compiler -Werror "$@" >> config.log
|
||||||
$cc -Werror "$@" >> config.log 2>&1 && return $?
|
$compiler -Werror "$@" >> config.log 2>&1 && return $?
|
||||||
error_exit "configure test passed without -Werror but failed with -Werror." \
|
error_exit "configure test passed without -Werror but failed with -Werror." \
|
||||||
"This is probably a bug in the configure script. The failing command" \
|
"This is probably a bug in the configure script. The failing command" \
|
||||||
"will be at the bottom of config.log." \
|
"will be at the bottom of config.log." \
|
||||||
"You can run configure with --disable-werror to bypass this check."
|
"You can run configure with --disable-werror to bypass this check."
|
||||||
}
|
}
|
||||||
|
|
||||||
|
do_cc() {
|
||||||
|
do_compiler "$cc" "$@"
|
||||||
|
}
|
||||||
|
|
||||||
|
do_cxx() {
|
||||||
|
do_compiler "$cxx" "$@"
|
||||||
|
}
|
||||||
|
|
||||||
|
update_cxxflags() {
|
||||||
|
# Set QEMU_CXXFLAGS from QEMU_CFLAGS by filtering out those
|
||||||
|
# options which some versions of GCC's C++ compiler complain about
|
||||||
|
# because they only make sense for C programs.
|
||||||
|
QEMU_CXXFLAGS=
|
||||||
|
for arg in $QEMU_CFLAGS; do
|
||||||
|
case $arg in
|
||||||
|
-Wstrict-prototypes|-Wmissing-prototypes|-Wnested-externs|\
|
||||||
|
-Wold-style-declaration|-Wold-style-definition|-Wredundant-decls)
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
QEMU_CXXFLAGS=${QEMU_CXXFLAGS:+$QEMU_CXXFLAGS }$arg
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
}
|
||||||
|
|
||||||
compile_object() {
|
compile_object() {
|
||||||
do_cc $QEMU_CFLAGS -c -o $TMPO $TMPC
|
do_cc $QEMU_CFLAGS -c -o $TMPO $TMPC
|
||||||
}
|
}
|
||||||
@@ -207,6 +236,7 @@ fdt=""
|
|||||||
netmap="no"
|
netmap="no"
|
||||||
pixman=""
|
pixman=""
|
||||||
sdl=""
|
sdl=""
|
||||||
|
sdlabi="1.2"
|
||||||
virtfs=""
|
virtfs=""
|
||||||
vnc="yes"
|
vnc="yes"
|
||||||
sparse="no"
|
sparse="no"
|
||||||
@@ -283,6 +313,8 @@ libusb=""
|
|||||||
usb_redir=""
|
usb_redir=""
|
||||||
glx=""
|
glx=""
|
||||||
zlib="yes"
|
zlib="yes"
|
||||||
|
lzo="no"
|
||||||
|
snappy="no"
|
||||||
guest_agent=""
|
guest_agent=""
|
||||||
guest_agent_with_vss="no"
|
guest_agent_with_vss="no"
|
||||||
vss_win32_sdk=""
|
vss_win32_sdk=""
|
||||||
@@ -364,12 +396,13 @@ query_pkg_config() {
|
|||||||
}
|
}
|
||||||
pkg_config=query_pkg_config
|
pkg_config=query_pkg_config
|
||||||
sdl_config="${SDL_CONFIG-${cross_prefix}sdl-config}"
|
sdl_config="${SDL_CONFIG-${cross_prefix}sdl-config}"
|
||||||
|
sdl2_config="${SDL2_CONFIG-${cross_prefix}sdl2-config}"
|
||||||
|
|
||||||
# If the user hasn't specified ARFLAGS, default to 'rv', just as make does.
|
# If the user hasn't specified ARFLAGS, default to 'rv', just as make does.
|
||||||
ARFLAGS="${ARFLAGS-rv}"
|
ARFLAGS="${ARFLAGS-rv}"
|
||||||
|
|
||||||
# default flags for all hosts
|
# default flags for all hosts
|
||||||
QEMU_CFLAGS="-fno-strict-aliasing $QEMU_CFLAGS"
|
QEMU_CFLAGS="-fno-strict-aliasing -fno-common $QEMU_CFLAGS"
|
||||||
QEMU_CFLAGS="-Wall -Wundef -Wwrite-strings -Wmissing-prototypes $QEMU_CFLAGS"
|
QEMU_CFLAGS="-Wall -Wundef -Wwrite-strings -Wmissing-prototypes $QEMU_CFLAGS"
|
||||||
QEMU_CFLAGS="-Wstrict-prototypes -Wredundant-decls $QEMU_CFLAGS"
|
QEMU_CFLAGS="-Wstrict-prototypes -Wredundant-decls $QEMU_CFLAGS"
|
||||||
QEMU_CFLAGS="-D_GNU_SOURCE -D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE $QEMU_CFLAGS"
|
QEMU_CFLAGS="-D_GNU_SOURCE -D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE $QEMU_CFLAGS"
|
||||||
@@ -773,6 +806,8 @@ for opt do
|
|||||||
;;
|
;;
|
||||||
--enable-sdl) sdl="yes"
|
--enable-sdl) sdl="yes"
|
||||||
;;
|
;;
|
||||||
|
--with-sdlabi=*) sdlabi="$optarg"
|
||||||
|
;;
|
||||||
--disable-qom-cast-debug) qom_cast_debug="no"
|
--disable-qom-cast-debug) qom_cast_debug="no"
|
||||||
;;
|
;;
|
||||||
--enable-qom-cast-debug) qom_cast_debug="yes"
|
--enable-qom-cast-debug) qom_cast_debug="yes"
|
||||||
@@ -995,6 +1030,10 @@ for opt do
|
|||||||
;;
|
;;
|
||||||
--disable-zlib-test) zlib="no"
|
--disable-zlib-test) zlib="no"
|
||||||
;;
|
;;
|
||||||
|
--enable-lzo) lzo="yes"
|
||||||
|
;;
|
||||||
|
--enable-snappy) snappy="yes"
|
||||||
|
;;
|
||||||
--enable-guest-agent) guest_agent="yes"
|
--enable-guest-agent) guest_agent="yes"
|
||||||
;;
|
;;
|
||||||
--disable-guest-agent) guest_agent="no"
|
--disable-guest-agent) guest_agent="no"
|
||||||
@@ -1190,6 +1229,7 @@ Advanced options (experts only):
|
|||||||
--disable-werror disable compilation abort on warning
|
--disable-werror disable compilation abort on warning
|
||||||
--disable-sdl disable SDL
|
--disable-sdl disable SDL
|
||||||
--enable-sdl enable SDL
|
--enable-sdl enable SDL
|
||||||
|
--with-sdlabi select preferred SDL ABI 1.2 or 2.0
|
||||||
--disable-gtk disable gtk UI
|
--disable-gtk disable gtk UI
|
||||||
--enable-gtk enable gtk UI
|
--enable-gtk enable gtk UI
|
||||||
--disable-virtfs disable VirtFS
|
--disable-virtfs disable VirtFS
|
||||||
@@ -1289,6 +1329,8 @@ Advanced options (experts only):
|
|||||||
--enable-libusb enable libusb (for usb passthrough)
|
--enable-libusb enable libusb (for usb passthrough)
|
||||||
--disable-usb-redir disable usb network redirection support
|
--disable-usb-redir disable usb network redirection support
|
||||||
--enable-usb-redir enable usb network redirection support
|
--enable-usb-redir enable usb network redirection support
|
||||||
|
--enable-lzo enable the support of lzo compression library
|
||||||
|
--enable-snappy enable the support of snappy compression library
|
||||||
--disable-guest-agent disable building of the QEMU Guest Agent
|
--disable-guest-agent disable building of the QEMU Guest Agent
|
||||||
--enable-guest-agent enable building of the QEMU Guest Agent
|
--enable-guest-agent enable building of the QEMU Guest Agent
|
||||||
--with-vss-sdk=SDK-path enable Windows VSS support in QEMU Guest Agent
|
--with-vss-sdk=SDK-path enable Windows VSS support in QEMU Guest Agent
|
||||||
@@ -1327,6 +1369,19 @@ if test "$ARCH" = "unknown"; then
|
|||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
# Consult white-list to determine whether to enable werror
|
||||||
|
# by default. Only enable by default for git builds
|
||||||
|
z_version=`cut -f3 -d. $source_path/VERSION`
|
||||||
|
|
||||||
|
if test -z "$werror" ; then
|
||||||
|
if test -d "$source_path/.git" -a \
|
||||||
|
"$linux" = "yes" ; then
|
||||||
|
werror="yes"
|
||||||
|
else
|
||||||
|
werror="no"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
# check that the C compiler works.
|
# check that the C compiler works.
|
||||||
cat > $TMPC <<EOF
|
cat > $TMPC <<EOF
|
||||||
int main(void) { return 0; }
|
int main(void) { return 0; }
|
||||||
@@ -1347,14 +1402,16 @@ EOF
|
|||||||
|
|
||||||
compile_object
|
compile_object
|
||||||
|
|
||||||
cat > $TMPC <<EOF
|
cat > $TMPCXX <<EOF
|
||||||
extern "C" {
|
extern "C" {
|
||||||
int c_function(void);
|
int c_function(void);
|
||||||
}
|
}
|
||||||
int c_function(void) { return 42; }
|
int c_function(void) { return 42; }
|
||||||
EOF
|
EOF
|
||||||
|
|
||||||
if (cc=$cxx do_cc $QEMU_CFLAGS -o $TMPE $TMPC $TMPO $LDFLAGS); then
|
update_cxxflags
|
||||||
|
|
||||||
|
if do_cxx $QEMU_CXXFLAGS -o $TMPE $TMPCXX $TMPO $LDFLAGS; then
|
||||||
# C++ compiler $cxx works ok with C compiler $cc
|
# C++ compiler $cxx works ok with C compiler $cc
|
||||||
:
|
:
|
||||||
else
|
else
|
||||||
@@ -1367,19 +1424,6 @@ else
|
|||||||
cxx=
|
cxx=
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Consult white-list to determine whether to enable werror
|
|
||||||
# by default. Only enable by default for git builds
|
|
||||||
z_version=`cut -f3 -d. $source_path/VERSION`
|
|
||||||
|
|
||||||
if test -z "$werror" ; then
|
|
||||||
if test -d "$source_path/.git" -a \
|
|
||||||
"$linux" = "yes" ; then
|
|
||||||
werror="yes"
|
|
||||||
else
|
|
||||||
werror="no"
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
|
|
||||||
gcc_flags="-Wold-style-declaration -Wold-style-definition -Wtype-limits"
|
gcc_flags="-Wold-style-declaration -Wold-style-definition -Wtype-limits"
|
||||||
gcc_flags="-Wformat-security -Wformat-y2k -Winit-self -Wignored-qualifiers $gcc_flags"
|
gcc_flags="-Wformat-security -Wformat-y2k -Winit-self -Wignored-qualifiers $gcc_flags"
|
||||||
gcc_flags="-Wmissing-include-dirs -Wempty-body -Wnested-externs $gcc_flags"
|
gcc_flags="-Wmissing-include-dirs -Wempty-body -Wnested-externs $gcc_flags"
|
||||||
@@ -1657,7 +1701,43 @@ EOF
|
|||||||
"Make sure to have the zlib libs and headers installed."
|
"Make sure to have the zlib libs and headers installed."
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
libs_softmmu="$libs_softmmu -lz"
|
LIBS="$LIBS -lz"
|
||||||
|
|
||||||
|
##########################################
|
||||||
|
# lzo check
|
||||||
|
|
||||||
|
if test "$lzo" != "no" ; then
|
||||||
|
cat > $TMPC << EOF
|
||||||
|
#include <lzo/lzo1x.h>
|
||||||
|
int main(void) { lzo_version(); return 0; }
|
||||||
|
EOF
|
||||||
|
if compile_prog "" "-llzo2" ; then
|
||||||
|
:
|
||||||
|
else
|
||||||
|
error_exit "lzo check failed" \
|
||||||
|
"Make sure to have the lzo libs and headers installed."
|
||||||
|
fi
|
||||||
|
|
||||||
|
libs_softmmu="$libs_softmmu -llzo2"
|
||||||
|
fi
|
||||||
|
|
||||||
|
##########################################
|
||||||
|
# snappy check
|
||||||
|
|
||||||
|
if test "$snappy" != "no" ; then
|
||||||
|
cat > $TMPC << EOF
|
||||||
|
#include <snappy-c.h>
|
||||||
|
int main(void) { snappy_max_compressed_length(4096); return 0; }
|
||||||
|
EOF
|
||||||
|
if compile_prog "" "-lsnappy" ; then
|
||||||
|
:
|
||||||
|
else
|
||||||
|
error_exit "snappy check failed" \
|
||||||
|
"Make sure to have the snappy libs and headers installed."
|
||||||
|
fi
|
||||||
|
|
||||||
|
libs_softmmu="$libs_softmmu -lsnappy"
|
||||||
|
fi
|
||||||
|
|
||||||
##########################################
|
##########################################
|
||||||
# libseccomp check
|
# libseccomp check
|
||||||
@@ -1911,12 +1991,22 @@ fi
|
|||||||
|
|
||||||
# Look for sdl configuration program (pkg-config or sdl-config). Try
|
# Look for sdl configuration program (pkg-config or sdl-config). Try
|
||||||
# sdl-config even without cross prefix, and favour pkg-config over sdl-config.
|
# sdl-config even without cross prefix, and favour pkg-config over sdl-config.
|
||||||
if test "`basename $sdl_config`" != sdl-config && ! has ${sdl_config}; then
|
|
||||||
sdl_config=sdl-config
|
if test $sdlabi = "2.0"; then
|
||||||
|
sdl_config=$sdl2_config
|
||||||
|
sdlname=sdl2
|
||||||
|
sdlconfigname=sdl2_config
|
||||||
|
else
|
||||||
|
sdlname=sdl
|
||||||
|
sdlconfigname=sdl_config
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if $pkg_config sdl --exists; then
|
if test "`basename $sdl_config`" != $sdlconfigname && ! has ${sdl_config}; then
|
||||||
sdlconfig="$pkg_config sdl"
|
sdl_config=$sdlconfigname
|
||||||
|
fi
|
||||||
|
|
||||||
|
if $pkg_config $sdlname --exists; then
|
||||||
|
sdlconfig="$pkg_config $sdlname"
|
||||||
_sdlversion=`$sdlconfig --modversion 2>/dev/null | sed 's/[^0-9]//g'`
|
_sdlversion=`$sdlconfig --modversion 2>/dev/null | sed 's/[^0-9]//g'`
|
||||||
elif has ${sdl_config}; then
|
elif has ${sdl_config}; then
|
||||||
sdlconfig="$sdl_config"
|
sdlconfig="$sdl_config"
|
||||||
@@ -2249,13 +2339,21 @@ EOF
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
##########################################
|
##########################################
|
||||||
# netmap headers probe
|
# netmap support probe
|
||||||
|
# Apart from looking for netmap headers, we make sure that the host API version
|
||||||
|
# supports the netmap backend (>=11). The upper bound (15) is meant to simulate
|
||||||
|
# a minor/major version number. Minor new features will be marked with values up
|
||||||
|
# to 15, and if something happens that requires a change to the backend we will
|
||||||
|
# move above 15, submit the backend fixes and modify this two bounds.
|
||||||
if test "$netmap" != "no" ; then
|
if test "$netmap" != "no" ; then
|
||||||
cat > $TMPC << EOF
|
cat > $TMPC << EOF
|
||||||
#include <inttypes.h>
|
#include <inttypes.h>
|
||||||
#include <net/if.h>
|
#include <net/if.h>
|
||||||
#include <net/netmap.h>
|
#include <net/netmap.h>
|
||||||
#include <net/netmap_user.h>
|
#include <net/netmap_user.h>
|
||||||
|
#if (NETMAP_API < 11) || (NETMAP_API > 15)
|
||||||
|
#error
|
||||||
|
#endif
|
||||||
int main(void) { return 0; }
|
int main(void) { return 0; }
|
||||||
EOF
|
EOF
|
||||||
if compile_prog "" "" ; then
|
if compile_prog "" "" ; then
|
||||||
@@ -4037,6 +4135,8 @@ echo "TPM passthrough $tpm_passthrough"
|
|||||||
echo "QOM debugging $qom_cast_debug"
|
echo "QOM debugging $qom_cast_debug"
|
||||||
echo "vhdx $vhdx"
|
echo "vhdx $vhdx"
|
||||||
echo "Quorum $quorum"
|
echo "Quorum $quorum"
|
||||||
|
echo "lzo support $lzo"
|
||||||
|
echo "snappy support $snappy"
|
||||||
|
|
||||||
if test "$sdl_too_old" = "yes"; then
|
if test "$sdl_too_old" = "yes"; then
|
||||||
echo "-> Your SDL version is too old - please upgrade to have SDL support"
|
echo "-> Your SDL version is too old - please upgrade to have SDL support"
|
||||||
@@ -4360,6 +4460,14 @@ if test "$glx" = "yes" ; then
|
|||||||
echo "GLX_LIBS=$glx_libs" >> $config_host_mak
|
echo "GLX_LIBS=$glx_libs" >> $config_host_mak
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
if test "$lzo" = "yes" ; then
|
||||||
|
echo "CONFIG_LZO=y" >> $config_host_mak
|
||||||
|
fi
|
||||||
|
|
||||||
|
if test "$snappy" = "yes" ; then
|
||||||
|
echo "CONFIG_SNAPPY=y" >> $config_host_mak
|
||||||
|
fi
|
||||||
|
|
||||||
if test "$libiscsi" = "yes" ; then
|
if test "$libiscsi" = "yes" ; then
|
||||||
echo "CONFIG_LIBISCSI=m" >> $config_host_mak
|
echo "CONFIG_LIBISCSI=m" >> $config_host_mak
|
||||||
if test "$libiscsi_version" = "1.4.0"; then
|
if test "$libiscsi_version" = "1.4.0"; then
|
||||||
|
@@ -477,7 +477,7 @@ int cpu_exec(CPUArchState *env)
|
|||||||
}
|
}
|
||||||
#elif defined(TARGET_ARM)
|
#elif defined(TARGET_ARM)
|
||||||
if (interrupt_request & CPU_INTERRUPT_FIQ
|
if (interrupt_request & CPU_INTERRUPT_FIQ
|
||||||
&& !(env->uncached_cpsr & CPSR_F)) {
|
&& !(env->daif & PSTATE_F)) {
|
||||||
env->exception_index = EXCP_FIQ;
|
env->exception_index = EXCP_FIQ;
|
||||||
cc->do_interrupt(cpu);
|
cc->do_interrupt(cpu);
|
||||||
next_tb = 0;
|
next_tb = 0;
|
||||||
@@ -493,7 +493,7 @@ int cpu_exec(CPUArchState *env)
|
|||||||
pc contains a magic address. */
|
pc contains a magic address. */
|
||||||
if (interrupt_request & CPU_INTERRUPT_HARD
|
if (interrupt_request & CPU_INTERRUPT_HARD
|
||||||
&& ((IS_M(env) && env->regs[15] < 0xfffffff0)
|
&& ((IS_M(env) && env->regs[15] < 0xfffffff0)
|
||||||
|| !(env->uncached_cpsr & CPSR_I))) {
|
|| !(env->daif & PSTATE_I))) {
|
||||||
env->exception_index = EXCP_IRQ;
|
env->exception_index = EXCP_IRQ;
|
||||||
cc->do_interrupt(cpu);
|
cc->do_interrupt(cpu);
|
||||||
next_tb = 0;
|
next_tb = 0;
|
||||||
|
@@ -47,4 +47,5 @@ CONFIG_E500=y
|
|||||||
CONFIG_OPENPIC_KVM=$(and $(CONFIG_E500),$(CONFIG_KVM))
|
CONFIG_OPENPIC_KVM=$(and $(CONFIG_E500),$(CONFIG_KVM))
|
||||||
# For PReP
|
# For PReP
|
||||||
CONFIG_MC146818RTC=y
|
CONFIG_MC146818RTC=y
|
||||||
|
CONFIG_ETSEC=y
|
||||||
CONFIG_ISA_TESTDEV=y
|
CONFIG_ISA_TESTDEV=y
|
||||||
|
@@ -1,2 +1,3 @@
|
|||||||
CONFIG_VIRTIO=y
|
CONFIG_VIRTIO=y
|
||||||
CONFIG_SCLPCONSOLE=y
|
CONFIG_SCLPCONSOLE=y
|
||||||
|
CONFIG_S390_FLIC=$(CONFIG_KVM)
|
||||||
|
@@ -10,6 +10,7 @@ CONFIG_EMPTY_SLOT=y
|
|||||||
CONFIG_PCNET_COMMON=y
|
CONFIG_PCNET_COMMON=y
|
||||||
CONFIG_LANCE=y
|
CONFIG_LANCE=y
|
||||||
CONFIG_TCX=y
|
CONFIG_TCX=y
|
||||||
|
CONFIG_CG3=y
|
||||||
CONFIG_SLAVIO=y
|
CONFIG_SLAVIO=y
|
||||||
CONFIG_CS4231=y
|
CONFIG_CS4231=y
|
||||||
CONFIG_GRLIB=y
|
CONFIG_GRLIB=y
|
||||||
|
@@ -225,6 +225,45 @@ Data:
|
|||||||
"timestamp": { "seconds": 1368697518, "microseconds": 326866 } }
|
"timestamp": { "seconds": 1368697518, "microseconds": 326866 } }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QUORUM_FAILURE
|
||||||
|
--------------
|
||||||
|
|
||||||
|
Emitted by the Quorum block driver if it fails to establish a quorum.
|
||||||
|
|
||||||
|
Data:
|
||||||
|
|
||||||
|
- "reference": device name if defined else node name.
|
||||||
|
- "sector-num": Number of the first sector of the failed read operation.
|
||||||
|
- "sector-count": Failed read operation sector count.
|
||||||
|
|
||||||
|
Example:
|
||||||
|
|
||||||
|
{ "event": "QUORUM_FAILURE",
|
||||||
|
"data": { "reference": "usr1", "sector-num": 345435, "sector-count": 5 },
|
||||||
|
"timestamp": { "seconds": 1344522075, "microseconds": 745528 } }
|
||||||
|
|
||||||
|
QUORUM_REPORT_BAD
|
||||||
|
-----------------
|
||||||
|
|
||||||
|
Emitted to report a corruption of a Quorum file.
|
||||||
|
|
||||||
|
Data:
|
||||||
|
|
||||||
|
- "error": Error message (json-string, optional)
|
||||||
|
Only present on failure. This field contains a human-readable
|
||||||
|
error message. There are no semantics other than that the
|
||||||
|
block layer reported an error and clients should not try to
|
||||||
|
interpret the error string.
|
||||||
|
- "node-name": The graph node name of the block driver state.
|
||||||
|
- "sector-num": Number of the first sector of the failed read operation.
|
||||||
|
- "sector-count": Failed read operation sector count.
|
||||||
|
|
||||||
|
Example:
|
||||||
|
|
||||||
|
{ "event": "QUORUM_REPORT_BAD",
|
||||||
|
"data": { "node-name": "1.raw", "sector-num": 345435, "sector-count": 5 },
|
||||||
|
"timestamp": { "seconds": 1344522075, "microseconds": 745528 } }
|
||||||
|
|
||||||
RESET
|
RESET
|
||||||
-----
|
-----
|
||||||
|
|
||||||
@@ -500,39 +539,3 @@ Example:
|
|||||||
|
|
||||||
Note: If action is "reset", "shutdown", or "pause" the WATCHDOG event is
|
Note: If action is "reset", "shutdown", or "pause" the WATCHDOG event is
|
||||||
followed respectively by the RESET, SHUTDOWN, or STOP events.
|
followed respectively by the RESET, SHUTDOWN, or STOP events.
|
||||||
|
|
||||||
QUORUM_FAILURE
|
|
||||||
--------------
|
|
||||||
|
|
||||||
Emitted by the Quorum block driver if it fails to establish a quorum.
|
|
||||||
|
|
||||||
Data:
|
|
||||||
|
|
||||||
- "reference": device name if defined else node name.
|
|
||||||
- "sector-num": Number of the first sector of the failed read operation.
|
|
||||||
- "sector-count": Failed read operation sector count.
|
|
||||||
|
|
||||||
Example:
|
|
||||||
|
|
||||||
{ "event": "QUORUM_FAILURE",
|
|
||||||
"data": { "reference": "usr1", "sector-num": 345435, "sector-count": 5 },
|
|
||||||
"timestamp": { "seconds": 1344522075, "microseconds": 745528 } }
|
|
||||||
|
|
||||||
QUORUM_REPORT_BAD
|
|
||||||
-----------------
|
|
||||||
|
|
||||||
Emitted to report a corruption of a Quorum file.
|
|
||||||
|
|
||||||
Data:
|
|
||||||
|
|
||||||
- "ret": The IO return code.
|
|
||||||
- "node-name": The graph node name of the block driver state.
|
|
||||||
- "sector-num": Number of the first sector of the failed read operation.
|
|
||||||
- "sector-count": Failed read operation sector count.
|
|
||||||
|
|
||||||
Example:
|
|
||||||
|
|
||||||
{ "event": "QUORUM_REPORT_BAD",
|
|
||||||
"data": { "ret": 0, "node-name": "1.raw", "sector-num": 345435,
|
|
||||||
"sector-count": 5 },
|
|
||||||
"timestamp": { "seconds": 1344522075, "microseconds": 745528 } }
|
|
||||||
|
@@ -66,7 +66,7 @@ bulk-phase round of the migration and can be enabled for extremely
|
|||||||
high-performance RDMA hardware using the following command:
|
high-performance RDMA hardware using the following command:
|
||||||
|
|
||||||
QEMU Monitor Command:
|
QEMU Monitor Command:
|
||||||
$ migrate_set_capability x-rdma-pin-all on # disabled by default
|
$ migrate_set_capability rdma-pin-all on # disabled by default
|
||||||
|
|
||||||
Performing this action will cause all 8GB to be pinned, so if that's
|
Performing this action will cause all 8GB to be pinned, so if that's
|
||||||
not what you want, then please ignore this step altogether.
|
not what you want, then please ignore this step altogether.
|
||||||
@@ -93,12 +93,12 @@ $ migrate_set_speed 40g # or whatever is the MAX of your RDMA device
|
|||||||
|
|
||||||
Next, on the destination machine, add the following to the QEMU command line:
|
Next, on the destination machine, add the following to the QEMU command line:
|
||||||
|
|
||||||
qemu ..... -incoming x-rdma:host:port
|
qemu ..... -incoming rdma:host:port
|
||||||
|
|
||||||
Finally, perform the actual migration on the source machine:
|
Finally, perform the actual migration on the source machine:
|
||||||
|
|
||||||
QEMU Monitor Command:
|
QEMU Monitor Command:
|
||||||
$ migrate -d x-rdma:host:port
|
$ migrate -d rdma:host:port
|
||||||
|
|
||||||
PERFORMANCE
|
PERFORMANCE
|
||||||
===========
|
===========
|
||||||
@@ -120,8 +120,8 @@ For example, in the same 8GB RAM example with all 8GB of memory in
|
|||||||
active use and the VM itself is completely idle using the same 40 gbps
|
active use and the VM itself is completely idle using the same 40 gbps
|
||||||
infiniband link:
|
infiniband link:
|
||||||
|
|
||||||
1. x-rdma-pin-all disabled total time: approximately 7.5 seconds @ 9.5 Gbps
|
1. rdma-pin-all disabled total time: approximately 7.5 seconds @ 9.5 Gbps
|
||||||
2. x-rdma-pin-all enabled total time: approximately 4 seconds @ 26 Gbps
|
2. rdma-pin-all enabled total time: approximately 4 seconds @ 26 Gbps
|
||||||
|
|
||||||
These numbers would of course scale up to whatever size virtual machine
|
These numbers would of course scale up to whatever size virtual machine
|
||||||
you have to migrate using RDMA.
|
you have to migrate using RDMA.
|
||||||
@@ -407,18 +407,14 @@ socket is broken during a non-RDMA based migration.
|
|||||||
|
|
||||||
TODO:
|
TODO:
|
||||||
=====
|
=====
|
||||||
1. 'migrate x-rdma:host:port' and '-incoming x-rdma' options will be
|
1. Currently, 'ulimit -l' mlock() limits as well as cgroups swap limits
|
||||||
renamed to 'rdma' after the experimental phase of this work has
|
|
||||||
completed upstream.
|
|
||||||
2. Currently, 'ulimit -l' mlock() limits as well as cgroups swap limits
|
|
||||||
are not compatible with infinband memory pinning and will result in
|
are not compatible with infinband memory pinning and will result in
|
||||||
an aborted migration (but with the source VM left unaffected).
|
an aborted migration (but with the source VM left unaffected).
|
||||||
3. Use of the recent /proc/<pid>/pagemap would likely speed up
|
2. Use of the recent /proc/<pid>/pagemap would likely speed up
|
||||||
the use of KSM and ballooning while using RDMA.
|
the use of KSM and ballooning while using RDMA.
|
||||||
4. Also, some form of balloon-device usage tracking would also
|
3. Also, some form of balloon-device usage tracking would also
|
||||||
help alleviate some issues.
|
help alleviate some issues.
|
||||||
5. Move UNREGISTER requests to a separate thread.
|
4. Use LRU to provide more fine-grained direction of UNREGISTER
|
||||||
6. Use LRU to provide more fine-grained direction of UNREGISTER
|
|
||||||
requests for unpinning memory in an overcommitted environment.
|
requests for unpinning memory in an overcommitted environment.
|
||||||
7. Expose UNREGISTER support to the user by way of workload-specific
|
5. Expose UNREGISTER support to the user by way of workload-specific
|
||||||
hints about application behavior.
|
hints about application behavior.
|
||||||
|
4
exec.c
4
exec.c
@@ -17,9 +17,7 @@
|
|||||||
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
#ifdef _WIN32
|
#ifndef _WIN32
|
||||||
#include <windows.h>
|
|
||||||
#else
|
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
#include <sys/mman.h>
|
#include <sys/mman.h>
|
||||||
#endif
|
#endif
|
||||||
|
@@ -1,4 +1,6 @@
|
|||||||
ifeq ($(CONFIG_REALLY_VIRTFS),y)
|
ifeq ($(CONFIG_VIRTIO)$(CONFIG_VIRTFS)$(CONFIG_PCI),yyy)
|
||||||
|
# Lots of the fsdev/9pcode is pulled in by vl.c via qemu_fsdev_add.
|
||||||
|
# only pull in the actual virtio-9p device if we also enabled virtio.
|
||||||
common-obj-y = qemu-fsdev.o virtio-9p-marshal.o
|
common-obj-y = qemu-fsdev.o virtio-9p-marshal.o
|
||||||
else
|
else
|
||||||
common-obj-y = qemu-fsdev-dummy.o
|
common-obj-y = qemu-fsdev-dummy.o
|
||||||
|
@@ -595,7 +595,7 @@ static int do_readlink(struct iovec *iovec, struct iovec *out_iovec)
|
|||||||
}
|
}
|
||||||
buffer = g_malloc(size);
|
buffer = g_malloc(size);
|
||||||
v9fs_string_init(&target);
|
v9fs_string_init(&target);
|
||||||
retval = readlink(path.data, buffer, size);
|
retval = readlink(path.data, buffer, size - 1);
|
||||||
if (retval > 0) {
|
if (retval > 0) {
|
||||||
buffer[retval] = '\0';
|
buffer[retval] = '\0';
|
||||||
v9fs_string_sprintf(&target, "%s", buffer);
|
v9fs_string_sprintf(&target, "%s", buffer);
|
||||||
|
5
hmp.c
5
hmp.c
@@ -1311,8 +1311,11 @@ void hmp_dump_guest_memory(Monitor *mon, const QDict *qdict)
|
|||||||
const char *file = qdict_get_str(qdict, "filename");
|
const char *file = qdict_get_str(qdict, "filename");
|
||||||
bool has_begin = qdict_haskey(qdict, "begin");
|
bool has_begin = qdict_haskey(qdict, "begin");
|
||||||
bool has_length = qdict_haskey(qdict, "length");
|
bool has_length = qdict_haskey(qdict, "length");
|
||||||
|
/* kdump-compressed format is not supported for HMP */
|
||||||
|
bool has_format = false;
|
||||||
int64_t begin = 0;
|
int64_t begin = 0;
|
||||||
int64_t length = 0;
|
int64_t length = 0;
|
||||||
|
enum DumpGuestMemoryFormat dump_format = DUMP_GUEST_MEMORY_FORMAT_ELF;
|
||||||
char *prot;
|
char *prot;
|
||||||
|
|
||||||
if (has_begin) {
|
if (has_begin) {
|
||||||
@@ -1325,7 +1328,7 @@ void hmp_dump_guest_memory(Monitor *mon, const QDict *qdict)
|
|||||||
prot = g_strconcat("file:", file, NULL);
|
prot = g_strconcat("file:", file, NULL);
|
||||||
|
|
||||||
qmp_dump_guest_memory(paging, prot, has_begin, begin, has_length, length,
|
qmp_dump_guest_memory(paging, prot, has_begin, begin, has_length, length,
|
||||||
&errp);
|
has_format, dump_format, &errp);
|
||||||
hmp_handle_error(mon, &errp);
|
hmp_handle_error(mon, &errp);
|
||||||
g_free(prot);
|
g_free(prot);
|
||||||
}
|
}
|
||||||
|
@@ -17,35 +17,55 @@
|
|||||||
#include "block/coroutine.h"
|
#include "block/coroutine.h"
|
||||||
#include "virtio-9p-coth.h"
|
#include "virtio-9p-coth.h"
|
||||||
|
|
||||||
|
static ssize_t __readlink(V9fsState *s, V9fsPath *path, V9fsString *buf)
|
||||||
|
{
|
||||||
|
ssize_t len, maxlen = PATH_MAX;
|
||||||
|
|
||||||
|
buf->data = g_malloc(PATH_MAX);
|
||||||
|
for(;;) {
|
||||||
|
len = s->ops->readlink(&s->ctx, path, buf->data, maxlen);
|
||||||
|
if (len < 0) {
|
||||||
|
g_free(buf->data);
|
||||||
|
buf->data = NULL;
|
||||||
|
buf->size = 0;
|
||||||
|
break;
|
||||||
|
} else if (len == maxlen) {
|
||||||
|
/*
|
||||||
|
* We dodn't have space to put the NULL or we have more
|
||||||
|
* to read. Increase the size and try again
|
||||||
|
*/
|
||||||
|
maxlen *= 2;
|
||||||
|
g_free(buf->data);
|
||||||
|
buf->data = g_malloc(maxlen);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
* Null terminate the readlink output
|
||||||
|
*/
|
||||||
|
buf->data[len] = '\0';
|
||||||
|
buf->size = len;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return len;
|
||||||
|
}
|
||||||
|
|
||||||
int v9fs_co_readlink(V9fsPDU *pdu, V9fsPath *path, V9fsString *buf)
|
int v9fs_co_readlink(V9fsPDU *pdu, V9fsPath *path, V9fsString *buf)
|
||||||
{
|
{
|
||||||
int err;
|
int err;
|
||||||
ssize_t len;
|
|
||||||
V9fsState *s = pdu->s;
|
V9fsState *s = pdu->s;
|
||||||
|
|
||||||
if (v9fs_request_cancelled(pdu)) {
|
if (v9fs_request_cancelled(pdu)) {
|
||||||
return -EINTR;
|
return -EINTR;
|
||||||
}
|
}
|
||||||
buf->data = g_malloc(PATH_MAX);
|
|
||||||
v9fs_path_read_lock(s);
|
v9fs_path_read_lock(s);
|
||||||
v9fs_co_run_in_worker(
|
v9fs_co_run_in_worker(
|
||||||
{
|
{
|
||||||
len = s->ops->readlink(&s->ctx, path,
|
err = __readlink(s, path, buf);
|
||||||
buf->data, PATH_MAX - 1);
|
if (err < 0) {
|
||||||
if (len > -1) {
|
|
||||||
buf->size = len;
|
|
||||||
buf->data[len] = 0;
|
|
||||||
err = 0;
|
|
||||||
} else {
|
|
||||||
err = -errno;
|
err = -errno;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
v9fs_path_unlock(s);
|
v9fs_path_unlock(s);
|
||||||
if (err) {
|
|
||||||
g_free(buf->data);
|
|
||||||
buf->data = NULL;
|
|
||||||
buf->size = 0;
|
|
||||||
}
|
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -498,7 +498,7 @@ static int handle_lremovexattr(FsContext *ctx, V9fsPath *fs_path,
|
|||||||
static int handle_name_to_path(FsContext *ctx, V9fsPath *dir_path,
|
static int handle_name_to_path(FsContext *ctx, V9fsPath *dir_path,
|
||||||
const char *name, V9fsPath *target)
|
const char *name, V9fsPath *target)
|
||||||
{
|
{
|
||||||
char buffer[PATH_MAX];
|
char *buffer;
|
||||||
struct file_handle *fh;
|
struct file_handle *fh;
|
||||||
int dirfd, ret, mnt_id;
|
int dirfd, ret, mnt_id;
|
||||||
struct handle_data *data = (struct handle_data *)ctx->private;
|
struct handle_data *data = (struct handle_data *)ctx->private;
|
||||||
@@ -513,7 +513,9 @@ static int handle_name_to_path(FsContext *ctx, V9fsPath *dir_path,
|
|||||||
dirfd = open_by_handle(data->mountfd, dir_path->data, O_PATH);
|
dirfd = open_by_handle(data->mountfd, dir_path->data, O_PATH);
|
||||||
} else {
|
} else {
|
||||||
/* relative to export root */
|
/* relative to export root */
|
||||||
dirfd = open(rpath(ctx, ".", buffer), O_DIRECTORY);
|
buffer = rpath(ctx, ".");
|
||||||
|
dirfd = open(buffer, O_DIRECTORY);
|
||||||
|
g_free(buffer);
|
||||||
}
|
}
|
||||||
if (dirfd < 0) {
|
if (dirfd < 0) {
|
||||||
return dirfd;
|
return dirfd;
|
||||||
@@ -521,7 +523,7 @@ static int handle_name_to_path(FsContext *ctx, V9fsPath *dir_path,
|
|||||||
fh = g_malloc(sizeof(struct file_handle) + data->handle_bytes);
|
fh = g_malloc(sizeof(struct file_handle) + data->handle_bytes);
|
||||||
fh->handle_bytes = data->handle_bytes;
|
fh->handle_bytes = data->handle_bytes;
|
||||||
/* add a "./" at the beginning of the path */
|
/* add a "./" at the beginning of the path */
|
||||||
snprintf(buffer, PATH_MAX, "./%s", name);
|
buffer = g_strdup_printf("./%s", name);
|
||||||
/* flag = 0 imply don't follow symlink */
|
/* flag = 0 imply don't follow symlink */
|
||||||
ret = name_to_handle(dirfd, buffer, fh, &mnt_id, 0);
|
ret = name_to_handle(dirfd, buffer, fh, &mnt_id, 0);
|
||||||
if (!ret) {
|
if (!ret) {
|
||||||
@@ -531,6 +533,7 @@ static int handle_name_to_path(FsContext *ctx, V9fsPath *dir_path,
|
|||||||
g_free(fh);
|
g_free(fh);
|
||||||
}
|
}
|
||||||
close(dirfd);
|
close(dirfd);
|
||||||
|
g_free(buffer);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -42,18 +42,18 @@
|
|||||||
|
|
||||||
#define VIRTFS_META_DIR ".virtfs_metadata"
|
#define VIRTFS_META_DIR ".virtfs_metadata"
|
||||||
|
|
||||||
static const char *local_mapped_attr_path(FsContext *ctx,
|
static char *local_mapped_attr_path(FsContext *ctx, const char *path)
|
||||||
const char *path, char *buffer)
|
|
||||||
{
|
{
|
||||||
char *dir_name;
|
char *dir_name;
|
||||||
char *tmp_path = g_strdup(path);
|
char *tmp_path = g_strdup(path);
|
||||||
char *base_name = basename(tmp_path);
|
char *base_name = basename(tmp_path);
|
||||||
|
char *buffer;
|
||||||
|
|
||||||
/* NULL terminate the directory */
|
/* NULL terminate the directory */
|
||||||
dir_name = tmp_path;
|
dir_name = tmp_path;
|
||||||
*(base_name - 1) = '\0';
|
*(base_name - 1) = '\0';
|
||||||
|
|
||||||
snprintf(buffer, PATH_MAX, "%s/%s/%s/%s",
|
buffer = g_strdup_printf("%s/%s/%s/%s",
|
||||||
ctx->fs_root, dir_name, VIRTFS_META_DIR, base_name);
|
ctx->fs_root, dir_name, VIRTFS_META_DIR, base_name);
|
||||||
g_free(tmp_path);
|
g_free(tmp_path);
|
||||||
return buffer;
|
return buffer;
|
||||||
@@ -92,10 +92,11 @@ static void local_mapped_file_attr(FsContext *ctx, const char *path,
|
|||||||
{
|
{
|
||||||
FILE *fp;
|
FILE *fp;
|
||||||
char buf[ATTR_MAX];
|
char buf[ATTR_MAX];
|
||||||
char attr_path[PATH_MAX];
|
char *attr_path;
|
||||||
|
|
||||||
local_mapped_attr_path(ctx, path, attr_path);
|
attr_path = local_mapped_attr_path(ctx, path);
|
||||||
fp = local_fopen(attr_path, "r");
|
fp = local_fopen(attr_path, "r");
|
||||||
|
g_free(attr_path);
|
||||||
if (!fp) {
|
if (!fp) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -118,12 +119,13 @@ static void local_mapped_file_attr(FsContext *ctx, const char *path,
|
|||||||
static int local_lstat(FsContext *fs_ctx, V9fsPath *fs_path, struct stat *stbuf)
|
static int local_lstat(FsContext *fs_ctx, V9fsPath *fs_path, struct stat *stbuf)
|
||||||
{
|
{
|
||||||
int err;
|
int err;
|
||||||
char buffer[PATH_MAX];
|
char *buffer;
|
||||||
char *path = fs_path->data;
|
char *path = fs_path->data;
|
||||||
|
|
||||||
err = lstat(rpath(fs_ctx, path, buffer), stbuf);
|
buffer = rpath(fs_ctx, path);
|
||||||
|
err = lstat(buffer, stbuf);
|
||||||
if (err) {
|
if (err) {
|
||||||
return err;
|
goto err_out;
|
||||||
}
|
}
|
||||||
if (fs_ctx->export_flags & V9FS_SM_MAPPED) {
|
if (fs_ctx->export_flags & V9FS_SM_MAPPED) {
|
||||||
/* Actual credentials are part of extended attrs */
|
/* Actual credentials are part of extended attrs */
|
||||||
@@ -131,41 +133,42 @@ static int local_lstat(FsContext *fs_ctx, V9fsPath *fs_path, struct stat *stbuf)
|
|||||||
gid_t tmp_gid;
|
gid_t tmp_gid;
|
||||||
mode_t tmp_mode;
|
mode_t tmp_mode;
|
||||||
dev_t tmp_dev;
|
dev_t tmp_dev;
|
||||||
if (getxattr(rpath(fs_ctx, path, buffer), "user.virtfs.uid", &tmp_uid,
|
if (getxattr(buffer, "user.virtfs.uid", &tmp_uid, sizeof(uid_t)) > 0) {
|
||||||
sizeof(uid_t)) > 0) {
|
|
||||||
stbuf->st_uid = tmp_uid;
|
stbuf->st_uid = tmp_uid;
|
||||||
}
|
}
|
||||||
if (getxattr(rpath(fs_ctx, path, buffer), "user.virtfs.gid", &tmp_gid,
|
if (getxattr(buffer, "user.virtfs.gid", &tmp_gid, sizeof(gid_t)) > 0) {
|
||||||
sizeof(gid_t)) > 0) {
|
|
||||||
stbuf->st_gid = tmp_gid;
|
stbuf->st_gid = tmp_gid;
|
||||||
}
|
}
|
||||||
if (getxattr(rpath(fs_ctx, path, buffer), "user.virtfs.mode",
|
if (getxattr(buffer, "user.virtfs.mode",
|
||||||
&tmp_mode, sizeof(mode_t)) > 0) {
|
&tmp_mode, sizeof(mode_t)) > 0) {
|
||||||
stbuf->st_mode = tmp_mode;
|
stbuf->st_mode = tmp_mode;
|
||||||
}
|
}
|
||||||
if (getxattr(rpath(fs_ctx, path, buffer), "user.virtfs.rdev", &tmp_dev,
|
if (getxattr(buffer, "user.virtfs.rdev", &tmp_dev, sizeof(dev_t)) > 0) {
|
||||||
sizeof(dev_t)) > 0) {
|
|
||||||
stbuf->st_rdev = tmp_dev;
|
stbuf->st_rdev = tmp_dev;
|
||||||
}
|
}
|
||||||
} else if (fs_ctx->export_flags & V9FS_SM_MAPPED_FILE) {
|
} else if (fs_ctx->export_flags & V9FS_SM_MAPPED_FILE) {
|
||||||
local_mapped_file_attr(fs_ctx, path, stbuf);
|
local_mapped_file_attr(fs_ctx, path, stbuf);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
err_out:
|
||||||
|
g_free(buffer);
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int local_create_mapped_attr_dir(FsContext *ctx, const char *path)
|
static int local_create_mapped_attr_dir(FsContext *ctx, const char *path)
|
||||||
{
|
{
|
||||||
int err;
|
int err;
|
||||||
char attr_dir[PATH_MAX];
|
char *attr_dir;
|
||||||
char *tmp_path = g_strdup(path);
|
char *tmp_path = g_strdup(path);
|
||||||
|
|
||||||
snprintf(attr_dir, PATH_MAX, "%s/%s/%s",
|
attr_dir = g_strdup_printf("%s/%s/%s",
|
||||||
ctx->fs_root, dirname(tmp_path), VIRTFS_META_DIR);
|
ctx->fs_root, dirname(tmp_path), VIRTFS_META_DIR);
|
||||||
|
|
||||||
err = mkdir(attr_dir, 0700);
|
err = mkdir(attr_dir, 0700);
|
||||||
if (err < 0 && errno == EEXIST) {
|
if (err < 0 && errno == EEXIST) {
|
||||||
err = 0;
|
err = 0;
|
||||||
}
|
}
|
||||||
|
g_free(attr_dir);
|
||||||
g_free(tmp_path);
|
g_free(tmp_path);
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
@@ -176,10 +179,11 @@ static int local_set_mapped_file_attr(FsContext *ctx,
|
|||||||
FILE *fp;
|
FILE *fp;
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
char buf[ATTR_MAX];
|
char buf[ATTR_MAX];
|
||||||
char attr_path[PATH_MAX];
|
char *attr_path;
|
||||||
int uid = -1, gid = -1, mode = -1, rdev = -1;
|
int uid = -1, gid = -1, mode = -1, rdev = -1;
|
||||||
|
|
||||||
fp = local_fopen(local_mapped_attr_path(ctx, path, attr_path), "r");
|
attr_path = local_mapped_attr_path(ctx, path);
|
||||||
|
fp = local_fopen(attr_path, "r");
|
||||||
if (!fp) {
|
if (!fp) {
|
||||||
goto create_map_file;
|
goto create_map_file;
|
||||||
}
|
}
|
||||||
@@ -241,6 +245,7 @@ update_map_file:
|
|||||||
fclose(fp);
|
fclose(fp);
|
||||||
|
|
||||||
err_out:
|
err_out:
|
||||||
|
g_free(attr_path);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -282,36 +287,43 @@ static int local_set_xattr(const char *path, FsCred *credp)
|
|||||||
static int local_post_create_passthrough(FsContext *fs_ctx, const char *path,
|
static int local_post_create_passthrough(FsContext *fs_ctx, const char *path,
|
||||||
FsCred *credp)
|
FsCred *credp)
|
||||||
{
|
{
|
||||||
char buffer[PATH_MAX];
|
char *buffer;
|
||||||
|
|
||||||
if (lchown(rpath(fs_ctx, path, buffer), credp->fc_uid,
|
buffer = rpath(fs_ctx, path);
|
||||||
credp->fc_gid) < 0) {
|
if (lchown(buffer, credp->fc_uid, credp->fc_gid) < 0) {
|
||||||
/*
|
/*
|
||||||
* If we fail to change ownership and if we are
|
* If we fail to change ownership and if we are
|
||||||
* using security model none. Ignore the error
|
* using security model none. Ignore the error
|
||||||
*/
|
*/
|
||||||
if ((fs_ctx->export_flags & V9FS_SEC_MASK) != V9FS_SM_NONE) {
|
if ((fs_ctx->export_flags & V9FS_SEC_MASK) != V9FS_SM_NONE) {
|
||||||
return -1;
|
goto err;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (chmod(rpath(fs_ctx, path, buffer), credp->fc_mode & 07777) < 0) {
|
if (chmod(buffer, credp->fc_mode & 07777) < 0) {
|
||||||
return -1;
|
goto err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
g_free(buffer);
|
||||||
return 0;
|
return 0;
|
||||||
|
err:
|
||||||
|
g_free(buffer);
|
||||||
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static ssize_t local_readlink(FsContext *fs_ctx, V9fsPath *fs_path,
|
static ssize_t local_readlink(FsContext *fs_ctx, V9fsPath *fs_path,
|
||||||
char *buf, size_t bufsz)
|
char *buf, size_t bufsz)
|
||||||
{
|
{
|
||||||
ssize_t tsize = -1;
|
ssize_t tsize = -1;
|
||||||
char buffer[PATH_MAX];
|
char *buffer;
|
||||||
char *path = fs_path->data;
|
char *path = fs_path->data;
|
||||||
|
|
||||||
if ((fs_ctx->export_flags & V9FS_SM_MAPPED) ||
|
if ((fs_ctx->export_flags & V9FS_SM_MAPPED) ||
|
||||||
(fs_ctx->export_flags & V9FS_SM_MAPPED_FILE)) {
|
(fs_ctx->export_flags & V9FS_SM_MAPPED_FILE)) {
|
||||||
int fd;
|
int fd;
|
||||||
fd = open(rpath(fs_ctx, path, buffer), O_RDONLY | O_NOFOLLOW);
|
buffer = rpath(fs_ctx, path);
|
||||||
|
fd = open(buffer, O_RDONLY | O_NOFOLLOW);
|
||||||
|
g_free(buffer);
|
||||||
if (fd == -1) {
|
if (fd == -1) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
@@ -322,7 +334,9 @@ static ssize_t local_readlink(FsContext *fs_ctx, V9fsPath *fs_path,
|
|||||||
return tsize;
|
return tsize;
|
||||||
} else if ((fs_ctx->export_flags & V9FS_SM_PASSTHROUGH) ||
|
} else if ((fs_ctx->export_flags & V9FS_SM_PASSTHROUGH) ||
|
||||||
(fs_ctx->export_flags & V9FS_SM_NONE)) {
|
(fs_ctx->export_flags & V9FS_SM_NONE)) {
|
||||||
tsize = readlink(rpath(fs_ctx, path, buffer), buf, bufsz);
|
buffer = rpath(fs_ctx, path);
|
||||||
|
tsize = readlink(buffer, buf, bufsz);
|
||||||
|
g_free(buffer);
|
||||||
}
|
}
|
||||||
return tsize;
|
return tsize;
|
||||||
}
|
}
|
||||||
@@ -340,20 +354,24 @@ static int local_closedir(FsContext *ctx, V9fsFidOpenState *fs)
|
|||||||
static int local_open(FsContext *ctx, V9fsPath *fs_path,
|
static int local_open(FsContext *ctx, V9fsPath *fs_path,
|
||||||
int flags, V9fsFidOpenState *fs)
|
int flags, V9fsFidOpenState *fs)
|
||||||
{
|
{
|
||||||
char buffer[PATH_MAX];
|
char *buffer;
|
||||||
char *path = fs_path->data;
|
char *path = fs_path->data;
|
||||||
|
|
||||||
fs->fd = open(rpath(ctx, path, buffer), flags | O_NOFOLLOW);
|
buffer = rpath(ctx, path);
|
||||||
|
fs->fd = open(buffer, flags | O_NOFOLLOW);
|
||||||
|
g_free(buffer);
|
||||||
return fs->fd;
|
return fs->fd;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int local_opendir(FsContext *ctx,
|
static int local_opendir(FsContext *ctx,
|
||||||
V9fsPath *fs_path, V9fsFidOpenState *fs)
|
V9fsPath *fs_path, V9fsFidOpenState *fs)
|
||||||
{
|
{
|
||||||
char buffer[PATH_MAX];
|
char *buffer;
|
||||||
char *path = fs_path->data;
|
char *path = fs_path->data;
|
||||||
|
|
||||||
fs->dir = opendir(rpath(ctx, path, buffer));
|
buffer = rpath(ctx, path);
|
||||||
|
fs->dir = opendir(buffer);
|
||||||
|
g_free(buffer);
|
||||||
if (!fs->dir) {
|
if (!fs->dir) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
@@ -441,18 +459,23 @@ static ssize_t local_pwritev(FsContext *ctx, V9fsFidOpenState *fs,
|
|||||||
|
|
||||||
static int local_chmod(FsContext *fs_ctx, V9fsPath *fs_path, FsCred *credp)
|
static int local_chmod(FsContext *fs_ctx, V9fsPath *fs_path, FsCred *credp)
|
||||||
{
|
{
|
||||||
char buffer[PATH_MAX];
|
char *buffer;
|
||||||
|
int ret = -1;
|
||||||
char *path = fs_path->data;
|
char *path = fs_path->data;
|
||||||
|
|
||||||
if (fs_ctx->export_flags & V9FS_SM_MAPPED) {
|
if (fs_ctx->export_flags & V9FS_SM_MAPPED) {
|
||||||
return local_set_xattr(rpath(fs_ctx, path, buffer), credp);
|
buffer = rpath(fs_ctx, path);
|
||||||
|
ret = local_set_xattr(buffer, credp);
|
||||||
|
g_free(buffer);
|
||||||
} else if (fs_ctx->export_flags & V9FS_SM_MAPPED_FILE) {
|
} else if (fs_ctx->export_flags & V9FS_SM_MAPPED_FILE) {
|
||||||
return local_set_mapped_file_attr(fs_ctx, path, credp);
|
return local_set_mapped_file_attr(fs_ctx, path, credp);
|
||||||
} else if ((fs_ctx->export_flags & V9FS_SM_PASSTHROUGH) ||
|
} else if ((fs_ctx->export_flags & V9FS_SM_PASSTHROUGH) ||
|
||||||
(fs_ctx->export_flags & V9FS_SM_NONE)) {
|
(fs_ctx->export_flags & V9FS_SM_NONE)) {
|
||||||
return chmod(rpath(fs_ctx, path, buffer), credp->fc_mode);
|
buffer = rpath(fs_ctx, path);
|
||||||
|
ret = chmod(buffer, credp->fc_mode);
|
||||||
|
g_free(buffer);
|
||||||
}
|
}
|
||||||
return -1;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int local_mknod(FsContext *fs_ctx, V9fsPath *dir_path,
|
static int local_mknod(FsContext *fs_ctx, V9fsPath *dir_path,
|
||||||
@@ -462,7 +485,7 @@ static int local_mknod(FsContext *fs_ctx, V9fsPath *dir_path,
|
|||||||
int err = -1;
|
int err = -1;
|
||||||
int serrno = 0;
|
int serrno = 0;
|
||||||
V9fsString fullname;
|
V9fsString fullname;
|
||||||
char buffer[PATH_MAX];
|
char *buffer;
|
||||||
|
|
||||||
v9fs_string_init(&fullname);
|
v9fs_string_init(&fullname);
|
||||||
v9fs_string_sprintf(&fullname, "%s/%s", dir_path->data, name);
|
v9fs_string_sprintf(&fullname, "%s/%s", dir_path->data, name);
|
||||||
@@ -470,21 +493,23 @@ static int local_mknod(FsContext *fs_ctx, V9fsPath *dir_path,
|
|||||||
|
|
||||||
/* Determine the security model */
|
/* Determine the security model */
|
||||||
if (fs_ctx->export_flags & V9FS_SM_MAPPED) {
|
if (fs_ctx->export_flags & V9FS_SM_MAPPED) {
|
||||||
err = mknod(rpath(fs_ctx, path, buffer),
|
buffer = rpath(fs_ctx, path);
|
||||||
SM_LOCAL_MODE_BITS|S_IFREG, 0);
|
err = mknod(buffer, SM_LOCAL_MODE_BITS|S_IFREG, 0);
|
||||||
if (err == -1) {
|
if (err == -1) {
|
||||||
|
g_free(buffer);
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
err = local_set_xattr(rpath(fs_ctx, path, buffer), credp);
|
err = local_set_xattr(buffer, credp);
|
||||||
if (err == -1) {
|
if (err == -1) {
|
||||||
serrno = errno;
|
serrno = errno;
|
||||||
goto err_end;
|
goto err_end;
|
||||||
}
|
}
|
||||||
} else if (fs_ctx->export_flags & V9FS_SM_MAPPED_FILE) {
|
} else if (fs_ctx->export_flags & V9FS_SM_MAPPED_FILE) {
|
||||||
|
|
||||||
err = mknod(rpath(fs_ctx, path, buffer),
|
buffer = rpath(fs_ctx, path);
|
||||||
SM_LOCAL_MODE_BITS|S_IFREG, 0);
|
err = mknod(buffer, SM_LOCAL_MODE_BITS|S_IFREG, 0);
|
||||||
if (err == -1) {
|
if (err == -1) {
|
||||||
|
g_free(buffer);
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
err = local_set_mapped_file_attr(fs_ctx, path, credp);
|
err = local_set_mapped_file_attr(fs_ctx, path, credp);
|
||||||
@@ -494,9 +519,10 @@ static int local_mknod(FsContext *fs_ctx, V9fsPath *dir_path,
|
|||||||
}
|
}
|
||||||
} else if ((fs_ctx->export_flags & V9FS_SM_PASSTHROUGH) ||
|
} else if ((fs_ctx->export_flags & V9FS_SM_PASSTHROUGH) ||
|
||||||
(fs_ctx->export_flags & V9FS_SM_NONE)) {
|
(fs_ctx->export_flags & V9FS_SM_NONE)) {
|
||||||
err = mknod(rpath(fs_ctx, path, buffer), credp->fc_mode,
|
buffer = rpath(fs_ctx, path);
|
||||||
credp->fc_rdev);
|
err = mknod(buffer, credp->fc_mode, credp->fc_rdev);
|
||||||
if (err == -1) {
|
if (err == -1) {
|
||||||
|
g_free(buffer);
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
err = local_post_create_passthrough(fs_ctx, path, credp);
|
err = local_post_create_passthrough(fs_ctx, path, credp);
|
||||||
@@ -508,8 +534,9 @@ static int local_mknod(FsContext *fs_ctx, V9fsPath *dir_path,
|
|||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
err_end:
|
err_end:
|
||||||
remove(rpath(fs_ctx, path, buffer));
|
remove(buffer);
|
||||||
errno = serrno;
|
errno = serrno;
|
||||||
|
g_free(buffer);
|
||||||
out:
|
out:
|
||||||
v9fs_string_free(&fullname);
|
v9fs_string_free(&fullname);
|
||||||
return err;
|
return err;
|
||||||
@@ -522,7 +549,7 @@ static int local_mkdir(FsContext *fs_ctx, V9fsPath *dir_path,
|
|||||||
int err = -1;
|
int err = -1;
|
||||||
int serrno = 0;
|
int serrno = 0;
|
||||||
V9fsString fullname;
|
V9fsString fullname;
|
||||||
char buffer[PATH_MAX];
|
char *buffer;
|
||||||
|
|
||||||
v9fs_string_init(&fullname);
|
v9fs_string_init(&fullname);
|
||||||
v9fs_string_sprintf(&fullname, "%s/%s", dir_path->data, name);
|
v9fs_string_sprintf(&fullname, "%s/%s", dir_path->data, name);
|
||||||
@@ -530,19 +557,23 @@ static int local_mkdir(FsContext *fs_ctx, V9fsPath *dir_path,
|
|||||||
|
|
||||||
/* Determine the security model */
|
/* Determine the security model */
|
||||||
if (fs_ctx->export_flags & V9FS_SM_MAPPED) {
|
if (fs_ctx->export_flags & V9FS_SM_MAPPED) {
|
||||||
err = mkdir(rpath(fs_ctx, path, buffer), SM_LOCAL_DIR_MODE_BITS);
|
buffer = rpath(fs_ctx, path);
|
||||||
|
err = mkdir(buffer, SM_LOCAL_DIR_MODE_BITS);
|
||||||
if (err == -1) {
|
if (err == -1) {
|
||||||
|
g_free(buffer);
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
credp->fc_mode = credp->fc_mode|S_IFDIR;
|
credp->fc_mode = credp->fc_mode|S_IFDIR;
|
||||||
err = local_set_xattr(rpath(fs_ctx, path, buffer), credp);
|
err = local_set_xattr(buffer, credp);
|
||||||
if (err == -1) {
|
if (err == -1) {
|
||||||
serrno = errno;
|
serrno = errno;
|
||||||
goto err_end;
|
goto err_end;
|
||||||
}
|
}
|
||||||
} else if (fs_ctx->export_flags & V9FS_SM_MAPPED_FILE) {
|
} else if (fs_ctx->export_flags & V9FS_SM_MAPPED_FILE) {
|
||||||
err = mkdir(rpath(fs_ctx, path, buffer), SM_LOCAL_DIR_MODE_BITS);
|
buffer = rpath(fs_ctx, path);
|
||||||
|
err = mkdir(buffer, SM_LOCAL_DIR_MODE_BITS);
|
||||||
if (err == -1) {
|
if (err == -1) {
|
||||||
|
g_free(buffer);
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
credp->fc_mode = credp->fc_mode|S_IFDIR;
|
credp->fc_mode = credp->fc_mode|S_IFDIR;
|
||||||
@@ -553,8 +584,10 @@ static int local_mkdir(FsContext *fs_ctx, V9fsPath *dir_path,
|
|||||||
}
|
}
|
||||||
} else if ((fs_ctx->export_flags & V9FS_SM_PASSTHROUGH) ||
|
} else if ((fs_ctx->export_flags & V9FS_SM_PASSTHROUGH) ||
|
||||||
(fs_ctx->export_flags & V9FS_SM_NONE)) {
|
(fs_ctx->export_flags & V9FS_SM_NONE)) {
|
||||||
err = mkdir(rpath(fs_ctx, path, buffer), credp->fc_mode);
|
buffer = rpath(fs_ctx, path);
|
||||||
|
err = mkdir(buffer, credp->fc_mode);
|
||||||
if (err == -1) {
|
if (err == -1) {
|
||||||
|
g_free(buffer);
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
err = local_post_create_passthrough(fs_ctx, path, credp);
|
err = local_post_create_passthrough(fs_ctx, path, credp);
|
||||||
@@ -566,8 +599,9 @@ static int local_mkdir(FsContext *fs_ctx, V9fsPath *dir_path,
|
|||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
err_end:
|
err_end:
|
||||||
remove(rpath(fs_ctx, path, buffer));
|
remove(buffer);
|
||||||
errno = serrno;
|
errno = serrno;
|
||||||
|
g_free(buffer);
|
||||||
out:
|
out:
|
||||||
v9fs_string_free(&fullname);
|
v9fs_string_free(&fullname);
|
||||||
return err;
|
return err;
|
||||||
@@ -626,7 +660,7 @@ static int local_open2(FsContext *fs_ctx, V9fsPath *dir_path, const char *name,
|
|||||||
int err = -1;
|
int err = -1;
|
||||||
int serrno = 0;
|
int serrno = 0;
|
||||||
V9fsString fullname;
|
V9fsString fullname;
|
||||||
char buffer[PATH_MAX];
|
char *buffer;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Mark all the open to not follow symlinks
|
* Mark all the open to not follow symlinks
|
||||||
@@ -639,21 +673,25 @@ static int local_open2(FsContext *fs_ctx, V9fsPath *dir_path, const char *name,
|
|||||||
|
|
||||||
/* Determine the security model */
|
/* Determine the security model */
|
||||||
if (fs_ctx->export_flags & V9FS_SM_MAPPED) {
|
if (fs_ctx->export_flags & V9FS_SM_MAPPED) {
|
||||||
fd = open(rpath(fs_ctx, path, buffer), flags, SM_LOCAL_MODE_BITS);
|
buffer = rpath(fs_ctx, path);
|
||||||
|
fd = open(buffer, flags, SM_LOCAL_MODE_BITS);
|
||||||
if (fd == -1) {
|
if (fd == -1) {
|
||||||
|
g_free(buffer);
|
||||||
err = fd;
|
err = fd;
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
credp->fc_mode = credp->fc_mode|S_IFREG;
|
credp->fc_mode = credp->fc_mode|S_IFREG;
|
||||||
/* Set cleint credentials in xattr */
|
/* Set cleint credentials in xattr */
|
||||||
err = local_set_xattr(rpath(fs_ctx, path, buffer), credp);
|
err = local_set_xattr(buffer, credp);
|
||||||
if (err == -1) {
|
if (err == -1) {
|
||||||
serrno = errno;
|
serrno = errno;
|
||||||
goto err_end;
|
goto err_end;
|
||||||
}
|
}
|
||||||
} else if (fs_ctx->export_flags & V9FS_SM_MAPPED_FILE) {
|
} else if (fs_ctx->export_flags & V9FS_SM_MAPPED_FILE) {
|
||||||
fd = open(rpath(fs_ctx, path, buffer), flags, SM_LOCAL_MODE_BITS);
|
buffer = rpath(fs_ctx, path);
|
||||||
|
fd = open(buffer, flags, SM_LOCAL_MODE_BITS);
|
||||||
if (fd == -1) {
|
if (fd == -1) {
|
||||||
|
g_free(buffer);
|
||||||
err = fd;
|
err = fd;
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
@@ -666,8 +704,10 @@ static int local_open2(FsContext *fs_ctx, V9fsPath *dir_path, const char *name,
|
|||||||
}
|
}
|
||||||
} else if ((fs_ctx->export_flags & V9FS_SM_PASSTHROUGH) ||
|
} else if ((fs_ctx->export_flags & V9FS_SM_PASSTHROUGH) ||
|
||||||
(fs_ctx->export_flags & V9FS_SM_NONE)) {
|
(fs_ctx->export_flags & V9FS_SM_NONE)) {
|
||||||
fd = open(rpath(fs_ctx, path, buffer), flags, credp->fc_mode);
|
buffer = rpath(fs_ctx, path);
|
||||||
|
fd = open(buffer, flags, credp->fc_mode);
|
||||||
if (fd == -1) {
|
if (fd == -1) {
|
||||||
|
g_free(buffer);
|
||||||
err = fd;
|
err = fd;
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
@@ -683,8 +723,9 @@ static int local_open2(FsContext *fs_ctx, V9fsPath *dir_path, const char *name,
|
|||||||
|
|
||||||
err_end:
|
err_end:
|
||||||
close(fd);
|
close(fd);
|
||||||
remove(rpath(fs_ctx, path, buffer));
|
remove(buffer);
|
||||||
errno = serrno;
|
errno = serrno;
|
||||||
|
g_free(buffer);
|
||||||
out:
|
out:
|
||||||
v9fs_string_free(&fullname);
|
v9fs_string_free(&fullname);
|
||||||
return err;
|
return err;
|
||||||
@@ -698,7 +739,7 @@ static int local_symlink(FsContext *fs_ctx, const char *oldpath,
|
|||||||
int serrno = 0;
|
int serrno = 0;
|
||||||
char *newpath;
|
char *newpath;
|
||||||
V9fsString fullname;
|
V9fsString fullname;
|
||||||
char buffer[PATH_MAX];
|
char *buffer;
|
||||||
|
|
||||||
v9fs_string_init(&fullname);
|
v9fs_string_init(&fullname);
|
||||||
v9fs_string_sprintf(&fullname, "%s/%s", dir_path->data, name);
|
v9fs_string_sprintf(&fullname, "%s/%s", dir_path->data, name);
|
||||||
@@ -708,10 +749,10 @@ static int local_symlink(FsContext *fs_ctx, const char *oldpath,
|
|||||||
if (fs_ctx->export_flags & V9FS_SM_MAPPED) {
|
if (fs_ctx->export_flags & V9FS_SM_MAPPED) {
|
||||||
int fd;
|
int fd;
|
||||||
ssize_t oldpath_size, write_size;
|
ssize_t oldpath_size, write_size;
|
||||||
fd = open(rpath(fs_ctx, newpath, buffer),
|
buffer = rpath(fs_ctx, newpath);
|
||||||
O_CREAT|O_EXCL|O_RDWR|O_NOFOLLOW,
|
fd = open(buffer, O_CREAT|O_EXCL|O_RDWR|O_NOFOLLOW, SM_LOCAL_MODE_BITS);
|
||||||
SM_LOCAL_MODE_BITS);
|
|
||||||
if (fd == -1) {
|
if (fd == -1) {
|
||||||
|
g_free(buffer);
|
||||||
err = fd;
|
err = fd;
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
@@ -730,7 +771,7 @@ static int local_symlink(FsContext *fs_ctx, const char *oldpath,
|
|||||||
close(fd);
|
close(fd);
|
||||||
/* Set cleint credentials in symlink's xattr */
|
/* Set cleint credentials in symlink's xattr */
|
||||||
credp->fc_mode = credp->fc_mode|S_IFLNK;
|
credp->fc_mode = credp->fc_mode|S_IFLNK;
|
||||||
err = local_set_xattr(rpath(fs_ctx, newpath, buffer), credp);
|
err = local_set_xattr(buffer, credp);
|
||||||
if (err == -1) {
|
if (err == -1) {
|
||||||
serrno = errno;
|
serrno = errno;
|
||||||
goto err_end;
|
goto err_end;
|
||||||
@@ -738,10 +779,10 @@ static int local_symlink(FsContext *fs_ctx, const char *oldpath,
|
|||||||
} else if (fs_ctx->export_flags & V9FS_SM_MAPPED_FILE) {
|
} else if (fs_ctx->export_flags & V9FS_SM_MAPPED_FILE) {
|
||||||
int fd;
|
int fd;
|
||||||
ssize_t oldpath_size, write_size;
|
ssize_t oldpath_size, write_size;
|
||||||
fd = open(rpath(fs_ctx, newpath, buffer),
|
buffer = rpath(fs_ctx, newpath);
|
||||||
O_CREAT|O_EXCL|O_RDWR|O_NOFOLLOW,
|
fd = open(buffer, O_CREAT|O_EXCL|O_RDWR|O_NOFOLLOW, SM_LOCAL_MODE_BITS);
|
||||||
SM_LOCAL_MODE_BITS);
|
|
||||||
if (fd == -1) {
|
if (fd == -1) {
|
||||||
|
g_free(buffer);
|
||||||
err = fd;
|
err = fd;
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
@@ -767,12 +808,13 @@ static int local_symlink(FsContext *fs_ctx, const char *oldpath,
|
|||||||
}
|
}
|
||||||
} else if ((fs_ctx->export_flags & V9FS_SM_PASSTHROUGH) ||
|
} else if ((fs_ctx->export_flags & V9FS_SM_PASSTHROUGH) ||
|
||||||
(fs_ctx->export_flags & V9FS_SM_NONE)) {
|
(fs_ctx->export_flags & V9FS_SM_NONE)) {
|
||||||
err = symlink(oldpath, rpath(fs_ctx, newpath, buffer));
|
buffer = rpath(fs_ctx, newpath);
|
||||||
|
err = symlink(oldpath, buffer);
|
||||||
if (err) {
|
if (err) {
|
||||||
|
g_free(buffer);
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
err = lchown(rpath(fs_ctx, newpath, buffer), credp->fc_uid,
|
err = lchown(buffer, credp->fc_uid, credp->fc_gid);
|
||||||
credp->fc_gid);
|
|
||||||
if (err == -1) {
|
if (err == -1) {
|
||||||
/*
|
/*
|
||||||
* If we fail to change ownership and if we are
|
* If we fail to change ownership and if we are
|
||||||
@@ -788,8 +830,9 @@ static int local_symlink(FsContext *fs_ctx, const char *oldpath,
|
|||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
err_end:
|
err_end:
|
||||||
remove(rpath(fs_ctx, newpath, buffer));
|
remove(buffer);
|
||||||
errno = serrno;
|
errno = serrno;
|
||||||
|
g_free(buffer);
|
||||||
out:
|
out:
|
||||||
v9fs_string_free(&fullname);
|
v9fs_string_free(&fullname);
|
||||||
return err;
|
return err;
|
||||||
@@ -800,13 +843,16 @@ static int local_link(FsContext *ctx, V9fsPath *oldpath,
|
|||||||
{
|
{
|
||||||
int ret;
|
int ret;
|
||||||
V9fsString newpath;
|
V9fsString newpath;
|
||||||
char buffer[PATH_MAX], buffer1[PATH_MAX];
|
char *buffer, *buffer1;
|
||||||
|
|
||||||
v9fs_string_init(&newpath);
|
v9fs_string_init(&newpath);
|
||||||
v9fs_string_sprintf(&newpath, "%s/%s", dirpath->data, name);
|
v9fs_string_sprintf(&newpath, "%s/%s", dirpath->data, name);
|
||||||
|
|
||||||
ret = link(rpath(ctx, oldpath->data, buffer),
|
buffer = rpath(ctx, oldpath->data);
|
||||||
rpath(ctx, newpath.data, buffer1));
|
buffer1 = rpath(ctx, newpath.data);
|
||||||
|
ret = link(buffer, buffer1);
|
||||||
|
g_free(buffer);
|
||||||
|
g_free(buffer1);
|
||||||
|
|
||||||
/* now link the virtfs_metadata files */
|
/* now link the virtfs_metadata files */
|
||||||
if (!ret && (ctx->export_flags & V9FS_SM_MAPPED_FILE)) {
|
if (!ret && (ctx->export_flags & V9FS_SM_MAPPED_FILE)) {
|
||||||
@@ -815,8 +861,11 @@ static int local_link(FsContext *ctx, V9fsPath *oldpath,
|
|||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
goto err_out;
|
goto err_out;
|
||||||
}
|
}
|
||||||
ret = link(local_mapped_attr_path(ctx, oldpath->data, buffer),
|
buffer = local_mapped_attr_path(ctx, oldpath->data);
|
||||||
local_mapped_attr_path(ctx, newpath.data, buffer1));
|
buffer1 = local_mapped_attr_path(ctx, newpath.data);
|
||||||
|
ret = link(buffer, buffer1);
|
||||||
|
g_free(buffer);
|
||||||
|
g_free(buffer1);
|
||||||
if (ret < 0 && errno != ENOENT) {
|
if (ret < 0 && errno != ENOENT) {
|
||||||
goto err_out;
|
goto err_out;
|
||||||
}
|
}
|
||||||
@@ -828,17 +877,21 @@ err_out:
|
|||||||
|
|
||||||
static int local_truncate(FsContext *ctx, V9fsPath *fs_path, off_t size)
|
static int local_truncate(FsContext *ctx, V9fsPath *fs_path, off_t size)
|
||||||
{
|
{
|
||||||
char buffer[PATH_MAX];
|
char *buffer;
|
||||||
|
int ret;
|
||||||
char *path = fs_path->data;
|
char *path = fs_path->data;
|
||||||
|
|
||||||
return truncate(rpath(ctx, path, buffer), size);
|
buffer = rpath(ctx, path);
|
||||||
|
ret = truncate(buffer, size);
|
||||||
|
g_free(buffer);
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int local_rename(FsContext *ctx, const char *oldpath,
|
static int local_rename(FsContext *ctx, const char *oldpath,
|
||||||
const char *newpath)
|
const char *newpath)
|
||||||
{
|
{
|
||||||
int err;
|
int err;
|
||||||
char buffer[PATH_MAX], buffer1[PATH_MAX];
|
char *buffer, *buffer1;
|
||||||
|
|
||||||
if (ctx->export_flags & V9FS_SM_MAPPED_FILE) {
|
if (ctx->export_flags & V9FS_SM_MAPPED_FILE) {
|
||||||
err = local_create_mapped_attr_dir(ctx, newpath);
|
err = local_create_mapped_attr_dir(ctx, newpath);
|
||||||
@@ -846,50 +899,69 @@ static int local_rename(FsContext *ctx, const char *oldpath,
|
|||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
/* rename the .virtfs_metadata files */
|
/* rename the .virtfs_metadata files */
|
||||||
err = rename(local_mapped_attr_path(ctx, oldpath, buffer),
|
buffer = local_mapped_attr_path(ctx, oldpath);
|
||||||
local_mapped_attr_path(ctx, newpath, buffer1));
|
buffer1 = local_mapped_attr_path(ctx, newpath);
|
||||||
|
err = rename(buffer, buffer1);
|
||||||
|
g_free(buffer);
|
||||||
|
g_free(buffer1);
|
||||||
if (err < 0 && errno != ENOENT) {
|
if (err < 0 && errno != ENOENT) {
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return rename(rpath(ctx, oldpath, buffer), rpath(ctx, newpath, buffer1));
|
|
||||||
|
buffer = rpath(ctx, oldpath);
|
||||||
|
buffer1 = rpath(ctx, newpath);
|
||||||
|
err = rename(buffer, buffer1);
|
||||||
|
g_free(buffer);
|
||||||
|
g_free(buffer1);
|
||||||
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int local_chown(FsContext *fs_ctx, V9fsPath *fs_path, FsCred *credp)
|
static int local_chown(FsContext *fs_ctx, V9fsPath *fs_path, FsCred *credp)
|
||||||
{
|
{
|
||||||
char buffer[PATH_MAX];
|
char *buffer;
|
||||||
|
int ret = -1;
|
||||||
char *path = fs_path->data;
|
char *path = fs_path->data;
|
||||||
|
|
||||||
if ((credp->fc_uid == -1 && credp->fc_gid == -1) ||
|
if ((credp->fc_uid == -1 && credp->fc_gid == -1) ||
|
||||||
(fs_ctx->export_flags & V9FS_SM_PASSTHROUGH) ||
|
(fs_ctx->export_flags & V9FS_SM_PASSTHROUGH) ||
|
||||||
(fs_ctx->export_flags & V9FS_SM_NONE)) {
|
(fs_ctx->export_flags & V9FS_SM_NONE)) {
|
||||||
return lchown(rpath(fs_ctx, path, buffer),
|
buffer = rpath(fs_ctx, path);
|
||||||
credp->fc_uid, credp->fc_gid);
|
ret = lchown(buffer, credp->fc_uid, credp->fc_gid);
|
||||||
|
g_free(buffer);
|
||||||
} else if (fs_ctx->export_flags & V9FS_SM_MAPPED) {
|
} else if (fs_ctx->export_flags & V9FS_SM_MAPPED) {
|
||||||
return local_set_xattr(rpath(fs_ctx, path, buffer), credp);
|
buffer = rpath(fs_ctx, path);
|
||||||
|
ret = local_set_xattr(buffer, credp);
|
||||||
|
g_free(buffer);
|
||||||
} else if (fs_ctx->export_flags & V9FS_SM_MAPPED_FILE) {
|
} else if (fs_ctx->export_flags & V9FS_SM_MAPPED_FILE) {
|
||||||
return local_set_mapped_file_attr(fs_ctx, path, credp);
|
return local_set_mapped_file_attr(fs_ctx, path, credp);
|
||||||
}
|
}
|
||||||
return -1;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int local_utimensat(FsContext *s, V9fsPath *fs_path,
|
static int local_utimensat(FsContext *s, V9fsPath *fs_path,
|
||||||
const struct timespec *buf)
|
const struct timespec *buf)
|
||||||
{
|
{
|
||||||
char buffer[PATH_MAX];
|
char *buffer;
|
||||||
|
int ret;
|
||||||
char *path = fs_path->data;
|
char *path = fs_path->data;
|
||||||
|
|
||||||
return qemu_utimens(rpath(s, path, buffer), buf);
|
buffer = rpath(s, path);
|
||||||
|
ret = qemu_utimens(buffer, buf);
|
||||||
|
g_free(buffer);
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int local_remove(FsContext *ctx, const char *path)
|
static int local_remove(FsContext *ctx, const char *path)
|
||||||
{
|
{
|
||||||
int err;
|
int err;
|
||||||
struct stat stbuf;
|
struct stat stbuf;
|
||||||
char buffer[PATH_MAX];
|
char *buffer;
|
||||||
|
|
||||||
if (ctx->export_flags & V9FS_SM_MAPPED_FILE) {
|
if (ctx->export_flags & V9FS_SM_MAPPED_FILE) {
|
||||||
err = lstat(rpath(ctx, path, buffer), &stbuf);
|
buffer = rpath(ctx, path);
|
||||||
|
err = lstat(buffer, &stbuf);
|
||||||
|
g_free(buffer);
|
||||||
if (err) {
|
if (err) {
|
||||||
goto err_out;
|
goto err_out;
|
||||||
}
|
}
|
||||||
@@ -898,8 +970,10 @@ static int local_remove(FsContext *ctx, const char *path)
|
|||||||
* directory
|
* directory
|
||||||
*/
|
*/
|
||||||
if (S_ISDIR(stbuf.st_mode)) {
|
if (S_ISDIR(stbuf.st_mode)) {
|
||||||
sprintf(buffer, "%s/%s/%s", ctx->fs_root, path, VIRTFS_META_DIR);
|
buffer = g_strdup_printf("%s/%s/%s", ctx->fs_root,
|
||||||
|
path, VIRTFS_META_DIR);
|
||||||
err = remove(buffer);
|
err = remove(buffer);
|
||||||
|
g_free(buffer);
|
||||||
if (err < 0 && errno != ENOENT) {
|
if (err < 0 && errno != ENOENT) {
|
||||||
/*
|
/*
|
||||||
* We didn't had the .virtfs_metadata file. May be file created
|
* We didn't had the .virtfs_metadata file. May be file created
|
||||||
@@ -912,7 +986,9 @@ static int local_remove(FsContext *ctx, const char *path)
|
|||||||
* Now remove the name from parent directory
|
* Now remove the name from parent directory
|
||||||
* .virtfs_metadata directory
|
* .virtfs_metadata directory
|
||||||
*/
|
*/
|
||||||
err = remove(local_mapped_attr_path(ctx, path, buffer));
|
buffer = local_mapped_attr_path(ctx, path);
|
||||||
|
err = remove(buffer);
|
||||||
|
g_free(buffer);
|
||||||
if (err < 0 && errno != ENOENT) {
|
if (err < 0 && errno != ENOENT) {
|
||||||
/*
|
/*
|
||||||
* We didn't had the .virtfs_metadata file. May be file created
|
* We didn't had the .virtfs_metadata file. May be file created
|
||||||
@@ -921,7 +997,10 @@ static int local_remove(FsContext *ctx, const char *path)
|
|||||||
goto err_out;
|
goto err_out;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return remove(rpath(ctx, path, buffer));
|
|
||||||
|
buffer = rpath(ctx, path);
|
||||||
|
err = remove(buffer);
|
||||||
|
g_free(buffer);
|
||||||
err_out:
|
err_out:
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
@@ -946,10 +1025,14 @@ static int local_fsync(FsContext *ctx, int fid_type,
|
|||||||
|
|
||||||
static int local_statfs(FsContext *s, V9fsPath *fs_path, struct statfs *stbuf)
|
static int local_statfs(FsContext *s, V9fsPath *fs_path, struct statfs *stbuf)
|
||||||
{
|
{
|
||||||
char buffer[PATH_MAX];
|
char *buffer;
|
||||||
|
int ret;
|
||||||
char *path = fs_path->data;
|
char *path = fs_path->data;
|
||||||
|
|
||||||
return statfs(rpath(s, path, buffer), stbuf);
|
buffer = rpath(s, path);
|
||||||
|
ret = statfs(buffer, stbuf);
|
||||||
|
g_free(buffer);
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static ssize_t local_lgetxattr(FsContext *ctx, V9fsPath *fs_path,
|
static ssize_t local_lgetxattr(FsContext *ctx, V9fsPath *fs_path,
|
||||||
@@ -1022,7 +1105,7 @@ static int local_unlinkat(FsContext *ctx, V9fsPath *dir,
|
|||||||
{
|
{
|
||||||
int ret;
|
int ret;
|
||||||
V9fsString fullname;
|
V9fsString fullname;
|
||||||
char buffer[PATH_MAX];
|
char *buffer;
|
||||||
|
|
||||||
v9fs_string_init(&fullname);
|
v9fs_string_init(&fullname);
|
||||||
|
|
||||||
@@ -1033,9 +1116,10 @@ static int local_unlinkat(FsContext *ctx, V9fsPath *dir,
|
|||||||
* If directory remove .virtfs_metadata contained in the
|
* If directory remove .virtfs_metadata contained in the
|
||||||
* directory
|
* directory
|
||||||
*/
|
*/
|
||||||
sprintf(buffer, "%s/%s/%s", ctx->fs_root,
|
buffer = g_strdup_printf("%s/%s/%s", ctx->fs_root,
|
||||||
fullname.data, VIRTFS_META_DIR);
|
fullname.data, VIRTFS_META_DIR);
|
||||||
ret = remove(buffer);
|
ret = remove(buffer);
|
||||||
|
g_free(buffer);
|
||||||
if (ret < 0 && errno != ENOENT) {
|
if (ret < 0 && errno != ENOENT) {
|
||||||
/*
|
/*
|
||||||
* We didn't had the .virtfs_metadata file. May be file created
|
* We didn't had the .virtfs_metadata file. May be file created
|
||||||
@@ -1048,7 +1132,9 @@ static int local_unlinkat(FsContext *ctx, V9fsPath *dir,
|
|||||||
* Now remove the name from parent directory
|
* Now remove the name from parent directory
|
||||||
* .virtfs_metadata directory.
|
* .virtfs_metadata directory.
|
||||||
*/
|
*/
|
||||||
ret = remove(local_mapped_attr_path(ctx, fullname.data, buffer));
|
buffer = local_mapped_attr_path(ctx, fullname.data);
|
||||||
|
ret = remove(buffer);
|
||||||
|
g_free(buffer);
|
||||||
if (ret < 0 && errno != ENOENT) {
|
if (ret < 0 && errno != ENOENT) {
|
||||||
/*
|
/*
|
||||||
* We didn't had the .virtfs_metadata file. May be file created
|
* We didn't had the .virtfs_metadata file. May be file created
|
||||||
@@ -1058,10 +1144,12 @@ static int local_unlinkat(FsContext *ctx, V9fsPath *dir,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
/* Remove the name finally */
|
/* Remove the name finally */
|
||||||
ret = remove(rpath(ctx, fullname.data, buffer));
|
buffer = rpath(ctx, fullname.data);
|
||||||
v9fs_string_free(&fullname);
|
ret = remove(buffer);
|
||||||
|
g_free(buffer);
|
||||||
|
|
||||||
err_out:
|
err_out:
|
||||||
|
v9fs_string_free(&fullname);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -26,8 +26,13 @@
|
|||||||
static ssize_t mp_pacl_getxattr(FsContext *ctx, const char *path,
|
static ssize_t mp_pacl_getxattr(FsContext *ctx, const char *path,
|
||||||
const char *name, void *value, size_t size)
|
const char *name, void *value, size_t size)
|
||||||
{
|
{
|
||||||
char buffer[PATH_MAX];
|
char *buffer;
|
||||||
return lgetxattr(rpath(ctx, path, buffer), MAP_ACL_ACCESS, value, size);
|
ssize_t ret;
|
||||||
|
|
||||||
|
buffer = rpath(ctx, path);
|
||||||
|
ret = lgetxattr(buffer, MAP_ACL_ACCESS, value, size);
|
||||||
|
g_free(buffer);
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static ssize_t mp_pacl_listxattr(FsContext *ctx, const char *path,
|
static ssize_t mp_pacl_listxattr(FsContext *ctx, const char *path,
|
||||||
@@ -52,17 +57,23 @@ static ssize_t mp_pacl_listxattr(FsContext *ctx, const char *path,
|
|||||||
static int mp_pacl_setxattr(FsContext *ctx, const char *path, const char *name,
|
static int mp_pacl_setxattr(FsContext *ctx, const char *path, const char *name,
|
||||||
void *value, size_t size, int flags)
|
void *value, size_t size, int flags)
|
||||||
{
|
{
|
||||||
char buffer[PATH_MAX];
|
char *buffer;
|
||||||
return lsetxattr(rpath(ctx, path, buffer), MAP_ACL_ACCESS, value,
|
int ret;
|
||||||
size, flags);
|
|
||||||
|
buffer = rpath(ctx, path);
|
||||||
|
ret = lsetxattr(buffer, MAP_ACL_ACCESS, value, size, flags);
|
||||||
|
g_free(buffer);
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int mp_pacl_removexattr(FsContext *ctx,
|
static int mp_pacl_removexattr(FsContext *ctx,
|
||||||
const char *path, const char *name)
|
const char *path, const char *name)
|
||||||
{
|
{
|
||||||
int ret;
|
int ret;
|
||||||
char buffer[PATH_MAX];
|
char *buffer;
|
||||||
ret = lremovexattr(rpath(ctx, path, buffer), MAP_ACL_ACCESS);
|
|
||||||
|
buffer = rpath(ctx, path);
|
||||||
|
ret = lremovexattr(buffer, MAP_ACL_ACCESS);
|
||||||
if (ret == -1 && errno == ENODATA) {
|
if (ret == -1 && errno == ENODATA) {
|
||||||
/*
|
/*
|
||||||
* We don't get ENODATA error when trying to remove a
|
* We don't get ENODATA error when trying to remove a
|
||||||
@@ -72,14 +83,20 @@ static int mp_pacl_removexattr(FsContext *ctx,
|
|||||||
errno = 0;
|
errno = 0;
|
||||||
ret = 0;
|
ret = 0;
|
||||||
}
|
}
|
||||||
|
g_free(buffer);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static ssize_t mp_dacl_getxattr(FsContext *ctx, const char *path,
|
static ssize_t mp_dacl_getxattr(FsContext *ctx, const char *path,
|
||||||
const char *name, void *value, size_t size)
|
const char *name, void *value, size_t size)
|
||||||
{
|
{
|
||||||
char buffer[PATH_MAX];
|
char *buffer;
|
||||||
return lgetxattr(rpath(ctx, path, buffer), MAP_ACL_DEFAULT, value, size);
|
ssize_t ret;
|
||||||
|
|
||||||
|
buffer = rpath(ctx, path);
|
||||||
|
ret = lgetxattr(buffer, MAP_ACL_DEFAULT, value, size);
|
||||||
|
g_free(buffer);
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static ssize_t mp_dacl_listxattr(FsContext *ctx, const char *path,
|
static ssize_t mp_dacl_listxattr(FsContext *ctx, const char *path,
|
||||||
@@ -104,17 +121,23 @@ static ssize_t mp_dacl_listxattr(FsContext *ctx, const char *path,
|
|||||||
static int mp_dacl_setxattr(FsContext *ctx, const char *path, const char *name,
|
static int mp_dacl_setxattr(FsContext *ctx, const char *path, const char *name,
|
||||||
void *value, size_t size, int flags)
|
void *value, size_t size, int flags)
|
||||||
{
|
{
|
||||||
char buffer[PATH_MAX];
|
char *buffer;
|
||||||
return lsetxattr(rpath(ctx, path, buffer), MAP_ACL_DEFAULT, value,
|
int ret;
|
||||||
size, flags);
|
|
||||||
|
buffer = rpath(ctx, path);
|
||||||
|
ret = lsetxattr(buffer, MAP_ACL_DEFAULT, value, size, flags);
|
||||||
|
g_free(buffer);
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int mp_dacl_removexattr(FsContext *ctx,
|
static int mp_dacl_removexattr(FsContext *ctx,
|
||||||
const char *path, const char *name)
|
const char *path, const char *name)
|
||||||
{
|
{
|
||||||
int ret;
|
int ret;
|
||||||
char buffer[PATH_MAX];
|
char *buffer;
|
||||||
ret = lremovexattr(rpath(ctx, path, buffer), MAP_ACL_DEFAULT);
|
|
||||||
|
buffer = rpath(ctx, path);
|
||||||
|
ret = lremovexattr(buffer, MAP_ACL_DEFAULT);
|
||||||
if (ret == -1 && errno == ENODATA) {
|
if (ret == -1 && errno == ENODATA) {
|
||||||
/*
|
/*
|
||||||
* We don't get ENODATA error when trying to remove a
|
* We don't get ENODATA error when trying to remove a
|
||||||
@@ -124,6 +147,7 @@ static int mp_dacl_removexattr(FsContext *ctx,
|
|||||||
errno = 0;
|
errno = 0;
|
||||||
ret = 0;
|
ret = 0;
|
||||||
}
|
}
|
||||||
|
g_free(buffer);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -21,7 +21,9 @@
|
|||||||
static ssize_t mp_user_getxattr(FsContext *ctx, const char *path,
|
static ssize_t mp_user_getxattr(FsContext *ctx, const char *path,
|
||||||
const char *name, void *value, size_t size)
|
const char *name, void *value, size_t size)
|
||||||
{
|
{
|
||||||
char buffer[PATH_MAX];
|
char *buffer;
|
||||||
|
ssize_t ret;
|
||||||
|
|
||||||
if (strncmp(name, "user.virtfs.", 12) == 0) {
|
if (strncmp(name, "user.virtfs.", 12) == 0) {
|
||||||
/*
|
/*
|
||||||
* Don't allow fetch of user.virtfs namesapce
|
* Don't allow fetch of user.virtfs namesapce
|
||||||
@@ -30,7 +32,10 @@ static ssize_t mp_user_getxattr(FsContext *ctx, const char *path,
|
|||||||
errno = ENOATTR;
|
errno = ENOATTR;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
return lgetxattr(rpath(ctx, path, buffer), name, value, size);
|
buffer = rpath(ctx, path);
|
||||||
|
ret = lgetxattr(buffer, name, value, size);
|
||||||
|
g_free(buffer);
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static ssize_t mp_user_listxattr(FsContext *ctx, const char *path,
|
static ssize_t mp_user_listxattr(FsContext *ctx, const char *path,
|
||||||
@@ -69,7 +74,9 @@ static ssize_t mp_user_listxattr(FsContext *ctx, const char *path,
|
|||||||
static int mp_user_setxattr(FsContext *ctx, const char *path, const char *name,
|
static int mp_user_setxattr(FsContext *ctx, const char *path, const char *name,
|
||||||
void *value, size_t size, int flags)
|
void *value, size_t size, int flags)
|
||||||
{
|
{
|
||||||
char buffer[PATH_MAX];
|
char *buffer;
|
||||||
|
int ret;
|
||||||
|
|
||||||
if (strncmp(name, "user.virtfs.", 12) == 0) {
|
if (strncmp(name, "user.virtfs.", 12) == 0) {
|
||||||
/*
|
/*
|
||||||
* Don't allow fetch of user.virtfs namesapce
|
* Don't allow fetch of user.virtfs namesapce
|
||||||
@@ -78,13 +85,18 @@ static int mp_user_setxattr(FsContext *ctx, const char *path, const char *name,
|
|||||||
errno = EACCES;
|
errno = EACCES;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
return lsetxattr(rpath(ctx, path, buffer), name, value, size, flags);
|
buffer = rpath(ctx, path);
|
||||||
|
ret = lsetxattr(buffer, name, value, size, flags);
|
||||||
|
g_free(buffer);
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int mp_user_removexattr(FsContext *ctx,
|
static int mp_user_removexattr(FsContext *ctx,
|
||||||
const char *path, const char *name)
|
const char *path, const char *name)
|
||||||
{
|
{
|
||||||
char buffer[PATH_MAX];
|
char *buffer;
|
||||||
|
int ret;
|
||||||
|
|
||||||
if (strncmp(name, "user.virtfs.", 12) == 0) {
|
if (strncmp(name, "user.virtfs.", 12) == 0) {
|
||||||
/*
|
/*
|
||||||
* Don't allow fetch of user.virtfs namesapce
|
* Don't allow fetch of user.virtfs namesapce
|
||||||
@@ -93,7 +105,10 @@ static int mp_user_removexattr(FsContext *ctx,
|
|||||||
errno = EACCES;
|
errno = EACCES;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
return lremovexattr(rpath(ctx, path, buffer), name);
|
buffer = rpath(ctx, path);
|
||||||
|
ret = lremovexattr(buffer, name);
|
||||||
|
g_free(buffer);
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
XattrOperations mapped_user_xattr = {
|
XattrOperations mapped_user_xattr = {
|
||||||
|
@@ -67,21 +67,24 @@ ssize_t v9fs_list_xattr(FsContext *ctx, const char *path,
|
|||||||
void *value, size_t vsize)
|
void *value, size_t vsize)
|
||||||
{
|
{
|
||||||
ssize_t size = 0;
|
ssize_t size = 0;
|
||||||
char buffer[PATH_MAX];
|
char *buffer;
|
||||||
void *ovalue = value;
|
void *ovalue = value;
|
||||||
XattrOperations *xops;
|
XattrOperations *xops;
|
||||||
char *orig_value, *orig_value_start;
|
char *orig_value, *orig_value_start;
|
||||||
ssize_t xattr_len, parsed_len = 0, attr_len;
|
ssize_t xattr_len, parsed_len = 0, attr_len;
|
||||||
|
|
||||||
/* Get the actual len */
|
/* Get the actual len */
|
||||||
xattr_len = llistxattr(rpath(ctx, path, buffer), value, 0);
|
buffer = rpath(ctx, path);
|
||||||
|
xattr_len = llistxattr(buffer, value, 0);
|
||||||
if (xattr_len <= 0) {
|
if (xattr_len <= 0) {
|
||||||
|
g_free(buffer);
|
||||||
return xattr_len;
|
return xattr_len;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Now fetch the xattr and find the actual size */
|
/* Now fetch the xattr and find the actual size */
|
||||||
orig_value = g_malloc(xattr_len);
|
orig_value = g_malloc(xattr_len);
|
||||||
xattr_len = llistxattr(rpath(ctx, path, buffer), orig_value, xattr_len);
|
xattr_len = llistxattr(buffer, orig_value, xattr_len);
|
||||||
|
g_free(buffer);
|
||||||
|
|
||||||
/* store the orig pointer */
|
/* store the orig pointer */
|
||||||
orig_value_start = orig_value;
|
orig_value_start = orig_value;
|
||||||
|
@@ -54,23 +54,38 @@ ssize_t pt_listxattr(FsContext *ctx, const char *path, char *name, void *value,
|
|||||||
static inline ssize_t pt_getxattr(FsContext *ctx, const char *path,
|
static inline ssize_t pt_getxattr(FsContext *ctx, const char *path,
|
||||||
const char *name, void *value, size_t size)
|
const char *name, void *value, size_t size)
|
||||||
{
|
{
|
||||||
char buffer[PATH_MAX];
|
char *buffer;
|
||||||
return lgetxattr(rpath(ctx, path, buffer), name, value, size);
|
ssize_t ret;
|
||||||
|
|
||||||
|
buffer = rpath(ctx, path);
|
||||||
|
ret = lgetxattr(buffer, name, value, size);
|
||||||
|
g_free(buffer);
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline int pt_setxattr(FsContext *ctx, const char *path,
|
static inline int pt_setxattr(FsContext *ctx, const char *path,
|
||||||
const char *name, void *value,
|
const char *name, void *value,
|
||||||
size_t size, int flags)
|
size_t size, int flags)
|
||||||
{
|
{
|
||||||
char buffer[PATH_MAX];
|
char *buffer;
|
||||||
return lsetxattr(rpath(ctx, path, buffer), name, value, size, flags);
|
int ret;
|
||||||
|
|
||||||
|
buffer = rpath(ctx, path);
|
||||||
|
ret = lsetxattr(buffer, name, value, size, flags);
|
||||||
|
g_free(buffer);
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline int pt_removexattr(FsContext *ctx,
|
static inline int pt_removexattr(FsContext *ctx,
|
||||||
const char *path, const char *name)
|
const char *path, const char *name)
|
||||||
{
|
{
|
||||||
char buffer[PATH_MAX];
|
char *buffer;
|
||||||
return lremovexattr(rpath(ctx, path, buffer), name);
|
int ret;
|
||||||
|
|
||||||
|
buffer = rpath(ctx, path);
|
||||||
|
ret = lremovexattr(path, name);
|
||||||
|
g_free(buffer);
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline ssize_t notsup_getxattr(FsContext *ctx, const char *path,
|
static inline ssize_t notsup_getxattr(FsContext *ctx, const char *path,
|
||||||
|
@@ -6,6 +6,7 @@
|
|||||||
#include <sys/time.h>
|
#include <sys/time.h>
|
||||||
#include <utime.h>
|
#include <utime.h>
|
||||||
#include <sys/resource.h>
|
#include <sys/resource.h>
|
||||||
|
#include <glib.h>
|
||||||
#include "hw/virtio/virtio.h"
|
#include "hw/virtio/virtio.h"
|
||||||
#include "fsdev/file-op-9p.h"
|
#include "fsdev/file-op-9p.h"
|
||||||
#include "fsdev/virtio-9p-marshal.h"
|
#include "fsdev/virtio-9p-marshal.h"
|
||||||
@@ -112,10 +113,9 @@ enum p9_proto_version {
|
|||||||
|
|
||||||
#define FID_REFERENCED 0x1
|
#define FID_REFERENCED 0x1
|
||||||
#define FID_NON_RECLAIMABLE 0x2
|
#define FID_NON_RECLAIMABLE 0x2
|
||||||
static inline const char *rpath(FsContext *ctx, const char *path, char *buffer)
|
static inline char *rpath(FsContext *ctx, const char *path)
|
||||||
{
|
{
|
||||||
snprintf(buffer, PATH_MAX, "%s/%s", ctx->fs_root, path);
|
return g_strdup_printf("%s/%s", ctx->fs_root, path);
|
||||||
return buffer;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@@ -1,4 +1,4 @@
|
|||||||
devices-dirs-$(CONFIG_REALLY_VIRTFS) += 9pfs/
|
devices-dirs-$(call land, $(CONFIG_VIRTIO),$(call land,$(CONFIG_VIRTFS),$(CONFIG_PCI))) += 9pfs/
|
||||||
devices-dirs-$(CONFIG_ACPI) += acpi/
|
devices-dirs-$(CONFIG_ACPI) += acpi/
|
||||||
devices-dirs-$(CONFIG_SOFTMMU) += audio/
|
devices-dirs-$(CONFIG_SOFTMMU) += audio/
|
||||||
devices-dirs-$(CONFIG_SOFTMMU) += block/
|
devices-dirs-$(CONFIG_SOFTMMU) += block/
|
||||||
|
@@ -92,8 +92,6 @@
|
|||||||
#define MP_ETH_CRDP3 0x4AC
|
#define MP_ETH_CRDP3 0x4AC
|
||||||
#define MP_ETH_CTDP0 0x4E0
|
#define MP_ETH_CTDP0 0x4E0
|
||||||
#define MP_ETH_CTDP1 0x4E4
|
#define MP_ETH_CTDP1 0x4E4
|
||||||
#define MP_ETH_CTDP2 0x4E8
|
|
||||||
#define MP_ETH_CTDP3 0x4EC
|
|
||||||
|
|
||||||
/* MII PHY access */
|
/* MII PHY access */
|
||||||
#define MP_ETH_SMIR_DATA 0x0000FFFF
|
#define MP_ETH_SMIR_DATA 0x0000FFFF
|
||||||
@@ -308,7 +306,7 @@ static uint64_t mv88w8618_eth_read(void *opaque, hwaddr offset,
|
|||||||
case MP_ETH_CRDP0 ... MP_ETH_CRDP3:
|
case MP_ETH_CRDP0 ... MP_ETH_CRDP3:
|
||||||
return s->rx_queue[(offset - MP_ETH_CRDP0)/4];
|
return s->rx_queue[(offset - MP_ETH_CRDP0)/4];
|
||||||
|
|
||||||
case MP_ETH_CTDP0 ... MP_ETH_CTDP3:
|
case MP_ETH_CTDP0 ... MP_ETH_CTDP1:
|
||||||
return s->tx_queue[(offset - MP_ETH_CTDP0)/4];
|
return s->tx_queue[(offset - MP_ETH_CTDP0)/4];
|
||||||
|
|
||||||
default:
|
default:
|
||||||
@@ -362,7 +360,7 @@ static void mv88w8618_eth_write(void *opaque, hwaddr offset,
|
|||||||
s->cur_rx[(offset - MP_ETH_CRDP0)/4] = value;
|
s->cur_rx[(offset - MP_ETH_CRDP0)/4] = value;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case MP_ETH_CTDP0 ... MP_ETH_CTDP3:
|
case MP_ETH_CTDP0 ... MP_ETH_CTDP1:
|
||||||
s->tx_queue[(offset - MP_ETH_CTDP0)/4] = value;
|
s->tx_queue[(offset - MP_ETH_CTDP0)/4] = value;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -632,7 +630,7 @@ static int musicpal_lcd_init(SysBusDevice *sbd)
|
|||||||
"musicpal-lcd", MP_LCD_SIZE);
|
"musicpal-lcd", MP_LCD_SIZE);
|
||||||
sysbus_init_mmio(sbd, &s->iomem);
|
sysbus_init_mmio(sbd, &s->iomem);
|
||||||
|
|
||||||
s->con = graphic_console_init(dev, &musicpal_gfx_ops, s);
|
s->con = graphic_console_init(dev, 0, &musicpal_gfx_ops, s);
|
||||||
qemu_console_resize(s->con, 128*3, 64*3);
|
qemu_console_resize(s->con, 128*3, 64*3);
|
||||||
|
|
||||||
qdev_init_gpio_in(dev, musicpal_lcd_gpio_brightness_in, 3);
|
qdev_init_gpio_in(dev, musicpal_lcd_gpio_brightness_in, 3);
|
||||||
|
@@ -272,11 +272,11 @@ static void pxa2xx_pwrmode_write(CPUARMState *env, const ARMCPRegInfo *ri,
|
|||||||
goto message;
|
goto message;
|
||||||
|
|
||||||
case 3:
|
case 3:
|
||||||
s->cpu->env.uncached_cpsr =
|
s->cpu->env.uncached_cpsr = ARM_CPU_MODE_SVC;
|
||||||
ARM_CPU_MODE_SVC | CPSR_A | CPSR_F | CPSR_I;
|
s->cpu->env.daif = PSTATE_A | PSTATE_F | PSTATE_I;
|
||||||
s->cpu->env.cp15.c1_sys = 0;
|
s->cpu->env.cp15.c1_sys = 0;
|
||||||
s->cpu->env.cp15.c1_coproc = 0;
|
s->cpu->env.cp15.c1_coproc = 0;
|
||||||
s->cpu->env.cp15.c2_base0 = 0;
|
s->cpu->env.cp15.ttbr0_el1 = 0;
|
||||||
s->cpu->env.cp15.c3 = 0;
|
s->cpu->env.cp15.c3 = 0;
|
||||||
s->pm_regs[PSSR >> 2] |= 0x8; /* Set STS */
|
s->pm_regs[PSSR >> 2] |= 0x8; /* Set STS */
|
||||||
s->pm_regs[RCSR >> 2] |= 0x8; /* Set GPR */
|
s->pm_regs[RCSR >> 2] |= 0x8; /* Set GPR */
|
||||||
|
@@ -157,6 +157,9 @@ struct HDAAudioStream {
|
|||||||
uint32_t bpos;
|
uint32_t bpos;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#define TYPE_HDA_AUDIO "hda-audio"
|
||||||
|
#define HDA_AUDIO(obj) OBJECT_CHECK(HDAAudioState, (obj), TYPE_HDA_AUDIO)
|
||||||
|
|
||||||
struct HDAAudioState {
|
struct HDAAudioState {
|
||||||
HDACodecDevice hda;
|
HDACodecDevice hda;
|
||||||
const char *name;
|
const char *name;
|
||||||
@@ -288,7 +291,7 @@ static void hda_audio_setup(HDAAudioStream *st)
|
|||||||
|
|
||||||
static void hda_audio_command(HDACodecDevice *hda, uint32_t nid, uint32_t data)
|
static void hda_audio_command(HDACodecDevice *hda, uint32_t nid, uint32_t data)
|
||||||
{
|
{
|
||||||
HDAAudioState *a = DO_UPCAST(HDAAudioState, hda, hda);
|
HDAAudioState *a = HDA_AUDIO(hda);
|
||||||
HDAAudioStream *st;
|
HDAAudioStream *st;
|
||||||
const desc_node *node = NULL;
|
const desc_node *node = NULL;
|
||||||
const desc_param *param;
|
const desc_param *param;
|
||||||
@@ -448,7 +451,7 @@ fail:
|
|||||||
|
|
||||||
static void hda_audio_stream(HDACodecDevice *hda, uint32_t stnr, bool running, bool output)
|
static void hda_audio_stream(HDACodecDevice *hda, uint32_t stnr, bool running, bool output)
|
||||||
{
|
{
|
||||||
HDAAudioState *a = DO_UPCAST(HDAAudioState, hda, hda);
|
HDAAudioState *a = HDA_AUDIO(hda);
|
||||||
int s;
|
int s;
|
||||||
|
|
||||||
a->running_compat[stnr] = running;
|
a->running_compat[stnr] = running;
|
||||||
@@ -469,7 +472,7 @@ static void hda_audio_stream(HDACodecDevice *hda, uint32_t stnr, bool running, b
|
|||||||
|
|
||||||
static int hda_audio_init(HDACodecDevice *hda, const struct desc_codec *desc)
|
static int hda_audio_init(HDACodecDevice *hda, const struct desc_codec *desc)
|
||||||
{
|
{
|
||||||
HDAAudioState *a = DO_UPCAST(HDAAudioState, hda, hda);
|
HDAAudioState *a = HDA_AUDIO(hda);
|
||||||
HDAAudioStream *st;
|
HDAAudioStream *st;
|
||||||
const desc_node *node;
|
const desc_node *node;
|
||||||
const desc_param *param;
|
const desc_param *param;
|
||||||
@@ -514,7 +517,7 @@ static int hda_audio_init(HDACodecDevice *hda, const struct desc_codec *desc)
|
|||||||
|
|
||||||
static int hda_audio_exit(HDACodecDevice *hda)
|
static int hda_audio_exit(HDACodecDevice *hda)
|
||||||
{
|
{
|
||||||
HDAAudioState *a = DO_UPCAST(HDAAudioState, hda, hda);
|
HDAAudioState *a = HDA_AUDIO(hda);
|
||||||
HDAAudioStream *st;
|
HDAAudioStream *st;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
@@ -561,7 +564,7 @@ static int hda_audio_post_load(void *opaque, int version)
|
|||||||
|
|
||||||
static void hda_audio_reset(DeviceState *dev)
|
static void hda_audio_reset(DeviceState *dev)
|
||||||
{
|
{
|
||||||
HDAAudioState *a = DO_UPCAST(HDAAudioState, hda.qdev, dev);
|
HDAAudioState *a = HDA_AUDIO(dev);
|
||||||
HDAAudioStream *st;
|
HDAAudioStream *st;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
@@ -613,7 +616,7 @@ static Property hda_audio_properties[] = {
|
|||||||
|
|
||||||
static int hda_audio_init_output(HDACodecDevice *hda)
|
static int hda_audio_init_output(HDACodecDevice *hda)
|
||||||
{
|
{
|
||||||
HDAAudioState *a = DO_UPCAST(HDAAudioState, hda, hda);
|
HDAAudioState *a = HDA_AUDIO(hda);
|
||||||
|
|
||||||
if (!a->mixer) {
|
if (!a->mixer) {
|
||||||
return hda_audio_init(hda, &output_nomixemu);
|
return hda_audio_init(hda, &output_nomixemu);
|
||||||
@@ -624,7 +627,7 @@ static int hda_audio_init_output(HDACodecDevice *hda)
|
|||||||
|
|
||||||
static int hda_audio_init_duplex(HDACodecDevice *hda)
|
static int hda_audio_init_duplex(HDACodecDevice *hda)
|
||||||
{
|
{
|
||||||
HDAAudioState *a = DO_UPCAST(HDAAudioState, hda, hda);
|
HDAAudioState *a = HDA_AUDIO(hda);
|
||||||
|
|
||||||
if (!a->mixer) {
|
if (!a->mixer) {
|
||||||
return hda_audio_init(hda, &duplex_nomixemu);
|
return hda_audio_init(hda, &duplex_nomixemu);
|
||||||
@@ -635,7 +638,7 @@ static int hda_audio_init_duplex(HDACodecDevice *hda)
|
|||||||
|
|
||||||
static int hda_audio_init_micro(HDACodecDevice *hda)
|
static int hda_audio_init_micro(HDACodecDevice *hda)
|
||||||
{
|
{
|
||||||
HDAAudioState *a = DO_UPCAST(HDAAudioState, hda, hda);
|
HDAAudioState *a = HDA_AUDIO(hda);
|
||||||
|
|
||||||
if (!a->mixer) {
|
if (!a->mixer) {
|
||||||
return hda_audio_init(hda, µ_nomixemu);
|
return hda_audio_init(hda, µ_nomixemu);
|
||||||
@@ -644,25 +647,39 @@ static int hda_audio_init_micro(HDACodecDevice *hda)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void hda_audio_base_class_init(ObjectClass *klass, void *data)
|
||||||
|
{
|
||||||
|
DeviceClass *dc = DEVICE_CLASS(klass);
|
||||||
|
HDACodecDeviceClass *k = HDA_CODEC_DEVICE_CLASS(klass);
|
||||||
|
|
||||||
|
k->exit = hda_audio_exit;
|
||||||
|
k->command = hda_audio_command;
|
||||||
|
k->stream = hda_audio_stream;
|
||||||
|
set_bit(DEVICE_CATEGORY_SOUND, dc->categories);
|
||||||
|
dc->reset = hda_audio_reset;
|
||||||
|
dc->vmsd = &vmstate_hda_audio;
|
||||||
|
dc->props = hda_audio_properties;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const TypeInfo hda_audio_info = {
|
||||||
|
.name = TYPE_HDA_AUDIO,
|
||||||
|
.parent = TYPE_HDA_CODEC_DEVICE,
|
||||||
|
.class_init = hda_audio_base_class_init,
|
||||||
|
.abstract = true,
|
||||||
|
};
|
||||||
|
|
||||||
static void hda_audio_output_class_init(ObjectClass *klass, void *data)
|
static void hda_audio_output_class_init(ObjectClass *klass, void *data)
|
||||||
{
|
{
|
||||||
DeviceClass *dc = DEVICE_CLASS(klass);
|
DeviceClass *dc = DEVICE_CLASS(klass);
|
||||||
HDACodecDeviceClass *k = HDA_CODEC_DEVICE_CLASS(klass);
|
HDACodecDeviceClass *k = HDA_CODEC_DEVICE_CLASS(klass);
|
||||||
|
|
||||||
k->init = hda_audio_init_output;
|
k->init = hda_audio_init_output;
|
||||||
k->exit = hda_audio_exit;
|
|
||||||
k->command = hda_audio_command;
|
|
||||||
k->stream = hda_audio_stream;
|
|
||||||
set_bit(DEVICE_CATEGORY_SOUND, dc->categories);
|
|
||||||
dc->desc = "HDA Audio Codec, output-only (line-out)";
|
dc->desc = "HDA Audio Codec, output-only (line-out)";
|
||||||
dc->reset = hda_audio_reset;
|
|
||||||
dc->vmsd = &vmstate_hda_audio;
|
|
||||||
dc->props = hda_audio_properties;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static const TypeInfo hda_audio_output_info = {
|
static const TypeInfo hda_audio_output_info = {
|
||||||
.name = "hda-output",
|
.name = "hda-output",
|
||||||
.parent = TYPE_HDA_CODEC_DEVICE,
|
.parent = TYPE_HDA_AUDIO,
|
||||||
.instance_size = sizeof(HDAAudioState),
|
.instance_size = sizeof(HDAAudioState),
|
||||||
.class_init = hda_audio_output_class_init,
|
.class_init = hda_audio_output_class_init,
|
||||||
};
|
};
|
||||||
@@ -673,19 +690,12 @@ static void hda_audio_duplex_class_init(ObjectClass *klass, void *data)
|
|||||||
HDACodecDeviceClass *k = HDA_CODEC_DEVICE_CLASS(klass);
|
HDACodecDeviceClass *k = HDA_CODEC_DEVICE_CLASS(klass);
|
||||||
|
|
||||||
k->init = hda_audio_init_duplex;
|
k->init = hda_audio_init_duplex;
|
||||||
k->exit = hda_audio_exit;
|
|
||||||
k->command = hda_audio_command;
|
|
||||||
k->stream = hda_audio_stream;
|
|
||||||
set_bit(DEVICE_CATEGORY_SOUND, dc->categories);
|
|
||||||
dc->desc = "HDA Audio Codec, duplex (line-out, line-in)";
|
dc->desc = "HDA Audio Codec, duplex (line-out, line-in)";
|
||||||
dc->reset = hda_audio_reset;
|
|
||||||
dc->vmsd = &vmstate_hda_audio;
|
|
||||||
dc->props = hda_audio_properties;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static const TypeInfo hda_audio_duplex_info = {
|
static const TypeInfo hda_audio_duplex_info = {
|
||||||
.name = "hda-duplex",
|
.name = "hda-duplex",
|
||||||
.parent = TYPE_HDA_CODEC_DEVICE,
|
.parent = TYPE_HDA_AUDIO,
|
||||||
.instance_size = sizeof(HDAAudioState),
|
.instance_size = sizeof(HDAAudioState),
|
||||||
.class_init = hda_audio_duplex_class_init,
|
.class_init = hda_audio_duplex_class_init,
|
||||||
};
|
};
|
||||||
@@ -696,25 +706,19 @@ static void hda_audio_micro_class_init(ObjectClass *klass, void *data)
|
|||||||
HDACodecDeviceClass *k = HDA_CODEC_DEVICE_CLASS(klass);
|
HDACodecDeviceClass *k = HDA_CODEC_DEVICE_CLASS(klass);
|
||||||
|
|
||||||
k->init = hda_audio_init_micro;
|
k->init = hda_audio_init_micro;
|
||||||
k->exit = hda_audio_exit;
|
|
||||||
k->command = hda_audio_command;
|
|
||||||
k->stream = hda_audio_stream;
|
|
||||||
set_bit(DEVICE_CATEGORY_SOUND, dc->categories);
|
|
||||||
dc->desc = "HDA Audio Codec, duplex (speaker, microphone)";
|
dc->desc = "HDA Audio Codec, duplex (speaker, microphone)";
|
||||||
dc->reset = hda_audio_reset;
|
|
||||||
dc->vmsd = &vmstate_hda_audio;
|
|
||||||
dc->props = hda_audio_properties;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static const TypeInfo hda_audio_micro_info = {
|
static const TypeInfo hda_audio_micro_info = {
|
||||||
.name = "hda-micro",
|
.name = "hda-micro",
|
||||||
.parent = TYPE_HDA_CODEC_DEVICE,
|
.parent = TYPE_HDA_AUDIO,
|
||||||
.instance_size = sizeof(HDAAudioState),
|
.instance_size = sizeof(HDAAudioState),
|
||||||
.class_init = hda_audio_micro_class_init,
|
.class_init = hda_audio_micro_class_init,
|
||||||
};
|
};
|
||||||
|
|
||||||
static void hda_audio_register_types(void)
|
static void hda_audio_register_types(void)
|
||||||
{
|
{
|
||||||
|
type_register_static(&hda_audio_info);
|
||||||
type_register_static(&hda_audio_output_info);
|
type_register_static(&hda_audio_output_info);
|
||||||
type_register_static(&hda_audio_duplex_info);
|
type_register_static(&hda_audio_duplex_info);
|
||||||
type_register_static(&hda_audio_micro_info);
|
type_register_static(&hda_audio_micro_info);
|
||||||
|
@@ -284,12 +284,30 @@ static void *load_at(int fd, int offset, int size)
|
|||||||
#define SZ 64
|
#define SZ 64
|
||||||
#include "hw/elf_ops.h"
|
#include "hw/elf_ops.h"
|
||||||
|
|
||||||
|
const char *load_elf_strerror(int error)
|
||||||
|
{
|
||||||
|
switch (error) {
|
||||||
|
case 0:
|
||||||
|
return "No error";
|
||||||
|
case ELF_LOAD_FAILED:
|
||||||
|
return "Failed to load ELF";
|
||||||
|
case ELF_LOAD_NOT_ELF:
|
||||||
|
return "The image is not ELF";
|
||||||
|
case ELF_LOAD_WRONG_ARCH:
|
||||||
|
return "The image is from incompatible architecture";
|
||||||
|
case ELF_LOAD_WRONG_ENDIAN:
|
||||||
|
return "The image has incorrect endianness";
|
||||||
|
default:
|
||||||
|
return "Unknown error";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* return < 0 if error, otherwise the number of bytes loaded in memory */
|
/* return < 0 if error, otherwise the number of bytes loaded in memory */
|
||||||
int load_elf(const char *filename, uint64_t (*translate_fn)(void *, uint64_t),
|
int load_elf(const char *filename, uint64_t (*translate_fn)(void *, uint64_t),
|
||||||
void *translate_opaque, uint64_t *pentry, uint64_t *lowaddr,
|
void *translate_opaque, uint64_t *pentry, uint64_t *lowaddr,
|
||||||
uint64_t *highaddr, int big_endian, int elf_machine, int clear_lsb)
|
uint64_t *highaddr, int big_endian, int elf_machine, int clear_lsb)
|
||||||
{
|
{
|
||||||
int fd, data_order, target_data_order, must_swab, ret;
|
int fd, data_order, target_data_order, must_swab, ret = ELF_LOAD_FAILED;
|
||||||
uint8_t e_ident[EI_NIDENT];
|
uint8_t e_ident[EI_NIDENT];
|
||||||
|
|
||||||
fd = open(filename, O_RDONLY | O_BINARY);
|
fd = open(filename, O_RDONLY | O_BINARY);
|
||||||
@@ -302,8 +320,10 @@ int load_elf(const char *filename, uint64_t (*translate_fn)(void *, uint64_t),
|
|||||||
if (e_ident[0] != ELFMAG0 ||
|
if (e_ident[0] != ELFMAG0 ||
|
||||||
e_ident[1] != ELFMAG1 ||
|
e_ident[1] != ELFMAG1 ||
|
||||||
e_ident[2] != ELFMAG2 ||
|
e_ident[2] != ELFMAG2 ||
|
||||||
e_ident[3] != ELFMAG3)
|
e_ident[3] != ELFMAG3) {
|
||||||
|
ret = ELF_LOAD_NOT_ELF;
|
||||||
goto fail;
|
goto fail;
|
||||||
|
}
|
||||||
#ifdef HOST_WORDS_BIGENDIAN
|
#ifdef HOST_WORDS_BIGENDIAN
|
||||||
data_order = ELFDATA2MSB;
|
data_order = ELFDATA2MSB;
|
||||||
#else
|
#else
|
||||||
@@ -317,6 +337,7 @@ int load_elf(const char *filename, uint64_t (*translate_fn)(void *, uint64_t),
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (target_data_order != e_ident[EI_DATA]) {
|
if (target_data_order != e_ident[EI_DATA]) {
|
||||||
|
ret = ELF_LOAD_WRONG_ENDIAN;
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -329,12 +350,9 @@ int load_elf(const char *filename, uint64_t (*translate_fn)(void *, uint64_t),
|
|||||||
pentry, lowaddr, highaddr, elf_machine, clear_lsb);
|
pentry, lowaddr, highaddr, elf_machine, clear_lsb);
|
||||||
}
|
}
|
||||||
|
|
||||||
close(fd);
|
|
||||||
return ret;
|
|
||||||
|
|
||||||
fail:
|
fail:
|
||||||
close(fd);
|
close(fd);
|
||||||
return -1;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void bswap_uboot_header(uboot_image_header_t *hdr)
|
static void bswap_uboot_header(uboot_image_header_t *hdr)
|
||||||
|
@@ -440,27 +440,33 @@ DeviceState *qdev_find_recursive(BusState *bus, const char *id)
|
|||||||
static void qbus_realize(BusState *bus, DeviceState *parent, const char *name)
|
static void qbus_realize(BusState *bus, DeviceState *parent, const char *name)
|
||||||
{
|
{
|
||||||
const char *typename = object_get_typename(OBJECT(bus));
|
const char *typename = object_get_typename(OBJECT(bus));
|
||||||
|
BusClass *bc;
|
||||||
char *buf;
|
char *buf;
|
||||||
int i,len;
|
int i, len, bus_id;
|
||||||
|
|
||||||
bus->parent = parent;
|
bus->parent = parent;
|
||||||
|
|
||||||
if (name) {
|
if (name) {
|
||||||
bus->name = g_strdup(name);
|
bus->name = g_strdup(name);
|
||||||
} else if (bus->parent && bus->parent->id) {
|
} else if (bus->parent && bus->parent->id) {
|
||||||
/* parent device has id -> use it for bus name */
|
/* parent device has id -> use it plus parent-bus-id for bus name */
|
||||||
|
bus_id = bus->parent->num_child_bus;
|
||||||
|
|
||||||
len = strlen(bus->parent->id) + 16;
|
len = strlen(bus->parent->id) + 16;
|
||||||
buf = g_malloc(len);
|
buf = g_malloc(len);
|
||||||
snprintf(buf, len, "%s.%d", bus->parent->id, bus->parent->num_child_bus);
|
snprintf(buf, len, "%s.%d", bus->parent->id, bus_id);
|
||||||
bus->name = buf;
|
bus->name = buf;
|
||||||
} else {
|
} else {
|
||||||
/* no id -> use lowercase bus type for bus name */
|
/* no id -> use lowercase bus type plus global bus-id for bus name */
|
||||||
|
bc = BUS_GET_CLASS(bus);
|
||||||
|
bus_id = bc->automatic_ids++;
|
||||||
|
|
||||||
len = strlen(typename) + 16;
|
len = strlen(typename) + 16;
|
||||||
buf = g_malloc(len);
|
buf = g_malloc(len);
|
||||||
len = snprintf(buf, len, "%s.%d", typename,
|
len = snprintf(buf, len, "%s.%d", typename, bus_id);
|
||||||
bus->parent ? bus->parent->num_child_bus : 0);
|
for (i = 0; i < len; i++) {
|
||||||
for (i = 0; i < len; i++)
|
|
||||||
buf[i] = qemu_tolower(buf[i]);
|
buf[i] = qemu_tolower(buf[i]);
|
||||||
|
}
|
||||||
bus->name = buf;
|
bus->name = buf;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -28,6 +28,7 @@ obj-$(CONFIG_OMAP) += omap_lcdc.o
|
|||||||
obj-$(CONFIG_PXA2XX) += pxa2xx_lcd.o
|
obj-$(CONFIG_PXA2XX) += pxa2xx_lcd.o
|
||||||
obj-$(CONFIG_SM501) += sm501.o
|
obj-$(CONFIG_SM501) += sm501.o
|
||||||
obj-$(CONFIG_TCX) += tcx.o
|
obj-$(CONFIG_TCX) += tcx.o
|
||||||
|
obj-$(CONFIG_CG3) += cg3.o
|
||||||
|
|
||||||
obj-$(CONFIG_VGA) += vga.o
|
obj-$(CONFIG_VGA) += vga.o
|
||||||
|
|
||||||
|
@@ -956,7 +956,7 @@ void *s1d13745_init(qemu_irq gpio_int)
|
|||||||
|
|
||||||
s->fb = g_malloc(0x180000);
|
s->fb = g_malloc(0x180000);
|
||||||
|
|
||||||
s->con = graphic_console_init(NULL, &blizzard_ops, s);
|
s->con = graphic_console_init(NULL, 0, &blizzard_ops, s);
|
||||||
surface = qemu_console_surface(s->con);
|
surface = qemu_console_surface(s->con);
|
||||||
|
|
||||||
switch (surface_bits_per_pixel(surface)) {
|
switch (surface_bits_per_pixel(surface)) {
|
||||||
|
385
hw/display/cg3.c
Normal file
385
hw/display/cg3.c
Normal file
@@ -0,0 +1,385 @@
|
|||||||
|
/*
|
||||||
|
* QEMU CG3 Frame buffer
|
||||||
|
*
|
||||||
|
* Copyright (c) 2012 Bob Breuer
|
||||||
|
* Copyright (c) 2013 Mark Cave-Ayland
|
||||||
|
*
|
||||||
|
* 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-common.h"
|
||||||
|
#include "qemu/error-report.h"
|
||||||
|
#include "ui/console.h"
|
||||||
|
#include "hw/sysbus.h"
|
||||||
|
#include "hw/loader.h"
|
||||||
|
|
||||||
|
/* Change to 1 to enable debugging */
|
||||||
|
#define DEBUG_CG3 0
|
||||||
|
|
||||||
|
#define CG3_ROM_FILE "QEMU,cgthree.bin"
|
||||||
|
#define FCODE_MAX_ROM_SIZE 0x10000
|
||||||
|
|
||||||
|
#define CG3_REG_SIZE 0x20
|
||||||
|
|
||||||
|
#define CG3_REG_BT458_ADDR 0x0
|
||||||
|
#define CG3_REG_BT458_COLMAP 0x4
|
||||||
|
#define CG3_REG_FBC_CTRL 0x10
|
||||||
|
#define CG3_REG_FBC_STATUS 0x11
|
||||||
|
#define CG3_REG_FBC_CURSTART 0x12
|
||||||
|
#define CG3_REG_FBC_CUREND 0x13
|
||||||
|
#define CG3_REG_FBC_VCTRL 0x14
|
||||||
|
|
||||||
|
/* Control register flags */
|
||||||
|
#define CG3_CR_ENABLE_INTS 0x80
|
||||||
|
|
||||||
|
/* Status register flags */
|
||||||
|
#define CG3_SR_PENDING_INT 0x80
|
||||||
|
#define CG3_SR_1152_900_76_B 0x60
|
||||||
|
#define CG3_SR_ID_COLOR 0x01
|
||||||
|
|
||||||
|
#define CG3_VRAM_SIZE 0x100000
|
||||||
|
#define CG3_VRAM_OFFSET 0x800000
|
||||||
|
|
||||||
|
#define DPRINTF(fmt, ...) do { \
|
||||||
|
if (DEBUG_CG3) { \
|
||||||
|
printf("CG3: " fmt , ## __VA_ARGS__); \
|
||||||
|
} \
|
||||||
|
} while (0);
|
||||||
|
|
||||||
|
#define TYPE_CG3 "cgthree"
|
||||||
|
#define CG3(obj) OBJECT_CHECK(CG3State, (obj), TYPE_CG3)
|
||||||
|
|
||||||
|
typedef struct CG3State {
|
||||||
|
SysBusDevice parent_obj;
|
||||||
|
|
||||||
|
QemuConsole *con;
|
||||||
|
qemu_irq irq;
|
||||||
|
hwaddr prom_addr;
|
||||||
|
MemoryRegion vram_mem;
|
||||||
|
MemoryRegion rom;
|
||||||
|
MemoryRegion reg;
|
||||||
|
uint32_t vram_size;
|
||||||
|
int full_update;
|
||||||
|
uint8_t regs[16];
|
||||||
|
uint8_t r[256], g[256], b[256];
|
||||||
|
uint16_t width, height, depth;
|
||||||
|
uint8_t dac_index, dac_state;
|
||||||
|
} CG3State;
|
||||||
|
|
||||||
|
static void cg3_update_display(void *opaque)
|
||||||
|
{
|
||||||
|
CG3State *s = opaque;
|
||||||
|
DisplaySurface *surface = qemu_console_surface(s->con);
|
||||||
|
const uint8_t *pix;
|
||||||
|
uint32_t *data;
|
||||||
|
uint32_t dval;
|
||||||
|
int x, y, y_start;
|
||||||
|
unsigned int width, height;
|
||||||
|
ram_addr_t page, page_min, page_max;
|
||||||
|
|
||||||
|
if (surface_bits_per_pixel(surface) != 32) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
width = s->width;
|
||||||
|
height = s->height;
|
||||||
|
|
||||||
|
y_start = -1;
|
||||||
|
page_min = -1;
|
||||||
|
page_max = 0;
|
||||||
|
page = 0;
|
||||||
|
pix = memory_region_get_ram_ptr(&s->vram_mem);
|
||||||
|
data = (uint32_t *)surface_data(surface);
|
||||||
|
|
||||||
|
for (y = 0; y < height; y++) {
|
||||||
|
int update = s->full_update;
|
||||||
|
|
||||||
|
page = (y * width) & TARGET_PAGE_MASK;
|
||||||
|
update |= memory_region_get_dirty(&s->vram_mem, page, page + width,
|
||||||
|
DIRTY_MEMORY_VGA);
|
||||||
|
if (update) {
|
||||||
|
if (y_start < 0) {
|
||||||
|
y_start = y;
|
||||||
|
}
|
||||||
|
if (page < page_min) {
|
||||||
|
page_min = page;
|
||||||
|
}
|
||||||
|
if (page > page_max) {
|
||||||
|
page_max = page;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (x = 0; x < width; x++) {
|
||||||
|
dval = *pix++;
|
||||||
|
dval = (s->r[dval] << 16) | (s->g[dval] << 8) | s->b[dval];
|
||||||
|
*data++ = dval;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (y_start >= 0) {
|
||||||
|
dpy_gfx_update(s->con, 0, y_start, s->width, y - y_start);
|
||||||
|
y_start = -1;
|
||||||
|
}
|
||||||
|
pix += width;
|
||||||
|
data += width;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
s->full_update = 0;
|
||||||
|
if (y_start >= 0) {
|
||||||
|
dpy_gfx_update(s->con, 0, y_start, s->width, y - y_start);
|
||||||
|
}
|
||||||
|
if (page_max >= page_min) {
|
||||||
|
memory_region_reset_dirty(&s->vram_mem,
|
||||||
|
page_min, page_max - page_min + TARGET_PAGE_SIZE,
|
||||||
|
DIRTY_MEMORY_VGA);
|
||||||
|
}
|
||||||
|
/* vsync interrupt? */
|
||||||
|
if (s->regs[0] & CG3_CR_ENABLE_INTS) {
|
||||||
|
s->regs[1] |= CG3_SR_PENDING_INT;
|
||||||
|
qemu_irq_raise(s->irq);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void cg3_invalidate_display(void *opaque)
|
||||||
|
{
|
||||||
|
CG3State *s = opaque;
|
||||||
|
|
||||||
|
memory_region_set_dirty(&s->vram_mem, 0, CG3_VRAM_SIZE);
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint64_t cg3_reg_read(void *opaque, hwaddr addr, unsigned size)
|
||||||
|
{
|
||||||
|
CG3State *s = opaque;
|
||||||
|
int val;
|
||||||
|
|
||||||
|
switch (addr) {
|
||||||
|
case CG3_REG_BT458_ADDR:
|
||||||
|
case CG3_REG_BT458_COLMAP:
|
||||||
|
val = 0;
|
||||||
|
break;
|
||||||
|
case CG3_REG_FBC_CTRL:
|
||||||
|
val = s->regs[0];
|
||||||
|
break;
|
||||||
|
case CG3_REG_FBC_STATUS:
|
||||||
|
/* monitor ID 6, board type = 1 (color) */
|
||||||
|
val = s->regs[1] | CG3_SR_1152_900_76_B | CG3_SR_ID_COLOR;
|
||||||
|
break;
|
||||||
|
case CG3_REG_FBC_CURSTART ... CG3_REG_SIZE:
|
||||||
|
val = s->regs[addr - 0x10];
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
qemu_log_mask(LOG_UNIMP,
|
||||||
|
"cg3: Unimplemented register read "
|
||||||
|
"reg 0x%" HWADDR_PRIx " size 0x%x\n",
|
||||||
|
addr, size);
|
||||||
|
val = 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
DPRINTF("read %02x from reg %" HWADDR_PRIx "\n", val, addr);
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void cg3_reg_write(void *opaque, hwaddr addr, uint64_t val,
|
||||||
|
unsigned size)
|
||||||
|
{
|
||||||
|
CG3State *s = opaque;
|
||||||
|
uint8_t regval;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
DPRINTF("write %" PRIx64 " to reg %" HWADDR_PRIx " size %d\n",
|
||||||
|
val, addr, size);
|
||||||
|
|
||||||
|
switch (addr) {
|
||||||
|
case CG3_REG_BT458_ADDR:
|
||||||
|
s->dac_index = val;
|
||||||
|
s->dac_state = 0;
|
||||||
|
break;
|
||||||
|
case CG3_REG_BT458_COLMAP:
|
||||||
|
/* This register can be written to as either a long word or a byte */
|
||||||
|
if (size == 1) {
|
||||||
|
val <<= 24;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < size; i++) {
|
||||||
|
regval = val >> 24;
|
||||||
|
|
||||||
|
switch (s->dac_state) {
|
||||||
|
case 0:
|
||||||
|
s->r[s->dac_index] = regval;
|
||||||
|
s->dac_state++;
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
s->g[s->dac_index] = regval;
|
||||||
|
s->dac_state++;
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
s->b[s->dac_index] = regval;
|
||||||
|
/* Index autoincrement */
|
||||||
|
s->dac_index = (s->dac_index + 1) & 0xff;
|
||||||
|
default:
|
||||||
|
s->dac_state = 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
val <<= 8;
|
||||||
|
}
|
||||||
|
s->full_update = 1;
|
||||||
|
break;
|
||||||
|
case CG3_REG_FBC_CTRL:
|
||||||
|
s->regs[0] = val;
|
||||||
|
break;
|
||||||
|
case CG3_REG_FBC_STATUS:
|
||||||
|
if (s->regs[1] & CG3_SR_PENDING_INT) {
|
||||||
|
/* clear interrupt */
|
||||||
|
s->regs[1] &= ~CG3_SR_PENDING_INT;
|
||||||
|
qemu_irq_lower(s->irq);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case CG3_REG_FBC_CURSTART ... CG3_REG_SIZE:
|
||||||
|
s->regs[addr - 0x10] = val;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
qemu_log_mask(LOG_UNIMP,
|
||||||
|
"cg3: Unimplemented register write "
|
||||||
|
"reg 0x%" HWADDR_PRIx " size 0x%x value 0x%" PRIx64 "\n",
|
||||||
|
addr, size, val);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static const MemoryRegionOps cg3_reg_ops = {
|
||||||
|
.read = cg3_reg_read,
|
||||||
|
.write = cg3_reg_write,
|
||||||
|
.endianness = DEVICE_NATIVE_ENDIAN,
|
||||||
|
.valid = {
|
||||||
|
.min_access_size = 1,
|
||||||
|
.max_access_size = 4,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
static const GraphicHwOps cg3_ops = {
|
||||||
|
.invalidate = cg3_invalidate_display,
|
||||||
|
.gfx_update = cg3_update_display,
|
||||||
|
};
|
||||||
|
|
||||||
|
static void cg3_realizefn(DeviceState *dev, Error **errp)
|
||||||
|
{
|
||||||
|
SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
|
||||||
|
CG3State *s = CG3(dev);
|
||||||
|
int ret;
|
||||||
|
char *fcode_filename;
|
||||||
|
|
||||||
|
/* FCode ROM */
|
||||||
|
memory_region_init_ram(&s->rom, NULL, "cg3.prom", FCODE_MAX_ROM_SIZE);
|
||||||
|
vmstate_register_ram_global(&s->rom);
|
||||||
|
memory_region_set_readonly(&s->rom, true);
|
||||||
|
sysbus_init_mmio(sbd, &s->rom);
|
||||||
|
|
||||||
|
fcode_filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, CG3_ROM_FILE);
|
||||||
|
if (fcode_filename) {
|
||||||
|
ret = load_image_targphys(fcode_filename, s->prom_addr,
|
||||||
|
FCODE_MAX_ROM_SIZE);
|
||||||
|
if (ret < 0 || ret > FCODE_MAX_ROM_SIZE) {
|
||||||
|
error_report("cg3: could not load prom '%s'", CG3_ROM_FILE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
memory_region_init_io(&s->reg, NULL, &cg3_reg_ops, s, "cg3.reg",
|
||||||
|
CG3_REG_SIZE);
|
||||||
|
sysbus_init_mmio(sbd, &s->reg);
|
||||||
|
|
||||||
|
memory_region_init_ram(&s->vram_mem, NULL, "cg3.vram", s->vram_size);
|
||||||
|
vmstate_register_ram_global(&s->vram_mem);
|
||||||
|
sysbus_init_mmio(sbd, &s->vram_mem);
|
||||||
|
|
||||||
|
sysbus_init_irq(sbd, &s->irq);
|
||||||
|
|
||||||
|
s->con = graphic_console_init(DEVICE(dev), 0, &cg3_ops, s);
|
||||||
|
qemu_console_resize(s->con, s->width, s->height);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int vmstate_cg3_post_load(void *opaque, int version_id)
|
||||||
|
{
|
||||||
|
CG3State *s = opaque;
|
||||||
|
|
||||||
|
cg3_invalidate_display(s);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const VMStateDescription vmstate_cg3 = {
|
||||||
|
.name = "cg3",
|
||||||
|
.version_id = 1,
|
||||||
|
.minimum_version_id = 1,
|
||||||
|
.post_load = vmstate_cg3_post_load,
|
||||||
|
.fields = (VMStateField[]) {
|
||||||
|
VMSTATE_UINT16(height, CG3State),
|
||||||
|
VMSTATE_UINT16(width, CG3State),
|
||||||
|
VMSTATE_UINT16(depth, CG3State),
|
||||||
|
VMSTATE_BUFFER(r, CG3State),
|
||||||
|
VMSTATE_BUFFER(g, CG3State),
|
||||||
|
VMSTATE_BUFFER(b, CG3State),
|
||||||
|
VMSTATE_UINT8(dac_index, CG3State),
|
||||||
|
VMSTATE_UINT8(dac_state, CG3State),
|
||||||
|
VMSTATE_END_OF_LIST()
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
static void cg3_reset(DeviceState *d)
|
||||||
|
{
|
||||||
|
CG3State *s = CG3(d);
|
||||||
|
|
||||||
|
/* Initialize palette */
|
||||||
|
memset(s->r, 0, 256);
|
||||||
|
memset(s->g, 0, 256);
|
||||||
|
memset(s->b, 0, 256);
|
||||||
|
|
||||||
|
s->dac_state = 0;
|
||||||
|
s->full_update = 1;
|
||||||
|
qemu_irq_lower(s->irq);
|
||||||
|
}
|
||||||
|
|
||||||
|
static Property cg3_properties[] = {
|
||||||
|
DEFINE_PROP_UINT32("vram-size", CG3State, vram_size, -1),
|
||||||
|
DEFINE_PROP_UINT16("width", CG3State, width, -1),
|
||||||
|
DEFINE_PROP_UINT16("height", CG3State, height, -1),
|
||||||
|
DEFINE_PROP_UINT16("depth", CG3State, depth, -1),
|
||||||
|
DEFINE_PROP_UINT64("prom-addr", CG3State, prom_addr, -1),
|
||||||
|
DEFINE_PROP_END_OF_LIST(),
|
||||||
|
};
|
||||||
|
|
||||||
|
static void cg3_class_init(ObjectClass *klass, void *data)
|
||||||
|
{
|
||||||
|
DeviceClass *dc = DEVICE_CLASS(klass);
|
||||||
|
|
||||||
|
dc->realize = cg3_realizefn;
|
||||||
|
dc->reset = cg3_reset;
|
||||||
|
dc->vmsd = &vmstate_cg3;
|
||||||
|
dc->props = cg3_properties;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const TypeInfo cg3_info = {
|
||||||
|
.name = TYPE_CG3,
|
||||||
|
.parent = TYPE_SYS_BUS_DEVICE,
|
||||||
|
.instance_size = sizeof(CG3State),
|
||||||
|
.class_init = cg3_class_init,
|
||||||
|
};
|
||||||
|
|
||||||
|
static void cg3_register_types(void)
|
||||||
|
{
|
||||||
|
type_register_static(&cg3_info);
|
||||||
|
}
|
||||||
|
|
||||||
|
type_init(cg3_register_types)
|
@@ -2917,7 +2917,7 @@ static void isa_cirrus_vga_realizefn(DeviceState *dev, Error **errp)
|
|||||||
cirrus_init_common(&d->cirrus_vga, OBJECT(dev), CIRRUS_ID_CLGD5430, 0,
|
cirrus_init_common(&d->cirrus_vga, OBJECT(dev), CIRRUS_ID_CLGD5430, 0,
|
||||||
isa_address_space(isadev),
|
isa_address_space(isadev),
|
||||||
isa_address_space_io(isadev));
|
isa_address_space_io(isadev));
|
||||||
s->con = graphic_console_init(dev, s->hw_ops, s);
|
s->con = graphic_console_init(dev, 0, s->hw_ops, s);
|
||||||
rom_add_vga(VGABIOS_CIRRUS_FILENAME);
|
rom_add_vga(VGABIOS_CIRRUS_FILENAME);
|
||||||
/* XXX ISA-LFB support */
|
/* XXX ISA-LFB support */
|
||||||
/* FIXME not qdev yet */
|
/* FIXME not qdev yet */
|
||||||
@@ -2963,7 +2963,7 @@ static int pci_cirrus_vga_initfn(PCIDevice *dev)
|
|||||||
vga_common_init(&s->vga, OBJECT(dev));
|
vga_common_init(&s->vga, OBJECT(dev));
|
||||||
cirrus_init_common(s, OBJECT(dev), device_id, 1, pci_address_space(dev),
|
cirrus_init_common(s, OBJECT(dev), device_id, 1, pci_address_space(dev),
|
||||||
pci_address_space_io(dev));
|
pci_address_space_io(dev));
|
||||||
s->vga.con = graphic_console_init(DEVICE(dev), s->vga.hw_ops, &s->vga);
|
s->vga.con = graphic_console_init(DEVICE(dev), 0, s->vga.hw_ops, &s->vga);
|
||||||
|
|
||||||
/* setup PCI */
|
/* setup PCI */
|
||||||
|
|
||||||
|
@@ -1917,7 +1917,7 @@ static int exynos4210_fimd_init(SysBusDevice *dev)
|
|||||||
memory_region_init_io(&s->iomem, OBJECT(s), &exynos4210_fimd_mmio_ops, s,
|
memory_region_init_io(&s->iomem, OBJECT(s), &exynos4210_fimd_mmio_ops, s,
|
||||||
"exynos4210.fimd", FIMD_REGS_SIZE);
|
"exynos4210.fimd", FIMD_REGS_SIZE);
|
||||||
sysbus_init_mmio(dev, &s->iomem);
|
sysbus_init_mmio(dev, &s->iomem);
|
||||||
s->console = graphic_console_init(DEVICE(dev), &exynos4210_fimd_ops, s);
|
s->console = graphic_console_init(DEVICE(dev), 0, &exynos4210_fimd_ops, s);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@@ -484,7 +484,7 @@ static void g364fb_init(DeviceState *dev, G364State *s)
|
|||||||
{
|
{
|
||||||
s->vram = g_malloc0(s->vram_size);
|
s->vram = g_malloc0(s->vram_size);
|
||||||
|
|
||||||
s->con = graphic_console_init(dev, &g364fb_ops, s);
|
s->con = graphic_console_init(dev, 0, &g364fb_ops, s);
|
||||||
|
|
||||||
memory_region_init_io(&s->mem_ctrl, NULL, &g364fb_ctrl_ops, s, "ctrl", 0x180000);
|
memory_region_init_io(&s->mem_ctrl, NULL, &g364fb_ctrl_ops, s, "ctrl", 0x180000);
|
||||||
memory_region_init_ram_ptr(&s->mem_vram, NULL, "vram",
|
memory_region_init_ram_ptr(&s->mem_vram, NULL, "vram",
|
||||||
|
@@ -271,7 +271,7 @@ static int jazz_led_init(SysBusDevice *dev)
|
|||||||
memory_region_init_io(&s->iomem, OBJECT(s), &led_ops, s, "led", 1);
|
memory_region_init_io(&s->iomem, OBJECT(s), &led_ops, s, "led", 1);
|
||||||
sysbus_init_mmio(dev, &s->iomem);
|
sysbus_init_mmio(dev, &s->iomem);
|
||||||
|
|
||||||
s->con = graphic_console_init(DEVICE(dev), &jazz_led_ops, s);
|
s->con = graphic_console_init(DEVICE(dev), 0, &jazz_led_ops, s);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@@ -290,7 +290,7 @@ static int milkymist_vgafb_init(SysBusDevice *dev)
|
|||||||
"milkymist-vgafb", R_MAX * 4);
|
"milkymist-vgafb", R_MAX * 4);
|
||||||
sysbus_init_mmio(dev, &s->regs_region);
|
sysbus_init_mmio(dev, &s->regs_region);
|
||||||
|
|
||||||
s->con = graphic_console_init(DEVICE(dev), &vgafb_ops, s);
|
s->con = graphic_console_init(DEVICE(dev), 0, &vgafb_ops, s);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@@ -406,7 +406,7 @@ struct omap_lcd_panel_s *omap_lcdc_init(MemoryRegion *sysmem,
|
|||||||
memory_region_init_io(&s->iomem, NULL, &omap_lcdc_ops, s, "omap.lcdc", 0x100);
|
memory_region_init_io(&s->iomem, NULL, &omap_lcdc_ops, s, "omap.lcdc", 0x100);
|
||||||
memory_region_add_subregion(sysmem, base, &s->iomem);
|
memory_region_add_subregion(sysmem, base, &s->iomem);
|
||||||
|
|
||||||
s->con = graphic_console_init(NULL, &omap_ops, s);
|
s->con = graphic_console_init(NULL, 0, &omap_ops, s);
|
||||||
|
|
||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
|
@@ -464,7 +464,7 @@ static int pl110_initfn(SysBusDevice *sbd)
|
|||||||
sysbus_init_mmio(sbd, &s->iomem);
|
sysbus_init_mmio(sbd, &s->iomem);
|
||||||
sysbus_init_irq(sbd, &s->irq);
|
sysbus_init_irq(sbd, &s->irq);
|
||||||
qdev_init_gpio_in(dev, pl110_mux_ctrl_set, 1);
|
qdev_init_gpio_in(dev, pl110_mux_ctrl_set, 1);
|
||||||
s->con = graphic_console_init(dev, &pl110_gfx_ops, s);
|
s->con = graphic_console_init(dev, 0, &pl110_gfx_ops, s);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -1013,7 +1013,7 @@ PXA2xxLCDState *pxa2xx_lcdc_init(MemoryRegion *sysmem,
|
|||||||
"pxa2xx-lcd-controller", 0x00100000);
|
"pxa2xx-lcd-controller", 0x00100000);
|
||||||
memory_region_add_subregion(sysmem, base, &s->iomem);
|
memory_region_add_subregion(sysmem, base, &s->iomem);
|
||||||
|
|
||||||
s->con = graphic_console_init(NULL, &pxa2xx_ops, s);
|
s->con = graphic_console_init(NULL, 0, &pxa2xx_ops, s);
|
||||||
surface = qemu_console_surface(s->con);
|
surface = qemu_console_surface(s->con);
|
||||||
|
|
||||||
switch (surface_bits_per_pixel(surface)) {
|
switch (surface_bits_per_pixel(surface)) {
|
||||||
|
@@ -2069,7 +2069,7 @@ static int qxl_init_primary(PCIDevice *dev)
|
|||||||
portio_list_set_flush_coalesced(qxl_vga_port_list);
|
portio_list_set_flush_coalesced(qxl_vga_port_list);
|
||||||
portio_list_add(qxl_vga_port_list, pci_address_space_io(dev), 0x3b0);
|
portio_list_add(qxl_vga_port_list, pci_address_space_io(dev), 0x3b0);
|
||||||
|
|
||||||
vga->con = graphic_console_init(DEVICE(dev), &qxl_ops, qxl);
|
vga->con = graphic_console_init(DEVICE(dev), 0, &qxl_ops, qxl);
|
||||||
qemu_spice_display_init_common(&qxl->ssd);
|
qemu_spice_display_init_common(&qxl->ssd);
|
||||||
|
|
||||||
rc = qxl_init_common(qxl);
|
rc = qxl_init_common(qxl);
|
||||||
@@ -2094,7 +2094,7 @@ static int qxl_init_secondary(PCIDevice *dev)
|
|||||||
qxl->vga.vram_size);
|
qxl->vga.vram_size);
|
||||||
vmstate_register_ram(&qxl->vga.vram, &qxl->pci.qdev);
|
vmstate_register_ram(&qxl->vga.vram, &qxl->pci.qdev);
|
||||||
qxl->vga.vram_ptr = memory_region_get_ram_ptr(&qxl->vga.vram);
|
qxl->vga.vram_ptr = memory_region_get_ram_ptr(&qxl->vga.vram);
|
||||||
qxl->vga.con = graphic_console_init(DEVICE(dev), &qxl_ops, qxl);
|
qxl->vga.con = graphic_console_init(DEVICE(dev), 0, &qxl_ops, qxl);
|
||||||
|
|
||||||
return qxl_init_common(qxl);
|
return qxl_init_common(qxl);
|
||||||
}
|
}
|
||||||
|
@@ -1449,5 +1449,5 @@ void sm501_init(MemoryRegion *address_space_mem, uint32_t base,
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* create qemu graphic console */
|
/* create qemu graphic console */
|
||||||
s->con = graphic_console_init(DEVICE(dev), &sm501_ops, s);
|
s->con = graphic_console_init(DEVICE(dev), 0, &sm501_ops, s);
|
||||||
}
|
}
|
||||||
|
@@ -299,7 +299,7 @@ static int ssd0303_init(I2CSlave *i2c)
|
|||||||
{
|
{
|
||||||
ssd0303_state *s = SSD0303(i2c);
|
ssd0303_state *s = SSD0303(i2c);
|
||||||
|
|
||||||
s->con = graphic_console_init(DEVICE(i2c), &ssd0303_ops, s);
|
s->con = graphic_console_init(DEVICE(i2c), 0, &ssd0303_ops, s);
|
||||||
qemu_console_resize(s->con, 96 * MAGNIFY, 16 * MAGNIFY);
|
qemu_console_resize(s->con, 96 * MAGNIFY, 16 * MAGNIFY);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@@ -342,7 +342,7 @@ static int ssd0323_init(SSISlave *dev)
|
|||||||
|
|
||||||
s->col_end = 63;
|
s->col_end = 63;
|
||||||
s->row_end = 79;
|
s->row_end = 79;
|
||||||
s->con = graphic_console_init(DEVICE(dev), &ssd0323_ops, s);
|
s->con = graphic_console_init(DEVICE(dev), 0, &ssd0323_ops, s);
|
||||||
qemu_console_resize(s->con, 128 * MAGNIFY, 64 * MAGNIFY);
|
qemu_console_resize(s->con, 128 * MAGNIFY, 64 * MAGNIFY);
|
||||||
|
|
||||||
qdev_init_gpio_in(&dev->qdev, ssd0323_cd, 1);
|
qdev_init_gpio_in(&dev->qdev, ssd0323_cd, 1);
|
||||||
|
@@ -587,7 +587,7 @@ TC6393xbState *tc6393xb_init(MemoryRegion *sysmem, uint32_t base, qemu_irq irq)
|
|||||||
memory_region_add_subregion(sysmem, base + 0x100000, &s->vram);
|
memory_region_add_subregion(sysmem, base + 0x100000, &s->vram);
|
||||||
s->scr_width = 480;
|
s->scr_width = 480;
|
||||||
s->scr_height = 640;
|
s->scr_height = 640;
|
||||||
s->con = graphic_console_init(NULL, &tc6393xb_gfx_ops, s);
|
s->con = graphic_console_init(NULL, 0, &tc6393xb_gfx_ops, s);
|
||||||
|
|
||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
|
@@ -602,14 +602,14 @@ static int tcx_init1(SysBusDevice *dev)
|
|||||||
&s->vram_mem, vram_offset, size);
|
&s->vram_mem, vram_offset, size);
|
||||||
sysbus_init_mmio(dev, &s->vram_cplane);
|
sysbus_init_mmio(dev, &s->vram_cplane);
|
||||||
|
|
||||||
s->con = graphic_console_init(DEVICE(dev), &tcx24_ops, s);
|
s->con = graphic_console_init(DEVICE(dev), 0, &tcx24_ops, s);
|
||||||
} else {
|
} else {
|
||||||
/* THC 8 bit (dummy) */
|
/* THC 8 bit (dummy) */
|
||||||
memory_region_init_io(&s->thc8, OBJECT(s), &dummy_ops, s, "tcx.thc8",
|
memory_region_init_io(&s->thc8, OBJECT(s), &dummy_ops, s, "tcx.thc8",
|
||||||
TCX_THC_NREGS_8);
|
TCX_THC_NREGS_8);
|
||||||
sysbus_init_mmio(dev, &s->thc8);
|
sysbus_init_mmio(dev, &s->thc8);
|
||||||
|
|
||||||
s->con = graphic_console_init(DEVICE(dev), &tcx_ops, s);
|
s->con = graphic_console_init(DEVICE(dev), 0, &tcx_ops, s);
|
||||||
}
|
}
|
||||||
|
|
||||||
qemu_console_resize(s->con, s->width, s->height);
|
qemu_console_resize(s->con, s->width, s->height);
|
||||||
|
@@ -135,7 +135,7 @@ int isa_vga_mm_init(hwaddr vram_base,
|
|||||||
vga_common_init(&s->vga, NULL);
|
vga_common_init(&s->vga, NULL);
|
||||||
vga_mm_init(s, vram_base, ctrl_base, it_shift, address_space);
|
vga_mm_init(s, vram_base, ctrl_base, it_shift, address_space);
|
||||||
|
|
||||||
s->vga.con = graphic_console_init(NULL, s->vga.hw_ops, s);
|
s->vga.con = graphic_console_init(NULL, 0, s->vga.hw_ops, s);
|
||||||
|
|
||||||
vga_init_vbe(&s->vga, NULL, address_space);
|
vga_init_vbe(&s->vga, NULL, address_space);
|
||||||
return 0;
|
return 0;
|
||||||
|
@@ -67,7 +67,7 @@ static void vga_isa_realizefn(DeviceState *dev, Error **errp)
|
|||||||
isa_mem_base + 0x000a0000,
|
isa_mem_base + 0x000a0000,
|
||||||
vga_io_memory, 1);
|
vga_io_memory, 1);
|
||||||
memory_region_set_coalescing(vga_io_memory);
|
memory_region_set_coalescing(vga_io_memory);
|
||||||
s->con = graphic_console_init(DEVICE(dev), s->hw_ops, s);
|
s->con = graphic_console_init(DEVICE(dev), 0, s->hw_ops, s);
|
||||||
|
|
||||||
vga_init_vbe(s, OBJECT(dev), isa_address_space(isadev));
|
vga_init_vbe(s, OBJECT(dev), isa_address_space(isadev));
|
||||||
/* ROM BIOS */
|
/* ROM BIOS */
|
||||||
|
@@ -151,7 +151,7 @@ static int pci_std_vga_initfn(PCIDevice *dev)
|
|||||||
vga_init(s, OBJECT(dev), pci_address_space(dev), pci_address_space_io(dev),
|
vga_init(s, OBJECT(dev), pci_address_space(dev), pci_address_space_io(dev),
|
||||||
true);
|
true);
|
||||||
|
|
||||||
s->con = graphic_console_init(DEVICE(dev), s->hw_ops, s);
|
s->con = graphic_console_init(DEVICE(dev), 0, s->hw_ops, s);
|
||||||
|
|
||||||
/* XXX: VGA_RAM_SIZE must be a power of two */
|
/* XXX: VGA_RAM_SIZE must be a power of two */
|
||||||
pci_register_bar(&d->dev, 0, PCI_BASE_ADDRESS_MEM_PREFETCH, &s->vram);
|
pci_register_bar(&d->dev, 0, PCI_BASE_ADDRESS_MEM_PREFETCH, &s->vram);
|
||||||
|
@@ -1199,7 +1199,7 @@ static void vmsvga_init(DeviceState *dev, struct vmsvga_state_s *s,
|
|||||||
s->scratch_size = SVGA_SCRATCH_SIZE;
|
s->scratch_size = SVGA_SCRATCH_SIZE;
|
||||||
s->scratch = g_malloc(s->scratch_size * 4);
|
s->scratch = g_malloc(s->scratch_size * 4);
|
||||||
|
|
||||||
s->vga.con = graphic_console_init(dev, &vmsvga_ops, s);
|
s->vga.con = graphic_console_init(dev, 0, &vmsvga_ops, s);
|
||||||
|
|
||||||
s->fifo_size = SVGA_FIFO_SIZE;
|
s->fifo_size = SVGA_FIFO_SIZE;
|
||||||
memory_region_init_ram(&s->fifo_ram, NULL, "vmsvga.fifo", s->fifo_size);
|
memory_region_init_ram(&s->fifo_ram, NULL, "vmsvga.fifo", s->fifo_size);
|
||||||
|
@@ -992,7 +992,7 @@ wait_more:
|
|||||||
|
|
||||||
/* vfb */
|
/* vfb */
|
||||||
fb = container_of(xfb, struct XenFB, c.xendev);
|
fb = container_of(xfb, struct XenFB, c.xendev);
|
||||||
fb->c.con = graphic_console_init(NULL, &xenfb_ops, fb);
|
fb->c.con = graphic_console_init(NULL, 0, &xenfb_ops, fb);
|
||||||
fb->have_console = 1;
|
fb->have_console = 1;
|
||||||
|
|
||||||
/* vkbd */
|
/* vkbd */
|
||||||
|
@@ -227,7 +227,8 @@ static const VMStateDescription vmstate_pl330_queue = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
struct PL330State {
|
struct PL330State {
|
||||||
SysBusDevice busdev;
|
SysBusDevice parent_obj;
|
||||||
|
|
||||||
MemoryRegion iomem;
|
MemoryRegion iomem;
|
||||||
qemu_irq irq_abort;
|
qemu_irq irq_abort;
|
||||||
qemu_irq *irq;
|
qemu_irq *irq;
|
||||||
@@ -577,7 +578,7 @@ static inline void pl330_queue_remove_tagged(PL330Queue *s, uint8_t tag)
|
|||||||
|
|
||||||
static inline void pl330_fault(PL330Chan *ch, uint32_t flags)
|
static inline void pl330_fault(PL330Chan *ch, uint32_t flags)
|
||||||
{
|
{
|
||||||
DB_PRINT("ch: %p, flags: %x\n", ch, flags);
|
DB_PRINT("ch: %p, flags: %" PRIx32 "\n", ch, flags);
|
||||||
ch->fault_type |= flags;
|
ch->fault_type |= flags;
|
||||||
if (ch->state == pl330_chan_fault) {
|
if (ch->state == pl330_chan_fault) {
|
||||||
return;
|
return;
|
||||||
@@ -600,10 +601,12 @@ static inline void pl330_fault(PL330Chan *ch, uint32_t flags)
|
|||||||
* LEN - number of elements in ARGS array
|
* LEN - number of elements in ARGS array
|
||||||
*/
|
*/
|
||||||
|
|
||||||
static void pl330_dmaaddh(PL330Chan *ch, uint8_t opcode, uint8_t *args, int len)
|
static void pl330_dmaadxh(PL330Chan *ch, uint8_t *args, bool ra, bool neg)
|
||||||
{
|
{
|
||||||
uint16_t im = (((uint16_t)args[1]) << 8) | ((uint16_t)args[0]);
|
uint32_t im = (args[1] << 8) | args[0];
|
||||||
uint8_t ra = (opcode >> 1) & 1;
|
if (neg) {
|
||||||
|
im |= 0xffffu << 16;
|
||||||
|
}
|
||||||
|
|
||||||
if (ch->is_manager) {
|
if (ch->is_manager) {
|
||||||
pl330_fault(ch, PL330_FAULT_UNDEF_INSTR);
|
pl330_fault(ch, PL330_FAULT_UNDEF_INSTR);
|
||||||
@@ -616,6 +619,16 @@ static void pl330_dmaaddh(PL330Chan *ch, uint8_t opcode, uint8_t *args, int len)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void pl330_dmaaddh(PL330Chan *ch, uint8_t opcode, uint8_t *args, int len)
|
||||||
|
{
|
||||||
|
pl330_dmaadxh(ch, args, extract32(opcode, 1, 1), false);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void pl330_dmaadnh(PL330Chan *ch, uint8_t opcode, uint8_t *args, int len)
|
||||||
|
{
|
||||||
|
pl330_dmaadxh(ch, args, extract32(opcode, 1, 1), true);
|
||||||
|
}
|
||||||
|
|
||||||
static void pl330_dmaend(PL330Chan *ch, uint8_t opcode,
|
static void pl330_dmaend(PL330Chan *ch, uint8_t opcode,
|
||||||
uint8_t *args, int len)
|
uint8_t *args, int len)
|
||||||
{
|
{
|
||||||
@@ -723,7 +736,8 @@ static void pl330_dmald(PL330Chan *ch, uint8_t opcode, uint8_t *args, int len)
|
|||||||
ch->stall = pl330_queue_put_insn(&ch->parent->read_queue, ch->src,
|
ch->stall = pl330_queue_put_insn(&ch->parent->read_queue, ch->src,
|
||||||
size, num, inc, 0, ch->tag);
|
size, num, inc, 0, ch->tag);
|
||||||
if (!ch->stall) {
|
if (!ch->stall) {
|
||||||
DB_PRINT("channel:%d address:%08x size:%d num:%d %c\n",
|
DB_PRINT("channel:%" PRId8 " address:%08" PRIx32 " size:%" PRIx32
|
||||||
|
" num:%" PRId32 " %c\n",
|
||||||
ch->tag, ch->src, size, num, inc ? 'Y' : 'N');
|
ch->tag, ch->src, size, num, inc ? 'Y' : 'N');
|
||||||
ch->src += inc ? size * num - (ch->src & (size - 1)) : 0;
|
ch->src += inc ? size * num - (ch->src & (size - 1)) : 0;
|
||||||
}
|
}
|
||||||
@@ -868,9 +882,10 @@ static void pl330_dmasev(PL330Chan *ch, uint8_t opcode, uint8_t *args, int len)
|
|||||||
}
|
}
|
||||||
if (ch->parent->inten & (1 << ev_id)) {
|
if (ch->parent->inten & (1 << ev_id)) {
|
||||||
ch->parent->int_status |= (1 << ev_id);
|
ch->parent->int_status |= (1 << ev_id);
|
||||||
DB_PRINT("event interrupt raised %d\n", ev_id);
|
DB_PRINT("event interrupt raised %" PRId8 "\n", ev_id);
|
||||||
qemu_irq_raise(ch->parent->irq[ev_id]);
|
qemu_irq_raise(ch->parent->irq[ev_id]);
|
||||||
}
|
}
|
||||||
|
DB_PRINT("event raised %" PRId8 "\n", ev_id);
|
||||||
ch->parent->ev_status |= (1 << ev_id);
|
ch->parent->ev_status |= (1 << ev_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -895,7 +910,8 @@ static void pl330_dmast(PL330Chan *ch, uint8_t opcode, uint8_t *args, int len)
|
|||||||
ch->stall = pl330_queue_put_insn(&ch->parent->write_queue, ch->dst,
|
ch->stall = pl330_queue_put_insn(&ch->parent->write_queue, ch->dst,
|
||||||
size, num, inc, 0, ch->tag);
|
size, num, inc, 0, ch->tag);
|
||||||
if (!ch->stall) {
|
if (!ch->stall) {
|
||||||
DB_PRINT("channel:%d address:%08x size:%d num:%d %c\n",
|
DB_PRINT("channel:%" PRId8 " address:%08" PRIx32 " size:%" PRIx32
|
||||||
|
" num:%" PRId32 " %c\n",
|
||||||
ch->tag, ch->dst, size, num, inc ? 'Y' : 'N');
|
ch->tag, ch->dst, size, num, inc ? 'Y' : 'N');
|
||||||
ch->dst += inc ? size * num - (ch->dst & (size - 1)) : 0;
|
ch->dst += inc ? size * num - (ch->dst & (size - 1)) : 0;
|
||||||
}
|
}
|
||||||
@@ -972,6 +988,7 @@ static void pl330_dmawfe(PL330Chan *ch, uint8_t opcode,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
ch->parent->ev_status &= ~(1 << ev_id);
|
ch->parent->ev_status &= ~(1 << ev_id);
|
||||||
|
DB_PRINT("event lowered %" PRIx8 "\n", ev_id);
|
||||||
} else {
|
} else {
|
||||||
ch->stall = 1;
|
ch->stall = 1;
|
||||||
}
|
}
|
||||||
@@ -1037,6 +1054,7 @@ static void pl330_dmawmb(PL330Chan *ch, uint8_t opcode,
|
|||||||
/* NULL terminated array of the instruction descriptions. */
|
/* NULL terminated array of the instruction descriptions. */
|
||||||
static const PL330InsnDesc insn_desc[] = {
|
static const PL330InsnDesc insn_desc[] = {
|
||||||
{ .opcode = 0x54, .opmask = 0xFD, .size = 3, .exec = pl330_dmaaddh, },
|
{ .opcode = 0x54, .opmask = 0xFD, .size = 3, .exec = pl330_dmaaddh, },
|
||||||
|
{ .opcode = 0x5c, .opmask = 0xFD, .size = 3, .exec = pl330_dmaadnh, },
|
||||||
{ .opcode = 0x00, .opmask = 0xFF, .size = 1, .exec = pl330_dmaend, },
|
{ .opcode = 0x00, .opmask = 0xFF, .size = 1, .exec = pl330_dmaend, },
|
||||||
{ .opcode = 0x35, .opmask = 0xFF, .size = 2, .exec = pl330_dmaflushp, },
|
{ .opcode = 0x35, .opmask = 0xFF, .size = 2, .exec = pl330_dmaflushp, },
|
||||||
{ .opcode = 0xA0, .opmask = 0xFD, .size = 6, .exec = pl330_dmago, },
|
{ .opcode = 0xA0, .opmask = 0xFD, .size = 6, .exec = pl330_dmago, },
|
||||||
@@ -1108,7 +1126,6 @@ static int pl330_chan_exec(PL330Chan *ch)
|
|||||||
ch->state != pl330_chan_waiting_periph &&
|
ch->state != pl330_chan_waiting_periph &&
|
||||||
ch->state != pl330_chan_at_barrier &&
|
ch->state != pl330_chan_at_barrier &&
|
||||||
ch->state != pl330_chan_waiting_event) {
|
ch->state != pl330_chan_waiting_event) {
|
||||||
DB_PRINT("%d\n", ch->state);
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
ch->stall = 0;
|
ch->stall = 0;
|
||||||
@@ -1155,7 +1172,7 @@ static int pl330_exec_cycle(PL330Chan *channel)
|
|||||||
|
|
||||||
dma_memory_read(&address_space_memory, q->addr, buf, len);
|
dma_memory_read(&address_space_memory, q->addr, buf, len);
|
||||||
if (PL330_ERR_DEBUG > 1) {
|
if (PL330_ERR_DEBUG > 1) {
|
||||||
DB_PRINT("PL330 read from memory @%08x (size = %08x):\n",
|
DB_PRINT("PL330 read from memory @%08" PRIx32 " (size = %08x):\n",
|
||||||
q->addr, len);
|
q->addr, len);
|
||||||
qemu_hexdump((char *)buf, stderr, "", len);
|
qemu_hexdump((char *)buf, stderr, "", len);
|
||||||
}
|
}
|
||||||
@@ -1187,8 +1204,8 @@ static int pl330_exec_cycle(PL330Chan *channel)
|
|||||||
if (fifo_res == PL330_FIFO_OK || q->z) {
|
if (fifo_res == PL330_FIFO_OK || q->z) {
|
||||||
dma_memory_write(&address_space_memory, q->addr, buf, len);
|
dma_memory_write(&address_space_memory, q->addr, buf, len);
|
||||||
if (PL330_ERR_DEBUG > 1) {
|
if (PL330_ERR_DEBUG > 1) {
|
||||||
DB_PRINT("PL330 read from memory @%08x (size = %08x):\n",
|
DB_PRINT("PL330 read from memory @%08" PRIx32
|
||||||
q->addr, len);
|
" (size = %08x):\n", q->addr, len);
|
||||||
qemu_hexdump((char *)buf, stderr, "", len);
|
qemu_hexdump((char *)buf, stderr, "", len);
|
||||||
}
|
}
|
||||||
if (q->inc) {
|
if (q->inc) {
|
||||||
@@ -1277,7 +1294,7 @@ static void pl330_debug_exec(PL330State *s)
|
|||||||
args[2] = (s->dbg[1] >> 8) & 0xff;
|
args[2] = (s->dbg[1] >> 8) & 0xff;
|
||||||
args[3] = (s->dbg[1] >> 16) & 0xff;
|
args[3] = (s->dbg[1] >> 16) & 0xff;
|
||||||
args[4] = (s->dbg[1] >> 24) & 0xff;
|
args[4] = (s->dbg[1] >> 24) & 0xff;
|
||||||
DB_PRINT("chan id: %d\n", chan_id);
|
DB_PRINT("chan id: %" PRIx8 "\n", chan_id);
|
||||||
if (s->dbg[0] & 1) {
|
if (s->dbg[0] & 1) {
|
||||||
ch = &s->chan[chan_id];
|
ch = &s->chan[chan_id];
|
||||||
} else {
|
} else {
|
||||||
@@ -1311,7 +1328,7 @@ static void pl330_iomem_write(void *opaque, hwaddr offset,
|
|||||||
uint64_t value, unsigned size)
|
uint64_t value, unsigned size)
|
||||||
{
|
{
|
||||||
PL330State *s = (PL330State *) opaque;
|
PL330State *s = (PL330State *) opaque;
|
||||||
uint32_t i;
|
int i;
|
||||||
|
|
||||||
DB_PRINT("addr: %08x data: %08x\n", (unsigned)offset, (unsigned)value);
|
DB_PRINT("addr: %08x data: %08x\n", (unsigned)offset, (unsigned)value);
|
||||||
|
|
||||||
@@ -1467,8 +1484,8 @@ static inline uint32_t pl330_iomem_read_imp(void *opaque,
|
|||||||
static uint64_t pl330_iomem_read(void *opaque, hwaddr offset,
|
static uint64_t pl330_iomem_read(void *opaque, hwaddr offset,
|
||||||
unsigned size)
|
unsigned size)
|
||||||
{
|
{
|
||||||
int ret = pl330_iomem_read_imp(opaque, offset);
|
uint32_t ret = pl330_iomem_read_imp(opaque, offset);
|
||||||
DB_PRINT("addr: %08x data: %08x\n", (unsigned)offset, ret);
|
DB_PRINT("addr: %08" HWADDR_PRIx " data: %08" PRIx32 "\n", offset, ret);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1554,7 +1571,7 @@ static void pl330_realize(DeviceState *dev, Error **errp)
|
|||||||
s->cfg[1] |= 5;
|
s->cfg[1] |= 5;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
error_setg(errp, "Bad value for i-cache_len property: %d\n",
|
error_setg(errp, "Bad value for i-cache_len property: %" PRIx8 "\n",
|
||||||
s->i_cache_len);
|
s->i_cache_len);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -1589,7 +1606,7 @@ static void pl330_realize(DeviceState *dev, Error **errp)
|
|||||||
s->cfg[CFG_CRD] |= 0x4;
|
s->cfg[CFG_CRD] |= 0x4;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
error_setg(errp, "Bad value for data_width property: %d\n",
|
error_setg(errp, "Bad value for data_width property: %" PRIx8 "\n",
|
||||||
s->data_width);
|
s->data_width);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -1602,7 +1619,7 @@ static void pl330_realize(DeviceState *dev, Error **errp)
|
|||||||
|
|
||||||
pl330_queue_init(&s->read_queue, s->rd_q_dep, s);
|
pl330_queue_init(&s->read_queue, s->rd_q_dep, s);
|
||||||
pl330_queue_init(&s->write_queue, s->wr_q_dep, s);
|
pl330_queue_init(&s->write_queue, s->wr_q_dep, s);
|
||||||
pl330_fifo_init(&s->fifo, s->data_buffer_dep);
|
pl330_fifo_init(&s->fifo, s->data_width / 4 * s->data_buffer_dep);
|
||||||
}
|
}
|
||||||
|
|
||||||
static Property pl330_properties[] = {
|
static Property pl330_properties[] = {
|
||||||
|
@@ -221,10 +221,16 @@ static void pc_init1(QEMUMachineInitArgs *args,
|
|||||||
} else {
|
} else {
|
||||||
for(i = 0; i < MAX_IDE_BUS; i++) {
|
for(i = 0; i < MAX_IDE_BUS; i++) {
|
||||||
ISADevice *dev;
|
ISADevice *dev;
|
||||||
|
char busname[] = "ide.0";
|
||||||
dev = isa_ide_init(isa_bus, ide_iobase[i], ide_iobase2[i],
|
dev = isa_ide_init(isa_bus, ide_iobase[i], ide_iobase2[i],
|
||||||
ide_irq[i],
|
ide_irq[i],
|
||||||
hd[MAX_IDE_DEVS * i], hd[MAX_IDE_DEVS * i + 1]);
|
hd[MAX_IDE_DEVS * i], hd[MAX_IDE_DEVS * i + 1]);
|
||||||
idebus[i] = qdev_get_child_bus(DEVICE(dev), "ide.0");
|
/*
|
||||||
|
* The ide bus name is ide.0 for the first bus and ide.1 for the
|
||||||
|
* second one.
|
||||||
|
*/
|
||||||
|
busname[4] = '0' + i;
|
||||||
|
idebus[i] = qdev_get_child_bus(DEVICE(dev), busname);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -40,7 +40,7 @@
|
|||||||
#define AHCI_PORT_PRIV_DMA_SZ (AHCI_CMD_SLOT_SZ + AHCI_CMD_TBL_AR_SZ + \
|
#define AHCI_PORT_PRIV_DMA_SZ (AHCI_CMD_SLOT_SZ + AHCI_CMD_TBL_AR_SZ + \
|
||||||
AHCI_RX_FIS_SZ)
|
AHCI_RX_FIS_SZ)
|
||||||
|
|
||||||
#define AHCI_IRQ_ON_SG (1 << 31)
|
#define AHCI_IRQ_ON_SG (1U << 31)
|
||||||
#define AHCI_CMD_ATAPI (1 << 5)
|
#define AHCI_CMD_ATAPI (1 << 5)
|
||||||
#define AHCI_CMD_WRITE (1 << 6)
|
#define AHCI_CMD_WRITE (1 << 6)
|
||||||
#define AHCI_CMD_PREFETCH (1 << 7)
|
#define AHCI_CMD_PREFETCH (1 << 7)
|
||||||
@@ -61,7 +61,7 @@
|
|||||||
/* HOST_CTL bits */
|
/* HOST_CTL bits */
|
||||||
#define HOST_CTL_RESET (1 << 0) /* reset controller; self-clear */
|
#define HOST_CTL_RESET (1 << 0) /* reset controller; self-clear */
|
||||||
#define HOST_CTL_IRQ_EN (1 << 1) /* global IRQ enable */
|
#define HOST_CTL_IRQ_EN (1 << 1) /* global IRQ enable */
|
||||||
#define HOST_CTL_AHCI_EN (1 << 31) /* AHCI enabled */
|
#define HOST_CTL_AHCI_EN (1U << 31) /* AHCI enabled */
|
||||||
|
|
||||||
/* HOST_CAP bits */
|
/* HOST_CAP bits */
|
||||||
#define HOST_CAP_SSC (1 << 14) /* Slumber capable */
|
#define HOST_CAP_SSC (1 << 14) /* Slumber capable */
|
||||||
@@ -69,7 +69,7 @@
|
|||||||
#define HOST_CAP_CLO (1 << 24) /* Command List Override support */
|
#define HOST_CAP_CLO (1 << 24) /* Command List Override support */
|
||||||
#define HOST_CAP_SSS (1 << 27) /* Staggered Spin-up */
|
#define HOST_CAP_SSS (1 << 27) /* Staggered Spin-up */
|
||||||
#define HOST_CAP_NCQ (1 << 30) /* Native Command Queueing */
|
#define HOST_CAP_NCQ (1 << 30) /* Native Command Queueing */
|
||||||
#define HOST_CAP_64 (1 << 31) /* PCI DAC (64-bit DMA) support */
|
#define HOST_CAP_64 (1U << 31) /* PCI DAC (64-bit DMA) support */
|
||||||
|
|
||||||
/* registers for each SATA port */
|
/* registers for each SATA port */
|
||||||
#define PORT_LST_ADDR 0x00 /* command list DMA addr */
|
#define PORT_LST_ADDR 0x00 /* command list DMA addr */
|
||||||
@@ -89,7 +89,7 @@
|
|||||||
#define PORT_RESERVED 0x3c /* reserved */
|
#define PORT_RESERVED 0x3c /* reserved */
|
||||||
|
|
||||||
/* PORT_IRQ_{STAT,MASK} bits */
|
/* PORT_IRQ_{STAT,MASK} bits */
|
||||||
#define PORT_IRQ_COLD_PRES (1 << 31) /* cold presence detect */
|
#define PORT_IRQ_COLD_PRES (1U << 31) /* cold presence detect */
|
||||||
#define PORT_IRQ_TF_ERR (1 << 30) /* task file error */
|
#define PORT_IRQ_TF_ERR (1 << 30) /* task file error */
|
||||||
#define PORT_IRQ_HBUS_ERR (1 << 29) /* host bus fatal error */
|
#define PORT_IRQ_HBUS_ERR (1 << 29) /* host bus fatal error */
|
||||||
#define PORT_IRQ_HBUS_DATA_ERR (1 << 28) /* host bus data error */
|
#define PORT_IRQ_HBUS_DATA_ERR (1 << 28) /* host bus data error */
|
||||||
@@ -151,7 +151,7 @@
|
|||||||
#define PORT_IRQ_STAT_HBDS (1 << 28) /* Host Bus Data Error Status */
|
#define PORT_IRQ_STAT_HBDS (1 << 28) /* Host Bus Data Error Status */
|
||||||
#define PORT_IRQ_STAT_HBFS (1 << 29) /* Host Bus Fatal Error Status */
|
#define PORT_IRQ_STAT_HBFS (1 << 29) /* Host Bus Fatal Error Status */
|
||||||
#define PORT_IRQ_STAT_TFES (1 << 30) /* Task File Error Status */
|
#define PORT_IRQ_STAT_TFES (1 << 30) /* Task File Error Status */
|
||||||
#define PORT_IRQ_STAT_CPDS (1 << 31) /* Code Port Detect Status */
|
#define PORT_IRQ_STAT_CPDS (1U << 31) /* Code Port Detect Status */
|
||||||
|
|
||||||
/* ap->flags bits */
|
/* ap->flags bits */
|
||||||
#define AHCI_FLAG_NO_NCQ (1 << 24)
|
#define AHCI_FLAG_NO_NCQ (1 << 24)
|
||||||
|
@@ -25,3 +25,4 @@ obj-$(CONFIG_SH4) += sh_intc.o
|
|||||||
obj-$(CONFIG_XICS) += xics.o
|
obj-$(CONFIG_XICS) += xics.o
|
||||||
obj-$(CONFIG_XICS_KVM) += xics_kvm.o
|
obj-$(CONFIG_XICS_KVM) += xics_kvm.o
|
||||||
obj-$(CONFIG_ALLWINNER_A10_PIC) += allwinner-a10-pic.o
|
obj-$(CONFIG_ALLWINNER_A10_PIC) += allwinner-a10-pic.o
|
||||||
|
obj-$(CONFIG_S390_FLIC) += s390_flic.o
|
||||||
|
@@ -3,6 +3,7 @@
|
|||||||
*
|
*
|
||||||
* Copyright (c) 2012 Linaro Limited
|
* Copyright (c) 2012 Linaro Limited
|
||||||
* Written by Peter Maydell
|
* Written by Peter Maydell
|
||||||
|
* Save/Restore logic added by Christoffer Dall.
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* 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
|
* it under the terms of the GNU General Public License as published by
|
||||||
@@ -23,6 +24,20 @@
|
|||||||
#include "kvm_arm.h"
|
#include "kvm_arm.h"
|
||||||
#include "gic_internal.h"
|
#include "gic_internal.h"
|
||||||
|
|
||||||
|
//#define DEBUG_GIC_KVM
|
||||||
|
|
||||||
|
#ifdef DEBUG_GIC_KVM
|
||||||
|
static const int debug_gic_kvm = 1;
|
||||||
|
#else
|
||||||
|
static const int debug_gic_kvm = 0;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define DPRINTF(fmt, ...) do { \
|
||||||
|
if (debug_gic_kvm) { \
|
||||||
|
printf("arm_gic: " fmt , ## __VA_ARGS__); \
|
||||||
|
} \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
#define TYPE_KVM_ARM_GIC "kvm-arm-gic"
|
#define TYPE_KVM_ARM_GIC "kvm-arm-gic"
|
||||||
#define KVM_ARM_GIC(obj) \
|
#define KVM_ARM_GIC(obj) \
|
||||||
OBJECT_CHECK(GICState, (obj), TYPE_KVM_ARM_GIC)
|
OBJECT_CHECK(GICState, (obj), TYPE_KVM_ARM_GIC)
|
||||||
@@ -72,14 +87,419 @@ static void kvm_arm_gic_set_irq(void *opaque, int irq, int level)
|
|||||||
kvm_set_irq(kvm_state, kvm_irq, !!level);
|
kvm_set_irq(kvm_state, kvm_irq, !!level);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool kvm_arm_gic_can_save_restore(GICState *s)
|
||||||
|
{
|
||||||
|
return s->dev_fd >= 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void kvm_gic_access(GICState *s, int group, int offset,
|
||||||
|
int cpu, uint32_t *val, bool write)
|
||||||
|
{
|
||||||
|
struct kvm_device_attr attr;
|
||||||
|
int type;
|
||||||
|
int err;
|
||||||
|
|
||||||
|
cpu = cpu & 0xff;
|
||||||
|
|
||||||
|
attr.flags = 0;
|
||||||
|
attr.group = group;
|
||||||
|
attr.attr = (((uint64_t)cpu << KVM_DEV_ARM_VGIC_CPUID_SHIFT) &
|
||||||
|
KVM_DEV_ARM_VGIC_CPUID_MASK) |
|
||||||
|
(((uint64_t)offset << KVM_DEV_ARM_VGIC_OFFSET_SHIFT) &
|
||||||
|
KVM_DEV_ARM_VGIC_OFFSET_MASK);
|
||||||
|
attr.addr = (uintptr_t)val;
|
||||||
|
|
||||||
|
if (write) {
|
||||||
|
type = KVM_SET_DEVICE_ATTR;
|
||||||
|
} else {
|
||||||
|
type = KVM_GET_DEVICE_ATTR;
|
||||||
|
}
|
||||||
|
|
||||||
|
err = kvm_device_ioctl(s->dev_fd, type, &attr);
|
||||||
|
if (err < 0) {
|
||||||
|
fprintf(stderr, "KVM_{SET/GET}_DEVICE_ATTR failed: %s\n",
|
||||||
|
strerror(-err));
|
||||||
|
abort();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void kvm_gicd_access(GICState *s, int offset, int cpu,
|
||||||
|
uint32_t *val, bool write)
|
||||||
|
{
|
||||||
|
kvm_gic_access(s, KVM_DEV_ARM_VGIC_GRP_DIST_REGS,
|
||||||
|
offset, cpu, val, write);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void kvm_gicc_access(GICState *s, int offset, int cpu,
|
||||||
|
uint32_t *val, bool write)
|
||||||
|
{
|
||||||
|
kvm_gic_access(s, KVM_DEV_ARM_VGIC_GRP_CPU_REGS,
|
||||||
|
offset, cpu, val, write);
|
||||||
|
}
|
||||||
|
|
||||||
|
#define for_each_irq_reg(_ctr, _max_irq, _field_width) \
|
||||||
|
for (_ctr = 0; _ctr < ((_max_irq) / (32 / (_field_width))); _ctr++)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Translate from the in-kernel field for an IRQ value to/from the qemu
|
||||||
|
* representation.
|
||||||
|
*/
|
||||||
|
typedef void (*vgic_translate_fn)(GICState *s, int irq, int cpu,
|
||||||
|
uint32_t *field, bool to_kernel);
|
||||||
|
|
||||||
|
/* synthetic translate function used for clear/set registers to completely
|
||||||
|
* clear a setting using a clear-register before setting the remaing bits
|
||||||
|
* using a set-register */
|
||||||
|
static void translate_clear(GICState *s, int irq, int cpu,
|
||||||
|
uint32_t *field, bool to_kernel)
|
||||||
|
{
|
||||||
|
if (to_kernel) {
|
||||||
|
*field = ~0;
|
||||||
|
} else {
|
||||||
|
/* does not make sense: qemu model doesn't use set/clear regs */
|
||||||
|
abort();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void translate_enabled(GICState *s, int irq, int cpu,
|
||||||
|
uint32_t *field, bool to_kernel)
|
||||||
|
{
|
||||||
|
int cm = (irq < GIC_INTERNAL) ? (1 << cpu) : ALL_CPU_MASK;
|
||||||
|
|
||||||
|
if (to_kernel) {
|
||||||
|
*field = GIC_TEST_ENABLED(irq, cm);
|
||||||
|
} else {
|
||||||
|
if (*field & 1) {
|
||||||
|
GIC_SET_ENABLED(irq, cm);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void translate_pending(GICState *s, int irq, int cpu,
|
||||||
|
uint32_t *field, bool to_kernel)
|
||||||
|
{
|
||||||
|
int cm = (irq < GIC_INTERNAL) ? (1 << cpu) : ALL_CPU_MASK;
|
||||||
|
|
||||||
|
if (to_kernel) {
|
||||||
|
*field = gic_test_pending(s, irq, cm);
|
||||||
|
} else {
|
||||||
|
if (*field & 1) {
|
||||||
|
GIC_SET_PENDING(irq, cm);
|
||||||
|
/* TODO: Capture is level-line is held high in the kernel */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void translate_active(GICState *s, int irq, int cpu,
|
||||||
|
uint32_t *field, bool to_kernel)
|
||||||
|
{
|
||||||
|
int cm = (irq < GIC_INTERNAL) ? (1 << cpu) : ALL_CPU_MASK;
|
||||||
|
|
||||||
|
if (to_kernel) {
|
||||||
|
*field = GIC_TEST_ACTIVE(irq, cm);
|
||||||
|
} else {
|
||||||
|
if (*field & 1) {
|
||||||
|
GIC_SET_ACTIVE(irq, cm);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void translate_trigger(GICState *s, int irq, int cpu,
|
||||||
|
uint32_t *field, bool to_kernel)
|
||||||
|
{
|
||||||
|
if (to_kernel) {
|
||||||
|
*field = (GIC_TEST_EDGE_TRIGGER(irq)) ? 0x2 : 0x0;
|
||||||
|
} else {
|
||||||
|
if (*field & 0x2) {
|
||||||
|
GIC_SET_EDGE_TRIGGER(irq);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void translate_priority(GICState *s, int irq, int cpu,
|
||||||
|
uint32_t *field, bool to_kernel)
|
||||||
|
{
|
||||||
|
if (to_kernel) {
|
||||||
|
*field = GIC_GET_PRIORITY(irq, cpu) & 0xff;
|
||||||
|
} else {
|
||||||
|
gic_set_priority(s, cpu, irq, *field & 0xff);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void translate_targets(GICState *s, int irq, int cpu,
|
||||||
|
uint32_t *field, bool to_kernel)
|
||||||
|
{
|
||||||
|
if (to_kernel) {
|
||||||
|
*field = s->irq_target[irq] & 0xff;
|
||||||
|
} else {
|
||||||
|
s->irq_target[irq] = *field & 0xff;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void translate_sgisource(GICState *s, int irq, int cpu,
|
||||||
|
uint32_t *field, bool to_kernel)
|
||||||
|
{
|
||||||
|
if (to_kernel) {
|
||||||
|
*field = s->sgi_pending[irq][cpu] & 0xff;
|
||||||
|
} else {
|
||||||
|
s->sgi_pending[irq][cpu] = *field & 0xff;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Read a register group from the kernel VGIC */
|
||||||
|
static void kvm_dist_get(GICState *s, uint32_t offset, int width,
|
||||||
|
int maxirq, vgic_translate_fn translate_fn)
|
||||||
|
{
|
||||||
|
uint32_t reg;
|
||||||
|
int i;
|
||||||
|
int j;
|
||||||
|
int irq;
|
||||||
|
int cpu;
|
||||||
|
int regsz = 32 / width; /* irqs per kernel register */
|
||||||
|
uint32_t field;
|
||||||
|
|
||||||
|
for_each_irq_reg(i, maxirq, width) {
|
||||||
|
irq = i * regsz;
|
||||||
|
cpu = 0;
|
||||||
|
while ((cpu < s->num_cpu && irq < GIC_INTERNAL) || cpu == 0) {
|
||||||
|
kvm_gicd_access(s, offset, cpu, ®, false);
|
||||||
|
for (j = 0; j < regsz; j++) {
|
||||||
|
field = extract32(reg, j * width, width);
|
||||||
|
translate_fn(s, irq + j, cpu, &field, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
cpu++;
|
||||||
|
}
|
||||||
|
offset += 4;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Write a register group to the kernel VGIC */
|
||||||
|
static void kvm_dist_put(GICState *s, uint32_t offset, int width,
|
||||||
|
int maxirq, vgic_translate_fn translate_fn)
|
||||||
|
{
|
||||||
|
uint32_t reg;
|
||||||
|
int i;
|
||||||
|
int j;
|
||||||
|
int irq;
|
||||||
|
int cpu;
|
||||||
|
int regsz = 32 / width; /* irqs per kernel register */
|
||||||
|
uint32_t field;
|
||||||
|
|
||||||
|
for_each_irq_reg(i, maxirq, width) {
|
||||||
|
irq = i * regsz;
|
||||||
|
cpu = 0;
|
||||||
|
while ((cpu < s->num_cpu && irq < GIC_INTERNAL) || cpu == 0) {
|
||||||
|
reg = 0;
|
||||||
|
for (j = 0; j < regsz; j++) {
|
||||||
|
translate_fn(s, irq + j, cpu, &field, true);
|
||||||
|
reg = deposit32(reg, j * width, width, field);
|
||||||
|
}
|
||||||
|
kvm_gicd_access(s, offset, cpu, ®, true);
|
||||||
|
|
||||||
|
cpu++;
|
||||||
|
}
|
||||||
|
offset += 4;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static void kvm_arm_gic_put(GICState *s)
|
static void kvm_arm_gic_put(GICState *s)
|
||||||
{
|
{
|
||||||
/* TODO: there isn't currently a kernel interface to set the GIC state */
|
uint32_t reg;
|
||||||
|
int i;
|
||||||
|
int cpu;
|
||||||
|
int num_cpu;
|
||||||
|
int num_irq;
|
||||||
|
|
||||||
|
if (!kvm_arm_gic_can_save_restore(s)) {
|
||||||
|
DPRINTF("Cannot put kernel gic state, no kernel interface");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Note: We do the restore in a slightly different order than the save
|
||||||
|
* (where the order doesn't matter and is simply ordered according to the
|
||||||
|
* register offset values */
|
||||||
|
|
||||||
|
/*****************************************************************
|
||||||
|
* Distributor State
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* s->enabled -> GICD_CTLR */
|
||||||
|
reg = s->enabled;
|
||||||
|
kvm_gicd_access(s, 0x0, 0, ®, true);
|
||||||
|
|
||||||
|
/* Sanity checking on GICD_TYPER and s->num_irq, s->num_cpu */
|
||||||
|
kvm_gicd_access(s, 0x4, 0, ®, false);
|
||||||
|
num_irq = ((reg & 0x1f) + 1) * 32;
|
||||||
|
num_cpu = ((reg & 0xe0) >> 5) + 1;
|
||||||
|
|
||||||
|
if (num_irq < s->num_irq) {
|
||||||
|
fprintf(stderr, "Restoring %u IRQs, but kernel supports max %d\n",
|
||||||
|
s->num_irq, num_irq);
|
||||||
|
abort();
|
||||||
|
} else if (num_cpu != s->num_cpu) {
|
||||||
|
fprintf(stderr, "Restoring %u CPU interfaces, kernel only has %d\n",
|
||||||
|
s->num_cpu, num_cpu);
|
||||||
|
/* Did we not create the VCPUs in the kernel yet? */
|
||||||
|
abort();
|
||||||
|
}
|
||||||
|
|
||||||
|
/* TODO: Consider checking compatibility with the IIDR ? */
|
||||||
|
|
||||||
|
/* irq_state[n].enabled -> GICD_ISENABLERn */
|
||||||
|
kvm_dist_put(s, 0x180, 1, s->num_irq, translate_clear);
|
||||||
|
kvm_dist_put(s, 0x100, 1, s->num_irq, translate_enabled);
|
||||||
|
|
||||||
|
/* s->irq_target[irq] -> GICD_ITARGETSRn
|
||||||
|
* (restore targets before pending to ensure the pending state is set on
|
||||||
|
* the appropriate CPU interfaces in the kernel) */
|
||||||
|
kvm_dist_put(s, 0x800, 8, s->num_irq, translate_targets);
|
||||||
|
|
||||||
|
/* irq_state[n].pending + irq_state[n].level -> GICD_ISPENDRn */
|
||||||
|
kvm_dist_put(s, 0x280, 1, s->num_irq, translate_clear);
|
||||||
|
kvm_dist_put(s, 0x200, 1, s->num_irq, translate_pending);
|
||||||
|
|
||||||
|
/* irq_state[n].active -> GICD_ISACTIVERn */
|
||||||
|
kvm_dist_put(s, 0x380, 1, s->num_irq, translate_clear);
|
||||||
|
kvm_dist_put(s, 0x300, 1, s->num_irq, translate_active);
|
||||||
|
|
||||||
|
/* irq_state[n].trigger -> GICD_ICFRn */
|
||||||
|
kvm_dist_put(s, 0xc00, 2, s->num_irq, translate_trigger);
|
||||||
|
|
||||||
|
/* s->priorityX[irq] -> ICD_IPRIORITYRn */
|
||||||
|
kvm_dist_put(s, 0x400, 8, s->num_irq, translate_priority);
|
||||||
|
|
||||||
|
/* s->sgi_pending -> ICD_CPENDSGIRn */
|
||||||
|
kvm_dist_put(s, 0xf10, 8, GIC_NR_SGIS, translate_clear);
|
||||||
|
kvm_dist_put(s, 0xf20, 8, GIC_NR_SGIS, translate_sgisource);
|
||||||
|
|
||||||
|
|
||||||
|
/*****************************************************************
|
||||||
|
* CPU Interface(s) State
|
||||||
|
*/
|
||||||
|
|
||||||
|
for (cpu = 0; cpu < s->num_cpu; cpu++) {
|
||||||
|
/* s->cpu_enabled[cpu] -> GICC_CTLR */
|
||||||
|
reg = s->cpu_enabled[cpu];
|
||||||
|
kvm_gicc_access(s, 0x00, cpu, ®, true);
|
||||||
|
|
||||||
|
/* s->priority_mask[cpu] -> GICC_PMR */
|
||||||
|
reg = (s->priority_mask[cpu] & 0xff);
|
||||||
|
kvm_gicc_access(s, 0x04, cpu, ®, true);
|
||||||
|
|
||||||
|
/* s->bpr[cpu] -> GICC_BPR */
|
||||||
|
reg = (s->bpr[cpu] & 0x7);
|
||||||
|
kvm_gicc_access(s, 0x08, cpu, ®, true);
|
||||||
|
|
||||||
|
/* s->abpr[cpu] -> GICC_ABPR */
|
||||||
|
reg = (s->abpr[cpu] & 0x7);
|
||||||
|
kvm_gicc_access(s, 0x1c, cpu, ®, true);
|
||||||
|
|
||||||
|
/* s->apr[n][cpu] -> GICC_APRn */
|
||||||
|
for (i = 0; i < 4; i++) {
|
||||||
|
reg = s->apr[i][cpu];
|
||||||
|
kvm_gicc_access(s, 0xd0 + i * 4, cpu, ®, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void kvm_arm_gic_get(GICState *s)
|
static void kvm_arm_gic_get(GICState *s)
|
||||||
{
|
{
|
||||||
/* TODO: there isn't currently a kernel interface to get the GIC state */
|
uint32_t reg;
|
||||||
|
int i;
|
||||||
|
int cpu;
|
||||||
|
|
||||||
|
if (!kvm_arm_gic_can_save_restore(s)) {
|
||||||
|
DPRINTF("Cannot get kernel gic state, no kernel interface");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*****************************************************************
|
||||||
|
* Distributor State
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* GICD_CTLR -> s->enabled */
|
||||||
|
kvm_gicd_access(s, 0x0, 0, ®, false);
|
||||||
|
s->enabled = reg & 1;
|
||||||
|
|
||||||
|
/* Sanity checking on GICD_TYPER -> s->num_irq, s->num_cpu */
|
||||||
|
kvm_gicd_access(s, 0x4, 0, ®, false);
|
||||||
|
s->num_irq = ((reg & 0x1f) + 1) * 32;
|
||||||
|
s->num_cpu = ((reg & 0xe0) >> 5) + 1;
|
||||||
|
|
||||||
|
if (s->num_irq > GIC_MAXIRQ) {
|
||||||
|
fprintf(stderr, "Too many IRQs reported from the kernel: %d\n",
|
||||||
|
s->num_irq);
|
||||||
|
abort();
|
||||||
|
}
|
||||||
|
|
||||||
|
/* GICD_IIDR -> ? */
|
||||||
|
kvm_gicd_access(s, 0x8, 0, ®, false);
|
||||||
|
|
||||||
|
/* Verify no GROUP 1 interrupts configured in the kernel */
|
||||||
|
for_each_irq_reg(i, s->num_irq, 1) {
|
||||||
|
kvm_gicd_access(s, 0x80 + (i * 4), 0, ®, false);
|
||||||
|
if (reg != 0) {
|
||||||
|
fprintf(stderr, "Unsupported GICD_IGROUPRn value: %08x\n",
|
||||||
|
reg);
|
||||||
|
abort();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Clear all the IRQ settings */
|
||||||
|
for (i = 0; i < s->num_irq; i++) {
|
||||||
|
memset(&s->irq_state[i], 0, sizeof(s->irq_state[0]));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* GICD_ISENABLERn -> irq_state[n].enabled */
|
||||||
|
kvm_dist_get(s, 0x100, 1, s->num_irq, translate_enabled);
|
||||||
|
|
||||||
|
/* GICD_ISPENDRn -> irq_state[n].pending + irq_state[n].level */
|
||||||
|
kvm_dist_get(s, 0x200, 1, s->num_irq, translate_pending);
|
||||||
|
|
||||||
|
/* GICD_ISACTIVERn -> irq_state[n].active */
|
||||||
|
kvm_dist_get(s, 0x300, 1, s->num_irq, translate_active);
|
||||||
|
|
||||||
|
/* GICD_ICFRn -> irq_state[n].trigger */
|
||||||
|
kvm_dist_get(s, 0xc00, 2, s->num_irq, translate_trigger);
|
||||||
|
|
||||||
|
/* GICD_IPRIORITYRn -> s->priorityX[irq] */
|
||||||
|
kvm_dist_get(s, 0x400, 8, s->num_irq, translate_priority);
|
||||||
|
|
||||||
|
/* GICD_ITARGETSRn -> s->irq_target[irq] */
|
||||||
|
kvm_dist_get(s, 0x800, 8, s->num_irq, translate_targets);
|
||||||
|
|
||||||
|
/* GICD_CPENDSGIRn -> s->sgi_pending */
|
||||||
|
kvm_dist_get(s, 0xf10, 8, GIC_NR_SGIS, translate_sgisource);
|
||||||
|
|
||||||
|
|
||||||
|
/*****************************************************************
|
||||||
|
* CPU Interface(s) State
|
||||||
|
*/
|
||||||
|
|
||||||
|
for (cpu = 0; cpu < s->num_cpu; cpu++) {
|
||||||
|
/* GICC_CTLR -> s->cpu_enabled[cpu] */
|
||||||
|
kvm_gicc_access(s, 0x00, cpu, ®, false);
|
||||||
|
s->cpu_enabled[cpu] = (reg & 1);
|
||||||
|
|
||||||
|
/* GICC_PMR -> s->priority_mask[cpu] */
|
||||||
|
kvm_gicc_access(s, 0x04, cpu, ®, false);
|
||||||
|
s->priority_mask[cpu] = (reg & 0xff);
|
||||||
|
|
||||||
|
/* GICC_BPR -> s->bpr[cpu] */
|
||||||
|
kvm_gicc_access(s, 0x08, cpu, ®, false);
|
||||||
|
s->bpr[cpu] = (reg & 0x7);
|
||||||
|
|
||||||
|
/* GICC_ABPR -> s->abpr[cpu] */
|
||||||
|
kvm_gicc_access(s, 0x1c, cpu, ®, false);
|
||||||
|
s->abpr[cpu] = (reg & 0x7);
|
||||||
|
|
||||||
|
/* GICC_APRn -> s->apr[n][cpu] */
|
||||||
|
for (i = 0; i < 4; i++) {
|
||||||
|
kvm_gicc_access(s, 0xd0 + i * 4, cpu, ®, false);
|
||||||
|
s->apr[i][cpu] = reg;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void kvm_arm_gic_reset(DeviceState *dev)
|
static void kvm_arm_gic_reset(DeviceState *dev)
|
||||||
@@ -97,6 +517,7 @@ static void kvm_arm_gic_realize(DeviceState *dev, Error **errp)
|
|||||||
GICState *s = KVM_ARM_GIC(dev);
|
GICState *s = KVM_ARM_GIC(dev);
|
||||||
SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
|
SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
|
||||||
KVMARMGICClass *kgc = KVM_ARM_GIC_GET_CLASS(s);
|
KVMARMGICClass *kgc = KVM_ARM_GIC_GET_CLASS(s);
|
||||||
|
int ret;
|
||||||
|
|
||||||
kgc->parent_realize(dev, errp);
|
kgc->parent_realize(dev, errp);
|
||||||
if (error_is_set(errp)) {
|
if (error_is_set(errp)) {
|
||||||
@@ -119,13 +540,27 @@ static void kvm_arm_gic_realize(DeviceState *dev, Error **errp)
|
|||||||
for (i = 0; i < s->num_cpu; i++) {
|
for (i = 0; i < s->num_cpu; i++) {
|
||||||
sysbus_init_irq(sbd, &s->parent_irq[i]);
|
sysbus_init_irq(sbd, &s->parent_irq[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Try to create the device via the device control API */
|
||||||
|
s->dev_fd = -1;
|
||||||
|
ret = kvm_create_device(kvm_state, KVM_DEV_TYPE_ARM_VGIC_V2, false);
|
||||||
|
if (ret >= 0) {
|
||||||
|
s->dev_fd = ret;
|
||||||
|
} else if (ret != -ENODEV && ret != -ENOTSUP) {
|
||||||
|
error_setg_errno(errp, -ret, "error creating in-kernel VGIC");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
/* Distributor */
|
/* Distributor */
|
||||||
memory_region_init_reservation(&s->iomem, OBJECT(s),
|
memory_region_init_reservation(&s->iomem, OBJECT(s),
|
||||||
"kvm-gic_dist", 0x1000);
|
"kvm-gic_dist", 0x1000);
|
||||||
sysbus_init_mmio(sbd, &s->iomem);
|
sysbus_init_mmio(sbd, &s->iomem);
|
||||||
kvm_arm_register_device(&s->iomem,
|
kvm_arm_register_device(&s->iomem,
|
||||||
(KVM_ARM_DEVICE_VGIC_V2 << KVM_ARM_DEVICE_ID_SHIFT)
|
(KVM_ARM_DEVICE_VGIC_V2 << KVM_ARM_DEVICE_ID_SHIFT)
|
||||||
| KVM_VGIC_V2_ADDR_TYPE_DIST);
|
| KVM_VGIC_V2_ADDR_TYPE_DIST,
|
||||||
|
KVM_DEV_ARM_VGIC_GRP_ADDR,
|
||||||
|
KVM_VGIC_V2_ADDR_TYPE_DIST,
|
||||||
|
s->dev_fd);
|
||||||
/* CPU interface for current core. Unlike arm_gic, we don't
|
/* CPU interface for current core. Unlike arm_gic, we don't
|
||||||
* provide the "interface for core #N" memory regions, because
|
* provide the "interface for core #N" memory regions, because
|
||||||
* cores with a VGIC don't have those.
|
* cores with a VGIC don't have those.
|
||||||
@@ -135,7 +570,10 @@ static void kvm_arm_gic_realize(DeviceState *dev, Error **errp)
|
|||||||
sysbus_init_mmio(sbd, &s->cpuiomem[0]);
|
sysbus_init_mmio(sbd, &s->cpuiomem[0]);
|
||||||
kvm_arm_register_device(&s->cpuiomem[0],
|
kvm_arm_register_device(&s->cpuiomem[0],
|
||||||
(KVM_ARM_DEVICE_VGIC_V2 << KVM_ARM_DEVICE_ID_SHIFT)
|
(KVM_ARM_DEVICE_VGIC_V2 << KVM_ARM_DEVICE_ID_SHIFT)
|
||||||
| KVM_VGIC_V2_ADDR_TYPE_CPU);
|
| KVM_VGIC_V2_ADDR_TYPE_CPU,
|
||||||
|
KVM_DEV_ARM_VGIC_GRP_ADDR,
|
||||||
|
KVM_VGIC_V2_ADDR_TYPE_CPU,
|
||||||
|
s->dev_fd);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void kvm_arm_gic_class_init(ObjectClass *klass, void *data)
|
static void kvm_arm_gic_class_init(ObjectClass *klass, void *data)
|
||||||
|
@@ -418,7 +418,7 @@ static int exynos4210_combiner_init(SysBusDevice *sbd)
|
|||||||
qdev_init_gpio_in(dev, exynos4210_combiner_handler, IIC_NIRQ);
|
qdev_init_gpio_in(dev, exynos4210_combiner_handler, IIC_NIRQ);
|
||||||
|
|
||||||
/* Connect SysBusDev irqs to device specific irqs */
|
/* Connect SysBusDev irqs to device specific irqs */
|
||||||
for (i = 0; i < IIC_NIRQ; i++) {
|
for (i = 0; i < IIC_NGRP; i++) {
|
||||||
sysbus_init_irq(sbd, &s->output_irq[i]);
|
sysbus_init_irq(sbd, &s->output_irq[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -40,7 +40,7 @@
|
|||||||
#define GIC_SET_MODEL(irq) s->irq_state[irq].model = true
|
#define GIC_SET_MODEL(irq) s->irq_state[irq].model = true
|
||||||
#define GIC_CLEAR_MODEL(irq) s->irq_state[irq].model = false
|
#define GIC_CLEAR_MODEL(irq) s->irq_state[irq].model = false
|
||||||
#define GIC_TEST_MODEL(irq) s->irq_state[irq].model
|
#define GIC_TEST_MODEL(irq) s->irq_state[irq].model
|
||||||
#define GIC_SET_LEVEL(irq, cm) s->irq_state[irq].level = (cm)
|
#define GIC_SET_LEVEL(irq, cm) s->irq_state[irq].level |= (cm)
|
||||||
#define GIC_CLEAR_LEVEL(irq, cm) s->irq_state[irq].level &= ~(cm)
|
#define GIC_CLEAR_LEVEL(irq, cm) s->irq_state[irq].level &= ~(cm)
|
||||||
#define GIC_TEST_LEVEL(irq, cm) ((s->irq_state[irq].level & (cm)) != 0)
|
#define GIC_TEST_LEVEL(irq, cm) ((s->irq_state[irq].level & (cm)) != 0)
|
||||||
#define GIC_SET_EDGE_TRIGGER(irq) s->irq_state[irq].edge_trigger = true
|
#define GIC_SET_EDGE_TRIGGER(irq) s->irq_state[irq].edge_trigger = true
|
||||||
|
@@ -228,7 +228,7 @@ int kvm_openpic_connect_vcpu(DeviceState *d, CPUState *cs)
|
|||||||
|
|
||||||
encap.cap = KVM_CAP_IRQ_MPIC;
|
encap.cap = KVM_CAP_IRQ_MPIC;
|
||||||
encap.args[0] = opp->fd;
|
encap.args[0] = opp->fd;
|
||||||
encap.args[1] = cs->cpu_index;
|
encap.args[1] = kvm_arch_vcpu_id(cs);
|
||||||
|
|
||||||
return kvm_vcpu_ioctl(cs, KVM_ENABLE_CAP, &encap);
|
return kvm_vcpu_ioctl(cs, KVM_ENABLE_CAP, &encap);
|
||||||
}
|
}
|
||||||
|
322
hw/intc/s390_flic.c
Normal file
322
hw/intc/s390_flic.c
Normal file
@@ -0,0 +1,322 @@
|
|||||||
|
/*
|
||||||
|
* QEMU S390x KVM floating interrupt controller (flic)
|
||||||
|
*
|
||||||
|
* Copyright 2014 IBM Corp.
|
||||||
|
* Author(s): Jens Freimann <jfrei@linux.vnet.ibm.com>
|
||||||
|
*
|
||||||
|
* This work is licensed under the terms of the GNU GPL, version 2 or (at
|
||||||
|
* your option) any later version. See the COPYING file in the top-level
|
||||||
|
* directory.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <sys/ioctl.h>
|
||||||
|
#include "qemu/error-report.h"
|
||||||
|
#include "hw/sysbus.h"
|
||||||
|
#include "sysemu/kvm.h"
|
||||||
|
#include "migration/qemu-file.h"
|
||||||
|
#include "hw/s390x/s390_flic.h"
|
||||||
|
#include "trace.h"
|
||||||
|
|
||||||
|
#define FLIC_SAVE_INITIAL_SIZE getpagesize()
|
||||||
|
#define FLIC_FAILED (-1UL)
|
||||||
|
#define FLIC_SAVEVM_VERSION 1
|
||||||
|
|
||||||
|
void s390_flic_init(void)
|
||||||
|
{
|
||||||
|
DeviceState *dev;
|
||||||
|
int r;
|
||||||
|
|
||||||
|
if (kvm_enabled()) {
|
||||||
|
dev = qdev_create(NULL, "s390-flic");
|
||||||
|
object_property_add_child(qdev_get_machine(), "s390-flic",
|
||||||
|
OBJECT(dev), NULL);
|
||||||
|
r = qdev_init(dev);
|
||||||
|
if (r) {
|
||||||
|
error_report("flic: couldn't create qdev");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* flic_get_all_irqs - store all pending irqs in buffer
|
||||||
|
* @buf: pointer to buffer which is passed to kernel
|
||||||
|
* @len: length of buffer
|
||||||
|
* @flic: pointer to flic device state
|
||||||
|
*
|
||||||
|
* Returns: -ENOMEM if buffer is too small,
|
||||||
|
* -EINVAL if attr.group is invalid,
|
||||||
|
* -EFAULT if copying to userspace failed,
|
||||||
|
* on success return number of stored interrupts
|
||||||
|
*/
|
||||||
|
static int flic_get_all_irqs(KVMS390FLICState *flic,
|
||||||
|
void *buf, int len)
|
||||||
|
{
|
||||||
|
struct kvm_device_attr attr = {
|
||||||
|
.group = KVM_DEV_FLIC_GET_ALL_IRQS,
|
||||||
|
.addr = (uint64_t) buf,
|
||||||
|
.attr = len,
|
||||||
|
};
|
||||||
|
int rc;
|
||||||
|
|
||||||
|
rc = ioctl(flic->fd, KVM_GET_DEVICE_ATTR, &attr);
|
||||||
|
|
||||||
|
return rc == -1 ? -errno : rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void flic_enable_pfault(KVMS390FLICState *flic)
|
||||||
|
{
|
||||||
|
struct kvm_device_attr attr = {
|
||||||
|
.group = KVM_DEV_FLIC_APF_ENABLE,
|
||||||
|
};
|
||||||
|
int rc;
|
||||||
|
|
||||||
|
rc = ioctl(flic->fd, KVM_SET_DEVICE_ATTR, &attr);
|
||||||
|
|
||||||
|
if (rc) {
|
||||||
|
fprintf(stderr, "flic: couldn't enable pfault\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void flic_disable_wait_pfault(KVMS390FLICState *flic)
|
||||||
|
{
|
||||||
|
struct kvm_device_attr attr = {
|
||||||
|
.group = KVM_DEV_FLIC_APF_DISABLE_WAIT,
|
||||||
|
};
|
||||||
|
int rc;
|
||||||
|
|
||||||
|
rc = ioctl(flic->fd, KVM_SET_DEVICE_ATTR, &attr);
|
||||||
|
|
||||||
|
if (rc) {
|
||||||
|
fprintf(stderr, "flic: couldn't disable pfault\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** flic_enqueue_irqs - returns 0 on success
|
||||||
|
* @buf: pointer to buffer which is passed to kernel
|
||||||
|
* @len: length of buffer
|
||||||
|
* @flic: pointer to flic device state
|
||||||
|
*
|
||||||
|
* Returns: -EINVAL if attr.group is unknown
|
||||||
|
*/
|
||||||
|
static int flic_enqueue_irqs(void *buf, uint64_t len,
|
||||||
|
KVMS390FLICState *flic)
|
||||||
|
{
|
||||||
|
int rc;
|
||||||
|
struct kvm_device_attr attr = {
|
||||||
|
.group = KVM_DEV_FLIC_ENQUEUE,
|
||||||
|
.addr = (uint64_t) buf,
|
||||||
|
.attr = len,
|
||||||
|
};
|
||||||
|
|
||||||
|
rc = ioctl(flic->fd, KVM_SET_DEVICE_ATTR, &attr);
|
||||||
|
|
||||||
|
return rc ? -errno : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* __get_all_irqs - store all pending irqs in buffer
|
||||||
|
* @flic: pointer to flic device state
|
||||||
|
* @buf: pointer to pointer to a buffer
|
||||||
|
* @len: length of buffer
|
||||||
|
*
|
||||||
|
* Returns: return value of flic_get_all_irqs
|
||||||
|
* Note: Retry and increase buffer size until flic_get_all_irqs
|
||||||
|
* either returns a value >= 0 or a negative error code.
|
||||||
|
* -ENOMEM is an exception, which means the buffer is too small
|
||||||
|
* and we should try again. Other negative error codes can be
|
||||||
|
* -EFAULT and -EINVAL which we ignore at this point
|
||||||
|
*/
|
||||||
|
static int __get_all_irqs(KVMS390FLICState *flic,
|
||||||
|
void **buf, int len)
|
||||||
|
{
|
||||||
|
int r;
|
||||||
|
|
||||||
|
do {
|
||||||
|
/* returns -ENOMEM if buffer is too small and number
|
||||||
|
* of queued interrupts on success */
|
||||||
|
r = flic_get_all_irqs(flic, *buf, len);
|
||||||
|
if (r >= 0) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
len *= 2;
|
||||||
|
*buf = g_try_realloc(*buf, len);
|
||||||
|
if (!buf) {
|
||||||
|
return -ENOMEM;
|
||||||
|
}
|
||||||
|
} while (r == -ENOMEM && len <= KVM_S390_FLIC_MAX_BUFFER);
|
||||||
|
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* kvm_flic_save - Save pending floating interrupts
|
||||||
|
* @f: QEMUFile containing migration state
|
||||||
|
* @opaque: pointer to flic device state
|
||||||
|
*
|
||||||
|
* Note: Pass buf and len to kernel. Start with one page and
|
||||||
|
* increase until buffer is sufficient or maxium size is
|
||||||
|
* reached
|
||||||
|
*/
|
||||||
|
static void kvm_flic_save(QEMUFile *f, void *opaque)
|
||||||
|
{
|
||||||
|
KVMS390FLICState *flic = opaque;
|
||||||
|
int len = FLIC_SAVE_INITIAL_SIZE;
|
||||||
|
void *buf;
|
||||||
|
int count;
|
||||||
|
|
||||||
|
flic_disable_wait_pfault((struct KVMS390FLICState *) opaque);
|
||||||
|
|
||||||
|
buf = g_try_malloc0(len);
|
||||||
|
if (!buf) {
|
||||||
|
/* Storing FLIC_FAILED into the count field here will cause the
|
||||||
|
* target system to fail when attempting to load irqs from the
|
||||||
|
* migration state */
|
||||||
|
error_report("flic: couldn't allocate memory");
|
||||||
|
qemu_put_be64(f, FLIC_FAILED);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
count = __get_all_irqs(flic, &buf, len);
|
||||||
|
if (count < 0) {
|
||||||
|
error_report("flic: couldn't retrieve irqs from kernel, rc %d",
|
||||||
|
count);
|
||||||
|
/* Storing FLIC_FAILED into the count field here will cause the
|
||||||
|
* target system to fail when attempting to load irqs from the
|
||||||
|
* migration state */
|
||||||
|
qemu_put_be64(f, FLIC_FAILED);
|
||||||
|
} else {
|
||||||
|
qemu_put_be64(f, count);
|
||||||
|
qemu_put_buffer(f, (uint8_t *) buf,
|
||||||
|
count * sizeof(struct kvm_s390_irq));
|
||||||
|
}
|
||||||
|
g_free(buf);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* kvm_flic_load - Load pending floating interrupts
|
||||||
|
* @f: QEMUFile containing migration state
|
||||||
|
* @opaque: pointer to flic device state
|
||||||
|
* @version_id: version id for migration
|
||||||
|
*
|
||||||
|
* Returns: value of flic_enqueue_irqs, -EINVAL on error
|
||||||
|
* Note: Do nothing when no interrupts where stored
|
||||||
|
* in QEMUFile
|
||||||
|
*/
|
||||||
|
static int kvm_flic_load(QEMUFile *f, void *opaque, int version_id)
|
||||||
|
{
|
||||||
|
uint64_t len = 0;
|
||||||
|
uint64_t count = 0;
|
||||||
|
void *buf = NULL;
|
||||||
|
int r = 0;
|
||||||
|
|
||||||
|
if (version_id != FLIC_SAVEVM_VERSION) {
|
||||||
|
r = -EINVAL;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
flic_enable_pfault((struct KVMS390FLICState *) opaque);
|
||||||
|
|
||||||
|
count = qemu_get_be64(f);
|
||||||
|
len = count * sizeof(struct kvm_s390_irq);
|
||||||
|
if (count == FLIC_FAILED) {
|
||||||
|
r = -EINVAL;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
if (count == 0) {
|
||||||
|
r = 0;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
buf = g_try_malloc0(len);
|
||||||
|
if (!buf) {
|
||||||
|
r = -ENOMEM;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (qemu_get_buffer(f, (uint8_t *) buf, len) != len) {
|
||||||
|
r = -EINVAL;
|
||||||
|
goto out_free;
|
||||||
|
}
|
||||||
|
r = flic_enqueue_irqs(buf, len, (struct KVMS390FLICState *) opaque);
|
||||||
|
|
||||||
|
out_free:
|
||||||
|
g_free(buf);
|
||||||
|
out:
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void kvm_s390_flic_realize(DeviceState *dev, Error **errp)
|
||||||
|
{
|
||||||
|
KVMS390FLICState *flic_state = KVM_S390_FLIC(dev);
|
||||||
|
struct kvm_create_device cd = {0};
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
flic_state->fd = -1;
|
||||||
|
if (!kvm_check_extension(kvm_state, KVM_CAP_DEVICE_CTRL)) {
|
||||||
|
trace_flic_no_device_api(errno);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
cd.type = KVM_DEV_TYPE_FLIC;
|
||||||
|
ret = kvm_vm_ioctl(kvm_state, KVM_CREATE_DEVICE, &cd);
|
||||||
|
if (ret < 0) {
|
||||||
|
trace_flic_create_device(errno);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
flic_state->fd = cd.fd;
|
||||||
|
|
||||||
|
/* Register savevm handler for floating interrupts */
|
||||||
|
register_savevm(NULL, "s390-flic", 0, 1, kvm_flic_save,
|
||||||
|
kvm_flic_load, (void *) flic_state);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void kvm_s390_flic_unrealize(DeviceState *dev, Error **errp)
|
||||||
|
{
|
||||||
|
KVMS390FLICState *flic_state = KVM_S390_FLIC(dev);
|
||||||
|
|
||||||
|
unregister_savevm(DEVICE(flic_state), "s390-flic", flic_state);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void kvm_s390_flic_reset(DeviceState *dev)
|
||||||
|
{
|
||||||
|
KVMS390FLICState *flic = KVM_S390_FLIC(dev);
|
||||||
|
struct kvm_device_attr attr = {
|
||||||
|
.group = KVM_DEV_FLIC_CLEAR_IRQS,
|
||||||
|
};
|
||||||
|
int rc = 0;
|
||||||
|
|
||||||
|
if (flic->fd == -1) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
flic_disable_wait_pfault(flic);
|
||||||
|
|
||||||
|
rc = ioctl(flic->fd, KVM_SET_DEVICE_ATTR, &attr);
|
||||||
|
if (rc) {
|
||||||
|
trace_flic_reset_failed(errno);
|
||||||
|
}
|
||||||
|
|
||||||
|
flic_enable_pfault(flic);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void kvm_s390_flic_class_init(ObjectClass *oc, void *data)
|
||||||
|
{
|
||||||
|
DeviceClass *dc = DEVICE_CLASS(oc);
|
||||||
|
|
||||||
|
dc->realize = kvm_s390_flic_realize;
|
||||||
|
dc->unrealize = kvm_s390_flic_unrealize;
|
||||||
|
dc->reset = kvm_s390_flic_reset;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const TypeInfo kvm_s390_flic_info = {
|
||||||
|
.name = TYPE_KVM_S390_FLIC,
|
||||||
|
.parent = TYPE_SYS_BUS_DEVICE,
|
||||||
|
.instance_size = sizeof(KVMS390FLICState),
|
||||||
|
.class_init = kvm_s390_flic_class_init,
|
||||||
|
};
|
||||||
|
|
||||||
|
static void kvm_s390_flic_register_types(void)
|
||||||
|
{
|
||||||
|
type_register_static(&kvm_s390_flic_info);
|
||||||
|
}
|
||||||
|
|
||||||
|
type_init(kvm_s390_flic_register_types)
|
@@ -33,6 +33,17 @@
|
|||||||
#include "qemu/error-report.h"
|
#include "qemu/error-report.h"
|
||||||
#include "qapi/visitor.h"
|
#include "qapi/visitor.h"
|
||||||
|
|
||||||
|
static int get_cpu_index_by_dt_id(int cpu_dt_id)
|
||||||
|
{
|
||||||
|
PowerPCCPU *cpu = ppc_get_vcpu_by_dt_id(cpu_dt_id);
|
||||||
|
|
||||||
|
if (cpu) {
|
||||||
|
return cpu->parent_obj.cpu_index;
|
||||||
|
}
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
void xics_cpu_setup(XICSState *icp, PowerPCCPU *cpu)
|
void xics_cpu_setup(XICSState *icp, PowerPCCPU *cpu)
|
||||||
{
|
{
|
||||||
CPUState *cs = CPU(cpu);
|
CPUState *cs = CPU(cpu);
|
||||||
@@ -659,7 +670,7 @@ static target_ulong h_cppr(PowerPCCPU *cpu, sPAPREnvironment *spapr,
|
|||||||
static target_ulong h_ipi(PowerPCCPU *cpu, sPAPREnvironment *spapr,
|
static target_ulong h_ipi(PowerPCCPU *cpu, sPAPREnvironment *spapr,
|
||||||
target_ulong opcode, target_ulong *args)
|
target_ulong opcode, target_ulong *args)
|
||||||
{
|
{
|
||||||
target_ulong server = args[0];
|
target_ulong server = get_cpu_index_by_dt_id(args[0]);
|
||||||
target_ulong mfrr = args[1];
|
target_ulong mfrr = args[1];
|
||||||
|
|
||||||
if (server >= spapr->icp->nr_servers) {
|
if (server >= spapr->icp->nr_servers) {
|
||||||
@@ -728,7 +739,7 @@ static void rtas_set_xive(PowerPCCPU *cpu, sPAPREnvironment *spapr,
|
|||||||
}
|
}
|
||||||
|
|
||||||
nr = rtas_ld(args, 0);
|
nr = rtas_ld(args, 0);
|
||||||
server = rtas_ld(args, 1);
|
server = get_cpu_index_by_dt_id(rtas_ld(args, 1));
|
||||||
priority = rtas_ld(args, 2);
|
priority = rtas_ld(args, 2);
|
||||||
|
|
||||||
if (!ics_valid_irq(ics, nr) || (server >= ics->icp->nr_servers)
|
if (!ics_valid_irq(ics, nr) || (server >= ics->icp->nr_servers)
|
||||||
|
@@ -65,7 +65,7 @@ static void icp_get_kvm_state(ICPState *ss)
|
|||||||
ret = kvm_vcpu_ioctl(ss->cs, KVM_GET_ONE_REG, ®);
|
ret = kvm_vcpu_ioctl(ss->cs, KVM_GET_ONE_REG, ®);
|
||||||
if (ret != 0) {
|
if (ret != 0) {
|
||||||
error_report("Unable to retrieve KVM interrupt controller state"
|
error_report("Unable to retrieve KVM interrupt controller state"
|
||||||
" for CPU %d: %s", ss->cs->cpu_index, strerror(errno));
|
" for CPU %ld: %s", kvm_arch_vcpu_id(ss->cs), strerror(errno));
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -97,7 +97,7 @@ static int icp_set_kvm_state(ICPState *ss, int version_id)
|
|||||||
ret = kvm_vcpu_ioctl(ss->cs, KVM_SET_ONE_REG, ®);
|
ret = kvm_vcpu_ioctl(ss->cs, KVM_SET_ONE_REG, ®);
|
||||||
if (ret != 0) {
|
if (ret != 0) {
|
||||||
error_report("Unable to restore KVM interrupt controller state (0x%"
|
error_report("Unable to restore KVM interrupt controller state (0x%"
|
||||||
PRIx64 ") for CPU %d: %s", state, ss->cs->cpu_index,
|
PRIx64 ") for CPU %ld: %s", state, kvm_arch_vcpu_id(ss->cs),
|
||||||
strerror(errno));
|
strerror(errno));
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
@@ -325,15 +325,15 @@ static void xics_kvm_cpu_setup(XICSState *icp, PowerPCCPU *cpu)
|
|||||||
struct kvm_enable_cap xics_enable_cap = {
|
struct kvm_enable_cap xics_enable_cap = {
|
||||||
.cap = KVM_CAP_IRQ_XICS,
|
.cap = KVM_CAP_IRQ_XICS,
|
||||||
.flags = 0,
|
.flags = 0,
|
||||||
.args = {icpkvm->kernel_xics_fd, cs->cpu_index, 0, 0},
|
.args = {icpkvm->kernel_xics_fd, kvm_arch_vcpu_id(cs), 0, 0},
|
||||||
};
|
};
|
||||||
|
|
||||||
ss->cs = cs;
|
ss->cs = cs;
|
||||||
|
|
||||||
ret = kvm_vcpu_ioctl(ss->cs, KVM_ENABLE_CAP, &xics_enable_cap);
|
ret = kvm_vcpu_ioctl(ss->cs, KVM_ENABLE_CAP, &xics_enable_cap);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
error_report("Unable to connect CPU%d to kernel XICS: %s",
|
error_report("Unable to connect CPU%ld to kernel XICS: %s",
|
||||||
cs->cpu_index, strerror(errno));
|
kvm_arch_vcpu_id(cs), strerror(errno));
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -276,7 +276,7 @@ static bool vexpress_cfgctrl_read(arm_sysctl_state *s, unsigned int dcc,
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case SYS_CFG_OSC:
|
case SYS_CFG_OSC:
|
||||||
if (site == SYS_CFG_SITE_MB && device < sizeof(s->mb_clock)) {
|
if (site == SYS_CFG_SITE_MB && device < ARRAY_SIZE(s->mb_clock)) {
|
||||||
/* motherboard clock */
|
/* motherboard clock */
|
||||||
*val = s->mb_clock[device];
|
*val = s->mb_clock[device];
|
||||||
return true;
|
return true;
|
||||||
@@ -324,7 +324,7 @@ static bool vexpress_cfgctrl_write(arm_sysctl_state *s, unsigned int dcc,
|
|||||||
|
|
||||||
switch (function) {
|
switch (function) {
|
||||||
case SYS_CFG_OSC:
|
case SYS_CFG_OSC:
|
||||||
if (site == SYS_CFG_SITE_MB && device < sizeof(s->mb_clock)) {
|
if (site == SYS_CFG_SITE_MB && device < ARRAY_SIZE(s->mb_clock)) {
|
||||||
/* motherboard clock */
|
/* motherboard clock */
|
||||||
s->mb_clock[device] = val;
|
s->mb_clock[device] = val;
|
||||||
return true;
|
return true;
|
||||||
|
@@ -55,7 +55,7 @@ static void load_kernel(MoxieCPU *cpu, LoaderParams *loader_params)
|
|||||||
&entry, &kernel_low, &kernel_high, 1,
|
&entry, &kernel_low, &kernel_high, 1,
|
||||||
ELF_MACHINE, 0);
|
ELF_MACHINE, 0);
|
||||||
|
|
||||||
if (!kernel_size) {
|
if (kernel_size <= 0) {
|
||||||
fprintf(stderr, "qemu: could not load kernel '%s'\n",
|
fprintf(stderr, "qemu: could not load kernel '%s'\n",
|
||||||
loader_params->kernel_filename);
|
loader_params->kernel_filename);
|
||||||
exit(1);
|
exit(1);
|
||||||
|
@@ -32,3 +32,6 @@ obj-$(CONFIG_XILINX_ETHLITE) += xilinx_ethlite.o
|
|||||||
|
|
||||||
obj-$(CONFIG_VIRTIO) += virtio-net.o
|
obj-$(CONFIG_VIRTIO) += virtio-net.o
|
||||||
obj-y += vhost_net.o
|
obj-y += vhost_net.o
|
||||||
|
|
||||||
|
obj-$(CONFIG_ETSEC) += fsl_etsec/etsec.o fsl_etsec/registers.o \
|
||||||
|
fsl_etsec/rings.o fsl_etsec/miim.o
|
||||||
|
465
hw/net/fsl_etsec/etsec.c
Normal file
465
hw/net/fsl_etsec/etsec.c
Normal file
@@ -0,0 +1,465 @@
|
|||||||
|
/*
|
||||||
|
* QEMU Freescale eTSEC Emulator
|
||||||
|
*
|
||||||
|
* Copyright (c) 2011-2013 AdaCore
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This implementation doesn't include ring priority, TCP/IP Off-Load, QoS.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "sysemu/sysemu.h"
|
||||||
|
#include "hw/sysbus.h"
|
||||||
|
#include "trace.h"
|
||||||
|
#include "hw/ptimer.h"
|
||||||
|
#include "etsec.h"
|
||||||
|
#include "registers.h"
|
||||||
|
|
||||||
|
/* #define HEX_DUMP */
|
||||||
|
/* #define DEBUG_REGISTER */
|
||||||
|
|
||||||
|
#ifdef DEBUG_REGISTER
|
||||||
|
static const int debug_etsec = 1;
|
||||||
|
#else
|
||||||
|
static const int debug_etsec;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define DPRINTF(fmt, ...) do { \
|
||||||
|
if (debug_etsec) { \
|
||||||
|
qemu_log(fmt , ## __VA_ARGS__); \
|
||||||
|
} \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
static uint64_t etsec_read(void *opaque, hwaddr addr, unsigned size)
|
||||||
|
{
|
||||||
|
eTSEC *etsec = opaque;
|
||||||
|
uint32_t reg_index = addr / 4;
|
||||||
|
eTSEC_Register *reg = NULL;
|
||||||
|
uint32_t ret = 0x0;
|
||||||
|
|
||||||
|
assert(reg_index < ETSEC_REG_NUMBER);
|
||||||
|
|
||||||
|
reg = &etsec->regs[reg_index];
|
||||||
|
|
||||||
|
|
||||||
|
switch (reg->access) {
|
||||||
|
case ACC_WO:
|
||||||
|
ret = 0x00000000;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case ACC_RW:
|
||||||
|
case ACC_W1C:
|
||||||
|
case ACC_RO:
|
||||||
|
default:
|
||||||
|
ret = reg->value;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
DPRINTF("Read 0x%08x @ 0x" TARGET_FMT_plx
|
||||||
|
" : %s (%s)\n",
|
||||||
|
ret, addr, reg->name, reg->desc);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void write_tstat(eTSEC *etsec,
|
||||||
|
eTSEC_Register *reg,
|
||||||
|
uint32_t reg_index,
|
||||||
|
uint32_t value)
|
||||||
|
{
|
||||||
|
int i = 0;
|
||||||
|
|
||||||
|
for (i = 0; i < 8; i++) {
|
||||||
|
/* Check THLTi flag in TSTAT */
|
||||||
|
if (value & (1 << (31 - i))) {
|
||||||
|
etsec_walk_tx_ring(etsec, i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Write 1 to clear */
|
||||||
|
reg->value &= ~value;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void write_rstat(eTSEC *etsec,
|
||||||
|
eTSEC_Register *reg,
|
||||||
|
uint32_t reg_index,
|
||||||
|
uint32_t value)
|
||||||
|
{
|
||||||
|
int i = 0;
|
||||||
|
|
||||||
|
for (i = 0; i < 8; i++) {
|
||||||
|
/* Check QHLTi flag in RSTAT */
|
||||||
|
if (value & (1 << (23 - i)) && !(reg->value & (1 << (23 - i)))) {
|
||||||
|
etsec_walk_rx_ring(etsec, i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Write 1 to clear */
|
||||||
|
reg->value &= ~value;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void write_tbasex(eTSEC *etsec,
|
||||||
|
eTSEC_Register *reg,
|
||||||
|
uint32_t reg_index,
|
||||||
|
uint32_t value)
|
||||||
|
{
|
||||||
|
reg->value = value & ~0x7;
|
||||||
|
|
||||||
|
/* Copy this value in the ring's TxBD pointer */
|
||||||
|
etsec->regs[TBPTR0 + (reg_index - TBASE0)].value = value & ~0x7;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void write_rbasex(eTSEC *etsec,
|
||||||
|
eTSEC_Register *reg,
|
||||||
|
uint32_t reg_index,
|
||||||
|
uint32_t value)
|
||||||
|
{
|
||||||
|
reg->value = value & ~0x7;
|
||||||
|
|
||||||
|
/* Copy this value in the ring's RxBD pointer */
|
||||||
|
etsec->regs[RBPTR0 + (reg_index - RBASE0)].value = value & ~0x7;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void write_ievent(eTSEC *etsec,
|
||||||
|
eTSEC_Register *reg,
|
||||||
|
uint32_t reg_index,
|
||||||
|
uint32_t value)
|
||||||
|
{
|
||||||
|
/* Write 1 to clear */
|
||||||
|
reg->value &= ~value;
|
||||||
|
|
||||||
|
if (!(reg->value & (IEVENT_TXF | IEVENT_TXF))) {
|
||||||
|
qemu_irq_lower(etsec->tx_irq);
|
||||||
|
}
|
||||||
|
if (!(reg->value & (IEVENT_RXF | IEVENT_RXF))) {
|
||||||
|
qemu_irq_lower(etsec->rx_irq);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(reg->value & (IEVENT_MAG | IEVENT_GTSC | IEVENT_GRSC | IEVENT_TXC |
|
||||||
|
IEVENT_RXC | IEVENT_BABR | IEVENT_BABT | IEVENT_LC |
|
||||||
|
IEVENT_CRL | IEVENT_FGPI | IEVENT_FIR | IEVENT_FIQ |
|
||||||
|
IEVENT_DPE | IEVENT_PERR | IEVENT_EBERR | IEVENT_TXE |
|
||||||
|
IEVENT_XFUN | IEVENT_BSY | IEVENT_MSRO | IEVENT_MMRD |
|
||||||
|
IEVENT_MMRW))) {
|
||||||
|
qemu_irq_lower(etsec->err_irq);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void write_dmactrl(eTSEC *etsec,
|
||||||
|
eTSEC_Register *reg,
|
||||||
|
uint32_t reg_index,
|
||||||
|
uint32_t value)
|
||||||
|
{
|
||||||
|
reg->value = value;
|
||||||
|
|
||||||
|
if (value & DMACTRL_GRS) {
|
||||||
|
|
||||||
|
if (etsec->rx_buffer_len != 0) {
|
||||||
|
/* Graceful receive stop delayed until end of frame */
|
||||||
|
} else {
|
||||||
|
/* Graceful receive stop now */
|
||||||
|
etsec->regs[IEVENT].value |= IEVENT_GRSC;
|
||||||
|
if (etsec->regs[IMASK].value & IMASK_GRSCEN) {
|
||||||
|
qemu_irq_raise(etsec->err_irq);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (value & DMACTRL_GTS) {
|
||||||
|
|
||||||
|
if (etsec->tx_buffer_len != 0) {
|
||||||
|
/* Graceful transmit stop delayed until end of frame */
|
||||||
|
} else {
|
||||||
|
/* Graceful transmit stop now */
|
||||||
|
etsec->regs[IEVENT].value |= IEVENT_GTSC;
|
||||||
|
if (etsec->regs[IMASK].value & IMASK_GTSCEN) {
|
||||||
|
qemu_irq_raise(etsec->err_irq);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(value & DMACTRL_WOP)) {
|
||||||
|
/* Start polling */
|
||||||
|
ptimer_stop(etsec->ptimer);
|
||||||
|
ptimer_set_count(etsec->ptimer, 1);
|
||||||
|
ptimer_run(etsec->ptimer, 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void etsec_write(void *opaque,
|
||||||
|
hwaddr addr,
|
||||||
|
uint64_t value,
|
||||||
|
unsigned size)
|
||||||
|
{
|
||||||
|
eTSEC *etsec = opaque;
|
||||||
|
uint32_t reg_index = addr / 4;
|
||||||
|
eTSEC_Register *reg = NULL;
|
||||||
|
uint32_t before = 0x0;
|
||||||
|
|
||||||
|
assert(reg_index < ETSEC_REG_NUMBER);
|
||||||
|
|
||||||
|
reg = &etsec->regs[reg_index];
|
||||||
|
before = reg->value;
|
||||||
|
|
||||||
|
switch (reg_index) {
|
||||||
|
case IEVENT:
|
||||||
|
write_ievent(etsec, reg, reg_index, value);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case DMACTRL:
|
||||||
|
write_dmactrl(etsec, reg, reg_index, value);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case TSTAT:
|
||||||
|
write_tstat(etsec, reg, reg_index, value);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case RSTAT:
|
||||||
|
write_rstat(etsec, reg, reg_index, value);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case TBASE0 ... TBASE7:
|
||||||
|
write_tbasex(etsec, reg, reg_index, value);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case RBASE0 ... RBASE7:
|
||||||
|
write_rbasex(etsec, reg, reg_index, value);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case MIIMCFG ... MIIMIND:
|
||||||
|
etsec_write_miim(etsec, reg, reg_index, value);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
/* Default handling */
|
||||||
|
switch (reg->access) {
|
||||||
|
|
||||||
|
case ACC_RW:
|
||||||
|
case ACC_WO:
|
||||||
|
reg->value = value;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case ACC_W1C:
|
||||||
|
reg->value &= ~value;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case ACC_RO:
|
||||||
|
default:
|
||||||
|
/* Read Only or Unknown register */
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
DPRINTF("Write 0x%08x @ 0x" TARGET_FMT_plx
|
||||||
|
" val:0x%08x->0x%08x : %s (%s)\n",
|
||||||
|
(unsigned int)value, addr, before, reg->value,
|
||||||
|
reg->name, reg->desc);
|
||||||
|
}
|
||||||
|
|
||||||
|
static const MemoryRegionOps etsec_ops = {
|
||||||
|
.read = etsec_read,
|
||||||
|
.write = etsec_write,
|
||||||
|
.endianness = DEVICE_NATIVE_ENDIAN,
|
||||||
|
.impl = {
|
||||||
|
.min_access_size = 4,
|
||||||
|
.max_access_size = 4,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
static void etsec_timer_hit(void *opaque)
|
||||||
|
{
|
||||||
|
eTSEC *etsec = opaque;
|
||||||
|
|
||||||
|
ptimer_stop(etsec->ptimer);
|
||||||
|
|
||||||
|
if (!(etsec->regs[DMACTRL].value & DMACTRL_WOP)) {
|
||||||
|
|
||||||
|
if (!(etsec->regs[DMACTRL].value & DMACTRL_GTS)) {
|
||||||
|
etsec_walk_tx_ring(etsec, 0);
|
||||||
|
}
|
||||||
|
ptimer_set_count(etsec->ptimer, 1);
|
||||||
|
ptimer_run(etsec->ptimer, 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void etsec_reset(DeviceState *d)
|
||||||
|
{
|
||||||
|
eTSEC *etsec = ETSEC_COMMON(d);
|
||||||
|
int i = 0;
|
||||||
|
int reg_index = 0;
|
||||||
|
|
||||||
|
/* Default value for all registers */
|
||||||
|
for (i = 0; i < ETSEC_REG_NUMBER; i++) {
|
||||||
|
etsec->regs[i].name = "Reserved";
|
||||||
|
etsec->regs[i].desc = "";
|
||||||
|
etsec->regs[i].access = ACC_UNKNOWN;
|
||||||
|
etsec->regs[i].value = 0x00000000;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Set-up known registers */
|
||||||
|
for (i = 0; eTSEC_registers_def[i].name != NULL; i++) {
|
||||||
|
|
||||||
|
reg_index = eTSEC_registers_def[i].offset / 4;
|
||||||
|
|
||||||
|
etsec->regs[reg_index].name = eTSEC_registers_def[i].name;
|
||||||
|
etsec->regs[reg_index].desc = eTSEC_registers_def[i].desc;
|
||||||
|
etsec->regs[reg_index].access = eTSEC_registers_def[i].access;
|
||||||
|
etsec->regs[reg_index].value = eTSEC_registers_def[i].reset;
|
||||||
|
}
|
||||||
|
|
||||||
|
etsec->tx_buffer = NULL;
|
||||||
|
etsec->tx_buffer_len = 0;
|
||||||
|
etsec->rx_buffer = NULL;
|
||||||
|
etsec->rx_buffer_len = 0;
|
||||||
|
|
||||||
|
etsec->phy_status =
|
||||||
|
MII_SR_EXTENDED_CAPS | MII_SR_LINK_STATUS | MII_SR_AUTONEG_CAPS |
|
||||||
|
MII_SR_AUTONEG_COMPLETE | MII_SR_PREAMBLE_SUPPRESS |
|
||||||
|
MII_SR_EXTENDED_STATUS | MII_SR_100T2_HD_CAPS | MII_SR_100T2_FD_CAPS |
|
||||||
|
MII_SR_10T_HD_CAPS | MII_SR_10T_FD_CAPS | MII_SR_100X_HD_CAPS |
|
||||||
|
MII_SR_100X_FD_CAPS | MII_SR_100T4_CAPS;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void etsec_cleanup(NetClientState *nc)
|
||||||
|
{
|
||||||
|
/* qemu_log("eTSEC cleanup\n"); */
|
||||||
|
}
|
||||||
|
|
||||||
|
static int etsec_can_receive(NetClientState *nc)
|
||||||
|
{
|
||||||
|
eTSEC *etsec = qemu_get_nic_opaque(nc);
|
||||||
|
|
||||||
|
return etsec->rx_buffer_len == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static ssize_t etsec_receive(NetClientState *nc,
|
||||||
|
const uint8_t *buf,
|
||||||
|
size_t size)
|
||||||
|
{
|
||||||
|
eTSEC *etsec = qemu_get_nic_opaque(nc);
|
||||||
|
|
||||||
|
#if defined(HEX_DUMP)
|
||||||
|
fprintf(stderr, "%s receive size:%d\n", etsec->nic->nc.name, size);
|
||||||
|
qemu_hexdump(buf, stderr, "", size);
|
||||||
|
#endif
|
||||||
|
etsec_rx_ring_write(etsec, buf, size);
|
||||||
|
return size;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void etsec_set_link_status(NetClientState *nc)
|
||||||
|
{
|
||||||
|
eTSEC *etsec = qemu_get_nic_opaque(nc);
|
||||||
|
|
||||||
|
etsec_miim_link_status(etsec, nc);
|
||||||
|
}
|
||||||
|
|
||||||
|
static NetClientInfo net_etsec_info = {
|
||||||
|
.type = NET_CLIENT_OPTIONS_KIND_NIC,
|
||||||
|
.size = sizeof(NICState),
|
||||||
|
.can_receive = etsec_can_receive,
|
||||||
|
.receive = etsec_receive,
|
||||||
|
.cleanup = etsec_cleanup,
|
||||||
|
.link_status_changed = etsec_set_link_status,
|
||||||
|
};
|
||||||
|
|
||||||
|
static void etsec_realize(DeviceState *dev, Error **errp)
|
||||||
|
{
|
||||||
|
eTSEC *etsec = ETSEC_COMMON(dev);
|
||||||
|
|
||||||
|
etsec->nic = qemu_new_nic(&net_etsec_info, &etsec->conf,
|
||||||
|
object_get_typename(OBJECT(dev)), dev->id, etsec);
|
||||||
|
qemu_format_nic_info_str(qemu_get_queue(etsec->nic), etsec->conf.macaddr.a);
|
||||||
|
|
||||||
|
|
||||||
|
etsec->bh = qemu_bh_new(etsec_timer_hit, etsec);
|
||||||
|
etsec->ptimer = ptimer_init(etsec->bh);
|
||||||
|
ptimer_set_freq(etsec->ptimer, 100);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void etsec_instance_init(Object *obj)
|
||||||
|
{
|
||||||
|
eTSEC *etsec = ETSEC_COMMON(obj);
|
||||||
|
SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
|
||||||
|
|
||||||
|
memory_region_init_io(&etsec->io_area, OBJECT(etsec), &etsec_ops, etsec,
|
||||||
|
"eTSEC", 0x1000);
|
||||||
|
sysbus_init_mmio(sbd, &etsec->io_area);
|
||||||
|
|
||||||
|
sysbus_init_irq(sbd, &etsec->tx_irq);
|
||||||
|
sysbus_init_irq(sbd, &etsec->rx_irq);
|
||||||
|
sysbus_init_irq(sbd, &etsec->err_irq);
|
||||||
|
}
|
||||||
|
|
||||||
|
static Property etsec_properties[] = {
|
||||||
|
DEFINE_NIC_PROPERTIES(eTSEC, conf),
|
||||||
|
DEFINE_PROP_END_OF_LIST(),
|
||||||
|
};
|
||||||
|
|
||||||
|
static void etsec_class_init(ObjectClass *klass, void *data)
|
||||||
|
{
|
||||||
|
DeviceClass *dc = DEVICE_CLASS(klass);
|
||||||
|
|
||||||
|
dc->realize = etsec_realize;
|
||||||
|
dc->reset = etsec_reset;
|
||||||
|
dc->props = etsec_properties;
|
||||||
|
}
|
||||||
|
|
||||||
|
static TypeInfo etsec_info = {
|
||||||
|
.name = "eTSEC",
|
||||||
|
.parent = TYPE_SYS_BUS_DEVICE,
|
||||||
|
.instance_size = sizeof(eTSEC),
|
||||||
|
.class_init = etsec_class_init,
|
||||||
|
.instance_init = etsec_instance_init,
|
||||||
|
};
|
||||||
|
|
||||||
|
static void etsec_register_types(void)
|
||||||
|
{
|
||||||
|
type_register_static(&etsec_info);
|
||||||
|
}
|
||||||
|
|
||||||
|
type_init(etsec_register_types)
|
||||||
|
|
||||||
|
DeviceState *etsec_create(hwaddr base,
|
||||||
|
MemoryRegion * mr,
|
||||||
|
NICInfo * nd,
|
||||||
|
qemu_irq tx_irq,
|
||||||
|
qemu_irq rx_irq,
|
||||||
|
qemu_irq err_irq)
|
||||||
|
{
|
||||||
|
DeviceState *dev;
|
||||||
|
|
||||||
|
dev = qdev_create(NULL, "eTSEC");
|
||||||
|
qdev_set_nic_properties(dev, nd);
|
||||||
|
|
||||||
|
if (qdev_init(dev)) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, tx_irq);
|
||||||
|
sysbus_connect_irq(SYS_BUS_DEVICE(dev), 1, rx_irq);
|
||||||
|
sysbus_connect_irq(SYS_BUS_DEVICE(dev), 2, err_irq);
|
||||||
|
|
||||||
|
memory_region_add_subregion(mr, base,
|
||||||
|
SYS_BUS_DEVICE(dev)->mmio[0].memory);
|
||||||
|
|
||||||
|
return dev;
|
||||||
|
}
|
174
hw/net/fsl_etsec/etsec.h
Normal file
174
hw/net/fsl_etsec/etsec.h
Normal file
@@ -0,0 +1,174 @@
|
|||||||
|
/*
|
||||||
|
* QEMU Freescale eTSEC Emulator
|
||||||
|
*
|
||||||
|
* Copyright (c) 2011-2013 AdaCore
|
||||||
|
*
|
||||||
|
* 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 _ETSEC_H_
|
||||||
|
#define _ETSEC_H_
|
||||||
|
|
||||||
|
#include "hw/qdev.h"
|
||||||
|
#include "hw/sysbus.h"
|
||||||
|
#include "net/net.h"
|
||||||
|
#include "hw/ptimer.h"
|
||||||
|
|
||||||
|
/* Buffer Descriptors */
|
||||||
|
|
||||||
|
typedef struct eTSEC_rxtx_bd {
|
||||||
|
uint16_t flags;
|
||||||
|
uint16_t length;
|
||||||
|
uint32_t bufptr;
|
||||||
|
} eTSEC_rxtx_bd;
|
||||||
|
|
||||||
|
#define BD_WRAP (1 << 13)
|
||||||
|
#define BD_INTERRUPT (1 << 12)
|
||||||
|
#define BD_LAST (1 << 11)
|
||||||
|
|
||||||
|
#define BD_TX_READY (1 << 15)
|
||||||
|
#define BD_TX_PADCRC (1 << 14)
|
||||||
|
#define BD_TX_TC (1 << 10)
|
||||||
|
#define BD_TX_PREDEF (1 << 9)
|
||||||
|
#define BD_TX_HFELC (1 << 7)
|
||||||
|
#define BD_TX_CFRL (1 << 6)
|
||||||
|
#define BD_TX_RC_MASK 0xF
|
||||||
|
#define BD_TX_RC_OFFSET 0x2
|
||||||
|
#define BD_TX_TOEUN (1 << 1)
|
||||||
|
#define BD_TX_TR (1 << 0)
|
||||||
|
|
||||||
|
#define BD_RX_EMPTY (1 << 15)
|
||||||
|
#define BD_RX_RO1 (1 << 14)
|
||||||
|
#define BD_RX_FIRST (1 << 10)
|
||||||
|
#define BD_RX_MISS (1 << 8)
|
||||||
|
#define BD_RX_BROADCAST (1 << 7)
|
||||||
|
#define BD_RX_MULTICAST (1 << 6)
|
||||||
|
#define BD_RX_LG (1 << 5)
|
||||||
|
#define BD_RX_NO (1 << 4)
|
||||||
|
#define BD_RX_SH (1 << 3)
|
||||||
|
#define BD_RX_CR (1 << 2)
|
||||||
|
#define BD_RX_OV (1 << 1)
|
||||||
|
#define BD_RX_TR (1 << 0)
|
||||||
|
|
||||||
|
/* Tx FCB flags */
|
||||||
|
#define FCB_TX_VLN (1 << 7)
|
||||||
|
#define FCB_TX_IP (1 << 6)
|
||||||
|
#define FCB_TX_IP6 (1 << 5)
|
||||||
|
#define FCB_TX_TUP (1 << 4)
|
||||||
|
#define FCB_TX_UDP (1 << 3)
|
||||||
|
#define FCB_TX_CIP (1 << 2)
|
||||||
|
#define FCB_TX_CTU (1 << 1)
|
||||||
|
#define FCB_TX_NPH (1 << 0)
|
||||||
|
|
||||||
|
/* PHY Status Register */
|
||||||
|
#define MII_SR_EXTENDED_CAPS 0x0001 /* Extended register capabilities */
|
||||||
|
#define MII_SR_JABBER_DETECT 0x0002 /* Jabber Detected */
|
||||||
|
#define MII_SR_LINK_STATUS 0x0004 /* Link Status 1 = link */
|
||||||
|
#define MII_SR_AUTONEG_CAPS 0x0008 /* Auto Neg Capable */
|
||||||
|
#define MII_SR_REMOTE_FAULT 0x0010 /* Remote Fault Detect */
|
||||||
|
#define MII_SR_AUTONEG_COMPLETE 0x0020 /* Auto Neg Complete */
|
||||||
|
#define MII_SR_PREAMBLE_SUPPRESS 0x0040 /* Preamble may be suppressed */
|
||||||
|
#define MII_SR_EXTENDED_STATUS 0x0100 /* Ext. status info in Reg 0x0F */
|
||||||
|
#define MII_SR_100T2_HD_CAPS 0x0200 /* 100T2 Half Duplex Capable */
|
||||||
|
#define MII_SR_100T2_FD_CAPS 0x0400 /* 100T2 Full Duplex Capable */
|
||||||
|
#define MII_SR_10T_HD_CAPS 0x0800 /* 10T Half Duplex Capable */
|
||||||
|
#define MII_SR_10T_FD_CAPS 0x1000 /* 10T Full Duplex Capable */
|
||||||
|
#define MII_SR_100X_HD_CAPS 0x2000 /* 100X Half Duplex Capable */
|
||||||
|
#define MII_SR_100X_FD_CAPS 0x4000 /* 100X Full Duplex Capable */
|
||||||
|
#define MII_SR_100T4_CAPS 0x8000 /* 100T4 Capable */
|
||||||
|
|
||||||
|
/* eTSEC */
|
||||||
|
|
||||||
|
/* Number of register in the device */
|
||||||
|
#define ETSEC_REG_NUMBER 1024
|
||||||
|
|
||||||
|
typedef struct eTSEC_Register {
|
||||||
|
const char *name;
|
||||||
|
const char *desc;
|
||||||
|
uint32_t access;
|
||||||
|
uint32_t value;
|
||||||
|
} eTSEC_Register;
|
||||||
|
|
||||||
|
typedef struct eTSEC {
|
||||||
|
SysBusDevice busdev;
|
||||||
|
|
||||||
|
MemoryRegion io_area;
|
||||||
|
|
||||||
|
eTSEC_Register regs[ETSEC_REG_NUMBER];
|
||||||
|
|
||||||
|
NICState *nic;
|
||||||
|
NICConf conf;
|
||||||
|
|
||||||
|
/* Tx */
|
||||||
|
|
||||||
|
uint8_t *tx_buffer;
|
||||||
|
uint32_t tx_buffer_len;
|
||||||
|
eTSEC_rxtx_bd first_bd;
|
||||||
|
|
||||||
|
/* Rx */
|
||||||
|
|
||||||
|
uint8_t *rx_buffer;
|
||||||
|
uint32_t rx_buffer_len;
|
||||||
|
uint32_t rx_remaining_data;
|
||||||
|
uint8_t rx_first_in_frame;
|
||||||
|
uint8_t rx_fcb_size;
|
||||||
|
eTSEC_rxtx_bd rx_first_bd;
|
||||||
|
uint8_t rx_fcb[10];
|
||||||
|
uint32_t rx_padding;
|
||||||
|
|
||||||
|
/* IRQs */
|
||||||
|
qemu_irq tx_irq;
|
||||||
|
qemu_irq rx_irq;
|
||||||
|
qemu_irq err_irq;
|
||||||
|
|
||||||
|
|
||||||
|
uint16_t phy_status;
|
||||||
|
uint16_t phy_control;
|
||||||
|
|
||||||
|
/* Polling */
|
||||||
|
QEMUBH *bh;
|
||||||
|
struct ptimer_state *ptimer;
|
||||||
|
|
||||||
|
} eTSEC;
|
||||||
|
|
||||||
|
#define TYPE_ETSEC_COMMON "eTSEC"
|
||||||
|
#define ETSEC_COMMON(obj) \
|
||||||
|
OBJECT_CHECK(eTSEC, (obj), TYPE_ETSEC_COMMON)
|
||||||
|
|
||||||
|
#define eTSEC_TRANSMIT 1
|
||||||
|
#define eTSEC_RECEIVE 2
|
||||||
|
|
||||||
|
DeviceState *etsec_create(hwaddr base,
|
||||||
|
MemoryRegion *mr,
|
||||||
|
NICInfo *nd,
|
||||||
|
qemu_irq tx_irq,
|
||||||
|
qemu_irq rx_irq,
|
||||||
|
qemu_irq err_irq);
|
||||||
|
|
||||||
|
void etsec_walk_tx_ring(eTSEC *etsec, int ring_nbr);
|
||||||
|
void etsec_walk_rx_ring(eTSEC *etsec, int ring_nbr);
|
||||||
|
void etsec_rx_ring_write(eTSEC *etsec, const uint8_t *buf, size_t size);
|
||||||
|
|
||||||
|
void etsec_write_miim(eTSEC *etsec,
|
||||||
|
eTSEC_Register *reg,
|
||||||
|
uint32_t reg_index,
|
||||||
|
uint32_t value);
|
||||||
|
|
||||||
|
void etsec_miim_link_status(eTSEC *etsec, NetClientState *nc);
|
||||||
|
|
||||||
|
#endif /* ! _ETSEC_H_ */
|
146
hw/net/fsl_etsec/miim.c
Normal file
146
hw/net/fsl_etsec/miim.c
Normal file
@@ -0,0 +1,146 @@
|
|||||||
|
/*
|
||||||
|
* QEMU Freescale eTSEC Emulator
|
||||||
|
*
|
||||||
|
* Copyright (c) 2011-2013 AdaCore
|
||||||
|
*
|
||||||
|
* 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 "etsec.h"
|
||||||
|
#include "registers.h"
|
||||||
|
|
||||||
|
/* #define DEBUG_MIIM */
|
||||||
|
|
||||||
|
#define MIIM_CONTROL 0
|
||||||
|
#define MIIM_STATUS 1
|
||||||
|
#define MIIM_PHY_ID_1 2
|
||||||
|
#define MIIM_PHY_ID_2 3
|
||||||
|
#define MIIM_T2_STATUS 10
|
||||||
|
#define MIIM_EXT_STATUS 15
|
||||||
|
|
||||||
|
static void miim_read_cycle(eTSEC *etsec)
|
||||||
|
{
|
||||||
|
uint8_t phy;
|
||||||
|
uint8_t addr;
|
||||||
|
uint16_t value;
|
||||||
|
|
||||||
|
phy = (etsec->regs[MIIMADD].value >> 8) & 0x1F;
|
||||||
|
(void)phy; /* Unreferenced */
|
||||||
|
addr = etsec->regs[MIIMADD].value & 0x1F;
|
||||||
|
|
||||||
|
switch (addr) {
|
||||||
|
case MIIM_CONTROL:
|
||||||
|
value = etsec->phy_control;
|
||||||
|
break;
|
||||||
|
case MIIM_STATUS:
|
||||||
|
value = etsec->phy_status;
|
||||||
|
break;
|
||||||
|
case MIIM_T2_STATUS:
|
||||||
|
value = 0x1800; /* Local and remote receivers OK */
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
value = 0x0;
|
||||||
|
break;
|
||||||
|
};
|
||||||
|
|
||||||
|
#ifdef DEBUG_MIIM
|
||||||
|
qemu_log("%s phy:%d addr:0x%x value:0x%x\n", __func__, phy, addr, value);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
etsec->regs[MIIMSTAT].value = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void miim_write_cycle(eTSEC *etsec)
|
||||||
|
{
|
||||||
|
uint8_t phy;
|
||||||
|
uint8_t addr;
|
||||||
|
uint16_t value;
|
||||||
|
|
||||||
|
phy = (etsec->regs[MIIMADD].value >> 8) & 0x1F;
|
||||||
|
(void)phy; /* Unreferenced */
|
||||||
|
addr = etsec->regs[MIIMADD].value & 0x1F;
|
||||||
|
value = etsec->regs[MIIMCON].value & 0xffff;
|
||||||
|
|
||||||
|
#ifdef DEBUG_MIIM
|
||||||
|
qemu_log("%s phy:%d addr:0x%x value:0x%x\n", __func__, phy, addr, value);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
switch (addr) {
|
||||||
|
case MIIM_CONTROL:
|
||||||
|
etsec->phy_control = value & ~(0x8100);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
void etsec_write_miim(eTSEC *etsec,
|
||||||
|
eTSEC_Register *reg,
|
||||||
|
uint32_t reg_index,
|
||||||
|
uint32_t value)
|
||||||
|
{
|
||||||
|
|
||||||
|
switch (reg_index) {
|
||||||
|
|
||||||
|
case MIIMCOM:
|
||||||
|
/* Read and scan cycle */
|
||||||
|
|
||||||
|
if ((!(reg->value & MIIMCOM_READ)) && (value & MIIMCOM_READ)) {
|
||||||
|
/* Read */
|
||||||
|
miim_read_cycle(etsec);
|
||||||
|
}
|
||||||
|
reg->value = value;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case MIIMCON:
|
||||||
|
reg->value = value & 0xffff;
|
||||||
|
miim_write_cycle(etsec);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
/* Default handling */
|
||||||
|
switch (reg->access) {
|
||||||
|
|
||||||
|
case ACC_RW:
|
||||||
|
case ACC_WO:
|
||||||
|
reg->value = value;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case ACC_W1C:
|
||||||
|
reg->value &= ~value;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case ACC_RO:
|
||||||
|
default:
|
||||||
|
/* Read Only or Unknown register */
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void etsec_miim_link_status(eTSEC *etsec, NetClientState *nc)
|
||||||
|
{
|
||||||
|
/* Set link status */
|
||||||
|
if (nc->link_down) {
|
||||||
|
etsec->phy_status &= ~MII_SR_LINK_STATUS;
|
||||||
|
} else {
|
||||||
|
etsec->phy_status |= MII_SR_LINK_STATUS;
|
||||||
|
}
|
||||||
|
}
|
295
hw/net/fsl_etsec/registers.c
Normal file
295
hw/net/fsl_etsec/registers.c
Normal file
@@ -0,0 +1,295 @@
|
|||||||
|
/*
|
||||||
|
* QEMU Freescale eTSEC Emulator
|
||||||
|
*
|
||||||
|
* Copyright (c) 2011-2013 AdaCore
|
||||||
|
*
|
||||||
|
* 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 "registers.h"
|
||||||
|
|
||||||
|
const eTSEC_Register_Definition eTSEC_registers_def[] = {
|
||||||
|
{0x000, "TSEC_ID", "Controller ID register", ACC_RO, 0x01240000},
|
||||||
|
{0x004, "TSEC_ID2", "Controller ID register 2", ACC_RO, 0x003000F0},
|
||||||
|
{0x010, "IEVENT", "Interrupt event register", ACC_W1C, 0x00000000},
|
||||||
|
{0x014, "IMASK", "Interrupt mask register", ACC_RW, 0x00000000},
|
||||||
|
{0x018, "EDIS", "Error disabled register", ACC_RW, 0x00000000},
|
||||||
|
{0x020, "ECNTRL", "Ethernet control register", ACC_RW, 0x00000040},
|
||||||
|
{0x028, "PTV", "Pause time value register", ACC_RW, 0x00000000},
|
||||||
|
{0x02C, "DMACTRL", "DMA control register", ACC_RW, 0x00000000},
|
||||||
|
{0x030, "TBIPA", "TBI PHY address register", ACC_RW, 0x00000000},
|
||||||
|
|
||||||
|
/* eTSEC FIFO Control and Status Registers */
|
||||||
|
|
||||||
|
{0x058, "FIFO_RX_ALARM", "FIFO receive alarm start threshold register", ACC_RW, 0x00000040},
|
||||||
|
{0x05C, "FIFO_RX_ALARM_SHUTOFF", "FIFO receive alarm shut-off threshold register", ACC_RW, 0x00000080},
|
||||||
|
{0x08C, "FIFO_TX_THR", "FIFO transmit threshold register", ACC_RW, 0x00000080},
|
||||||
|
{0x098, "FIFO_TX_STARVE", "FIFO transmit starve register", ACC_RW, 0x00000040},
|
||||||
|
{0x09C, "FIFO_TX_STARVE_SHUTOFF", "FIFO transmit starve shut-off register", ACC_RW, 0x00000080},
|
||||||
|
|
||||||
|
/* eTSEC Transmit Control and Status Registers */
|
||||||
|
|
||||||
|
{0x100, "TCTRL", "Transmit control register", ACC_RW, 0x00000000},
|
||||||
|
{0x104, "TSTAT", "Transmit status register", ACC_W1C, 0x00000000},
|
||||||
|
{0x108, "DFVLAN", "Default VLAN control word", ACC_RW, 0x81000000},
|
||||||
|
{0x110, "TXIC", "Transmit interrupt coalescing register", ACC_RW, 0x00000000},
|
||||||
|
{0x114, "TQUEUE", "Transmit queue control register", ACC_RW, 0x00008000},
|
||||||
|
{0x140, "TR03WT", "TxBD Rings 0-3 round-robin weightings", ACC_RW, 0x00000000},
|
||||||
|
{0x144, "TR47WT", "TxBD Rings 4-7 round-robin weightings", ACC_RW, 0x00000000},
|
||||||
|
{0x180, "TBDBPH", "Tx data buffer pointer high bits", ACC_RW, 0x00000000},
|
||||||
|
{0x184, "TBPTR0", "TxBD pointer for ring 0", ACC_RW, 0x00000000},
|
||||||
|
{0x18C, "TBPTR1", "TxBD pointer for ring 1", ACC_RW, 0x00000000},
|
||||||
|
{0x194, "TBPTR2", "TxBD pointer for ring 2", ACC_RW, 0x00000000},
|
||||||
|
{0x19C, "TBPTR3", "TxBD pointer for ring 3", ACC_RW, 0x00000000},
|
||||||
|
{0x1A4, "TBPTR4", "TxBD pointer for ring 4", ACC_RW, 0x00000000},
|
||||||
|
{0x1AC, "TBPTR5", "TxBD pointer for ring 5", ACC_RW, 0x00000000},
|
||||||
|
{0x1B4, "TBPTR6", "TxBD pointer for ring 6", ACC_RW, 0x00000000},
|
||||||
|
{0x1BC, "TBPTR7", "TxBD pointer for ring 7", ACC_RW, 0x00000000},
|
||||||
|
{0x200, "TBASEH", "TxBD base address high bits", ACC_RW, 0x00000000},
|
||||||
|
{0x204, "TBASE0", "TxBD base address of ring 0", ACC_RW, 0x00000000},
|
||||||
|
{0x20C, "TBASE1", "TxBD base address of ring 1", ACC_RW, 0x00000000},
|
||||||
|
{0x214, "TBASE2", "TxBD base address of ring 2", ACC_RW, 0x00000000},
|
||||||
|
{0x21C, "TBASE3", "TxBD base address of ring 3", ACC_RW, 0x00000000},
|
||||||
|
{0x224, "TBASE4", "TxBD base address of ring 4", ACC_RW, 0x00000000},
|
||||||
|
{0x22C, "TBASE5", "TxBD base address of ring 5", ACC_RW, 0x00000000},
|
||||||
|
{0x234, "TBASE6", "TxBD base address of ring 6", ACC_RW, 0x00000000},
|
||||||
|
{0x23C, "TBASE7", "TxBD base address of ring 7", ACC_RW, 0x00000000},
|
||||||
|
{0x280, "TMR_TXTS1_ID", "Tx time stamp identification tag (set 1)", ACC_RO, 0x00000000},
|
||||||
|
{0x284, "TMR_TXTS2_ID", "Tx time stamp identification tag (set 2)", ACC_RO, 0x00000000},
|
||||||
|
{0x2C0, "TMR_TXTS1_H", "Tx time stamp high (set 1)", ACC_RO, 0x00000000},
|
||||||
|
{0x2C4, "TMR_TXTS1_L", "Tx time stamp high (set 1)", ACC_RO, 0x00000000},
|
||||||
|
{0x2C8, "TMR_TXTS2_H", "Tx time stamp high (set 2)", ACC_RO, 0x00000000},
|
||||||
|
{0x2CC, "TMR_TXTS2_L", "Tx time stamp high (set 2)", ACC_RO, 0x00000000},
|
||||||
|
|
||||||
|
/* eTSEC Receive Control and Status Registers */
|
||||||
|
|
||||||
|
{0x300, "RCTRL", "Receive control register", ACC_RW, 0x00000000},
|
||||||
|
{0x304, "RSTAT", "Receive status register", ACC_W1C, 0x00000000},
|
||||||
|
{0x310, "RXIC", "Receive interrupt coalescing register", ACC_RW, 0x00000000},
|
||||||
|
{0x314, "RQUEUE", "Receive queue control register.", ACC_RW, 0x00800080},
|
||||||
|
{0x330, "RBIFX", "Receive bit field extract control register", ACC_RW, 0x00000000},
|
||||||
|
{0x334, "RQFAR", "Receive queue filing table address register", ACC_RW, 0x00000000},
|
||||||
|
{0x338, "RQFCR", "Receive queue filing table control register", ACC_RW, 0x00000000},
|
||||||
|
{0x33C, "RQFPR", "Receive queue filing table property register", ACC_RW, 0x00000000},
|
||||||
|
{0x340, "MRBLR", "Maximum receive buffer length register", ACC_RW, 0x00000000},
|
||||||
|
{0x380, "RBDBPH", "Rx data buffer pointer high bits", ACC_RW, 0x00000000},
|
||||||
|
{0x384, "RBPTR0", "RxBD pointer for ring 0", ACC_RW, 0x00000000},
|
||||||
|
{0x38C, "RBPTR1", "RxBD pointer for ring 1", ACC_RW, 0x00000000},
|
||||||
|
{0x394, "RBPTR2", "RxBD pointer for ring 2", ACC_RW, 0x00000000},
|
||||||
|
{0x39C, "RBPTR3", "RxBD pointer for ring 3", ACC_RW, 0x00000000},
|
||||||
|
{0x3A4, "RBPTR4", "RxBD pointer for ring 4", ACC_RW, 0x00000000},
|
||||||
|
{0x3AC, "RBPTR5", "RxBD pointer for ring 5", ACC_RW, 0x00000000},
|
||||||
|
{0x3B4, "RBPTR6", "RxBD pointer for ring 6", ACC_RW, 0x00000000},
|
||||||
|
{0x3BC, "RBPTR7", "RxBD pointer for ring 7", ACC_RW, 0x00000000},
|
||||||
|
{0x400, "RBASEH", "RxBD base address high bits", ACC_RW, 0x00000000},
|
||||||
|
{0x404, "RBASE0", "RxBD base address of ring 0", ACC_RW, 0x00000000},
|
||||||
|
{0x40C, "RBASE1", "RxBD base address of ring 1", ACC_RW, 0x00000000},
|
||||||
|
{0x414, "RBASE2", "RxBD base address of ring 2", ACC_RW, 0x00000000},
|
||||||
|
{0x41C, "RBASE3", "RxBD base address of ring 3", ACC_RW, 0x00000000},
|
||||||
|
{0x424, "RBASE4", "RxBD base address of ring 4", ACC_RW, 0x00000000},
|
||||||
|
{0x42C, "RBASE5", "RxBD base address of ring 5", ACC_RW, 0x00000000},
|
||||||
|
{0x434, "RBASE6", "RxBD base address of ring 6", ACC_RW, 0x00000000},
|
||||||
|
{0x43C, "RBASE7", "RxBD base address of ring 7", ACC_RW, 0x00000000},
|
||||||
|
{0x4C0, "TMR_RXTS_H", "Rx timer time stamp register high", ACC_RW, 0x00000000},
|
||||||
|
{0x4C4, "TMR_RXTS_L", "Rx timer time stamp register low", ACC_RW, 0x00000000},
|
||||||
|
|
||||||
|
/* eTSEC MAC Registers */
|
||||||
|
|
||||||
|
{0x500, "MACCFG1", "MAC configuration register 1", ACC_RW, 0x00000000},
|
||||||
|
{0x504, "MACCFG2", "MAC configuration register 2", ACC_RW, 0x00007000},
|
||||||
|
{0x508, "IPGIFG", "Inter-packet/inter-frame gap register", ACC_RW, 0x40605060},
|
||||||
|
{0x50C, "HAFDUP", "Half-duplex control", ACC_RW, 0x00A1F037},
|
||||||
|
{0x510, "MAXFRM", "Maximum frame length", ACC_RW, 0x00000600},
|
||||||
|
{0x520, "MIIMCFG", "MII management configuration", ACC_RW, 0x00000007},
|
||||||
|
{0x524, "MIIMCOM", "MII management command", ACC_RW, 0x00000000},
|
||||||
|
{0x528, "MIIMADD", "MII management address", ACC_RW, 0x00000000},
|
||||||
|
{0x52C, "MIIMCON", "MII management control", ACC_WO, 0x00000000},
|
||||||
|
{0x530, "MIIMSTAT", "MII management status", ACC_RO, 0x00000000},
|
||||||
|
{0x534, "MIIMIND", "MII management indicator", ACC_RO, 0x00000000},
|
||||||
|
{0x53C, "IFSTAT", "Interface status", ACC_RO, 0x00000000},
|
||||||
|
{0x540, "MACSTNADDR1", "MAC station address register 1", ACC_RW, 0x00000000},
|
||||||
|
{0x544, "MACSTNADDR2", "MAC station address register 2", ACC_RW, 0x00000000},
|
||||||
|
{0x548, "MAC01ADDR1", "MAC exact match address 1, part 1", ACC_RW, 0x00000000},
|
||||||
|
{0x54C, "MAC01ADDR2", "MAC exact match address 1, part 2", ACC_RW, 0x00000000},
|
||||||
|
{0x550, "MAC02ADDR1", "MAC exact match address 2, part 1", ACC_RW, 0x00000000},
|
||||||
|
{0x554, "MAC02ADDR2", "MAC exact match address 2, part 2", ACC_RW, 0x00000000},
|
||||||
|
{0x558, "MAC03ADDR1", "MAC exact match address 3, part 1", ACC_RW, 0x00000000},
|
||||||
|
{0x55C, "MAC03ADDR2", "MAC exact match address 3, part 2", ACC_RW, 0x00000000},
|
||||||
|
{0x560, "MAC04ADDR1", "MAC exact match address 4, part 1", ACC_RW, 0x00000000},
|
||||||
|
{0x564, "MAC04ADDR2", "MAC exact match address 4, part 2", ACC_RW, 0x00000000},
|
||||||
|
{0x568, "MAC05ADDR1", "MAC exact match address 5, part 1", ACC_RW, 0x00000000},
|
||||||
|
{0x56C, "MAC05ADDR2", "MAC exact match address 5, part 2", ACC_RW, 0x00000000},
|
||||||
|
{0x570, "MAC06ADDR1", "MAC exact match address 6, part 1", ACC_RW, 0x00000000},
|
||||||
|
{0x574, "MAC06ADDR2", "MAC exact match address 6, part 2", ACC_RW, 0x00000000},
|
||||||
|
{0x578, "MAC07ADDR1", "MAC exact match address 7, part 1", ACC_RW, 0x00000000},
|
||||||
|
{0x57C, "MAC07ADDR2", "MAC exact match address 7, part 2", ACC_RW, 0x00000000},
|
||||||
|
{0x580, "MAC08ADDR1", "MAC exact match address 8, part 1", ACC_RW, 0x00000000},
|
||||||
|
{0x584, "MAC08ADDR2", "MAC exact match address 8, part 2", ACC_RW, 0x00000000},
|
||||||
|
{0x588, "MAC09ADDR1", "MAC exact match address 9, part 1", ACC_RW, 0x00000000},
|
||||||
|
{0x58C, "MAC09ADDR2", "MAC exact match address 9, part 2", ACC_RW, 0x00000000},
|
||||||
|
{0x590, "MAC10ADDR1", "MAC exact match address 10, part 1", ACC_RW, 0x00000000},
|
||||||
|
{0x594, "MAC10ADDR2", "MAC exact match address 10, part 2", ACC_RW, 0x00000000},
|
||||||
|
{0x598, "MAC11ADDR1", "MAC exact match address 11, part 1", ACC_RW, 0x00000000},
|
||||||
|
{0x59C, "MAC11ADDR2", "MAC exact match address 11, part 2", ACC_RW, 0x00000000},
|
||||||
|
{0x5A0, "MAC12ADDR1", "MAC exact match address 12, part 1", ACC_RW, 0x00000000},
|
||||||
|
{0x5A4, "MAC12ADDR2", "MAC exact match address 12, part 2", ACC_RW, 0x00000000},
|
||||||
|
{0x5A8, "MAC13ADDR1", "MAC exact match address 13, part 1", ACC_RW, 0x00000000},
|
||||||
|
{0x5AC, "MAC13ADDR2", "MAC exact match address 13, part 2", ACC_RW, 0x00000000},
|
||||||
|
{0x5B0, "MAC14ADDR1", "MAC exact match address 14, part 1", ACC_RW, 0x00000000},
|
||||||
|
{0x5B4, "MAC14ADDR2", "MAC exact match address 14, part 2", ACC_RW, 0x00000000},
|
||||||
|
{0x5B8, "MAC15ADDR1", "MAC exact match address 15, part 1", ACC_RW, 0x00000000},
|
||||||
|
{0x5BC, "MAC15ADDR2", "MAC exact match address 15, part 2", ACC_RW, 0x00000000},
|
||||||
|
|
||||||
|
/* eTSEC, "Transmit", "and", Receive, Counters */
|
||||||
|
|
||||||
|
{0x680, "TR64", "Transmit and receive 64-byte frame counter ", ACC_RW, 0x00000000},
|
||||||
|
{0x684, "TR127", "Transmit and receive 65- to 127-byte frame counter", ACC_RW, 0x00000000},
|
||||||
|
{0x688, "TR255", "Transmit and receive 128- to 255-byte frame counter", ACC_RW, 0x00000000},
|
||||||
|
{0x68C, "TR511", "Transmit and receive 256- to 511-byte frame counter", ACC_RW, 0x00000000},
|
||||||
|
{0x690, "TR1K", "Transmit and receive 512- to 1023-byte frame counter", ACC_RW, 0x00000000},
|
||||||
|
{0x694, "TRMAX", "Transmit and receive 1024- to 1518-byte frame counter", ACC_RW, 0x00000000},
|
||||||
|
{0x698, "TRMGV", "Transmit and receive 1519- to 1522-byte good VLAN frame count", ACC_RW, 0x00000000},
|
||||||
|
|
||||||
|
/* eTSEC Receive Counters */
|
||||||
|
|
||||||
|
{0x69C, "RBYT", "Receive byte counter", ACC_RW, 0x00000000},
|
||||||
|
{0x6A0, "RPKT", "Receive packet counter", ACC_RW, 0x00000000},
|
||||||
|
{0x6A4, "RFCS", "Receive FCS error counter", ACC_RW, 0x00000000},
|
||||||
|
{0x6A8, "RMCA", "Receive multicast packet counter", ACC_RW, 0x00000000},
|
||||||
|
{0x6AC, "RBCA", "Receive broadcast packet counter", ACC_RW, 0x00000000},
|
||||||
|
{0x6B0, "RXCF", "Receive control frame packet counter ", ACC_RW, 0x00000000},
|
||||||
|
{0x6B4, "RXPF", "Receive PAUSE frame packet counter", ACC_RW, 0x00000000},
|
||||||
|
{0x6B8, "RXUO", "Receive unknown OP code counter ", ACC_RW, 0x00000000},
|
||||||
|
{0x6BC, "RALN", "Receive alignment error counter ", ACC_RW, 0x00000000},
|
||||||
|
{0x6C0, "RFLR", "Receive frame length error counter ", ACC_RW, 0x00000000},
|
||||||
|
{0x6C4, "RCDE", "Receive code error counter ", ACC_RW, 0x00000000},
|
||||||
|
{0x6C8, "RCSE", "Receive carrier sense error counter", ACC_RW, 0x00000000},
|
||||||
|
{0x6CC, "RUND", "Receive undersize packet counter", ACC_RW, 0x00000000},
|
||||||
|
{0x6D0, "ROVR", "Receive oversize packet counter ", ACC_RW, 0x00000000},
|
||||||
|
{0x6D4, "RFRG", "Receive fragments counter", ACC_RW, 0x00000000},
|
||||||
|
{0x6D8, "RJBR", "Receive jabber counter ", ACC_RW, 0x00000000},
|
||||||
|
{0x6DC, "RDRP", "Receive drop counter", ACC_RW, 0x00000000},
|
||||||
|
|
||||||
|
/* eTSEC Transmit Counters */
|
||||||
|
|
||||||
|
{0x6E0, "TBYT", "Transmit byte counter", ACC_RW, 0x00000000},
|
||||||
|
{0x6E4, "TPKT", "Transmit packet counter", ACC_RW, 0x00000000},
|
||||||
|
{0x6E8, "TMCA", "Transmit multicast packet counter ", ACC_RW, 0x00000000},
|
||||||
|
{0x6EC, "TBCA", "Transmit broadcast packet counter ", ACC_RW, 0x00000000},
|
||||||
|
{0x6F0, "TXPF", "Transmit PAUSE control frame counter ", ACC_RW, 0x00000000},
|
||||||
|
{0x6F4, "TDFR", "Transmit deferral packet counter ", ACC_RW, 0x00000000},
|
||||||
|
{0x6F8, "TEDF", "Transmit excessive deferral packet counter ", ACC_RW, 0x00000000},
|
||||||
|
{0x6FC, "TSCL", "Transmit single collision packet counter", ACC_RW, 0x00000000},
|
||||||
|
{0x700, "TMCL", "Transmit multiple collision packet counter", ACC_RW, 0x00000000},
|
||||||
|
{0x704, "TLCL", "Transmit late collision packet counter", ACC_RW, 0x00000000},
|
||||||
|
{0x708, "TXCL", "Transmit excessive collision packet counter", ACC_RW, 0x00000000},
|
||||||
|
{0x70C, "TNCL", "Transmit total collision counter ", ACC_RW, 0x00000000},
|
||||||
|
{0x714, "TDRP", "Transmit drop frame counter", ACC_RW, 0x00000000},
|
||||||
|
{0x718, "TJBR", "Transmit jabber frame counter ", ACC_RW, 0x00000000},
|
||||||
|
{0x71C, "TFCS", "Transmit FCS error counter", ACC_RW, 0x00000000},
|
||||||
|
{0x720, "TXCF", "Transmit control frame counter ", ACC_RW, 0x00000000},
|
||||||
|
{0x724, "TOVR", "Transmit oversize frame counter", ACC_RW, 0x00000000},
|
||||||
|
{0x728, "TUND", "Transmit undersize frame counter ", ACC_RW, 0x00000000},
|
||||||
|
{0x72C, "TFRG", "Transmit fragments frame counter ", ACC_RW, 0x00000000},
|
||||||
|
|
||||||
|
/* eTSEC Counter Control and TOE Statistics Registers */
|
||||||
|
|
||||||
|
{0x730, "CAR1", "Carry register one register", ACC_W1C, 0x00000000},
|
||||||
|
{0x734, "CAR2", "Carry register two register ", ACC_W1C, 0x00000000},
|
||||||
|
{0x738, "CAM1", "Carry register one mask register ", ACC_RW, 0xFE03FFFF},
|
||||||
|
{0x73C, "CAM2", "Carry register two mask register ", ACC_RW, 0x000FFFFD},
|
||||||
|
{0x740, "RREJ", "Receive filer rejected packet counter", ACC_RW, 0x00000000},
|
||||||
|
|
||||||
|
/* Hash Function Registers */
|
||||||
|
|
||||||
|
{0x800, "IGADDR0", "Individual/group address register 0", ACC_RW, 0x00000000},
|
||||||
|
{0x804, "IGADDR1", "Individual/group address register 1", ACC_RW, 0x00000000},
|
||||||
|
{0x808, "IGADDR2", "Individual/group address register 2", ACC_RW, 0x00000000},
|
||||||
|
{0x80C, "IGADDR3", "Individual/group address register 3", ACC_RW, 0x00000000},
|
||||||
|
{0x810, "IGADDR4", "Individual/group address register 4", ACC_RW, 0x00000000},
|
||||||
|
{0x814, "IGADDR5", "Individual/group address register 5", ACC_RW, 0x00000000},
|
||||||
|
{0x818, "IGADDR6", "Individual/group address register 6", ACC_RW, 0x00000000},
|
||||||
|
{0x81C, "IGADDR7", "Individual/group address register 7", ACC_RW, 0x00000000},
|
||||||
|
{0x880, "GADDR0", "Group address register 0", ACC_RW, 0x00000000},
|
||||||
|
{0x884, "GADDR1", "Group address register 1", ACC_RW, 0x00000000},
|
||||||
|
{0x888, "GADDR2", "Group address register 2", ACC_RW, 0x00000000},
|
||||||
|
{0x88C, "GADDR3", "Group address register 3", ACC_RW, 0x00000000},
|
||||||
|
{0x890, "GADDR4", "Group address register 4", ACC_RW, 0x00000000},
|
||||||
|
{0x894, "GADDR5", "Group address register 5", ACC_RW, 0x00000000},
|
||||||
|
{0x898, "GADDR6", "Group address register 6", ACC_RW, 0x00000000},
|
||||||
|
{0x89C, "GADDR7", "Group address register 7", ACC_RW, 0x00000000},
|
||||||
|
|
||||||
|
/* eTSEC DMA Attribute Registers */
|
||||||
|
|
||||||
|
{0xBF8, "ATTR", "Attribute register", ACC_RW, 0x00000000},
|
||||||
|
{0xBFC, "ATTRELI", "Attribute extract length and extract index register", ACC_RW, 0x00000000},
|
||||||
|
|
||||||
|
|
||||||
|
/* eTSEC Lossless Flow Control Registers */
|
||||||
|
|
||||||
|
{0xC00, "RQPRM0", "Receive Queue Parameters register 0 ", ACC_RW, 0x00000000},
|
||||||
|
{0xC04, "RQPRM1", "Receive Queue Parameters register 1 ", ACC_RW, 0x00000000},
|
||||||
|
{0xC08, "RQPRM2", "Receive Queue Parameters register 2 ", ACC_RW, 0x00000000},
|
||||||
|
{0xC0C, "RQPRM3", "Receive Queue Parameters register 3 ", ACC_RW, 0x00000000},
|
||||||
|
{0xC10, "RQPRM4", "Receive Queue Parameters register 4 ", ACC_RW, 0x00000000},
|
||||||
|
{0xC14, "RQPRM5", "Receive Queue Parameters register 5 ", ACC_RW, 0x00000000},
|
||||||
|
{0xC18, "RQPRM6", "Receive Queue Parameters register 6 ", ACC_RW, 0x00000000},
|
||||||
|
{0xC1C, "RQPRM7", "Receive Queue Parameters register 7 ", ACC_RW, 0x00000000},
|
||||||
|
{0xC44, "RFBPTR0", "Last Free RxBD pointer for ring 0", ACC_RW, 0x00000000},
|
||||||
|
{0xC4C, "RFBPTR1", "Last Free RxBD pointer for ring 1", ACC_RW, 0x00000000},
|
||||||
|
{0xC54, "RFBPTR2", "Last Free RxBD pointer for ring 2", ACC_RW, 0x00000000},
|
||||||
|
{0xC5C, "RFBPTR3", "Last Free RxBD pointer for ring 3", ACC_RW, 0x00000000},
|
||||||
|
{0xC64, "RFBPTR4", "Last Free RxBD pointer for ring 4", ACC_RW, 0x00000000},
|
||||||
|
{0xC6C, "RFBPTR5", "Last Free RxBD pointer for ring 5", ACC_RW, 0x00000000},
|
||||||
|
{0xC74, "RFBPTR6", "Last Free RxBD pointer for ring 6", ACC_RW, 0x00000000},
|
||||||
|
{0xC7C, "RFBPTR7", "Last Free RxBD pointer for ring 7", ACC_RW, 0x00000000},
|
||||||
|
|
||||||
|
/* eTSEC Future Expansion Space */
|
||||||
|
|
||||||
|
/* Reserved*/
|
||||||
|
|
||||||
|
/* eTSEC IEEE 1588 Registers */
|
||||||
|
|
||||||
|
{0xE00, "TMR_CTRL", "Timer control register", ACC_RW, 0x00010001},
|
||||||
|
{0xE04, "TMR_TEVENT", "time stamp event register", ACC_W1C, 0x00000000},
|
||||||
|
{0xE08, "TMR_TEMASK", "Timer event mask register", ACC_RW, 0x00000000},
|
||||||
|
{0xE0C, "TMR_PEVENT", "time stamp event register", ACC_RW, 0x00000000},
|
||||||
|
{0xE10, "TMR_PEMASK", "Timer event mask register", ACC_RW, 0x00000000},
|
||||||
|
{0xE14, "TMR_STAT", "time stamp status register", ACC_RW, 0x00000000},
|
||||||
|
{0xE18, "TMR_CNT_H", "timer counter high register", ACC_RW, 0x00000000},
|
||||||
|
{0xE1C, "TMR_CNT_L", "timer counter low register", ACC_RW, 0x00000000},
|
||||||
|
{0xE20, "TMR_ADD", "Timer drift compensation addend register", ACC_RW, 0x00000000},
|
||||||
|
{0xE24, "TMR_ACC", "Timer accumulator register", ACC_RW, 0x00000000},
|
||||||
|
{0xE28, "TMR_PRSC", "Timer prescale", ACC_RW, 0x00000002},
|
||||||
|
{0xE30, "TMROFF_H", "Timer offset high", ACC_RW, 0x00000000},
|
||||||
|
{0xE34, "TMROFF_L", "Timer offset low", ACC_RW, 0x00000000},
|
||||||
|
{0xE40, "TMR_ALARM1_H", "Timer alarm 1 high register", ACC_RW, 0xFFFFFFFF},
|
||||||
|
{0xE44, "TMR_ALARM1_L", "Timer alarm 1 high register", ACC_RW, 0xFFFFFFFF},
|
||||||
|
{0xE48, "TMR_ALARM2_H", "Timer alarm 2 high register", ACC_RW, 0xFFFFFFFF},
|
||||||
|
{0xE4C, "TMR_ALARM2_L", "Timer alarm 2 high register", ACC_RW, 0xFFFFFFFF},
|
||||||
|
{0xE80, "TMR_FIPER1", "Timer fixed period interval", ACC_RW, 0xFFFFFFFF},
|
||||||
|
{0xE84, "TMR_FIPER2", "Timer fixed period interval", ACC_RW, 0xFFFFFFFF},
|
||||||
|
{0xE88, "TMR_FIPER3", "Timer fixed period interval", ACC_RW, 0xFFFFFFFF},
|
||||||
|
{0xEA0, "TMR_ETTS1_H", "Time stamp of general purpose external trigger ", ACC_RW, 0x00000000},
|
||||||
|
{0xEA4, "TMR_ETTS1_L", "Time stamp of general purpose external trigger", ACC_RW, 0x00000000},
|
||||||
|
{0xEA8, "TMR_ETTS2_H", "Time stamp of general purpose external trigger ", ACC_RW, 0x00000000},
|
||||||
|
{0xEAC, "TMR_ETTS2_L", "Time stamp of general purpose external trigger", ACC_RW, 0x00000000},
|
||||||
|
|
||||||
|
/* End Of Table */
|
||||||
|
{0x0, 0x0, 0x0, 0x0, 0x0}
|
||||||
|
};
|
320
hw/net/fsl_etsec/registers.h
Normal file
320
hw/net/fsl_etsec/registers.h
Normal file
@@ -0,0 +1,320 @@
|
|||||||
|
/*
|
||||||
|
* QEMU Freescale eTSEC Emulator
|
||||||
|
*
|
||||||
|
* Copyright (c) 2011-2013 AdaCore
|
||||||
|
*
|
||||||
|
* 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 _ETSEC_REGISTERS_H_
|
||||||
|
#define _ETSEC_REGISTERS_H_
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
enum eTSEC_Register_Access_Type {
|
||||||
|
ACC_RW = 1, /* Read/Write */
|
||||||
|
ACC_RO = 2, /* Read Only */
|
||||||
|
ACC_WO = 3, /* Write Only */
|
||||||
|
ACC_W1C = 4, /* Write 1 to clear */
|
||||||
|
ACC_UNKNOWN = 5 /* Unknown register*/
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef struct eTSEC_Register_Definition {
|
||||||
|
uint32_t offset;
|
||||||
|
const char *name;
|
||||||
|
const char *desc;
|
||||||
|
enum eTSEC_Register_Access_Type access;
|
||||||
|
uint32_t reset;
|
||||||
|
} eTSEC_Register_Definition;
|
||||||
|
|
||||||
|
extern const eTSEC_Register_Definition eTSEC_registers_def[];
|
||||||
|
|
||||||
|
#define DMACTRL_LE (1 << 15)
|
||||||
|
#define DMACTRL_GRS (1 << 4)
|
||||||
|
#define DMACTRL_GTS (1 << 3)
|
||||||
|
#define DMACTRL_WOP (1 << 0)
|
||||||
|
|
||||||
|
#define IEVENT_PERR (1 << 0)
|
||||||
|
#define IEVENT_DPE (1 << 1)
|
||||||
|
#define IEVENT_FIQ (1 << 2)
|
||||||
|
#define IEVENT_FIR (1 << 3)
|
||||||
|
#define IEVENT_FGPI (1 << 4)
|
||||||
|
#define IEVENT_RXF (1 << 7)
|
||||||
|
#define IEVENT_GRSC (1 << 8)
|
||||||
|
#define IEVENT_MMRW (1 << 9)
|
||||||
|
#define IEVENT_MMRD (1 << 10)
|
||||||
|
#define IEVENT_MAG (1 << 11)
|
||||||
|
#define IEVENT_RXB (1 << 15)
|
||||||
|
#define IEVENT_XFUN (1 << 16)
|
||||||
|
#define IEVENT_CRL (1 << 17)
|
||||||
|
#define IEVENT_LC (1 << 18)
|
||||||
|
#define IEVENT_TXF (1 << 20)
|
||||||
|
#define IEVENT_TXB (1 << 21)
|
||||||
|
#define IEVENT_TXE (1 << 22)
|
||||||
|
#define IEVENT_TXC (1 << 23)
|
||||||
|
#define IEVENT_BABT (1 << 24)
|
||||||
|
#define IEVENT_GTSC (1 << 25)
|
||||||
|
#define IEVENT_MSRO (1 << 26)
|
||||||
|
#define IEVENT_EBERR (1 << 28)
|
||||||
|
#define IEVENT_BSY (1 << 29)
|
||||||
|
#define IEVENT_RXC (1 << 30)
|
||||||
|
#define IEVENT_BABR (1 << 31)
|
||||||
|
|
||||||
|
#define IMASK_RXFEN (1 << 7)
|
||||||
|
#define IMASK_GRSCEN (1 << 8)
|
||||||
|
#define IMASK_RXBEN (1 << 15)
|
||||||
|
#define IMASK_TXFEN (1 << 20)
|
||||||
|
#define IMASK_TXBEN (1 << 21)
|
||||||
|
#define IMASK_GTSCEN (1 << 25)
|
||||||
|
|
||||||
|
#define MACCFG1_TX_EN (1 << 0)
|
||||||
|
#define MACCFG1_RX_EN (1 << 2)
|
||||||
|
|
||||||
|
#define MACCFG2_CRC_EN (1 << 1)
|
||||||
|
#define MACCFG2_PADCRC (1 << 2)
|
||||||
|
|
||||||
|
#define MIIMCOM_READ (1 << 0)
|
||||||
|
#define MIIMCOM_SCAN (1 << 1)
|
||||||
|
|
||||||
|
#define RCTRL_PRSDEP_MASK (0x3)
|
||||||
|
#define RCTRL_PRSDEP_OFFSET (6)
|
||||||
|
#define RCTRL_RSF (1 << 2)
|
||||||
|
|
||||||
|
/* Index of each register */
|
||||||
|
|
||||||
|
#define TSEC_ID (0x000 / 4)
|
||||||
|
#define TSEC_ID2 (0x004 / 4)
|
||||||
|
#define IEVENT (0x010 / 4)
|
||||||
|
#define IMASK (0x014 / 4)
|
||||||
|
#define EDIS (0x018 / 4)
|
||||||
|
#define ECNTRL (0x020 / 4)
|
||||||
|
#define PTV (0x028 / 4)
|
||||||
|
#define DMACTRL (0x02C / 4)
|
||||||
|
#define TBIPA (0x030 / 4)
|
||||||
|
#define TCTRL (0x100 / 4)
|
||||||
|
#define TSTAT (0x104 / 4)
|
||||||
|
#define DFVLAN (0x108 / 4)
|
||||||
|
#define TXIC (0x110 / 4)
|
||||||
|
#define TQUEUE (0x114 / 4)
|
||||||
|
#define TR03WT (0x140 / 4)
|
||||||
|
#define TR47WT (0x144 / 4)
|
||||||
|
#define TBDBPH (0x180 / 4)
|
||||||
|
#define TBPTR0 (0x184 / 4)
|
||||||
|
#define TBPTR1 (0x18C / 4)
|
||||||
|
#define TBPTR2 (0x194 / 4)
|
||||||
|
#define TBPTR3 (0x19C / 4)
|
||||||
|
#define TBPTR4 (0x1A4 / 4)
|
||||||
|
#define TBPTR5 (0x1AC / 4)
|
||||||
|
#define TBPTR6 (0x1B4 / 4)
|
||||||
|
#define TBPTR7 (0x1BC / 4)
|
||||||
|
#define TBASEH (0x200 / 4)
|
||||||
|
#define TBASE0 (0x204 / 4)
|
||||||
|
#define TBASE1 (0x20C / 4)
|
||||||
|
#define TBASE2 (0x214 / 4)
|
||||||
|
#define TBASE3 (0x21C / 4)
|
||||||
|
#define TBASE4 (0x224 / 4)
|
||||||
|
#define TBASE5 (0x22C / 4)
|
||||||
|
#define TBASE6 (0x234 / 4)
|
||||||
|
#define TBASE7 (0x23C / 4)
|
||||||
|
#define TMR_TXTS1_ID (0x280 / 4)
|
||||||
|
#define TMR_TXTS2_ID (0x284 / 4)
|
||||||
|
#define TMR_TXTS1_H (0x2C0 / 4)
|
||||||
|
#define TMR_TXTS1_L (0x2C4 / 4)
|
||||||
|
#define TMR_TXTS2_H (0x2C8 / 4)
|
||||||
|
#define TMR_TXTS2_L (0x2CC / 4)
|
||||||
|
#define RCTRL (0x300 / 4)
|
||||||
|
#define RSTAT (0x304 / 4)
|
||||||
|
#define RXIC (0x310 / 4)
|
||||||
|
#define RQUEUE (0x314 / 4)
|
||||||
|
#define RBIFX (0x330 / 4)
|
||||||
|
#define RQFAR (0x334 / 4)
|
||||||
|
#define RQFCR (0x338 / 4)
|
||||||
|
#define RQFPR (0x33C / 4)
|
||||||
|
#define MRBLR (0x340 / 4)
|
||||||
|
#define RBDBPH (0x380 / 4)
|
||||||
|
#define RBPTR0 (0x384 / 4)
|
||||||
|
#define RBPTR1 (0x38C / 4)
|
||||||
|
#define RBPTR2 (0x394 / 4)
|
||||||
|
#define RBPTR3 (0x39C / 4)
|
||||||
|
#define RBPTR4 (0x3A4 / 4)
|
||||||
|
#define RBPTR5 (0x3AC / 4)
|
||||||
|
#define RBPTR6 (0x3B4 / 4)
|
||||||
|
#define RBPTR7 (0x3BC / 4)
|
||||||
|
#define RBASEH (0x400 / 4)
|
||||||
|
#define RBASE0 (0x404 / 4)
|
||||||
|
#define RBASE1 (0x40C / 4)
|
||||||
|
#define RBASE2 (0x414 / 4)
|
||||||
|
#define RBASE3 (0x41C / 4)
|
||||||
|
#define RBASE4 (0x424 / 4)
|
||||||
|
#define RBASE5 (0x42C / 4)
|
||||||
|
#define RBASE6 (0x434 / 4)
|
||||||
|
#define RBASE7 (0x43C / 4)
|
||||||
|
#define TMR_RXTS_H (0x4C0 / 4)
|
||||||
|
#define TMR_RXTS_L (0x4C4 / 4)
|
||||||
|
#define MACCFG1 (0x500 / 4)
|
||||||
|
#define MACCFG2 (0x504 / 4)
|
||||||
|
#define IPGIFG (0x508 / 4)
|
||||||
|
#define HAFDUP (0x50C / 4)
|
||||||
|
#define MAXFRM (0x510 / 4)
|
||||||
|
#define MIIMCFG (0x520 / 4)
|
||||||
|
#define MIIMCOM (0x524 / 4)
|
||||||
|
#define MIIMADD (0x528 / 4)
|
||||||
|
#define MIIMCON (0x52C / 4)
|
||||||
|
#define MIIMSTAT (0x530 / 4)
|
||||||
|
#define MIIMIND (0x534 / 4)
|
||||||
|
#define IFSTAT (0x53C / 4)
|
||||||
|
#define MACSTNADDR1 (0x540 / 4)
|
||||||
|
#define MACSTNADDR2 (0x544 / 4)
|
||||||
|
#define MAC01ADDR1 (0x548 / 4)
|
||||||
|
#define MAC01ADDR2 (0x54C / 4)
|
||||||
|
#define MAC02ADDR1 (0x550 / 4)
|
||||||
|
#define MAC02ADDR2 (0x554 / 4)
|
||||||
|
#define MAC03ADDR1 (0x558 / 4)
|
||||||
|
#define MAC03ADDR2 (0x55C / 4)
|
||||||
|
#define MAC04ADDR1 (0x560 / 4)
|
||||||
|
#define MAC04ADDR2 (0x564 / 4)
|
||||||
|
#define MAC05ADDR1 (0x568 / 4)
|
||||||
|
#define MAC05ADDR2 (0x56C / 4)
|
||||||
|
#define MAC06ADDR1 (0x570 / 4)
|
||||||
|
#define MAC06ADDR2 (0x574 / 4)
|
||||||
|
#define MAC07ADDR1 (0x578 / 4)
|
||||||
|
#define MAC07ADDR2 (0x57C / 4)
|
||||||
|
#define MAC08ADDR1 (0x580 / 4)
|
||||||
|
#define MAC08ADDR2 (0x584 / 4)
|
||||||
|
#define MAC09ADDR1 (0x588 / 4)
|
||||||
|
#define MAC09ADDR2 (0x58C / 4)
|
||||||
|
#define MAC10ADDR1 (0x590 / 4)
|
||||||
|
#define MAC10ADDR2 (0x594 / 4)
|
||||||
|
#define MAC11ADDR1 (0x598 / 4)
|
||||||
|
#define MAC11ADDR2 (0x59C / 4)
|
||||||
|
#define MAC12ADDR1 (0x5A0 / 4)
|
||||||
|
#define MAC12ADDR2 (0x5A4 / 4)
|
||||||
|
#define MAC13ADDR1 (0x5A8 / 4)
|
||||||
|
#define MAC13ADDR2 (0x5AC / 4)
|
||||||
|
#define MAC14ADDR1 (0x5B0 / 4)
|
||||||
|
#define MAC14ADDR2 (0x5B4 / 4)
|
||||||
|
#define MAC15ADDR1 (0x5B8 / 4)
|
||||||
|
#define MAC15ADDR2 (0x5BC / 4)
|
||||||
|
#define TR64 (0x680 / 4)
|
||||||
|
#define TR127 (0x684 / 4)
|
||||||
|
#define TR255 (0x688 / 4)
|
||||||
|
#define TR511 (0x68C / 4)
|
||||||
|
#define TR1K (0x690 / 4)
|
||||||
|
#define TRMAX (0x694 / 4)
|
||||||
|
#define TRMGV (0x698 / 4)
|
||||||
|
#define RBYT (0x69C / 4)
|
||||||
|
#define RPKT (0x6A0 / 4)
|
||||||
|
#define RFCS (0x6A4 / 4)
|
||||||
|
#define RMCA (0x6A8 / 4)
|
||||||
|
#define RBCA (0x6AC / 4)
|
||||||
|
#define RXCF (0x6B0 / 4)
|
||||||
|
#define RXPF (0x6B4 / 4)
|
||||||
|
#define RXUO (0x6B8 / 4)
|
||||||
|
#define RALN (0x6BC / 4)
|
||||||
|
#define RFLR (0x6C0 / 4)
|
||||||
|
#define RCDE (0x6C4 / 4)
|
||||||
|
#define RCSE (0x6C8 / 4)
|
||||||
|
#define RUND (0x6CC / 4)
|
||||||
|
#define ROVR (0x6D0 / 4)
|
||||||
|
#define RFRG (0x6D4 / 4)
|
||||||
|
#define RJBR (0x6D8 / 4)
|
||||||
|
#define RDRP (0x6DC / 4)
|
||||||
|
#define TBYT (0x6E0 / 4)
|
||||||
|
#define TPKT (0x6E4 / 4)
|
||||||
|
#define TMCA (0x6E8 / 4)
|
||||||
|
#define TBCA (0x6EC / 4)
|
||||||
|
#define TXPF (0x6F0 / 4)
|
||||||
|
#define TDFR (0x6F4 / 4)
|
||||||
|
#define TEDF (0x6F8 / 4)
|
||||||
|
#define TSCL (0x6FC / 4)
|
||||||
|
#define TMCL (0x700 / 4)
|
||||||
|
#define TLCL (0x704 / 4)
|
||||||
|
#define TXCL (0x708 / 4)
|
||||||
|
#define TNCL (0x70C / 4)
|
||||||
|
#define TDRP (0x714 / 4)
|
||||||
|
#define TJBR (0x718 / 4)
|
||||||
|
#define TFCS (0x71C / 4)
|
||||||
|
#define TXCF (0x720 / 4)
|
||||||
|
#define TOVR (0x724 / 4)
|
||||||
|
#define TUND (0x728 / 4)
|
||||||
|
#define TFRG (0x72C / 4)
|
||||||
|
#define CAR1 (0x730 / 4)
|
||||||
|
#define CAR2 (0x734 / 4)
|
||||||
|
#define CAM1 (0x738 / 4)
|
||||||
|
#define CAM2 (0x73C / 4)
|
||||||
|
#define RREJ (0x740 / 4)
|
||||||
|
#define IGADDR0 (0x800 / 4)
|
||||||
|
#define IGADDR1 (0x804 / 4)
|
||||||
|
#define IGADDR2 (0x808 / 4)
|
||||||
|
#define IGADDR3 (0x80C / 4)
|
||||||
|
#define IGADDR4 (0x810 / 4)
|
||||||
|
#define IGADDR5 (0x814 / 4)
|
||||||
|
#define IGADDR6 (0x818 / 4)
|
||||||
|
#define IGADDR7 (0x81C / 4)
|
||||||
|
#define GADDR0 (0x880 / 4)
|
||||||
|
#define GADDR1 (0x884 / 4)
|
||||||
|
#define GADDR2 (0x888 / 4)
|
||||||
|
#define GADDR3 (0x88C / 4)
|
||||||
|
#define GADDR4 (0x890 / 4)
|
||||||
|
#define GADDR5 (0x894 / 4)
|
||||||
|
#define GADDR6 (0x898 / 4)
|
||||||
|
#define GADDR7 (0x89C / 4)
|
||||||
|
#define ATTR (0xBF8 / 4)
|
||||||
|
#define ATTRELI (0xBFC / 4)
|
||||||
|
#define RQPRM0 (0xC00 / 4)
|
||||||
|
#define RQPRM1 (0xC04 / 4)
|
||||||
|
#define RQPRM2 (0xC08 / 4)
|
||||||
|
#define RQPRM3 (0xC0C / 4)
|
||||||
|
#define RQPRM4 (0xC10 / 4)
|
||||||
|
#define RQPRM5 (0xC14 / 4)
|
||||||
|
#define RQPRM6 (0xC18 / 4)
|
||||||
|
#define RQPRM7 (0xC1C / 4)
|
||||||
|
#define RFBPTR0 (0xC44 / 4)
|
||||||
|
#define RFBPTR1 (0xC4C / 4)
|
||||||
|
#define RFBPTR2 (0xC54 / 4)
|
||||||
|
#define RFBPTR3 (0xC5C / 4)
|
||||||
|
#define RFBPTR4 (0xC64 / 4)
|
||||||
|
#define RFBPTR5 (0xC6C / 4)
|
||||||
|
#define RFBPTR6 (0xC74 / 4)
|
||||||
|
#define RFBPTR7 (0xC7C / 4)
|
||||||
|
#define TMR_CTRL (0xE00 / 4)
|
||||||
|
#define TMR_TEVENT (0xE04 / 4)
|
||||||
|
#define TMR_TEMASK (0xE08 / 4)
|
||||||
|
#define TMR_PEVENT (0xE0C / 4)
|
||||||
|
#define TMR_PEMASK (0xE10 / 4)
|
||||||
|
#define TMR_STAT (0xE14 / 4)
|
||||||
|
#define TMR_CNT_H (0xE18 / 4)
|
||||||
|
#define TMR_CNT_L (0xE1C / 4)
|
||||||
|
#define TMR_ADD (0xE20 / 4)
|
||||||
|
#define TMR_ACC (0xE24 / 4)
|
||||||
|
#define TMR_PRSC (0xE28 / 4)
|
||||||
|
#define TMROFF_H (0xE30 / 4)
|
||||||
|
#define TMROFF_L (0xE34 / 4)
|
||||||
|
#define TMR_ALARM1_H (0xE40 / 4)
|
||||||
|
#define TMR_ALARM1_L (0xE44 / 4)
|
||||||
|
#define TMR_ALARM2_H (0xE48 / 4)
|
||||||
|
#define TMR_ALARM2_L (0xE4C / 4)
|
||||||
|
#define TMR_FIPER1 (0xE80 / 4)
|
||||||
|
#define TMR_FIPER2 (0xE84 / 4)
|
||||||
|
#define TMR_FIPER3 (0xE88 / 4)
|
||||||
|
#define TMR_ETTS1_H (0xEA0 / 4)
|
||||||
|
#define TMR_ETTS1_L (0xEA4 / 4)
|
||||||
|
#define TMR_ETTS2_H (0xEA8 / 4)
|
||||||
|
#define TMR_ETTS2_L (0xEAC / 4)
|
||||||
|
|
||||||
|
#endif /* ! _ETSEC_REGISTERS_H_ */
|
650
hw/net/fsl_etsec/rings.c
Normal file
650
hw/net/fsl_etsec/rings.c
Normal file
@@ -0,0 +1,650 @@
|
|||||||
|
/*
|
||||||
|
* QEMU Freescale eTSEC Emulator
|
||||||
|
*
|
||||||
|
* Copyright (c) 2011-2013 AdaCore
|
||||||
|
*
|
||||||
|
* 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 "net/checksum.h"
|
||||||
|
|
||||||
|
#include "etsec.h"
|
||||||
|
#include "registers.h"
|
||||||
|
|
||||||
|
/* #define ETSEC_RING_DEBUG */
|
||||||
|
/* #define HEX_DUMP */
|
||||||
|
/* #define DEBUG_BD */
|
||||||
|
|
||||||
|
#ifdef ETSEC_RING_DEBUG
|
||||||
|
static const int debug_etsec = 1;
|
||||||
|
#else
|
||||||
|
static const int debug_etsec;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define RING_DEBUG(fmt, ...) do { \
|
||||||
|
if (debug_etsec) { \
|
||||||
|
qemu_log(fmt , ## __VA_ARGS__); \
|
||||||
|
} \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
#ifdef DEBUG_BD
|
||||||
|
|
||||||
|
static void print_tx_bd_flags(uint16_t flags)
|
||||||
|
{
|
||||||
|
qemu_log(" Ready: %d\n", !!(flags & BD_TX_READY));
|
||||||
|
qemu_log(" PAD/CRC: %d\n", !!(flags & BD_TX_PADCRC));
|
||||||
|
qemu_log(" Wrap: %d\n", !!(flags & BD_WRAP));
|
||||||
|
qemu_log(" Interrupt: %d\n", !!(flags & BD_INTERRUPT));
|
||||||
|
qemu_log(" Last in frame: %d\n", !!(flags & BD_LAST));
|
||||||
|
qemu_log(" Tx CRC: %d\n", !!(flags & BD_TX_TC));
|
||||||
|
qemu_log(" User-defined preamble / defer: %d\n",
|
||||||
|
!!(flags & BD_TX_PREDEF));
|
||||||
|
qemu_log(" Huge frame enable / Late collision: %d\n",
|
||||||
|
!!(flags & BD_TX_HFELC));
|
||||||
|
qemu_log(" Control frame / Retransmission Limit: %d\n",
|
||||||
|
!!(flags & BD_TX_CFRL));
|
||||||
|
qemu_log(" Retry count: %d\n",
|
||||||
|
(flags >> BD_TX_RC_OFFSET) & BD_TX_RC_MASK);
|
||||||
|
qemu_log(" Underrun / TCP/IP off-load enable: %d\n",
|
||||||
|
!!(flags & BD_TX_TOEUN));
|
||||||
|
qemu_log(" Truncation: %d\n", !!(flags & BD_TX_TR));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void print_rx_bd_flags(uint16_t flags)
|
||||||
|
{
|
||||||
|
qemu_log(" Empty: %d\n", !!(flags & BD_RX_EMPTY));
|
||||||
|
qemu_log(" Receive software ownership: %d\n", !!(flags & BD_RX_RO1));
|
||||||
|
qemu_log(" Wrap: %d\n", !!(flags & BD_WRAP));
|
||||||
|
qemu_log(" Interrupt: %d\n", !!(flags & BD_INTERRUPT));
|
||||||
|
qemu_log(" Last in frame: %d\n", !!(flags & BD_LAST));
|
||||||
|
qemu_log(" First in frame: %d\n", !!(flags & BD_RX_FIRST));
|
||||||
|
qemu_log(" Miss: %d\n", !!(flags & BD_RX_MISS));
|
||||||
|
qemu_log(" Broadcast: %d\n", !!(flags & BD_RX_BROADCAST));
|
||||||
|
qemu_log(" Multicast: %d\n", !!(flags & BD_RX_MULTICAST));
|
||||||
|
qemu_log(" Rx frame length violation: %d\n", !!(flags & BD_RX_LG));
|
||||||
|
qemu_log(" Rx non-octet aligned frame: %d\n", !!(flags & BD_RX_NO));
|
||||||
|
qemu_log(" Short frame: %d\n", !!(flags & BD_RX_SH));
|
||||||
|
qemu_log(" Rx CRC Error: %d\n", !!(flags & BD_RX_CR));
|
||||||
|
qemu_log(" Overrun: %d\n", !!(flags & BD_RX_OV));
|
||||||
|
qemu_log(" Truncation: %d\n", !!(flags & BD_RX_TR));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void print_bd(eTSEC_rxtx_bd bd, int mode, uint32_t index)
|
||||||
|
{
|
||||||
|
qemu_log("eTSEC %s Data Buffer Descriptor (%u)\n",
|
||||||
|
mode == eTSEC_TRANSMIT ? "Transmit" : "Receive",
|
||||||
|
index);
|
||||||
|
qemu_log(" Flags : 0x%04x\n", bd.flags);
|
||||||
|
if (mode == eTSEC_TRANSMIT) {
|
||||||
|
print_tx_bd_flags(bd.flags);
|
||||||
|
} else {
|
||||||
|
print_rx_bd_flags(bd.flags);
|
||||||
|
}
|
||||||
|
qemu_log(" Length : 0x%04x\n", bd.length);
|
||||||
|
qemu_log(" Pointer : 0x%08x\n", bd.bufptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* DEBUG_BD */
|
||||||
|
|
||||||
|
static void read_buffer_descriptor(eTSEC *etsec,
|
||||||
|
hwaddr addr,
|
||||||
|
eTSEC_rxtx_bd *bd)
|
||||||
|
{
|
||||||
|
assert(bd != NULL);
|
||||||
|
|
||||||
|
RING_DEBUG("READ Buffer Descriptor @ 0x" TARGET_FMT_plx"\n", addr);
|
||||||
|
cpu_physical_memory_read(addr,
|
||||||
|
bd,
|
||||||
|
sizeof(eTSEC_rxtx_bd));
|
||||||
|
|
||||||
|
if (etsec->regs[DMACTRL].value & DMACTRL_LE) {
|
||||||
|
bd->flags = lduw_le_p(&bd->flags);
|
||||||
|
bd->length = lduw_le_p(&bd->length);
|
||||||
|
bd->bufptr = ldl_le_p(&bd->bufptr);
|
||||||
|
} else {
|
||||||
|
bd->flags = lduw_be_p(&bd->flags);
|
||||||
|
bd->length = lduw_be_p(&bd->length);
|
||||||
|
bd->bufptr = ldl_be_p(&bd->bufptr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void write_buffer_descriptor(eTSEC *etsec,
|
||||||
|
hwaddr addr,
|
||||||
|
eTSEC_rxtx_bd *bd)
|
||||||
|
{
|
||||||
|
assert(bd != NULL);
|
||||||
|
|
||||||
|
if (etsec->regs[DMACTRL].value & DMACTRL_LE) {
|
||||||
|
stw_le_p(&bd->flags, bd->flags);
|
||||||
|
stw_le_p(&bd->length, bd->length);
|
||||||
|
stl_le_p(&bd->bufptr, bd->bufptr);
|
||||||
|
} else {
|
||||||
|
stw_be_p(&bd->flags, bd->flags);
|
||||||
|
stw_be_p(&bd->length, bd->length);
|
||||||
|
stl_be_p(&bd->bufptr, bd->bufptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
RING_DEBUG("Write Buffer Descriptor @ 0x" TARGET_FMT_plx"\n", addr);
|
||||||
|
cpu_physical_memory_write(addr,
|
||||||
|
bd,
|
||||||
|
sizeof(eTSEC_rxtx_bd));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ievent_set(eTSEC *etsec,
|
||||||
|
uint32_t flags)
|
||||||
|
{
|
||||||
|
etsec->regs[IEVENT].value |= flags;
|
||||||
|
|
||||||
|
if ((flags & IEVENT_TXB && etsec->regs[IMASK].value & IMASK_TXBEN)
|
||||||
|
|| (flags & IEVENT_TXF && etsec->regs[IMASK].value & IMASK_TXFEN)) {
|
||||||
|
qemu_irq_raise(etsec->tx_irq);
|
||||||
|
RING_DEBUG("%s Raise Tx IRQ\n", __func__);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((flags & IEVENT_RXB && etsec->regs[IMASK].value & IMASK_RXBEN)
|
||||||
|
|| (flags & IEVENT_RXF && etsec->regs[IMASK].value & IMASK_RXFEN)) {
|
||||||
|
qemu_irq_pulse(etsec->rx_irq);
|
||||||
|
RING_DEBUG("%s Raise Rx IRQ\n", __func__);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void tx_padding_and_crc(eTSEC *etsec, uint32_t min_frame_len)
|
||||||
|
{
|
||||||
|
int add = min_frame_len - etsec->tx_buffer_len;
|
||||||
|
|
||||||
|
/* Padding */
|
||||||
|
if (add > 0) {
|
||||||
|
RING_DEBUG("pad:%u\n", add);
|
||||||
|
etsec->tx_buffer = g_realloc(etsec->tx_buffer,
|
||||||
|
etsec->tx_buffer_len + add);
|
||||||
|
|
||||||
|
memset(etsec->tx_buffer + etsec->tx_buffer_len, 0x0, add);
|
||||||
|
etsec->tx_buffer_len += add;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Never add CRC in QEMU */
|
||||||
|
}
|
||||||
|
|
||||||
|
static void process_tx_fcb(eTSEC *etsec)
|
||||||
|
{
|
||||||
|
uint8_t flags = (uint8_t)(*etsec->tx_buffer);
|
||||||
|
/* L3 header offset from start of frame */
|
||||||
|
uint8_t l3_header_offset = (uint8_t)*(etsec->tx_buffer + 3);
|
||||||
|
/* L4 header offset from start of L3 header */
|
||||||
|
uint8_t l4_header_offset = (uint8_t)*(etsec->tx_buffer + 2);
|
||||||
|
/* L3 header */
|
||||||
|
uint8_t *l3_header = etsec->tx_buffer + 8 + l3_header_offset;
|
||||||
|
/* L4 header */
|
||||||
|
uint8_t *l4_header = l3_header + l4_header_offset;
|
||||||
|
|
||||||
|
/* if packet is IP4 and IP checksum is requested */
|
||||||
|
if (flags & FCB_TX_IP && flags & FCB_TX_CIP) {
|
||||||
|
/* do IP4 checksum (TODO This funtion does TCP/UDP checksum but not sure
|
||||||
|
* if it also does IP4 checksum. */
|
||||||
|
net_checksum_calculate(etsec->tx_buffer + 8,
|
||||||
|
etsec->tx_buffer_len - 8);
|
||||||
|
}
|
||||||
|
/* TODO Check the correct usage of the PHCS field of the FCB in case the NPH
|
||||||
|
* flag is on */
|
||||||
|
|
||||||
|
/* if packet is IP4 and TCP or UDP */
|
||||||
|
if (flags & FCB_TX_IP && flags & FCB_TX_TUP) {
|
||||||
|
/* if UDP */
|
||||||
|
if (flags & FCB_TX_UDP) {
|
||||||
|
/* if checksum is requested */
|
||||||
|
if (flags & FCB_TX_CTU) {
|
||||||
|
/* do UDP checksum */
|
||||||
|
|
||||||
|
net_checksum_calculate(etsec->tx_buffer + 8,
|
||||||
|
etsec->tx_buffer_len - 8);
|
||||||
|
} else {
|
||||||
|
/* set checksum field to 0 */
|
||||||
|
l4_header[6] = 0;
|
||||||
|
l4_header[7] = 0;
|
||||||
|
}
|
||||||
|
} else if (flags & FCB_TX_CTU) { /* if TCP and checksum is requested */
|
||||||
|
/* do TCP checksum */
|
||||||
|
net_checksum_calculate(etsec->tx_buffer + 8,
|
||||||
|
etsec->tx_buffer_len - 8);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void process_tx_bd(eTSEC *etsec,
|
||||||
|
eTSEC_rxtx_bd *bd)
|
||||||
|
{
|
||||||
|
uint8_t *tmp_buff = NULL;
|
||||||
|
hwaddr tbdbth = (hwaddr)(etsec->regs[TBDBPH].value & 0xF) << 32;
|
||||||
|
|
||||||
|
if (bd->length == 0) {
|
||||||
|
/* ERROR */
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (etsec->tx_buffer_len == 0) {
|
||||||
|
/* It's the first BD */
|
||||||
|
etsec->first_bd = *bd;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* TODO: if TxBD[TOE/UN] skip the Tx Frame Control Block*/
|
||||||
|
|
||||||
|
/* Load this Data Buffer */
|
||||||
|
etsec->tx_buffer = g_realloc(etsec->tx_buffer,
|
||||||
|
etsec->tx_buffer_len + bd->length);
|
||||||
|
tmp_buff = etsec->tx_buffer + etsec->tx_buffer_len;
|
||||||
|
cpu_physical_memory_read(bd->bufptr + tbdbth, tmp_buff, bd->length);
|
||||||
|
|
||||||
|
/* Update buffer length */
|
||||||
|
etsec->tx_buffer_len += bd->length;
|
||||||
|
|
||||||
|
|
||||||
|
if (etsec->tx_buffer_len != 0 && (bd->flags & BD_LAST)) {
|
||||||
|
if (etsec->regs[MACCFG1].value & MACCFG1_TX_EN) {
|
||||||
|
/* MAC Transmit enabled */
|
||||||
|
|
||||||
|
/* Process offload Tx FCB */
|
||||||
|
if (etsec->first_bd.flags & BD_TX_TOEUN) {
|
||||||
|
process_tx_fcb(etsec);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (etsec->first_bd.flags & BD_TX_PADCRC
|
||||||
|
|| etsec->regs[MACCFG2].value & MACCFG2_PADCRC) {
|
||||||
|
|
||||||
|
/* Padding and CRC (Padding implies CRC) */
|
||||||
|
tx_padding_and_crc(etsec, 64);
|
||||||
|
|
||||||
|
} else if (etsec->first_bd.flags & BD_TX_TC
|
||||||
|
|| etsec->regs[MACCFG2].value & MACCFG2_CRC_EN) {
|
||||||
|
|
||||||
|
/* Only CRC */
|
||||||
|
/* Never add CRC in QEMU */
|
||||||
|
}
|
||||||
|
|
||||||
|
#if defined(HEX_DUMP)
|
||||||
|
qemu_log("eTSEC Send packet size:%d\n", etsec->tx_buffer_len);
|
||||||
|
qemu_hexdump(etsec->tx_buffer, stderr, "", etsec->tx_buffer_len);
|
||||||
|
#endif /* ETSEC_RING_DEBUG */
|
||||||
|
|
||||||
|
if (etsec->first_bd.flags & BD_TX_TOEUN) {
|
||||||
|
qemu_send_packet(qemu_get_queue(etsec->nic),
|
||||||
|
etsec->tx_buffer + 8,
|
||||||
|
etsec->tx_buffer_len - 8);
|
||||||
|
} else {
|
||||||
|
qemu_send_packet(qemu_get_queue(etsec->nic),
|
||||||
|
etsec->tx_buffer,
|
||||||
|
etsec->tx_buffer_len);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
etsec->tx_buffer_len = 0;
|
||||||
|
|
||||||
|
if (bd->flags & BD_INTERRUPT) {
|
||||||
|
ievent_set(etsec, IEVENT_TXF);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (bd->flags & BD_INTERRUPT) {
|
||||||
|
ievent_set(etsec, IEVENT_TXB);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Update DB flags */
|
||||||
|
|
||||||
|
/* Clear Ready */
|
||||||
|
bd->flags &= ~BD_TX_READY;
|
||||||
|
|
||||||
|
/* Clear Defer */
|
||||||
|
bd->flags &= ~BD_TX_PREDEF;
|
||||||
|
|
||||||
|
/* Clear Late Collision */
|
||||||
|
bd->flags &= ~BD_TX_HFELC;
|
||||||
|
|
||||||
|
/* Clear Retransmission Limit */
|
||||||
|
bd->flags &= ~BD_TX_CFRL;
|
||||||
|
|
||||||
|
/* Clear Retry Count */
|
||||||
|
bd->flags &= ~(BD_TX_RC_MASK << BD_TX_RC_OFFSET);
|
||||||
|
|
||||||
|
/* Clear Underrun */
|
||||||
|
bd->flags &= ~BD_TX_TOEUN;
|
||||||
|
|
||||||
|
/* Clear Truncation */
|
||||||
|
bd->flags &= ~BD_TX_TR;
|
||||||
|
}
|
||||||
|
|
||||||
|
void etsec_walk_tx_ring(eTSEC *etsec, int ring_nbr)
|
||||||
|
{
|
||||||
|
hwaddr ring_base = 0;
|
||||||
|
hwaddr bd_addr = 0;
|
||||||
|
eTSEC_rxtx_bd bd;
|
||||||
|
uint16_t bd_flags;
|
||||||
|
|
||||||
|
if (!(etsec->regs[MACCFG1].value & MACCFG1_TX_EN)) {
|
||||||
|
RING_DEBUG("%s: MAC Transmit not enabled\n", __func__);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ring_base = (hwaddr)(etsec->regs[TBASEH].value & 0xF) << 32;
|
||||||
|
ring_base += etsec->regs[TBASE0 + ring_nbr].value & ~0x7;
|
||||||
|
bd_addr = etsec->regs[TBPTR0 + ring_nbr].value & ~0x7;
|
||||||
|
|
||||||
|
do {
|
||||||
|
read_buffer_descriptor(etsec, bd_addr, &bd);
|
||||||
|
|
||||||
|
#ifdef DEBUG_BD
|
||||||
|
print_bd(bd,
|
||||||
|
eTSEC_TRANSMIT,
|
||||||
|
(bd_addr - ring_base) / sizeof(eTSEC_rxtx_bd));
|
||||||
|
|
||||||
|
#endif /* DEBUG_BD */
|
||||||
|
|
||||||
|
/* Save flags before BD update */
|
||||||
|
bd_flags = bd.flags;
|
||||||
|
|
||||||
|
if (bd_flags & BD_TX_READY) {
|
||||||
|
process_tx_bd(etsec, &bd);
|
||||||
|
|
||||||
|
/* Write back BD after update */
|
||||||
|
write_buffer_descriptor(etsec, bd_addr, &bd);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Wrap or next BD */
|
||||||
|
if (bd_flags & BD_WRAP) {
|
||||||
|
bd_addr = ring_base;
|
||||||
|
} else {
|
||||||
|
bd_addr += sizeof(eTSEC_rxtx_bd);
|
||||||
|
}
|
||||||
|
|
||||||
|
} while (bd_addr != ring_base);
|
||||||
|
|
||||||
|
bd_addr = ring_base;
|
||||||
|
|
||||||
|
/* Save the Buffer Descriptor Pointers to current bd */
|
||||||
|
etsec->regs[TBPTR0 + ring_nbr].value = bd_addr;
|
||||||
|
|
||||||
|
/* Set transmit halt THLTx */
|
||||||
|
etsec->regs[TSTAT].value |= 1 << (31 - ring_nbr);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void fill_rx_bd(eTSEC *etsec,
|
||||||
|
eTSEC_rxtx_bd *bd,
|
||||||
|
const uint8_t **buf,
|
||||||
|
size_t *size)
|
||||||
|
{
|
||||||
|
uint16_t to_write;
|
||||||
|
hwaddr bufptr = bd->bufptr +
|
||||||
|
((hwaddr)(etsec->regs[TBDBPH].value & 0xF) << 32);
|
||||||
|
uint8_t padd[etsec->rx_padding];
|
||||||
|
uint8_t rem;
|
||||||
|
|
||||||
|
RING_DEBUG("eTSEC fill Rx buffer @ 0x%016" HWADDR_PRIx
|
||||||
|
" size:%zu(padding + crc:%u) + fcb:%u\n",
|
||||||
|
bufptr, *size, etsec->rx_padding, etsec->rx_fcb_size);
|
||||||
|
|
||||||
|
bd->length = 0;
|
||||||
|
|
||||||
|
/* This operation will only write FCB */
|
||||||
|
if (etsec->rx_fcb_size != 0) {
|
||||||
|
|
||||||
|
cpu_physical_memory_write(bufptr, etsec->rx_fcb, etsec->rx_fcb_size);
|
||||||
|
|
||||||
|
bufptr += etsec->rx_fcb_size;
|
||||||
|
bd->length += etsec->rx_fcb_size;
|
||||||
|
etsec->rx_fcb_size = 0;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/* We remove padding from the computation of to_write because it is not
|
||||||
|
* allocated in the buffer.
|
||||||
|
*/
|
||||||
|
to_write = MIN(*size - etsec->rx_padding,
|
||||||
|
etsec->regs[MRBLR].value - etsec->rx_fcb_size);
|
||||||
|
|
||||||
|
/* This operation can only write packet data and no padding */
|
||||||
|
if (to_write > 0) {
|
||||||
|
cpu_physical_memory_write(bufptr, *buf, to_write);
|
||||||
|
|
||||||
|
*buf += to_write;
|
||||||
|
bufptr += to_write;
|
||||||
|
*size -= to_write;
|
||||||
|
|
||||||
|
bd->flags &= ~BD_RX_EMPTY;
|
||||||
|
bd->length += to_write;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (*size == etsec->rx_padding) {
|
||||||
|
/* The remaining bytes are only for padding which is not actually
|
||||||
|
* allocated in the data buffer.
|
||||||
|
*/
|
||||||
|
|
||||||
|
rem = MIN(etsec->regs[MRBLR].value - bd->length, etsec->rx_padding);
|
||||||
|
|
||||||
|
if (rem > 0) {
|
||||||
|
memset(padd, 0x0, sizeof(padd));
|
||||||
|
etsec->rx_padding -= rem;
|
||||||
|
*size -= rem;
|
||||||
|
bd->length += rem;
|
||||||
|
cpu_physical_memory_write(bufptr, padd, rem);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void rx_init_frame(eTSEC *etsec, const uint8_t *buf, size_t size)
|
||||||
|
{
|
||||||
|
uint32_t fcb_size = 0;
|
||||||
|
uint8_t prsdep = (etsec->regs[RCTRL].value >> RCTRL_PRSDEP_OFFSET)
|
||||||
|
& RCTRL_PRSDEP_MASK;
|
||||||
|
|
||||||
|
if (prsdep != 0) {
|
||||||
|
/* Prepend FCB (FCB size + RCTRL[PAL]) */
|
||||||
|
fcb_size = 8 + ((etsec->regs[RCTRL].value >> 16) & 0x1F);
|
||||||
|
|
||||||
|
etsec->rx_fcb_size = fcb_size;
|
||||||
|
|
||||||
|
/* TODO: fill_FCB(etsec); */
|
||||||
|
memset(etsec->rx_fcb, 0x0, sizeof(etsec->rx_fcb));
|
||||||
|
|
||||||
|
} else {
|
||||||
|
etsec->rx_fcb_size = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (etsec->rx_buffer != NULL) {
|
||||||
|
g_free(etsec->rx_buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Do not copy the frame for now */
|
||||||
|
etsec->rx_buffer = (uint8_t *)buf;
|
||||||
|
etsec->rx_buffer_len = size;
|
||||||
|
|
||||||
|
/* CRC padding (We don't have to compute the CRC) */
|
||||||
|
etsec->rx_padding = 4;
|
||||||
|
|
||||||
|
etsec->rx_first_in_frame = 1;
|
||||||
|
etsec->rx_remaining_data = etsec->rx_buffer_len;
|
||||||
|
RING_DEBUG("%s: rx_buffer_len:%u rx_padding+crc:%u\n", __func__,
|
||||||
|
etsec->rx_buffer_len, etsec->rx_padding);
|
||||||
|
}
|
||||||
|
|
||||||
|
void etsec_rx_ring_write(eTSEC *etsec, const uint8_t *buf, size_t size)
|
||||||
|
{
|
||||||
|
int ring_nbr = 0; /* Always use ring0 (no filer) */
|
||||||
|
|
||||||
|
if (etsec->rx_buffer_len != 0) {
|
||||||
|
RING_DEBUG("%s: We can't receive now,"
|
||||||
|
" a buffer is already in the pipe\n", __func__);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (etsec->regs[RSTAT].value & 1 << (23 - ring_nbr)) {
|
||||||
|
RING_DEBUG("%s: The ring is halted\n", __func__);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (etsec->regs[DMACTRL].value & DMACTRL_GRS) {
|
||||||
|
RING_DEBUG("%s: Graceful receive stop\n", __func__);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(etsec->regs[MACCFG1].value & MACCFG1_RX_EN)) {
|
||||||
|
RING_DEBUG("%s: MAC Receive not enabled\n", __func__);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((etsec->regs[RCTRL].value & RCTRL_RSF) && (size < 60)) {
|
||||||
|
/* CRC is not in the packet yet, so short frame is below 60 bytes */
|
||||||
|
RING_DEBUG("%s: Drop short frame\n", __func__);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
rx_init_frame(etsec, buf, size);
|
||||||
|
|
||||||
|
etsec_walk_rx_ring(etsec, ring_nbr);
|
||||||
|
}
|
||||||
|
|
||||||
|
void etsec_walk_rx_ring(eTSEC *etsec, int ring_nbr)
|
||||||
|
{
|
||||||
|
hwaddr ring_base = 0;
|
||||||
|
hwaddr bd_addr = 0;
|
||||||
|
hwaddr start_bd_addr = 0;
|
||||||
|
eTSEC_rxtx_bd bd;
|
||||||
|
uint16_t bd_flags;
|
||||||
|
size_t remaining_data;
|
||||||
|
const uint8_t *buf;
|
||||||
|
uint8_t *tmp_buf;
|
||||||
|
size_t size;
|
||||||
|
|
||||||
|
if (etsec->rx_buffer_len == 0) {
|
||||||
|
/* No frame to send */
|
||||||
|
RING_DEBUG("No frame to send\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
remaining_data = etsec->rx_remaining_data + etsec->rx_padding;
|
||||||
|
buf = etsec->rx_buffer
|
||||||
|
+ (etsec->rx_buffer_len - etsec->rx_remaining_data);
|
||||||
|
size = etsec->rx_buffer_len + etsec->rx_padding;
|
||||||
|
|
||||||
|
ring_base = (hwaddr)(etsec->regs[RBASEH].value & 0xF) << 32;
|
||||||
|
ring_base += etsec->regs[RBASE0 + ring_nbr].value & ~0x7;
|
||||||
|
start_bd_addr = bd_addr = etsec->regs[RBPTR0 + ring_nbr].value & ~0x7;
|
||||||
|
|
||||||
|
do {
|
||||||
|
read_buffer_descriptor(etsec, bd_addr, &bd);
|
||||||
|
|
||||||
|
#ifdef DEBUG_BD
|
||||||
|
print_bd(bd,
|
||||||
|
eTSEC_RECEIVE,
|
||||||
|
(bd_addr - ring_base) / sizeof(eTSEC_rxtx_bd));
|
||||||
|
|
||||||
|
#endif /* DEBUG_BD */
|
||||||
|
|
||||||
|
/* Save flags before BD update */
|
||||||
|
bd_flags = bd.flags;
|
||||||
|
|
||||||
|
if (bd_flags & BD_RX_EMPTY) {
|
||||||
|
fill_rx_bd(etsec, &bd, &buf, &remaining_data);
|
||||||
|
|
||||||
|
if (etsec->rx_first_in_frame) {
|
||||||
|
bd.flags |= BD_RX_FIRST;
|
||||||
|
etsec->rx_first_in_frame = 0;
|
||||||
|
etsec->rx_first_bd = bd;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Last in frame */
|
||||||
|
if (remaining_data == 0) {
|
||||||
|
|
||||||
|
/* Clear flags */
|
||||||
|
|
||||||
|
bd.flags &= ~0x7ff;
|
||||||
|
|
||||||
|
bd.flags |= BD_LAST;
|
||||||
|
|
||||||
|
/* NOTE: non-octet aligned frame is impossible in qemu */
|
||||||
|
|
||||||
|
if (size >= etsec->regs[MAXFRM].value) {
|
||||||
|
/* frame length violation */
|
||||||
|
qemu_log("%s frame length violation: size:%zu MAXFRM:%d\n",
|
||||||
|
__func__, size, etsec->regs[MAXFRM].value);
|
||||||
|
|
||||||
|
bd.flags |= BD_RX_LG;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (size < 64) {
|
||||||
|
/* Short frame */
|
||||||
|
bd.flags |= BD_RX_SH;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* TODO: Broadcast and Multicast */
|
||||||
|
|
||||||
|
if (bd.flags | BD_INTERRUPT) {
|
||||||
|
/* Set RXFx */
|
||||||
|
etsec->regs[RSTAT].value |= 1 << (7 - ring_nbr);
|
||||||
|
|
||||||
|
/* Set IEVENT */
|
||||||
|
ievent_set(etsec, IEVENT_RXF);
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
if (bd.flags | BD_INTERRUPT) {
|
||||||
|
/* Set IEVENT */
|
||||||
|
ievent_set(etsec, IEVENT_RXB);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Write back BD after update */
|
||||||
|
write_buffer_descriptor(etsec, bd_addr, &bd);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Wrap or next BD */
|
||||||
|
if (bd_flags & BD_WRAP) {
|
||||||
|
bd_addr = ring_base;
|
||||||
|
} else {
|
||||||
|
bd_addr += sizeof(eTSEC_rxtx_bd);
|
||||||
|
}
|
||||||
|
} while (remaining_data != 0
|
||||||
|
&& (bd_flags & BD_RX_EMPTY)
|
||||||
|
&& bd_addr != start_bd_addr);
|
||||||
|
|
||||||
|
/* Reset ring ptr */
|
||||||
|
etsec->regs[RBPTR0 + ring_nbr].value = bd_addr;
|
||||||
|
|
||||||
|
/* The frame is too large to fit in the Rx ring */
|
||||||
|
if (remaining_data > 0) {
|
||||||
|
|
||||||
|
/* Set RSTAT[QHLTx] */
|
||||||
|
etsec->regs[RSTAT].value |= 1 << (23 - ring_nbr);
|
||||||
|
|
||||||
|
/* Save remaining data to send the end of the frame when the ring will
|
||||||
|
* be restarted
|
||||||
|
*/
|
||||||
|
etsec->rx_remaining_data = remaining_data;
|
||||||
|
|
||||||
|
/* Copy the frame */
|
||||||
|
tmp_buf = g_malloc(size);
|
||||||
|
memcpy(tmp_buf, etsec->rx_buffer, size);
|
||||||
|
etsec->rx_buffer = tmp_buf;
|
||||||
|
|
||||||
|
RING_DEBUG("no empty RxBD available any more\n");
|
||||||
|
} else {
|
||||||
|
etsec->rx_buffer_len = 0;
|
||||||
|
etsec->rx_buffer = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
RING_DEBUG("eTSEC End of ring_write: remaining_data:%zu\n", remaining_data);
|
||||||
|
}
|
@@ -405,6 +405,8 @@ static target_ulong h_add_logical_lan_buffer(PowerPCCPU *cpu,
|
|||||||
|
|
||||||
dev->rx_bufs++;
|
dev->rx_bufs++;
|
||||||
|
|
||||||
|
qemu_flush_queued_packets(qemu_get_queue(dev->nic));
|
||||||
|
|
||||||
DPRINTF("h_add_logical_lan_buffer(): Added buf ptr=%d rx_bufs=%d"
|
DPRINTF("h_add_logical_lan_buffer(): Added buf ptr=%d rx_bufs=%d"
|
||||||
" bd=0x%016llx\n", dev->add_buf_ptr, dev->rx_bufs,
|
" bd=0x%016llx\n", dev->add_buf_ptr, dev->rx_bufs,
|
||||||
(unsigned long long)buf);
|
(unsigned long long)buf);
|
||||||
|
@@ -176,7 +176,8 @@ static uint64_t stellaris_enet_read(void *opaque, hwaddr offset,
|
|||||||
return val;
|
return val;
|
||||||
case 0x14: /* IA0 */
|
case 0x14: /* IA0 */
|
||||||
return s->conf.macaddr.a[0] | (s->conf.macaddr.a[1] << 8)
|
return s->conf.macaddr.a[0] | (s->conf.macaddr.a[1] << 8)
|
||||||
| (s->conf.macaddr.a[2] << 16) | (s->conf.macaddr.a[3] << 24);
|
| (s->conf.macaddr.a[2] << 16)
|
||||||
|
| ((uint32_t)s->conf.macaddr.a[3] << 24);
|
||||||
case 0x18: /* IA1 */
|
case 0x18: /* IA1 */
|
||||||
return s->conf.macaddr.a[4] | (s->conf.macaddr.a[5] << 8);
|
return s->conf.macaddr.a[4] | (s->conf.macaddr.a[5] << 8);
|
||||||
case 0x1c: /* THR */
|
case 0x1c: /* THR */
|
||||||
|
@@ -106,7 +106,7 @@ struct vhost_net *vhost_net_init(NetClientState *backend, int devfd,
|
|||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
net->nc = backend;
|
net->nc = backend;
|
||||||
net->dev.backend_features = tap_has_vnet_hdr(backend) ? 0 :
|
net->dev.backend_features = qemu_has_vnet_hdr(backend) ? 0 :
|
||||||
(1 << VHOST_NET_F_VIRTIO_NET_HDR);
|
(1 << VHOST_NET_F_VIRTIO_NET_HDR);
|
||||||
net->backend = r;
|
net->backend = r;
|
||||||
|
|
||||||
@@ -117,8 +117,8 @@ struct vhost_net *vhost_net_init(NetClientState *backend, int devfd,
|
|||||||
if (r < 0) {
|
if (r < 0) {
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
if (!tap_has_vnet_hdr_len(backend,
|
if (!qemu_has_vnet_hdr_len(backend,
|
||||||
sizeof(struct virtio_net_hdr_mrg_rxbuf))) {
|
sizeof(struct virtio_net_hdr_mrg_rxbuf))) {
|
||||||
net->dev.features &= ~(1 << VIRTIO_NET_F_MRG_RXBUF);
|
net->dev.features &= ~(1 << VIRTIO_NET_F_MRG_RXBUF);
|
||||||
}
|
}
|
||||||
if (~net->dev.features & net->dev.backend_features) {
|
if (~net->dev.features & net->dev.backend_features) {
|
||||||
|
@@ -325,11 +325,7 @@ static void peer_test_vnet_hdr(VirtIONet *n)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (nc->peer->info->type != NET_CLIENT_OPTIONS_KIND_TAP) {
|
n->has_vnet_hdr = qemu_has_vnet_hdr(nc->peer);
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
n->has_vnet_hdr = tap_has_vnet_hdr(nc->peer);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int peer_has_vnet_hdr(VirtIONet *n)
|
static int peer_has_vnet_hdr(VirtIONet *n)
|
||||||
@@ -342,7 +338,7 @@ static int peer_has_ufo(VirtIONet *n)
|
|||||||
if (!peer_has_vnet_hdr(n))
|
if (!peer_has_vnet_hdr(n))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
n->has_ufo = tap_has_ufo(qemu_get_queue(n->nic)->peer);
|
n->has_ufo = qemu_has_ufo(qemu_get_queue(n->nic)->peer);
|
||||||
|
|
||||||
return n->has_ufo;
|
return n->has_ufo;
|
||||||
}
|
}
|
||||||
@@ -361,8 +357,8 @@ static void virtio_net_set_mrg_rx_bufs(VirtIONet *n, int mergeable_rx_bufs)
|
|||||||
nc = qemu_get_subqueue(n->nic, i);
|
nc = qemu_get_subqueue(n->nic, i);
|
||||||
|
|
||||||
if (peer_has_vnet_hdr(n) &&
|
if (peer_has_vnet_hdr(n) &&
|
||||||
tap_has_vnet_hdr_len(nc->peer, n->guest_hdr_len)) {
|
qemu_has_vnet_hdr_len(nc->peer, n->guest_hdr_len)) {
|
||||||
tap_set_vnet_hdr_len(nc->peer, n->guest_hdr_len);
|
qemu_set_vnet_hdr_len(nc->peer, n->guest_hdr_len);
|
||||||
n->host_hdr_len = n->guest_hdr_len;
|
n->host_hdr_len = n->guest_hdr_len;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -463,7 +459,7 @@ static uint32_t virtio_net_bad_features(VirtIODevice *vdev)
|
|||||||
|
|
||||||
static void virtio_net_apply_guest_offloads(VirtIONet *n)
|
static void virtio_net_apply_guest_offloads(VirtIONet *n)
|
||||||
{
|
{
|
||||||
tap_set_offload(qemu_get_subqueue(n->nic, 0)->peer,
|
qemu_set_offload(qemu_get_queue(n->nic)->peer,
|
||||||
!!(n->curr_guest_offloads & (1ULL << VIRTIO_NET_F_GUEST_CSUM)),
|
!!(n->curr_guest_offloads & (1ULL << VIRTIO_NET_F_GUEST_CSUM)),
|
||||||
!!(n->curr_guest_offloads & (1ULL << VIRTIO_NET_F_GUEST_TSO4)),
|
!!(n->curr_guest_offloads & (1ULL << VIRTIO_NET_F_GUEST_TSO4)),
|
||||||
!!(n->curr_guest_offloads & (1ULL << VIRTIO_NET_F_GUEST_TSO6)),
|
!!(n->curr_guest_offloads & (1ULL << VIRTIO_NET_F_GUEST_TSO6)),
|
||||||
@@ -1544,7 +1540,7 @@ static void virtio_net_device_realize(DeviceState *dev, Error **errp)
|
|||||||
peer_test_vnet_hdr(n);
|
peer_test_vnet_hdr(n);
|
||||||
if (peer_has_vnet_hdr(n)) {
|
if (peer_has_vnet_hdr(n)) {
|
||||||
for (i = 0; i < n->max_queues; i++) {
|
for (i = 0; i < n->max_queues; i++) {
|
||||||
tap_using_vnet_hdr(qemu_get_subqueue(n->nic, i)->peer, true);
|
qemu_using_vnet_hdr(qemu_get_subqueue(n->nic, i)->peer, true);
|
||||||
}
|
}
|
||||||
n->host_hdr_len = sizeof(struct virtio_net_hdr);
|
n->host_hdr_len = sizeof(struct virtio_net_hdr);
|
||||||
} else {
|
} else {
|
||||||
|
@@ -1290,12 +1290,12 @@ static void vmxnet3_update_features(VMXNET3State *s)
|
|||||||
s->lro_supported, rxcso_supported,
|
s->lro_supported, rxcso_supported,
|
||||||
s->rx_vlan_stripping);
|
s->rx_vlan_stripping);
|
||||||
if (s->peer_has_vhdr) {
|
if (s->peer_has_vhdr) {
|
||||||
tap_set_offload(qemu_get_queue(s->nic)->peer,
|
qemu_set_offload(qemu_get_queue(s->nic)->peer,
|
||||||
rxcso_supported,
|
rxcso_supported,
|
||||||
s->lro_supported,
|
s->lro_supported,
|
||||||
s->lro_supported,
|
s->lro_supported,
|
||||||
0,
|
0,
|
||||||
0);
|
0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1883,11 +1883,9 @@ static NetClientInfo net_vmxnet3_info = {
|
|||||||
|
|
||||||
static bool vmxnet3_peer_has_vnet_hdr(VMXNET3State *s)
|
static bool vmxnet3_peer_has_vnet_hdr(VMXNET3State *s)
|
||||||
{
|
{
|
||||||
NetClientState *peer = qemu_get_queue(s->nic)->peer;
|
NetClientState *nc = qemu_get_queue(s->nic);
|
||||||
|
|
||||||
if ((NULL != peer) &&
|
if (qemu_has_vnet_hdr(nc->peer)) {
|
||||||
(peer->info->type == NET_CLIENT_OPTIONS_KIND_TAP) &&
|
|
||||||
tap_has_vnet_hdr(peer)) {
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1935,10 +1933,10 @@ static void vmxnet3_net_init(VMXNET3State *s)
|
|||||||
s->lro_supported = false;
|
s->lro_supported = false;
|
||||||
|
|
||||||
if (s->peer_has_vhdr) {
|
if (s->peer_has_vhdr) {
|
||||||
tap_set_vnet_hdr_len(qemu_get_queue(s->nic)->peer,
|
qemu_set_vnet_hdr_len(qemu_get_queue(s->nic)->peer,
|
||||||
sizeof(struct virtio_net_hdr));
|
sizeof(struct virtio_net_hdr));
|
||||||
|
|
||||||
tap_using_vnet_hdr(qemu_get_queue(s->nic)->peer, 1);
|
qemu_using_vnet_hdr(qemu_get_queue(s->nic)->peer, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
qemu_format_nic_info_str(qemu_get_queue(s->nic), s->conf.macaddr.a);
|
qemu_format_nic_info_str(qemu_get_queue(s->nic), s->conf.macaddr.a);
|
||||||
|
@@ -238,6 +238,7 @@ static int ppce500_load_device_tree(QEMUMachineInitArgs *args,
|
|||||||
the first node as boot node and be happy */
|
the first node as boot node and be happy */
|
||||||
for (i = smp_cpus - 1; i >= 0; i--) {
|
for (i = smp_cpus - 1; i >= 0; i--) {
|
||||||
CPUState *cpu;
|
CPUState *cpu;
|
||||||
|
PowerPCCPU *pcpu;
|
||||||
char cpu_name[128];
|
char cpu_name[128];
|
||||||
uint64_t cpu_release_addr = MPC8544_SPIN_BASE + (i * 0x20);
|
uint64_t cpu_release_addr = MPC8544_SPIN_BASE + (i * 0x20);
|
||||||
|
|
||||||
@@ -246,14 +247,16 @@ static int ppce500_load_device_tree(QEMUMachineInitArgs *args,
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
env = cpu->env_ptr;
|
env = cpu->env_ptr;
|
||||||
|
pcpu = POWERPC_CPU(cpu);
|
||||||
|
|
||||||
snprintf(cpu_name, sizeof(cpu_name), "/cpus/PowerPC,8544@%x",
|
snprintf(cpu_name, sizeof(cpu_name), "/cpus/PowerPC,8544@%x",
|
||||||
cpu->cpu_index);
|
ppc_get_vcpu_dt_id(pcpu));
|
||||||
qemu_fdt_add_subnode(fdt, cpu_name);
|
qemu_fdt_add_subnode(fdt, cpu_name);
|
||||||
qemu_fdt_setprop_cell(fdt, cpu_name, "clock-frequency", clock_freq);
|
qemu_fdt_setprop_cell(fdt, cpu_name, "clock-frequency", clock_freq);
|
||||||
qemu_fdt_setprop_cell(fdt, cpu_name, "timebase-frequency", tb_freq);
|
qemu_fdt_setprop_cell(fdt, cpu_name, "timebase-frequency", tb_freq);
|
||||||
qemu_fdt_setprop_string(fdt, cpu_name, "device_type", "cpu");
|
qemu_fdt_setprop_string(fdt, cpu_name, "device_type", "cpu");
|
||||||
qemu_fdt_setprop_cell(fdt, cpu_name, "reg", cpu->cpu_index);
|
qemu_fdt_setprop_cell(fdt, cpu_name, "reg",
|
||||||
|
ppc_get_vcpu_dt_id(pcpu));
|
||||||
qemu_fdt_setprop_cell(fdt, cpu_name, "d-cache-line-size",
|
qemu_fdt_setprop_cell(fdt, cpu_name, "d-cache-line-size",
|
||||||
env->dcache_line_size);
|
env->dcache_line_size);
|
||||||
qemu_fdt_setprop_cell(fdt, cpu_name, "i-cache-line-size",
|
qemu_fdt_setprop_cell(fdt, cpu_name, "i-cache-line-size",
|
||||||
|
22
hw/ppc/ppc.c
22
hw/ppc/ppc.c
@@ -26,6 +26,7 @@
|
|||||||
#include "hw/ppc/ppc_e500.h"
|
#include "hw/ppc/ppc_e500.h"
|
||||||
#include "qemu/timer.h"
|
#include "qemu/timer.h"
|
||||||
#include "sysemu/sysemu.h"
|
#include "sysemu/sysemu.h"
|
||||||
|
#include "sysemu/cpus.h"
|
||||||
#include "hw/timer/m48t59.h"
|
#include "hw/timer/m48t59.h"
|
||||||
#include "qemu/log.h"
|
#include "qemu/log.h"
|
||||||
#include "hw/loader.h"
|
#include "hw/loader.h"
|
||||||
@@ -1362,3 +1363,24 @@ int PPC_NVRAM_set_params (nvram_t *nvram, uint16_t NVRAM_size,
|
|||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* CPU device-tree ID helpers */
|
||||||
|
int ppc_get_vcpu_dt_id(PowerPCCPU *cpu)
|
||||||
|
{
|
||||||
|
return cpu->cpu_dt_id;
|
||||||
|
}
|
||||||
|
|
||||||
|
PowerPCCPU *ppc_get_vcpu_by_dt_id(int cpu_dt_id)
|
||||||
|
{
|
||||||
|
CPUState *cs;
|
||||||
|
|
||||||
|
CPU_FOREACH(cs) {
|
||||||
|
PowerPCCPU *cpu = POWERPC_CPU(cs);
|
||||||
|
|
||||||
|
if (cpu->cpu_dt_id == cpu_dt_id) {
|
||||||
|
return cpu;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
@@ -49,6 +49,7 @@
|
|||||||
#include "exec/address-spaces.h"
|
#include "exec/address-spaces.h"
|
||||||
#include "hw/usb.h"
|
#include "hw/usb.h"
|
||||||
#include "qemu/config-file.h"
|
#include "qemu/config-file.h"
|
||||||
|
#include "qemu/error-report.h"
|
||||||
|
|
||||||
#include <libfdt.h>
|
#include <libfdt.h>
|
||||||
|
|
||||||
@@ -206,19 +207,20 @@ static int spapr_fixup_cpu_dt(void *fdt, sPAPREnvironment *spapr)
|
|||||||
|
|
||||||
CPU_FOREACH(cpu) {
|
CPU_FOREACH(cpu) {
|
||||||
DeviceClass *dc = DEVICE_GET_CLASS(cpu);
|
DeviceClass *dc = DEVICE_GET_CLASS(cpu);
|
||||||
|
int index = ppc_get_vcpu_dt_id(POWERPC_CPU(cpu));
|
||||||
uint32_t associativity[] = {cpu_to_be32(0x5),
|
uint32_t associativity[] = {cpu_to_be32(0x5),
|
||||||
cpu_to_be32(0x0),
|
cpu_to_be32(0x0),
|
||||||
cpu_to_be32(0x0),
|
cpu_to_be32(0x0),
|
||||||
cpu_to_be32(0x0),
|
cpu_to_be32(0x0),
|
||||||
cpu_to_be32(cpu->numa_node),
|
cpu_to_be32(cpu->numa_node),
|
||||||
cpu_to_be32(cpu->cpu_index)};
|
cpu_to_be32(index)};
|
||||||
|
|
||||||
if ((cpu->cpu_index % smt) != 0) {
|
if ((index % smt) != 0) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
snprintf(cpu_model, 32, "/cpus/%s@%x", dc->fw_name,
|
snprintf(cpu_model, 32, "/cpus/%s@%x", dc->fw_name,
|
||||||
cpu->cpu_index);
|
index);
|
||||||
|
|
||||||
offset = fdt_path_offset(fdt, cpu_model);
|
offset = fdt_path_offset(fdt, cpu_model);
|
||||||
if (offset < 0) {
|
if (offset < 0) {
|
||||||
@@ -367,7 +369,7 @@ static void *spapr_create_fdt_skel(hwaddr initrd_base,
|
|||||||
CPUPPCState *env = &cpu->env;
|
CPUPPCState *env = &cpu->env;
|
||||||
DeviceClass *dc = DEVICE_GET_CLASS(cs);
|
DeviceClass *dc = DEVICE_GET_CLASS(cs);
|
||||||
PowerPCCPUClass *pcc = POWERPC_CPU_GET_CLASS(cs);
|
PowerPCCPUClass *pcc = POWERPC_CPU_GET_CLASS(cs);
|
||||||
int index = cs->cpu_index;
|
int index = ppc_get_vcpu_dt_id(cpu);
|
||||||
uint32_t servers_prop[smp_threads];
|
uint32_t servers_prop[smp_threads];
|
||||||
uint32_t gservers_prop[smp_threads * 2];
|
uint32_t gservers_prop[smp_threads * 2];
|
||||||
char *nodename;
|
char *nodename;
|
||||||
@@ -685,6 +687,7 @@ static void spapr_reset_htab(sPAPREnvironment *spapr)
|
|||||||
if (shift > 0) {
|
if (shift > 0) {
|
||||||
/* Kernel handles htab, we don't need to allocate one */
|
/* Kernel handles htab, we don't need to allocate one */
|
||||||
spapr->htab_shift = shift;
|
spapr->htab_shift = shift;
|
||||||
|
kvmppc_kern_htab = true;
|
||||||
} else {
|
} else {
|
||||||
if (!spapr->htab) {
|
if (!spapr->htab) {
|
||||||
/* Allocate an htab if we don't yet have one */
|
/* Allocate an htab if we don't yet have one */
|
||||||
@@ -740,8 +743,21 @@ static void spapr_cpu_reset(void *opaque)
|
|||||||
env->spr[SPR_HIOR] = 0;
|
env->spr[SPR_HIOR] = 0;
|
||||||
|
|
||||||
env->external_htab = (uint8_t *)spapr->htab;
|
env->external_htab = (uint8_t *)spapr->htab;
|
||||||
|
if (kvm_enabled() && !env->external_htab) {
|
||||||
|
/*
|
||||||
|
* HV KVM, set external_htab to 1 so our ppc_hash64_load_hpte*
|
||||||
|
* functions do the right thing.
|
||||||
|
*/
|
||||||
|
env->external_htab = (void *)1;
|
||||||
|
}
|
||||||
env->htab_base = -1;
|
env->htab_base = -1;
|
||||||
env->htab_mask = HTAB_SIZE(spapr) - 1;
|
/*
|
||||||
|
* htab_mask is the mask used to normalize hash value to PTEG index.
|
||||||
|
* htab_shift is log2 of hash table size.
|
||||||
|
* We have 8 hpte per group, and each hpte is 16 bytes.
|
||||||
|
* ie have 128 bytes per hpte entry.
|
||||||
|
*/
|
||||||
|
env->htab_mask = (1ULL << ((spapr)->htab_shift - 7)) - 1;
|
||||||
env->spr[SPR_SDR1] = (target_ulong)(uintptr_t)spapr->htab |
|
env->spr[SPR_SDR1] = (target_ulong)(uintptr_t)spapr->htab |
|
||||||
(spapr->htab_shift - 18);
|
(spapr->htab_shift - 18);
|
||||||
}
|
}
|
||||||
@@ -1305,20 +1321,15 @@ static void ppc_spapr_init(QEMUMachineInitArgs *args)
|
|||||||
|
|
||||||
kernel_size = load_elf(kernel_filename, translate_kernel_address, NULL,
|
kernel_size = load_elf(kernel_filename, translate_kernel_address, NULL,
|
||||||
NULL, &lowaddr, NULL, 1, ELF_MACHINE, 0);
|
NULL, &lowaddr, NULL, 1, ELF_MACHINE, 0);
|
||||||
if (kernel_size < 0) {
|
if (kernel_size == ELF_LOAD_WRONG_ENDIAN) {
|
||||||
kernel_size = load_elf(kernel_filename,
|
kernel_size = load_elf(kernel_filename,
|
||||||
translate_kernel_address, NULL,
|
translate_kernel_address, NULL,
|
||||||
NULL, &lowaddr, NULL, 0, ELF_MACHINE, 0);
|
NULL, &lowaddr, NULL, 0, ELF_MACHINE, 0);
|
||||||
kernel_le = kernel_size > 0;
|
kernel_le = kernel_size > 0;
|
||||||
}
|
}
|
||||||
if (kernel_size < 0) {
|
if (kernel_size < 0) {
|
||||||
kernel_size = load_image_targphys(kernel_filename,
|
fprintf(stderr, "qemu: error loading %s: %s\n",
|
||||||
KERNEL_LOAD_ADDR,
|
kernel_filename, load_elf_strerror(kernel_size));
|
||||||
load_limit - KERNEL_LOAD_ADDR);
|
|
||||||
}
|
|
||||||
if (kernel_size < 0) {
|
|
||||||
fprintf(stderr, "qemu: could not load kernel '%s'\n",
|
|
||||||
kernel_filename);
|
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1366,6 +1377,24 @@ static void ppc_spapr_init(QEMUMachineInitArgs *args)
|
|||||||
assert(spapr->fdt_skel != NULL);
|
assert(spapr->fdt_skel != NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int spapr_kvm_type(const char *vm_type)
|
||||||
|
{
|
||||||
|
if (!vm_type) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!strcmp(vm_type, "HV")) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!strcmp(vm_type, "PR")) {
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
error_report("Unknown kvm-type specified '%s'", vm_type);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
static QEMUMachine spapr_machine = {
|
static QEMUMachine spapr_machine = {
|
||||||
.name = "pseries",
|
.name = "pseries",
|
||||||
.desc = "pSeries Logical Partition (PAPR compliant)",
|
.desc = "pSeries Logical Partition (PAPR compliant)",
|
||||||
@@ -1376,6 +1405,7 @@ static QEMUMachine spapr_machine = {
|
|||||||
.max_cpus = MAX_CPUS,
|
.max_cpus = MAX_CPUS,
|
||||||
.no_parallel = 1,
|
.no_parallel = 1,
|
||||||
.default_boot_order = NULL,
|
.default_boot_order = NULL,
|
||||||
|
.kvm_type = spapr_kvm_type,
|
||||||
};
|
};
|
||||||
|
|
||||||
static void spapr_machine_init(void)
|
static void spapr_machine_init(void)
|
||||||
|
@@ -40,6 +40,17 @@ static target_ulong compute_tlbie_rb(target_ulong v, target_ulong r,
|
|||||||
return rb;
|
return rb;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline bool valid_pte_index(CPUPPCState *env, target_ulong pte_index)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* hash value/pteg group index is normalized by htab_mask
|
||||||
|
*/
|
||||||
|
if (((pte_index & ~7ULL) / HPTES_PER_GROUP) & ~env->htab_mask) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
static target_ulong h_enter(PowerPCCPU *cpu, sPAPREnvironment *spapr,
|
static target_ulong h_enter(PowerPCCPU *cpu, sPAPREnvironment *spapr,
|
||||||
target_ulong opcode, target_ulong *args)
|
target_ulong opcode, target_ulong *args)
|
||||||
{
|
{
|
||||||
@@ -50,8 +61,8 @@ static target_ulong h_enter(PowerPCCPU *cpu, sPAPREnvironment *spapr,
|
|||||||
target_ulong ptel = args[3];
|
target_ulong ptel = args[3];
|
||||||
target_ulong page_shift = 12;
|
target_ulong page_shift = 12;
|
||||||
target_ulong raddr;
|
target_ulong raddr;
|
||||||
target_ulong i;
|
target_ulong index;
|
||||||
hwaddr hpte;
|
uint64_t token;
|
||||||
|
|
||||||
/* only handle 4k and 16M pages for now */
|
/* only handle 4k and 16M pages for now */
|
||||||
if (pteh & HPTE64_V_LARGE) {
|
if (pteh & HPTE64_V_LARGE) {
|
||||||
@@ -91,33 +102,37 @@ static target_ulong h_enter(PowerPCCPU *cpu, sPAPREnvironment *spapr,
|
|||||||
|
|
||||||
pteh &= ~0x60ULL;
|
pteh &= ~0x60ULL;
|
||||||
|
|
||||||
if ((pte_index * HASH_PTE_SIZE_64) & ~env->htab_mask) {
|
if (!valid_pte_index(env, pte_index)) {
|
||||||
return H_PARAMETER;
|
return H_PARAMETER;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
index = 0;
|
||||||
if (likely((flags & H_EXACT) == 0)) {
|
if (likely((flags & H_EXACT) == 0)) {
|
||||||
pte_index &= ~7ULL;
|
pte_index &= ~7ULL;
|
||||||
hpte = pte_index * HASH_PTE_SIZE_64;
|
token = ppc_hash64_start_access(cpu, pte_index);
|
||||||
for (i = 0; ; ++i) {
|
do {
|
||||||
if (i == 8) {
|
if (index == 8) {
|
||||||
|
ppc_hash64_stop_access(token);
|
||||||
return H_PTEG_FULL;
|
return H_PTEG_FULL;
|
||||||
}
|
}
|
||||||
if ((ppc_hash64_load_hpte0(env, hpte) & HPTE64_V_VALID) == 0) {
|
if ((ppc_hash64_load_hpte0(env, token, index) & HPTE64_V_VALID) == 0) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
hpte += HASH_PTE_SIZE_64;
|
} while (index++);
|
||||||
}
|
ppc_hash64_stop_access(token);
|
||||||
} else {
|
} else {
|
||||||
i = 0;
|
token = ppc_hash64_start_access(cpu, pte_index);
|
||||||
hpte = pte_index * HASH_PTE_SIZE_64;
|
if (ppc_hash64_load_hpte0(env, token, 0) & HPTE64_V_VALID) {
|
||||||
if (ppc_hash64_load_hpte0(env, hpte) & HPTE64_V_VALID) {
|
ppc_hash64_stop_access(token);
|
||||||
return H_PTEG_FULL;
|
return H_PTEG_FULL;
|
||||||
}
|
}
|
||||||
|
ppc_hash64_stop_access(token);
|
||||||
}
|
}
|
||||||
ppc_hash64_store_hpte1(env, hpte, ptel);
|
|
||||||
/* eieio(); FIXME: need some sort of barrier for smp? */
|
|
||||||
ppc_hash64_store_hpte0(env, hpte, pteh | HPTE64_V_HPTE_DIRTY);
|
|
||||||
|
|
||||||
args[0] = pte_index + i;
|
ppc_hash64_store_hpte(env, pte_index + index,
|
||||||
|
pteh | HPTE64_V_HPTE_DIRTY, ptel);
|
||||||
|
|
||||||
|
args[0] = pte_index + index;
|
||||||
return H_SUCCESS;
|
return H_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -133,17 +148,17 @@ static RemoveResult remove_hpte(CPUPPCState *env, target_ulong ptex,
|
|||||||
target_ulong flags,
|
target_ulong flags,
|
||||||
target_ulong *vp, target_ulong *rp)
|
target_ulong *vp, target_ulong *rp)
|
||||||
{
|
{
|
||||||
hwaddr hpte;
|
uint64_t token;
|
||||||
target_ulong v, r, rb;
|
target_ulong v, r, rb;
|
||||||
|
|
||||||
if ((ptex * HASH_PTE_SIZE_64) & ~env->htab_mask) {
|
if (!valid_pte_index(env, ptex)) {
|
||||||
return REMOVE_PARM;
|
return REMOVE_PARM;
|
||||||
}
|
}
|
||||||
|
|
||||||
hpte = ptex * HASH_PTE_SIZE_64;
|
token = ppc_hash64_start_access(ppc_env_get_cpu(env), ptex);
|
||||||
|
v = ppc_hash64_load_hpte0(env, token, 0);
|
||||||
v = ppc_hash64_load_hpte0(env, hpte);
|
r = ppc_hash64_load_hpte1(env, token, 0);
|
||||||
r = ppc_hash64_load_hpte1(env, hpte);
|
ppc_hash64_stop_access(token);
|
||||||
|
|
||||||
if ((v & HPTE64_V_VALID) == 0 ||
|
if ((v & HPTE64_V_VALID) == 0 ||
|
||||||
((flags & H_AVPN) && (v & ~0x7fULL) != avpn) ||
|
((flags & H_AVPN) && (v & ~0x7fULL) != avpn) ||
|
||||||
@@ -152,7 +167,7 @@ static RemoveResult remove_hpte(CPUPPCState *env, target_ulong ptex,
|
|||||||
}
|
}
|
||||||
*vp = v;
|
*vp = v;
|
||||||
*rp = r;
|
*rp = r;
|
||||||
ppc_hash64_store_hpte0(env, hpte, HPTE64_V_HPTE_DIRTY);
|
ppc_hash64_store_hpte(env, ptex, HPTE64_V_HPTE_DIRTY, 0);
|
||||||
rb = compute_tlbie_rb(v, r, ptex);
|
rb = compute_tlbie_rb(v, r, ptex);
|
||||||
ppc_tlb_invalidate_one(env, rb);
|
ppc_tlb_invalidate_one(env, rb);
|
||||||
return REMOVE_SUCCESS;
|
return REMOVE_SUCCESS;
|
||||||
@@ -259,17 +274,17 @@ static target_ulong h_protect(PowerPCCPU *cpu, sPAPREnvironment *spapr,
|
|||||||
target_ulong flags = args[0];
|
target_ulong flags = args[0];
|
||||||
target_ulong pte_index = args[1];
|
target_ulong pte_index = args[1];
|
||||||
target_ulong avpn = args[2];
|
target_ulong avpn = args[2];
|
||||||
hwaddr hpte;
|
uint64_t token;
|
||||||
target_ulong v, r, rb;
|
target_ulong v, r, rb;
|
||||||
|
|
||||||
if ((pte_index * HASH_PTE_SIZE_64) & ~env->htab_mask) {
|
if (!valid_pte_index(env, pte_index)) {
|
||||||
return H_PARAMETER;
|
return H_PARAMETER;
|
||||||
}
|
}
|
||||||
|
|
||||||
hpte = pte_index * HASH_PTE_SIZE_64;
|
token = ppc_hash64_start_access(cpu, pte_index);
|
||||||
|
v = ppc_hash64_load_hpte0(env, token, 0);
|
||||||
v = ppc_hash64_load_hpte0(env, hpte);
|
r = ppc_hash64_load_hpte1(env, token, 0);
|
||||||
r = ppc_hash64_load_hpte1(env, hpte);
|
ppc_hash64_stop_access(token);
|
||||||
|
|
||||||
if ((v & HPTE64_V_VALID) == 0 ||
|
if ((v & HPTE64_V_VALID) == 0 ||
|
||||||
((flags & H_AVPN) && (v & ~0x7fULL) != avpn)) {
|
((flags & H_AVPN) && (v & ~0x7fULL) != avpn)) {
|
||||||
@@ -282,11 +297,11 @@ static target_ulong h_protect(PowerPCCPU *cpu, sPAPREnvironment *spapr,
|
|||||||
r |= (flags << 48) & HPTE64_R_KEY_HI;
|
r |= (flags << 48) & HPTE64_R_KEY_HI;
|
||||||
r |= flags & (HPTE64_R_PP | HPTE64_R_N | HPTE64_R_KEY_LO);
|
r |= flags & (HPTE64_R_PP | HPTE64_R_N | HPTE64_R_KEY_LO);
|
||||||
rb = compute_tlbie_rb(v, r, pte_index);
|
rb = compute_tlbie_rb(v, r, pte_index);
|
||||||
ppc_hash64_store_hpte0(env, hpte, (v & ~HPTE64_V_VALID) | HPTE64_V_HPTE_DIRTY);
|
ppc_hash64_store_hpte(env, pte_index,
|
||||||
|
(v & ~HPTE64_V_VALID) | HPTE64_V_HPTE_DIRTY, 0);
|
||||||
ppc_tlb_invalidate_one(env, rb);
|
ppc_tlb_invalidate_one(env, rb);
|
||||||
ppc_hash64_store_hpte1(env, hpte, r);
|
|
||||||
/* Don't need a memory barrier, due to qemu's global lock */
|
/* Don't need a memory barrier, due to qemu's global lock */
|
||||||
ppc_hash64_store_hpte0(env, hpte, v | HPTE64_V_HPTE_DIRTY);
|
ppc_hash64_store_hpte(env, pte_index, v | HPTE64_V_HPTE_DIRTY, r);
|
||||||
return H_SUCCESS;
|
return H_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -299,7 +314,7 @@ static target_ulong h_read(PowerPCCPU *cpu, sPAPREnvironment *spapr,
|
|||||||
uint8_t *hpte;
|
uint8_t *hpte;
|
||||||
int i, ridx, n_entries = 1;
|
int i, ridx, n_entries = 1;
|
||||||
|
|
||||||
if ((pte_index * HASH_PTE_SIZE_64) & ~env->htab_mask) {
|
if (!valid_pte_index(env, pte_index)) {
|
||||||
return H_PARAMETER;
|
return H_PARAMETER;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -467,13 +482,13 @@ static target_ulong h_register_vpa(PowerPCCPU *cpu, sPAPREnvironment *spapr,
|
|||||||
target_ulong vpa = args[2];
|
target_ulong vpa = args[2];
|
||||||
target_ulong ret = H_PARAMETER;
|
target_ulong ret = H_PARAMETER;
|
||||||
CPUPPCState *tenv;
|
CPUPPCState *tenv;
|
||||||
CPUState *tcpu;
|
PowerPCCPU *tcpu;
|
||||||
|
|
||||||
tcpu = qemu_get_cpu(procno);
|
tcpu = ppc_get_vcpu_by_dt_id(procno);
|
||||||
if (!tcpu) {
|
if (!tcpu) {
|
||||||
return H_PARAMETER;
|
return H_PARAMETER;
|
||||||
}
|
}
|
||||||
tenv = tcpu->env_ptr;
|
tenv = &tcpu->env;
|
||||||
|
|
||||||
switch (flags) {
|
switch (flags) {
|
||||||
case FLAGS_REGISTER_VPA:
|
case FLAGS_REGISTER_VPA:
|
||||||
|
@@ -243,6 +243,42 @@ static target_ulong h_put_tce(PowerPCCPU *cpu, sPAPREnvironment *spapr,
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static target_ulong get_tce_emu(sPAPRTCETable *tcet, target_ulong ioba,
|
||||||
|
target_ulong *tce)
|
||||||
|
{
|
||||||
|
if (ioba >= tcet->window_size) {
|
||||||
|
hcall_dprintf("spapr_iommu_get_tce on out-of-bounds IOBA 0x"
|
||||||
|
TARGET_FMT_lx "\n", ioba);
|
||||||
|
return H_PARAMETER;
|
||||||
|
}
|
||||||
|
|
||||||
|
*tce = tcet->table[ioba >> SPAPR_TCE_PAGE_SHIFT];
|
||||||
|
|
||||||
|
return H_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
static target_ulong h_get_tce(PowerPCCPU *cpu, sPAPREnvironment *spapr,
|
||||||
|
target_ulong opcode, target_ulong *args)
|
||||||
|
{
|
||||||
|
target_ulong liobn = args[0];
|
||||||
|
target_ulong ioba = args[1];
|
||||||
|
target_ulong tce = 0;
|
||||||
|
target_ulong ret = H_PARAMETER;
|
||||||
|
sPAPRTCETable *tcet = spapr_tce_find_by_liobn(liobn);
|
||||||
|
|
||||||
|
ioba &= ~(SPAPR_TCE_PAGE_SIZE - 1);
|
||||||
|
|
||||||
|
if (tcet) {
|
||||||
|
ret = get_tce_emu(tcet, ioba, &tce);
|
||||||
|
if (!ret) {
|
||||||
|
args[0] = tce;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
trace_spapr_iommu_get(liobn, ioba, ret, tce);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
int spapr_dma_dt(void *fdt, int node_off, const char *propname,
|
int spapr_dma_dt(void *fdt, int node_off, const char *propname,
|
||||||
uint32_t liobn, uint64_t window, uint32_t size)
|
uint32_t liobn, uint64_t window, uint32_t size)
|
||||||
{
|
{
|
||||||
@@ -295,6 +331,7 @@ static void spapr_tce_table_class_init(ObjectClass *klass, void *data)
|
|||||||
|
|
||||||
/* hcall-tce */
|
/* hcall-tce */
|
||||||
spapr_register_hypercall(H_PUT_TCE, h_put_tce);
|
spapr_register_hypercall(H_PUT_TCE, h_put_tce);
|
||||||
|
spapr_register_hypercall(H_GET_TCE, h_get_tce);
|
||||||
}
|
}
|
||||||
|
|
||||||
static TypeInfo spapr_tce_table_info = {
|
static TypeInfo spapr_tce_table_info = {
|
||||||
|
@@ -469,6 +469,8 @@ static const MemoryRegionOps spapr_msi_ops = {
|
|||||||
|
|
||||||
void spapr_pci_msi_init(sPAPREnvironment *spapr, hwaddr addr)
|
void spapr_pci_msi_init(sPAPREnvironment *spapr, hwaddr addr)
|
||||||
{
|
{
|
||||||
|
uint64_t window_size = 4096;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* As MSI/MSIX interrupts trigger by writing at MSI/MSIX vectors,
|
* As MSI/MSIX interrupts trigger by writing at MSI/MSIX vectors,
|
||||||
* we need to allocate some memory to catch those writes coming
|
* we need to allocate some memory to catch those writes coming
|
||||||
@@ -476,10 +478,19 @@ void spapr_pci_msi_init(sPAPREnvironment *spapr, hwaddr addr)
|
|||||||
* As MSIMessage:addr is going to be the same and MSIMessage:data
|
* As MSIMessage:addr is going to be the same and MSIMessage:data
|
||||||
* is going to be a VIRQ number, 4 bytes of the MSI MR will only
|
* is going to be a VIRQ number, 4 bytes of the MSI MR will only
|
||||||
* be used.
|
* be used.
|
||||||
|
*
|
||||||
|
* For KVM we want to ensure that this memory is a full page so that
|
||||||
|
* our memory slot is of page size granularity.
|
||||||
*/
|
*/
|
||||||
|
#ifdef CONFIG_KVM
|
||||||
|
if (kvm_enabled()) {
|
||||||
|
window_size = getpagesize();
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
spapr->msi_win_addr = addr;
|
spapr->msi_win_addr = addr;
|
||||||
memory_region_init_io(&spapr->msiwindow, NULL, &spapr_msi_ops, spapr,
|
memory_region_init_io(&spapr->msiwindow, NULL, &spapr_msi_ops, spapr,
|
||||||
"msi", getpagesize());
|
"msi", window_size);
|
||||||
memory_region_add_subregion(get_system_memory(), spapr->msi_win_addr,
|
memory_region_add_subregion(get_system_memory(), spapr->msi_win_addr,
|
||||||
&spapr->msiwindow);
|
&spapr->msiwindow);
|
||||||
}
|
}
|
||||||
@@ -728,6 +739,8 @@ static void spapr_phb_class_init(ObjectClass *klass, void *data)
|
|||||||
dc->props = spapr_phb_properties;
|
dc->props = spapr_phb_properties;
|
||||||
dc->reset = spapr_phb_reset;
|
dc->reset = spapr_phb_reset;
|
||||||
dc->vmsd = &vmstate_spapr_pci;
|
dc->vmsd = &vmstate_spapr_pci;
|
||||||
|
set_bit(DEVICE_CATEGORY_BRIDGE, dc->categories);
|
||||||
|
dc->cannot_instantiate_with_device_add_yet = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
static const TypeInfo spapr_phb_info = {
|
static const TypeInfo spapr_phb_info = {
|
||||||
|
@@ -131,7 +131,7 @@ static void rtas_query_cpu_stopped_state(PowerPCCPU *cpu_,
|
|||||||
uint32_t nret, target_ulong rets)
|
uint32_t nret, target_ulong rets)
|
||||||
{
|
{
|
||||||
target_ulong id;
|
target_ulong id;
|
||||||
CPUState *cpu;
|
PowerPCCPU *cpu;
|
||||||
|
|
||||||
if (nargs != 1 || nret != 2) {
|
if (nargs != 1 || nret != 2) {
|
||||||
rtas_st(rets, 0, RTAS_OUT_PARAM_ERROR);
|
rtas_st(rets, 0, RTAS_OUT_PARAM_ERROR);
|
||||||
@@ -139,9 +139,9 @@ static void rtas_query_cpu_stopped_state(PowerPCCPU *cpu_,
|
|||||||
}
|
}
|
||||||
|
|
||||||
id = rtas_ld(args, 0);
|
id = rtas_ld(args, 0);
|
||||||
cpu = qemu_get_cpu(id);
|
cpu = ppc_get_vcpu_by_dt_id(id);
|
||||||
if (cpu != NULL) {
|
if (cpu != NULL) {
|
||||||
if (cpu->halted) {
|
if (CPU(cpu)->halted) {
|
||||||
rtas_st(rets, 1, 0);
|
rtas_st(rets, 1, 0);
|
||||||
} else {
|
} else {
|
||||||
rtas_st(rets, 1, 2);
|
rtas_st(rets, 1, 2);
|
||||||
@@ -161,7 +161,7 @@ static void rtas_start_cpu(PowerPCCPU *cpu_, sPAPREnvironment *spapr,
|
|||||||
uint32_t nret, target_ulong rets)
|
uint32_t nret, target_ulong rets)
|
||||||
{
|
{
|
||||||
target_ulong id, start, r3;
|
target_ulong id, start, r3;
|
||||||
CPUState *cs;
|
PowerPCCPU *cpu;
|
||||||
|
|
||||||
if (nargs != 3 || nret != 1) {
|
if (nargs != 3 || nret != 1) {
|
||||||
rtas_st(rets, 0, RTAS_OUT_PARAM_ERROR);
|
rtas_st(rets, 0, RTAS_OUT_PARAM_ERROR);
|
||||||
@@ -172,9 +172,9 @@ static void rtas_start_cpu(PowerPCCPU *cpu_, sPAPREnvironment *spapr,
|
|||||||
start = rtas_ld(args, 1);
|
start = rtas_ld(args, 1);
|
||||||
r3 = rtas_ld(args, 2);
|
r3 = rtas_ld(args, 2);
|
||||||
|
|
||||||
cs = qemu_get_cpu(id);
|
cpu = ppc_get_vcpu_by_dt_id(id);
|
||||||
if (cs != NULL) {
|
if (cpu != NULL) {
|
||||||
PowerPCCPU *cpu = POWERPC_CPU(cs);
|
CPUState *cs = CPU(cpu);
|
||||||
CPUPPCState *env = &cpu->env;
|
CPUPPCState *env = &cpu->env;
|
||||||
|
|
||||||
if (!cs->halted) {
|
if (!cs->halted) {
|
||||||
|
@@ -174,6 +174,19 @@ static int xilinx_load_device_tree(hwaddr addr,
|
|||||||
if (!fdt) {
|
if (!fdt) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
r = qemu_fdt_setprop_cell(fdt, "/chosen", "linux,initrd-start",
|
||||||
|
initrd_base);
|
||||||
|
if (r < 0) {
|
||||||
|
error_report("couldn't set /chosen/linux,initrd-start");
|
||||||
|
}
|
||||||
|
|
||||||
|
r = qemu_fdt_setprop_cell(fdt, "/chosen", "linux,initrd-end",
|
||||||
|
(initrd_base + initrd_size));
|
||||||
|
if (r < 0) {
|
||||||
|
error_report("couldn't set /chosen/linux,initrd-end");
|
||||||
|
}
|
||||||
|
|
||||||
r = qemu_fdt_setprop_string(fdt, "/chosen", "bootargs", kernel_cmdline);
|
r = qemu_fdt_setprop_string(fdt, "/chosen", "bootargs", kernel_cmdline);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
fprintf(stderr, "couldn't set /chosen/bootargs\n");
|
fprintf(stderr, "couldn't set /chosen/bootargs\n");
|
||||||
@@ -187,6 +200,8 @@ static void virtex_init(QEMUMachineInitArgs *args)
|
|||||||
const char *cpu_model = args->cpu_model;
|
const char *cpu_model = args->cpu_model;
|
||||||
const char *kernel_filename = args->kernel_filename;
|
const char *kernel_filename = args->kernel_filename;
|
||||||
const char *kernel_cmdline = args->kernel_cmdline;
|
const char *kernel_cmdline = args->kernel_cmdline;
|
||||||
|
hwaddr initrd_base = 0;
|
||||||
|
int initrd_size = 0;
|
||||||
MemoryRegion *address_space_mem = get_system_memory();
|
MemoryRegion *address_space_mem = get_system_memory();
|
||||||
DeviceState *dev;
|
DeviceState *dev;
|
||||||
PowerPCCPU *cpu;
|
PowerPCCPU *cpu;
|
||||||
@@ -259,10 +274,27 @@ static void virtex_init(QEMUMachineInitArgs *args)
|
|||||||
|
|
||||||
boot_info.ima_size = kernel_size;
|
boot_info.ima_size = kernel_size;
|
||||||
|
|
||||||
|
/* Load initrd. */
|
||||||
|
if (args->initrd_filename) {
|
||||||
|
initrd_base = high = ROUND_UP(high, 4);
|
||||||
|
initrd_size = load_image_targphys(args->initrd_filename,
|
||||||
|
high, ram_size - high);
|
||||||
|
|
||||||
|
if (initrd_size < 0) {
|
||||||
|
error_report("couldn't load ram disk '%s'",
|
||||||
|
args->initrd_filename);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
high = ROUND_UP(high + initrd_size, 4);
|
||||||
|
}
|
||||||
|
|
||||||
/* Provide a device-tree. */
|
/* Provide a device-tree. */
|
||||||
boot_info.fdt = high + (8192 * 2);
|
boot_info.fdt = high + (8192 * 2);
|
||||||
boot_info.fdt &= ~8191;
|
boot_info.fdt &= ~8191;
|
||||||
xilinx_load_device_tree(boot_info.fdt, ram_size, 0, 0, kernel_cmdline);
|
|
||||||
|
xilinx_load_device_tree(boot_info.fdt, ram_size,
|
||||||
|
initrd_base, initrd_size,
|
||||||
|
kernel_cmdline);
|
||||||
}
|
}
|
||||||
env->load_info = &boot_info;
|
env->load_info = &boot_info;
|
||||||
}
|
}
|
||||||
|
@@ -116,6 +116,15 @@ void css_conditional_io_interrupt(SubchDev *sch)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void css_adapter_interrupt(uint8_t isc)
|
||||||
|
{
|
||||||
|
S390CPU *cpu = s390_cpu_addr2state(0);
|
||||||
|
uint32_t io_int_word = (isc << 27) | IO_INT_WORD_AI;
|
||||||
|
|
||||||
|
trace_css_adapter_interrupt(isc);
|
||||||
|
s390_io_interrupt(cpu, 0, 0, 0, io_int_word);
|
||||||
|
}
|
||||||
|
|
||||||
static void sch_handle_clear_func(SubchDev *sch)
|
static void sch_handle_clear_func(SubchDev *sch)
|
||||||
{
|
{
|
||||||
PMCW *p = &sch->curr_status.pmcw;
|
PMCW *p = &sch->curr_status.pmcw;
|
||||||
@@ -1259,6 +1268,7 @@ void css_reset_sch(SubchDev *sch)
|
|||||||
sch->channel_prog = 0x0;
|
sch->channel_prog = 0x0;
|
||||||
sch->last_cmd_valid = false;
|
sch->last_cmd_valid = false;
|
||||||
sch->orb = NULL;
|
sch->orb = NULL;
|
||||||
|
sch->thinint_active = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void css_reset(void)
|
void css_reset(void)
|
||||||
|
@@ -77,6 +77,7 @@ struct SubchDev {
|
|||||||
CCW1 last_cmd;
|
CCW1 last_cmd;
|
||||||
bool last_cmd_valid;
|
bool last_cmd_valid;
|
||||||
ORB *orb;
|
ORB *orb;
|
||||||
|
bool thinint_active;
|
||||||
/* transport-provided data: */
|
/* transport-provided data: */
|
||||||
int (*ccw_cb) (SubchDev *, CCW1);
|
int (*ccw_cb) (SubchDev *, CCW1);
|
||||||
SenseId id;
|
SenseId id;
|
||||||
@@ -97,4 +98,5 @@ void css_queue_crw(uint8_t rsc, uint8_t erc, int chain, uint16_t rsid);
|
|||||||
void css_generate_sch_crws(uint8_t cssid, uint8_t ssid, uint16_t schid,
|
void css_generate_sch_crws(uint8_t cssid, uint8_t ssid, uint16_t schid,
|
||||||
int hotplugged, int add);
|
int hotplugged, int add);
|
||||||
void css_generate_chp_crws(uint8_t cssid, uint8_t chpid);
|
void css_generate_chp_crws(uint8_t cssid, uint8_t chpid);
|
||||||
|
void css_adapter_interrupt(uint8_t isc);
|
||||||
#endif
|
#endif
|
||||||
|
@@ -21,13 +21,13 @@
|
|||||||
#include "hw/s390x/sclp.h"
|
#include "hw/s390x/sclp.h"
|
||||||
#include "hw/s390x/event-facility.h"
|
#include "hw/s390x/event-facility.h"
|
||||||
|
|
||||||
typedef struct EventTypesBus {
|
typedef struct SCLPEventsBus {
|
||||||
BusState qbus;
|
BusState qbus;
|
||||||
} EventTypesBus;
|
} SCLPEventsBus;
|
||||||
|
|
||||||
struct SCLPEventFacility {
|
struct SCLPEventFacility {
|
||||||
EventTypesBus sbus;
|
SysBusDevice parent_obj;
|
||||||
DeviceState *qdev;
|
SCLPEventsBus sbus;
|
||||||
/* guest' receive mask */
|
/* guest' receive mask */
|
||||||
unsigned int receive_mask;
|
unsigned int receive_mask;
|
||||||
};
|
};
|
||||||
@@ -291,7 +291,7 @@ static void sclp_events_bus_class_init(ObjectClass *klass, void *data)
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
static const TypeInfo s390_sclp_events_bus_info = {
|
static const TypeInfo sclp_events_bus_info = {
|
||||||
.name = TYPE_SCLP_EVENTS_BUS,
|
.name = TYPE_SCLP_EVENTS_BUS,
|
||||||
.parent = TYPE_BUS,
|
.parent = TYPE_BUS,
|
||||||
.class_init = sclp_events_bus_class_init,
|
.class_init = sclp_events_bus_class_init,
|
||||||
@@ -299,7 +299,7 @@ static const TypeInfo s390_sclp_events_bus_info = {
|
|||||||
|
|
||||||
static void command_handler(SCLPEventFacility *ef, SCCB *sccb, uint64_t code)
|
static void command_handler(SCLPEventFacility *ef, SCCB *sccb, uint64_t code)
|
||||||
{
|
{
|
||||||
switch (code) {
|
switch (code & SCLP_CMD_CODE_MASK) {
|
||||||
case SCLP_CMD_READ_EVENT_DATA:
|
case SCLP_CMD_READ_EVENT_DATA:
|
||||||
read_event_data(ef, sccb);
|
read_event_data(ef, sccb);
|
||||||
break;
|
break;
|
||||||
@@ -315,21 +315,26 @@ static void command_handler(SCLPEventFacility *ef, SCCB *sccb, uint64_t code)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static int init_event_facility(S390SCLPDevice *sdev)
|
static const VMStateDescription vmstate_event_facility = {
|
||||||
|
.name = "vmstate-event-facility",
|
||||||
|
.version_id = 0,
|
||||||
|
.minimum_version_id = 0,
|
||||||
|
.minimum_version_id_old = 0,
|
||||||
|
.fields = (VMStateField[]) {
|
||||||
|
VMSTATE_UINT32(receive_mask, SCLPEventFacility),
|
||||||
|
VMSTATE_END_OF_LIST()
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
static int init_event_facility(SCLPEventFacility *event_facility)
|
||||||
{
|
{
|
||||||
SCLPEventFacility *event_facility;
|
DeviceState *sdev = DEVICE(event_facility);
|
||||||
DeviceState *quiesce;
|
DeviceState *quiesce;
|
||||||
|
|
||||||
event_facility = g_malloc0(sizeof(SCLPEventFacility));
|
/* Spawn a new bus for SCLP events */
|
||||||
sdev->ef = event_facility;
|
|
||||||
sdev->sclp_command_handler = command_handler;
|
|
||||||
sdev->event_pending = event_pending;
|
|
||||||
|
|
||||||
/* Spawn a new sclp-events facility */
|
|
||||||
qbus_create_inplace(&event_facility->sbus, sizeof(event_facility->sbus),
|
qbus_create_inplace(&event_facility->sbus, sizeof(event_facility->sbus),
|
||||||
TYPE_SCLP_EVENTS_BUS, DEVICE(sdev), NULL);
|
TYPE_SCLP_EVENTS_BUS, sdev, NULL);
|
||||||
event_facility->sbus.qbus.allow_hotplug = 0;
|
event_facility->sbus.qbus.allow_hotplug = 0;
|
||||||
event_facility->qdev = (DeviceState *) sdev;
|
|
||||||
|
|
||||||
quiesce = qdev_create(&event_facility->sbus.qbus, "sclpquiesce");
|
quiesce = qdev_create(&event_facility->sbus.qbus, "sclpquiesce");
|
||||||
if (!quiesce) {
|
if (!quiesce) {
|
||||||
@@ -346,43 +351,57 @@ static int init_event_facility(S390SCLPDevice *sdev)
|
|||||||
|
|
||||||
static void reset_event_facility(DeviceState *dev)
|
static void reset_event_facility(DeviceState *dev)
|
||||||
{
|
{
|
||||||
S390SCLPDevice *sdev = SCLP_S390_DEVICE(dev);
|
SCLPEventFacility *sdev = EVENT_FACILITY(dev);
|
||||||
|
|
||||||
sdev->ef->receive_mask = 0;
|
sdev->receive_mask = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void init_event_facility_class(ObjectClass *klass, void *data)
|
static void init_event_facility_class(ObjectClass *klass, void *data)
|
||||||
{
|
{
|
||||||
DeviceClass *dc = DEVICE_CLASS(klass);
|
SysBusDeviceClass *sbdc = SYS_BUS_DEVICE_CLASS(klass);
|
||||||
S390SCLPDeviceClass *k = SCLP_S390_DEVICE_CLASS(klass);
|
DeviceClass *dc = DEVICE_CLASS(sbdc);
|
||||||
|
SCLPEventFacilityClass *k = EVENT_FACILITY_CLASS(dc);
|
||||||
|
|
||||||
dc->reset = reset_event_facility;
|
dc->reset = reset_event_facility;
|
||||||
|
dc->vmsd = &vmstate_event_facility;
|
||||||
k->init = init_event_facility;
|
k->init = init_event_facility;
|
||||||
|
k->command_handler = command_handler;
|
||||||
|
k->event_pending = event_pending;
|
||||||
}
|
}
|
||||||
|
|
||||||
static const TypeInfo s390_sclp_event_facility_info = {
|
static const TypeInfo sclp_event_facility_info = {
|
||||||
.name = "s390-sclp-event-facility",
|
.name = TYPE_SCLP_EVENT_FACILITY,
|
||||||
.parent = TYPE_DEVICE_S390_SCLP,
|
.parent = TYPE_SYS_BUS_DEVICE,
|
||||||
.instance_size = sizeof(S390SCLPDevice),
|
.instance_size = sizeof(SCLPEventFacility),
|
||||||
.class_init = init_event_facility_class,
|
.class_init = init_event_facility_class,
|
||||||
|
.class_size = sizeof(SCLPEventFacilityClass),
|
||||||
};
|
};
|
||||||
|
|
||||||
static int event_qdev_init(DeviceState *qdev)
|
static void event_realize(DeviceState *qdev, Error **errp)
|
||||||
{
|
{
|
||||||
SCLPEvent *event = DO_UPCAST(SCLPEvent, qdev, qdev);
|
SCLPEvent *event = SCLP_EVENT(qdev);
|
||||||
SCLPEventClass *child = SCLP_EVENT_GET_CLASS(event);
|
SCLPEventClass *child = SCLP_EVENT_GET_CLASS(event);
|
||||||
|
|
||||||
return child->init(event);
|
if (child->init) {
|
||||||
|
int rc = child->init(event);
|
||||||
|
if (rc < 0) {
|
||||||
|
error_setg(errp, "SCLP event initialization failed.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static int event_qdev_exit(DeviceState *qdev)
|
static void event_unrealize(DeviceState *qdev, Error **errp)
|
||||||
{
|
{
|
||||||
SCLPEvent *event = DO_UPCAST(SCLPEvent, qdev, qdev);
|
SCLPEvent *event = SCLP_EVENT(qdev);
|
||||||
SCLPEventClass *child = SCLP_EVENT_GET_CLASS(event);
|
SCLPEventClass *child = SCLP_EVENT_GET_CLASS(event);
|
||||||
if (child->exit) {
|
if (child->exit) {
|
||||||
child->exit(event);
|
int rc = child->exit(event);
|
||||||
|
if (rc < 0) {
|
||||||
|
error_setg(errp, "SCLP event exit failed.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void event_class_init(ObjectClass *klass, void *data)
|
static void event_class_init(ObjectClass *klass, void *data)
|
||||||
@@ -391,11 +410,11 @@ static void event_class_init(ObjectClass *klass, void *data)
|
|||||||
|
|
||||||
dc->bus_type = TYPE_SCLP_EVENTS_BUS;
|
dc->bus_type = TYPE_SCLP_EVENTS_BUS;
|
||||||
dc->unplug = qdev_simple_unplug_cb;
|
dc->unplug = qdev_simple_unplug_cb;
|
||||||
dc->init = event_qdev_init;
|
dc->realize = event_realize;
|
||||||
dc->exit = event_qdev_exit;
|
dc->unrealize = event_unrealize;
|
||||||
}
|
}
|
||||||
|
|
||||||
static const TypeInfo s390_sclp_event_type_info = {
|
static const TypeInfo sclp_event_type_info = {
|
||||||
.name = TYPE_SCLP_EVENT,
|
.name = TYPE_SCLP_EVENT,
|
||||||
.parent = TYPE_DEVICE,
|
.parent = TYPE_DEVICE,
|
||||||
.instance_size = sizeof(SCLPEvent),
|
.instance_size = sizeof(SCLPEvent),
|
||||||
@@ -406,9 +425,9 @@ static const TypeInfo s390_sclp_event_type_info = {
|
|||||||
|
|
||||||
static void register_types(void)
|
static void register_types(void)
|
||||||
{
|
{
|
||||||
type_register_static(&s390_sclp_events_bus_info);
|
type_register_static(&sclp_events_bus_info);
|
||||||
type_register_static(&s390_sclp_event_facility_info);
|
type_register_static(&sclp_event_facility_info);
|
||||||
type_register_static(&s390_sclp_event_type_info);
|
type_register_static(&sclp_event_type_info);
|
||||||
}
|
}
|
||||||
|
|
||||||
type_init(register_types)
|
type_init(register_types)
|
||||||
|
@@ -95,24 +95,29 @@ static int s390_ipl_init(SysBusDevice *dev)
|
|||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
} else {
|
} else {
|
||||||
kernel_size = load_elf(ipl->kernel, NULL, NULL, NULL, NULL,
|
uint64_t pentry = KERN_IMAGE_START;
|
||||||
|
kernel_size = load_elf(ipl->kernel, NULL, NULL, &pentry, NULL,
|
||||||
NULL, 1, ELF_MACHINE, 0);
|
NULL, 1, ELF_MACHINE, 0);
|
||||||
if (kernel_size == -1) {
|
if (kernel_size < 0) {
|
||||||
kernel_size = load_image_targphys(ipl->kernel, 0, ram_size);
|
kernel_size = load_image_targphys(ipl->kernel, 0, ram_size);
|
||||||
}
|
}
|
||||||
if (kernel_size == -1) {
|
if (kernel_size < 0) {
|
||||||
fprintf(stderr, "could not load kernel '%s'\n", ipl->kernel);
|
fprintf(stderr, "could not load kernel '%s'\n", ipl->kernel);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
/* we have to overwrite values in the kernel image, which are "rom" */
|
|
||||||
strcpy(rom_ptr(KERN_PARM_AREA), ipl->cmdline);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* we can not rely on the ELF entry point, since up to 3.2 this
|
* Is it a Linux kernel (starting at 0x10000)? If yes, we fill in the
|
||||||
* value was 0x800 (the SALIPL loader) and it wont work. For
|
* kernel parameters here as well. Note: For old kernels (up to 3.2)
|
||||||
* all (Linux) cases 0x10000 (KERN_IMAGE_START) should be fine.
|
* we can not rely on the ELF entry point - it was 0x800 (the SALIPL
|
||||||
|
* loader) and it won't work. For this case we force it to 0x10000, too.
|
||||||
*/
|
*/
|
||||||
ipl->start_addr = KERN_IMAGE_START;
|
if (pentry == KERN_IMAGE_START || pentry == 0x800) {
|
||||||
|
ipl->start_addr = KERN_IMAGE_START;
|
||||||
|
/* Overwrite parameters in the kernel image, which are "rom" */
|
||||||
|
strcpy(rom_ptr(KERN_PARM_AREA), ipl->cmdline);
|
||||||
|
} else {
|
||||||
|
ipl->start_addr = pentry;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (ipl->initrd) {
|
if (ipl->initrd) {
|
||||||
ram_addr_t initrd_offset;
|
ram_addr_t initrd_offset;
|
||||||
|
@@ -13,13 +13,14 @@
|
|||||||
#include "exec/address-spaces.h"
|
#include "exec/address-spaces.h"
|
||||||
#include "s390-virtio.h"
|
#include "s390-virtio.h"
|
||||||
#include "hw/s390x/sclp.h"
|
#include "hw/s390x/sclp.h"
|
||||||
|
#include "hw/s390x/s390_flic.h"
|
||||||
#include "ioinst.h"
|
#include "ioinst.h"
|
||||||
#include "css.h"
|
#include "css.h"
|
||||||
#include "virtio-ccw.h"
|
#include "virtio-ccw.h"
|
||||||
|
|
||||||
void io_subsystem_reset(void)
|
void io_subsystem_reset(void)
|
||||||
{
|
{
|
||||||
DeviceState *css, *sclp;
|
DeviceState *css, *sclp, *flic;
|
||||||
|
|
||||||
css = DEVICE(object_resolve_path_type("", "virtual-css-bridge", NULL));
|
css = DEVICE(object_resolve_path_type("", "virtual-css-bridge", NULL));
|
||||||
if (css) {
|
if (css) {
|
||||||
@@ -30,6 +31,10 @@ void io_subsystem_reset(void)
|
|||||||
if (sclp) {
|
if (sclp) {
|
||||||
qdev_reset_all(sclp);
|
qdev_reset_all(sclp);
|
||||||
}
|
}
|
||||||
|
flic = DEVICE(object_resolve_path_type("", "s390-flic", NULL));
|
||||||
|
if (flic) {
|
||||||
|
qdev_reset_all(flic);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static int virtio_ccw_hcall_notify(const uint64_t *args)
|
static int virtio_ccw_hcall_notify(const uint64_t *args)
|
||||||
@@ -99,6 +104,7 @@ static void ccw_init(QEMUMachineInitArgs *args)
|
|||||||
s390_sclp_init();
|
s390_sclp_init();
|
||||||
s390_init_ipl_dev(args->kernel_filename, args->kernel_cmdline,
|
s390_init_ipl_dev(args->kernel_filename, args->kernel_cmdline,
|
||||||
args->initrd_filename, "s390-ccw.img");
|
args->initrd_filename, "s390-ccw.img");
|
||||||
|
s390_flic_init();
|
||||||
|
|
||||||
/* register hypercalls */
|
/* register hypercalls */
|
||||||
virtio_ccw_register_hcalls();
|
virtio_ccw_register_hcalls();
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user