Compare commits
432 Commits
pull-input
...
pull-vga-2
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
62232bf484 | ||
|
|
53476e07d2 | ||
|
|
220869e12d | ||
|
|
cf45ec6a52 | ||
|
|
24cdff7c82 | ||
|
|
b0411142f4 | ||
|
|
36e60ef6ac | ||
|
|
97a79eb70d | ||
|
|
5365718a9a | ||
|
|
8d6a91602e | ||
|
|
ebd27391b0 | ||
|
|
c19f47bf5e | ||
|
|
7e1df267a7 | ||
|
|
59c4b7e8df | ||
|
|
2b7ec66f02 | ||
|
|
44ee94e486 | ||
|
|
b781a60b10 | ||
|
|
6028ef0757 | ||
|
|
8190483196 | ||
|
|
71df1d8337 | ||
|
|
1640b200d5 | ||
|
|
8809cfc38e | ||
|
|
28d0de7a4f | ||
|
|
a4c7367f7d | ||
|
|
8122928a52 | ||
|
|
8416abb3b0 | ||
|
|
092b21aa7e | ||
|
|
ee09f84e6b | ||
|
|
2e29dd7c44 | ||
|
|
0daba1f037 | ||
|
|
779cec4d20 | ||
|
|
24a3142692 | ||
|
|
3bbf572345 | ||
|
|
11e66a15a0 | ||
|
|
bafc90bdc5 | ||
|
|
66e2ec2417 | ||
|
|
68c77acfb1 | ||
|
|
b66a67d751 | ||
|
|
7744752402 | ||
|
|
64130fa4a1 | ||
|
|
3de70c0899 | ||
|
|
f809c60512 | ||
|
|
fe6567d5fd | ||
|
|
2001d0cd6d | ||
|
|
71cdd1cb91 | ||
|
|
fb9e7e334b | ||
|
|
3751d7c43f | ||
|
|
f71e42a5c9 | ||
|
|
5aa113f0a2 | ||
|
|
e98094221e | ||
|
|
a9bad65d2c | ||
|
|
b4854f1384 | ||
|
|
9982f74bad | ||
|
|
3f7d846486 | ||
|
|
b216aa6c0f | ||
|
|
f794aa4a2f | ||
|
|
d7a0f71d9a | ||
|
|
f1f4b57e88 | ||
|
|
5045e9d912 | ||
|
|
ec05ec26f9 | ||
|
|
5f2cb94688 | ||
|
|
03eebc9e32 | ||
|
|
20015f72bd | ||
|
|
d114875b9a | ||
|
|
36546e5b80 | ||
|
|
9f02cfc84b | ||
|
|
9460dee4b2 | ||
|
|
e87f7778b6 | ||
|
|
72b47e79ce | ||
|
|
58d2707e87 | ||
|
|
fc377bcf61 | ||
|
|
9564f52da7 | ||
|
|
358653391b | ||
|
|
1652b97476 | ||
|
|
845b6214a3 | ||
|
|
49dfcec403 | ||
|
|
1bfbac4ee1 | ||
|
|
6f6a5ef3e4 | ||
|
|
ea8cb1a8d9 | ||
|
|
677e7805cf | ||
|
|
42af3e3a02 | ||
|
|
d55d42078b | ||
|
|
b2dfd71c48 | ||
|
|
2d1a35bef0 | ||
|
|
5299c0f2cf | ||
|
|
74259ae55b | ||
|
|
086f90e890 | ||
|
|
dbddac6da0 | ||
|
|
6b4ad3b28d | ||
|
|
db94604b20 | ||
|
|
e4afbf4fb4 | ||
|
|
dae02ba55a | ||
|
|
9157eee1b1 | ||
|
|
00967f4e0b | ||
|
|
0ba98885a0 | ||
|
|
b01d44cd06 | ||
|
|
ac58fe7b2c | ||
|
|
0389b8f8c7 | ||
|
|
9814fed0af | ||
|
|
068593deea | ||
|
|
a3084e8055 | ||
|
|
c255ac6012 | ||
|
|
4decd76d71 | ||
|
|
a1f12d855b | ||
|
|
782a847952 | ||
|
|
375ee58bed | ||
|
|
df46283ce7 | ||
|
|
3f4de6756c | ||
|
|
54f0077509 | ||
|
|
ed0bcecec1 | ||
|
|
9182886d79 | ||
|
|
f7c2114067 | ||
|
|
74266b4a58 | ||
|
|
1dedb9b76f | ||
|
|
111d7f4a69 | ||
|
|
a1c7610a68 | ||
|
|
92892330e7 | ||
|
|
4a33565f9f | ||
|
|
f821135cdd | ||
|
|
2daea9c16f | ||
|
|
1f65958d9c | ||
|
|
9bebf9863b | ||
|
|
aa752a4afc | ||
|
|
b8ae94bd39 | ||
|
|
aa9e14e684 | ||
|
|
d9d55f1108 | ||
|
|
c941f07485 | ||
|
|
9cb32c442e | ||
|
|
a91a1b20a2 | ||
|
|
d30107814c | ||
|
|
2aaa194068 | ||
|
|
ee0d0be168 | ||
|
|
d6688ba17b | ||
|
|
3b730f570c | ||
|
|
2700a976db | ||
|
|
309750fad5 | ||
|
|
6fa6b31276 | ||
|
|
6e7d82497d | ||
|
|
e3845e7c47 | ||
|
|
9a10bbb4e8 | ||
|
|
d2ceeb1d68 | ||
|
|
b5d3b03922 | ||
|
|
1de29aef17 | ||
|
|
006f8638c6 | ||
|
|
5a58e884d1 | ||
|
|
085eb217df | ||
|
|
026bfd89cb | ||
|
|
a34944fe2e | ||
|
|
076b35b5a5 | ||
|
|
c5bc152bc3 | ||
|
|
7454c7af91 | ||
|
|
cf8c704d5a | ||
|
|
62083979b0 | ||
|
|
7619c7b00c | ||
|
|
e4b798bb53 | ||
|
|
79853e18d9 | ||
|
|
31fe14d15d | ||
|
|
46503c2bc0 | ||
|
|
ab316865db | ||
|
|
886445a6ee | ||
|
|
8c8639df32 | ||
|
|
094d20585e | ||
|
|
bbf5c878ab | ||
|
|
11eec063f2 | ||
|
|
730fce593b | ||
|
|
68fea5a0d7 | ||
|
|
a1a4561243 | ||
|
|
f9ce8e0aa3 | ||
|
|
dea1b3ce75 | ||
|
|
ccf9ff8527 | ||
|
|
fae807a2b1 | ||
|
|
46c5874e9c | ||
|
|
d9d96a3cc7 | ||
|
|
3e1a01cb55 | ||
|
|
4290ca49ee | ||
|
|
c8545818b3 | ||
|
|
f1215ea702 | ||
|
|
12fd285358 | ||
|
|
421b1b27f6 | ||
|
|
31ce0adb79 | ||
|
|
28f490b24a | ||
|
|
62e9cd771c | ||
|
|
814550d73a | ||
|
|
0f6dd8e1d5 | ||
|
|
0e79e51a7d | ||
|
|
6a3042b23b | ||
|
|
0639b00d05 | ||
|
|
2118196bb3 | ||
|
|
40d14bef80 | ||
|
|
cb2ed8b3c6 | ||
|
|
dcdca29655 | ||
|
|
a43c6e2762 | ||
|
|
0d8935e337 | ||
|
|
a4894206e3 | ||
|
|
09e5b81922 | ||
|
|
ca6c18556c | ||
|
|
602141d997 | ||
|
|
ce6a28ee05 | ||
|
|
32d9ca15ba | ||
|
|
ca9b46bcec | ||
|
|
d5aaa1b045 | ||
|
|
977ad992f1 | ||
|
|
6652d0811c | ||
|
|
557772f26b | ||
|
|
cb3d37a93c | ||
|
|
b853d4cbf2 | ||
|
|
2a72ea5f66 | ||
|
|
de6a92185e | ||
|
|
de3852877f | ||
|
|
2801339f2f | ||
|
|
8b8f1c7e9d | ||
|
|
b6b099541d | ||
|
|
1597051b84 | ||
|
|
26c8acb3f3 | ||
|
|
294972ce54 | ||
|
|
5429273615 | ||
|
|
2c85fad022 | ||
|
|
a9c8a0d8d4 | ||
|
|
d4ef00af25 | ||
|
|
aaaee0b273 | ||
|
|
ca43b97b5f | ||
|
|
b64127244d | ||
|
|
5105505e65 | ||
|
|
aff0d5e57a | ||
|
|
0b0cc076b7 | ||
|
|
9ff7f5bddb | ||
|
|
9f9b026dc6 | ||
|
|
f19377bf23 | ||
|
|
c18f855697 | ||
|
|
bd4baf6eeb | ||
|
|
7df057bac3 | ||
|
|
d370dfa9f3 | ||
|
|
6e38a4ba78 | ||
|
|
2ba154cf4e | ||
|
|
5708b2b736 | ||
|
|
b8981dc9aa | ||
|
|
a2f533da00 | ||
|
|
44f192f364 | ||
|
|
1b93c9a104 | ||
|
|
38e5c119c2 | ||
|
|
be9f8a0872 | ||
|
|
458cf469f4 | ||
|
|
0e3bd56294 | ||
|
|
4964e18e49 | ||
|
|
6cc8a11c84 | ||
|
|
f6c2d1d842 | ||
|
|
d275b33d76 | ||
|
|
5b0a25e8d2 | ||
|
|
85d291a08c | ||
|
|
83a260135f | ||
|
|
07e415f239 | ||
|
|
a67bfbb9e4 | ||
|
|
42d58e7c67 | ||
|
|
94edf02c4c | ||
|
|
5f7a5a0edc | ||
|
|
ac9d32e396 | ||
|
|
c25bbf1545 | ||
|
|
a88a3f8871 | ||
|
|
0ad3393ad0 | ||
|
|
45ebe3916a | ||
|
|
0e7ef22136 | ||
|
|
c4ff1e68c6 | ||
|
|
d61bb2482d | ||
|
|
d1d35cf4ff | ||
|
|
b38ec5ee7a | ||
|
|
7611dae8a6 | ||
|
|
5c83b2f5b4 | ||
|
|
11d306b9df | ||
|
|
4771cd01da | ||
|
|
9718e4ae36 | ||
|
|
1850b6b7d0 | ||
|
|
0b2ff2ceb8 | ||
|
|
bd204e63a7 | ||
|
|
dfd90a8715 | ||
|
|
770c58f8d1 | ||
|
|
747d009dca | ||
|
|
57b6d95eb4 | ||
|
|
8742d49d6f | ||
|
|
51da90140b | ||
|
|
bdb9e2d66a | ||
|
|
a57633c08f | ||
|
|
ff05f37bab | ||
|
|
b9cb5323bb | ||
|
|
06ec4c8c9f | ||
|
|
95f949ac3d | ||
|
|
a903c449b4 | ||
|
|
3fc827d591 | ||
|
|
25611aa12b | ||
|
|
ef99b3ee06 | ||
|
|
e63d114b8a | ||
|
|
16c9d46d32 | ||
|
|
489653b5db | ||
|
|
9f3982f2dc | ||
|
|
f994b2587f | ||
|
|
6a50636f35 | ||
|
|
74358f2a16 | ||
|
|
c83fe23b58 | ||
|
|
7ef6cf6341 | ||
|
|
710aec915d | ||
|
|
452e0300a3 | ||
|
|
70ea0c5899 | ||
|
|
4086182fcd | ||
|
|
ba0510aad4 | ||
|
|
326283aa5d | ||
|
|
8a4f501c09 | ||
|
|
04e00c92ef | ||
|
|
318660f84a | ||
|
|
072ebe6b03 | ||
|
|
b8a185bc9a | ||
|
|
13cadefbda | ||
|
|
84add864eb | ||
|
|
65207c59d9 | ||
|
|
9e472263b0 | ||
|
|
b821cbe274 | ||
|
|
830d70db69 | ||
|
|
019a3edbb2 | ||
|
|
fdba6d967e | ||
|
|
434027badb | ||
|
|
afcf905cff | ||
|
|
68e6b0af78 | ||
|
|
af39d5363f | ||
|
|
f7bd7b8eb6 | ||
|
|
a57dddddd2 | ||
|
|
928b899657 | ||
|
|
96396e2858 | ||
|
|
c08cf07042 | ||
|
|
5cb18b3d7b | ||
|
|
9657cafceb | ||
|
|
56a3c24ffc | ||
|
|
116694c34a | ||
|
|
38d40ff10f | ||
|
|
c3bdc56c18 | ||
|
|
ea96bc629c | ||
|
|
6cd2234ccb | ||
|
|
936a7c1cf7 | ||
|
|
fd53c87cf6 | ||
|
|
b829c2a98f | ||
|
|
87b3bd1c85 | ||
|
|
d820331a0b | ||
|
|
74c85296dc | ||
|
|
10ceaa1e8f | ||
|
|
8dfbaa6ac4 | ||
|
|
8ad176aaed | ||
|
|
e83980455c | ||
|
|
da51a335aa | ||
|
|
cf34f533a1 | ||
|
|
13644819c5 | ||
|
|
6b8f102054 | ||
|
|
2332333c97 | ||
|
|
99fbeafee8 | ||
|
|
211b5b1d0a | ||
|
|
72d164aa73 | ||
|
|
d48f4fa69e | ||
|
|
d644b11657 | ||
|
|
865906f7fd | ||
|
|
25519b062c | ||
|
|
fddd179ab9 | ||
|
|
61f219dfb0 | ||
|
|
b6b5c8e492 | ||
|
|
f6d5a0bad2 | ||
|
|
faf7e4254f | ||
|
|
d765519bef | ||
|
|
d5303df710 | ||
|
|
bb08d8829b | ||
|
|
38ff32c6e6 | ||
|
|
4dfd8eaa19 | ||
|
|
42134ac9d7 | ||
|
|
1edbde82b8 | ||
|
|
dd754baf46 | ||
|
|
a7cde24dc2 | ||
|
|
f27086a731 | ||
|
|
4974920ab8 | ||
|
|
ecfa60e374 | ||
|
|
39b87c7b9f | ||
|
|
1190044ea5 | ||
|
|
07e15486fa | ||
|
|
9bbd4843c0 | ||
|
|
05b6ca9bbc | ||
|
|
97af820f53 | ||
|
|
2cc3bdbe2d | ||
|
|
2a90c454a1 | ||
|
|
9abe3bdc45 | ||
|
|
3960c336ad | ||
|
|
d7c2e2db28 | ||
|
|
135a67a692 | ||
|
|
d4e5de1ae0 | ||
|
|
e1f776c434 | ||
|
|
616ef329ad | ||
|
|
ed8176a37a | ||
|
|
467b07dfae | ||
|
|
ea7df04a02 | ||
|
|
922cc8823e | ||
|
|
b930fb9db4 | ||
|
|
ed8b5847e4 | ||
|
|
8434488400 | ||
|
|
d4bec5d876 | ||
|
|
243bdb79fb | ||
|
|
ee246400c1 | ||
|
|
982d06c561 | ||
|
|
c2f7c0c306 | ||
|
|
dfccd8cfd7 | ||
|
|
205d1d1c04 | ||
|
|
dc17ab1de5 | ||
|
|
f5d8c8cd79 | ||
|
|
6a1f001be3 | ||
|
|
afe0b3803f | ||
|
|
ff80dc7fa8 | ||
|
|
b1eced713d | ||
|
|
84549b6dcf | ||
|
|
647f767ba3 | ||
|
|
9dbbc748d6 | ||
|
|
3cf6a0fced | ||
|
|
c6f191642a | ||
|
|
38836a2cd4 | ||
|
|
012a906b19 | ||
|
|
c63285991b | ||
|
|
863b6589d7 | ||
|
|
8c6084bf10 | ||
|
|
f2932df777 | ||
|
|
e3b1d48099 | ||
|
|
7371036198 | ||
|
|
9441aa282b | ||
|
|
63c67b6d44 | ||
|
|
97edf3bd5e | ||
|
|
ba7c388963 | ||
|
|
7ced9e9f6d | ||
|
|
896e1a050a | ||
|
|
dcf30025c3 | ||
|
|
f7a8beb5e6 | ||
|
|
641381c1fc | ||
|
|
e95e203c08 | ||
|
|
246ca55faf |
@@ -486,7 +486,8 @@ F: hw/ppc/prep.c
|
|||||||
F: hw/pci-host/prep.[hc]
|
F: hw/pci-host/prep.[hc]
|
||||||
F: hw/isa/pc87312.[hc]
|
F: hw/isa/pc87312.[hc]
|
||||||
|
|
||||||
sPAPR
|
sPAPR (pseries)
|
||||||
|
M: David Gibson <david@gibson.dropbear.id.au>
|
||||||
M: Alexander Graf <agraf@suse.de>
|
M: Alexander Graf <agraf@suse.de>
|
||||||
L: qemu-ppc@nongnu.org
|
L: qemu-ppc@nongnu.org
|
||||||
S: Supported
|
S: Supported
|
||||||
|
|||||||
7
Makefile
7
Makefile
@@ -389,13 +389,8 @@ ifneq (,$(findstring qemu-ga,$(TOOLS)))
|
|||||||
endif
|
endif
|
||||||
endif
|
endif
|
||||||
|
|
||||||
install-confdir:
|
|
||||||
$(INSTALL_DIR) "$(DESTDIR)$(qemu_confdir)"
|
|
||||||
|
|
||||||
install-sysconfig: install-datadir install-confdir
|
install: all $(if $(BUILD_DOCS),install-doc) \
|
||||||
$(INSTALL_DATA) $(SRC_PATH)/sysconfigs/target/target-x86_64.conf "$(DESTDIR)$(qemu_confdir)"
|
|
||||||
|
|
||||||
install: all $(if $(BUILD_DOCS),install-doc) install-sysconfig \
|
|
||||||
install-datadir install-localstatedir
|
install-datadir install-localstatedir
|
||||||
ifneq ($(TOOLS),)
|
ifneq ($(TOOLS),)
|
||||||
$(call install-prog,$(TOOLS),$(DESTDIR)$(bindir))
|
$(call install-prog,$(TOOLS),$(DESTDIR)$(bindir))
|
||||||
|
|||||||
@@ -76,6 +76,8 @@ common-obj-$(CONFIG_SECCOMP) += qemu-seccomp.o
|
|||||||
|
|
||||||
common-obj-$(CONFIG_SMARTCARD_NSS) += $(libcacard-y)
|
common-obj-$(CONFIG_SMARTCARD_NSS) += $(libcacard-y)
|
||||||
|
|
||||||
|
common-obj-$(CONFIG_FDT) += device_tree.o
|
||||||
|
|
||||||
######################################################################
|
######################################################################
|
||||||
# qapi
|
# qapi
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
# -*- Mode: makefile -*-
|
# -*- Mode: makefile -*-
|
||||||
|
|
||||||
|
BUILD_DIR?=$(CURDIR)/..
|
||||||
|
|
||||||
include ../config-host.mak
|
include ../config-host.mak
|
||||||
include config-target.mak
|
include config-target.mak
|
||||||
include config-devices.mak
|
include config-devices.mak
|
||||||
@@ -129,7 +131,6 @@ ifdef CONFIG_SOFTMMU
|
|||||||
obj-y += arch_init.o cpus.o monitor.o gdbstub.o balloon.o ioport.o numa.o
|
obj-y += arch_init.o cpus.o monitor.o gdbstub.o balloon.o ioport.o numa.o
|
||||||
obj-y += qtest.o bootdevice.o
|
obj-y += qtest.o bootdevice.o
|
||||||
obj-y += hw/
|
obj-y += hw/
|
||||||
obj-$(CONFIG_FDT) += device_tree.o
|
|
||||||
obj-$(CONFIG_KVM) += kvm-all.o
|
obj-$(CONFIG_KVM) += kvm-all.o
|
||||||
obj-y += memory.o savevm.o cputlb.o
|
obj-y += memory.o savevm.o cputlb.o
|
||||||
obj-y += memory_mapping.o
|
obj-y += memory_mapping.o
|
||||||
|
|||||||
47
arch_init.c
47
arch_init.c
@@ -136,7 +136,6 @@ static struct defconfig_file {
|
|||||||
bool userconfig;
|
bool userconfig;
|
||||||
} default_config_files[] = {
|
} default_config_files[] = {
|
||||||
{ CONFIG_QEMU_CONFDIR "/qemu.conf", true },
|
{ CONFIG_QEMU_CONFDIR "/qemu.conf", true },
|
||||||
{ CONFIG_QEMU_CONFDIR "/target-" TARGET_NAME ".conf", true },
|
|
||||||
{ NULL }, /* end of list */
|
{ NULL }, /* end of list */
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -610,52 +609,10 @@ ram_addr_t migration_bitmap_find_and_reset_dirty(MemoryRegion *mr,
|
|||||||
return (next - base) << TARGET_PAGE_BITS;
|
return (next - base) << TARGET_PAGE_BITS;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline bool migration_bitmap_set_dirty(ram_addr_t addr)
|
|
||||||
{
|
|
||||||
bool ret;
|
|
||||||
int nr = addr >> TARGET_PAGE_BITS;
|
|
||||||
|
|
||||||
ret = test_and_set_bit(nr, migration_bitmap);
|
|
||||||
|
|
||||||
if (!ret) {
|
|
||||||
migration_dirty_pages++;
|
|
||||||
}
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void migration_bitmap_sync_range(ram_addr_t start, ram_addr_t length)
|
static void migration_bitmap_sync_range(ram_addr_t start, ram_addr_t length)
|
||||||
{
|
{
|
||||||
ram_addr_t addr;
|
migration_dirty_pages +=
|
||||||
unsigned long page = BIT_WORD(start >> TARGET_PAGE_BITS);
|
cpu_physical_memory_sync_dirty_bitmap(migration_bitmap, start, length);
|
||||||
|
|
||||||
/* start address is aligned at the start of a word? */
|
|
||||||
if (((page * BITS_PER_LONG) << TARGET_PAGE_BITS) == start) {
|
|
||||||
int k;
|
|
||||||
int nr = BITS_TO_LONGS(length >> TARGET_PAGE_BITS);
|
|
||||||
unsigned long *src = ram_list.dirty_memory[DIRTY_MEMORY_MIGRATION];
|
|
||||||
|
|
||||||
for (k = page; k < page + nr; k++) {
|
|
||||||
if (src[k]) {
|
|
||||||
unsigned long new_dirty;
|
|
||||||
new_dirty = ~migration_bitmap[k];
|
|
||||||
migration_bitmap[k] |= src[k];
|
|
||||||
new_dirty &= src[k];
|
|
||||||
migration_dirty_pages += ctpopl(new_dirty);
|
|
||||||
src[k] = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
for (addr = 0; addr < length; addr += TARGET_PAGE_SIZE) {
|
|
||||||
if (cpu_physical_memory_get_dirty(start + addr,
|
|
||||||
TARGET_PAGE_SIZE,
|
|
||||||
DIRTY_MEMORY_MIGRATION)) {
|
|
||||||
cpu_physical_memory_reset_dirty(start + addr,
|
|
||||||
TARGET_PAGE_SIZE,
|
|
||||||
DIRTY_MEMORY_MIGRATION);
|
|
||||||
migration_bitmap_set_dirty(start + addr);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -96,6 +96,20 @@ bool tpm_backend_get_tpm_established_flag(TPMBackend *s)
|
|||||||
return k->ops->get_tpm_established_flag(s);
|
return k->ops->get_tpm_established_flag(s);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int tpm_backend_reset_tpm_established_flag(TPMBackend *s, uint8_t locty)
|
||||||
|
{
|
||||||
|
TPMBackendClass *k = TPM_BACKEND_GET_CLASS(s);
|
||||||
|
|
||||||
|
return k->ops->reset_tpm_established_flag(s, locty);
|
||||||
|
}
|
||||||
|
|
||||||
|
TPMVersion tpm_backend_get_tpm_version(TPMBackend *s)
|
||||||
|
{
|
||||||
|
TPMBackendClass *k = TPM_BACKEND_GET_CLASS(s);
|
||||||
|
|
||||||
|
return k->ops->get_tpm_version(s);
|
||||||
|
}
|
||||||
|
|
||||||
static bool tpm_backend_prop_get_opened(Object *obj, Error **errp)
|
static bool tpm_backend_prop_get_opened(Object *obj, Error **errp)
|
||||||
{
|
{
|
||||||
TPMBackend *s = TPM_BACKEND(obj);
|
TPMBackend *s = TPM_BACKEND(obj);
|
||||||
|
|||||||
13
block.c
13
block.c
@@ -3116,6 +3116,17 @@ bool bdrv_dirty_bitmap_enabled(BdrvDirtyBitmap *bitmap)
|
|||||||
return !(bitmap->disabled || bitmap->successor);
|
return !(bitmap->disabled || bitmap->successor);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
DirtyBitmapStatus bdrv_dirty_bitmap_status(BdrvDirtyBitmap *bitmap)
|
||||||
|
{
|
||||||
|
if (bdrv_dirty_bitmap_frozen(bitmap)) {
|
||||||
|
return DIRTY_BITMAP_STATUS_FROZEN;
|
||||||
|
} else if (!bdrv_dirty_bitmap_enabled(bitmap)) {
|
||||||
|
return DIRTY_BITMAP_STATUS_DISABLED;
|
||||||
|
} else {
|
||||||
|
return DIRTY_BITMAP_STATUS_ACTIVE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a successor bitmap destined to replace this bitmap after an operation.
|
* Create a successor bitmap destined to replace this bitmap after an operation.
|
||||||
* Requires that the bitmap is not frozen and has no successor.
|
* Requires that the bitmap is not frozen and has no successor.
|
||||||
@@ -3256,7 +3267,7 @@ BlockDirtyInfoList *bdrv_query_dirty_bitmaps(BlockDriverState *bs)
|
|||||||
info->granularity = bdrv_dirty_bitmap_granularity(bm);
|
info->granularity = bdrv_dirty_bitmap_granularity(bm);
|
||||||
info->has_name = !!bm->name;
|
info->has_name = !!bm->name;
|
||||||
info->name = g_strdup(bm->name);
|
info->name = g_strdup(bm->name);
|
||||||
info->frozen = bdrv_dirty_bitmap_frozen(bm);
|
info->status = bdrv_dirty_bitmap_status(bm);
|
||||||
entry->value = info;
|
entry->value = info;
|
||||||
*plist = entry;
|
*plist = entry;
|
||||||
plist = &entry->next;
|
plist = &entry->next;
|
||||||
|
|||||||
@@ -216,10 +216,9 @@ static int get_event_by_name(const char *name, BlkDebugEvent *event)
|
|||||||
struct add_rule_data {
|
struct add_rule_data {
|
||||||
BDRVBlkdebugState *s;
|
BDRVBlkdebugState *s;
|
||||||
int action;
|
int action;
|
||||||
Error **errp;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
static int add_rule(QemuOpts *opts, void *opaque)
|
static int add_rule(void *opaque, QemuOpts *opts, Error **errp)
|
||||||
{
|
{
|
||||||
struct add_rule_data *d = opaque;
|
struct add_rule_data *d = opaque;
|
||||||
BDRVBlkdebugState *s = d->s;
|
BDRVBlkdebugState *s = d->s;
|
||||||
@@ -230,10 +229,10 @@ static int add_rule(QemuOpts *opts, void *opaque)
|
|||||||
/* Find the right event for the rule */
|
/* Find the right event for the rule */
|
||||||
event_name = qemu_opt_get(opts, "event");
|
event_name = qemu_opt_get(opts, "event");
|
||||||
if (!event_name) {
|
if (!event_name) {
|
||||||
error_setg(d->errp, "Missing event name for rule");
|
error_setg(errp, "Missing event name for rule");
|
||||||
return -1;
|
return -1;
|
||||||
} else if (get_event_by_name(event_name, &event) < 0) {
|
} else if (get_event_by_name(event_name, &event) < 0) {
|
||||||
error_setg(d->errp, "Invalid event name \"%s\"", event_name);
|
error_setg(errp, "Invalid event name \"%s\"", event_name);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -319,8 +318,7 @@ static int read_config(BDRVBlkdebugState *s, const char *filename,
|
|||||||
|
|
||||||
d.s = s;
|
d.s = s;
|
||||||
d.action = ACTION_INJECT_ERROR;
|
d.action = ACTION_INJECT_ERROR;
|
||||||
d.errp = &local_err;
|
qemu_opts_foreach(&inject_error_opts, add_rule, &d, &local_err);
|
||||||
qemu_opts_foreach(&inject_error_opts, add_rule, &d, 1);
|
|
||||||
if (local_err) {
|
if (local_err) {
|
||||||
error_propagate(errp, local_err);
|
error_propagate(errp, local_err);
|
||||||
ret = -EINVAL;
|
ret = -EINVAL;
|
||||||
@@ -328,7 +326,7 @@ static int read_config(BDRVBlkdebugState *s, const char *filename,
|
|||||||
}
|
}
|
||||||
|
|
||||||
d.action = ACTION_SET_STATE;
|
d.action = ACTION_SET_STATE;
|
||||||
qemu_opts_foreach(&set_state_opts, add_rule, &d, 1);
|
qemu_opts_foreach(&set_state_opts, add_rule, &d, &local_err);
|
||||||
if (local_err) {
|
if (local_err) {
|
||||||
error_propagate(errp, local_err);
|
error_propagate(errp, local_err);
|
||||||
ret = -EINVAL;
|
ret = -EINVAL;
|
||||||
|
|||||||
@@ -1323,13 +1323,6 @@ static int iscsi_open(BlockDriverState *bs, QDict *options, int flags,
|
|||||||
const char *filename;
|
const char *filename;
|
||||||
int i, ret = 0;
|
int i, ret = 0;
|
||||||
|
|
||||||
if ((BDRV_SECTOR_SIZE % 512) != 0) {
|
|
||||||
error_setg(errp, "iSCSI: Invalid BDRV_SECTOR_SIZE. "
|
|
||||||
"BDRV_SECTOR_SIZE(%lld) is not a multiple "
|
|
||||||
"of 512", BDRV_SECTOR_SIZE);
|
|
||||||
return -EINVAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
opts = qemu_opts_create(&runtime_opts, NULL, 0, &error_abort);
|
opts = qemu_opts_create(&runtime_opts, NULL, 0, &error_abort);
|
||||||
qemu_opts_absorb_qdict(opts, options, &local_err);
|
qemu_opts_absorb_qdict(opts, options, &local_err);
|
||||||
if (local_err) {
|
if (local_err) {
|
||||||
|
|||||||
@@ -2113,7 +2113,7 @@ void qmp_block_dirty_bitmap_clear(const char *node, const char *name,
|
|||||||
aio_context_release(aio_context);
|
aio_context_release(aio_context);
|
||||||
}
|
}
|
||||||
|
|
||||||
int hmp_drive_del(Monitor *mon, const QDict *qdict, QObject **ret_data)
|
void hmp_drive_del(Monitor *mon, const QDict *qdict)
|
||||||
{
|
{
|
||||||
const char *id = qdict_get_str(qdict, "id");
|
const char *id = qdict_get_str(qdict, "id");
|
||||||
BlockBackend *blk;
|
BlockBackend *blk;
|
||||||
@@ -2124,14 +2124,14 @@ int hmp_drive_del(Monitor *mon, const QDict *qdict, QObject **ret_data)
|
|||||||
blk = blk_by_name(id);
|
blk = blk_by_name(id);
|
||||||
if (!blk) {
|
if (!blk) {
|
||||||
error_report("Device '%s' not found", id);
|
error_report("Device '%s' not found", id);
|
||||||
return -1;
|
return;
|
||||||
}
|
}
|
||||||
bs = blk_bs(blk);
|
bs = blk_bs(blk);
|
||||||
|
|
||||||
if (!blk_legacy_dinfo(blk)) {
|
if (!blk_legacy_dinfo(blk)) {
|
||||||
error_report("Deleting device added with blockdev-add"
|
error_report("Deleting device added with blockdev-add"
|
||||||
" is not supported");
|
" is not supported");
|
||||||
return -1;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
aio_context = bdrv_get_aio_context(bs);
|
aio_context = bdrv_get_aio_context(bs);
|
||||||
@@ -2140,7 +2140,7 @@ int hmp_drive_del(Monitor *mon, const QDict *qdict, QObject **ret_data)
|
|||||||
if (bdrv_op_is_blocked(bs, BLOCK_OP_TYPE_DRIVE_DEL, &local_err)) {
|
if (bdrv_op_is_blocked(bs, BLOCK_OP_TYPE_DRIVE_DEL, &local_err)) {
|
||||||
error_report_err(local_err);
|
error_report_err(local_err);
|
||||||
aio_context_release(aio_context);
|
aio_context_release(aio_context);
|
||||||
return -1;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* quiesce block driver; prevent further io */
|
/* quiesce block driver; prevent further io */
|
||||||
@@ -2163,7 +2163,6 @@ int hmp_drive_del(Monitor *mon, const QDict *qdict, QObject **ret_data)
|
|||||||
}
|
}
|
||||||
|
|
||||||
aio_context_release(aio_context);
|
aio_context_release(aio_context);
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void qmp_block_resize(bool has_device, const char *device,
|
void qmp_block_resize(bool has_device, const char *device,
|
||||||
|
|||||||
@@ -108,10 +108,6 @@ void cpu_list_unlock(void)
|
|||||||
/***********************************************************/
|
/***********************************************************/
|
||||||
/* CPUX86 core interface */
|
/* CPUX86 core interface */
|
||||||
|
|
||||||
void cpu_smm_update(CPUX86State *env)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
uint64_t cpu_get_tsc(CPUX86State *env)
|
uint64_t cpu_get_tsc(CPUX86State *env)
|
||||||
{
|
{
|
||||||
return cpu_get_real_ticks();
|
return cpu_get_real_ticks();
|
||||||
|
|||||||
12
configure
vendored
12
configure
vendored
@@ -353,7 +353,7 @@ for opt do
|
|||||||
;;
|
;;
|
||||||
--cpu=*) cpu="$optarg"
|
--cpu=*) cpu="$optarg"
|
||||||
;;
|
;;
|
||||||
--extra-cflags=*) QEMU_CFLAGS="$optarg $QEMU_CFLAGS"
|
--extra-cflags=*) QEMU_CFLAGS="$QEMU_CFLAGS $optarg"
|
||||||
EXTRA_CFLAGS="$optarg"
|
EXTRA_CFLAGS="$optarg"
|
||||||
;;
|
;;
|
||||||
--extra-ldflags=*) LDFLAGS="$optarg $LDFLAGS"
|
--extra-ldflags=*) LDFLAGS="$optarg $LDFLAGS"
|
||||||
@@ -3115,9 +3115,11 @@ fi
|
|||||||
if test "$fdt" != "no" ; then
|
if test "$fdt" != "no" ; then
|
||||||
fdt_libs="-lfdt"
|
fdt_libs="-lfdt"
|
||||||
# explicitly check for libfdt_env.h as it is missing in some stable installs
|
# explicitly check for libfdt_env.h as it is missing in some stable installs
|
||||||
|
# and test for required functions to make sure we are on a version >= 1.4.0
|
||||||
cat > $TMPC << EOF
|
cat > $TMPC << EOF
|
||||||
|
#include <libfdt.h>
|
||||||
#include <libfdt_env.h>
|
#include <libfdt_env.h>
|
||||||
int main(void) { return 0; }
|
int main(void) { fdt_get_property_by_offset(0, 0, 0); return 0; }
|
||||||
EOF
|
EOF
|
||||||
if compile_prog "" "$fdt_libs" ; then
|
if compile_prog "" "$fdt_libs" ; then
|
||||||
# system DTC is good - use it
|
# system DTC is good - use it
|
||||||
@@ -3135,7 +3137,7 @@ EOF
|
|||||||
fdt_libs="-L\$(BUILD_DIR)/dtc/libfdt $fdt_libs"
|
fdt_libs="-L\$(BUILD_DIR)/dtc/libfdt $fdt_libs"
|
||||||
elif test "$fdt" = "yes" ; then
|
elif test "$fdt" = "yes" ; then
|
||||||
# have neither and want - prompt for system/submodule install
|
# have neither and want - prompt for system/submodule install
|
||||||
error_exit "DTC (libfdt) not present. Your options:" \
|
error_exit "DTC (libfdt) version >= 1.4.0 not present. Your options:" \
|
||||||
" (1) Preferred: Install the DTC (libfdt) devel package" \
|
" (1) Preferred: Install the DTC (libfdt) devel package" \
|
||||||
" (2) Fetch the DTC submodule, using:" \
|
" (2) Fetch the DTC submodule, using:" \
|
||||||
" git submodule update --init dtc"
|
" git submodule update --init dtc"
|
||||||
@@ -3166,14 +3168,14 @@ else
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
if test "$opengl" != "no" ; then
|
if test "$opengl" != "no" ; then
|
||||||
opengl_pkgs="gl glesv2"
|
opengl_pkgs="gl glesv2 epoxy egl"
|
||||||
if $pkg_config $opengl_pkgs x11 && test "$have_glx" = "yes"; then
|
if $pkg_config $opengl_pkgs x11 && test "$have_glx" = "yes"; then
|
||||||
opengl_cflags="$($pkg_config --cflags $opengl_pkgs) $x11_cflags"
|
opengl_cflags="$($pkg_config --cflags $opengl_pkgs) $x11_cflags"
|
||||||
opengl_libs="$($pkg_config --libs $opengl_pkgs) $x11_libs"
|
opengl_libs="$($pkg_config --libs $opengl_pkgs) $x11_libs"
|
||||||
opengl=yes
|
opengl=yes
|
||||||
else
|
else
|
||||||
if test "$opengl" = "yes" ; then
|
if test "$opengl" = "yes" ; then
|
||||||
feature_not_found "opengl" "Install GL devel (e.g. MESA)"
|
feature_not_found "opengl" "Please install opengl (mesa) devel pkgs: $opengl_pkgs"
|
||||||
fi
|
fi
|
||||||
opengl_cflags=""
|
opengl_cflags=""
|
||||||
opengl_libs=""
|
opengl_libs=""
|
||||||
|
|||||||
84
cpus.c
84
cpus.c
@@ -105,6 +105,7 @@ static bool all_cpu_threads_idle(void)
|
|||||||
|
|
||||||
/* Protected by TimersState seqlock */
|
/* Protected by TimersState seqlock */
|
||||||
|
|
||||||
|
static bool icount_sleep = true;
|
||||||
static int64_t vm_clock_warp_start = -1;
|
static int64_t vm_clock_warp_start = -1;
|
||||||
/* Conversion factor from emulated instructions to virtual clock ticks. */
|
/* Conversion factor from emulated instructions to virtual clock ticks. */
|
||||||
static int icount_time_shift;
|
static int icount_time_shift;
|
||||||
@@ -393,15 +394,18 @@ void qemu_clock_warp(QEMUClockType type)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
if (icount_sleep) {
|
||||||
* If the CPUs have been sleeping, advance QEMU_CLOCK_VIRTUAL timer now.
|
/*
|
||||||
* This ensures that the deadline for the timer is computed correctly below.
|
* If the CPUs have been sleeping, advance QEMU_CLOCK_VIRTUAL timer now.
|
||||||
* This also makes sure that the insn counter is synchronized before the
|
* This ensures that the deadline for the timer is computed correctly
|
||||||
* CPU starts running, in case the CPU is woken by an event other than
|
* below.
|
||||||
* the earliest QEMU_CLOCK_VIRTUAL timer.
|
* This also makes sure that the insn counter is synchronized before
|
||||||
*/
|
* the CPU starts running, in case the CPU is woken by an event other
|
||||||
icount_warp_rt(NULL);
|
* than the earliest QEMU_CLOCK_VIRTUAL timer.
|
||||||
timer_del(icount_warp_timer);
|
*/
|
||||||
|
icount_warp_rt(NULL);
|
||||||
|
timer_del(icount_warp_timer);
|
||||||
|
}
|
||||||
if (!all_cpu_threads_idle()) {
|
if (!all_cpu_threads_idle()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -415,6 +419,11 @@ void qemu_clock_warp(QEMUClockType type)
|
|||||||
clock = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL_RT);
|
clock = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL_RT);
|
||||||
deadline = qemu_clock_deadline_ns_all(QEMU_CLOCK_VIRTUAL);
|
deadline = qemu_clock_deadline_ns_all(QEMU_CLOCK_VIRTUAL);
|
||||||
if (deadline < 0) {
|
if (deadline < 0) {
|
||||||
|
static bool notified;
|
||||||
|
if (!icount_sleep && !notified) {
|
||||||
|
error_report("WARNING: icount sleep disabled and no active timers");
|
||||||
|
notified = true;
|
||||||
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -425,23 +434,35 @@ void qemu_clock_warp(QEMUClockType type)
|
|||||||
* interrupt to wake it up, but the interrupt never comes because
|
* interrupt to wake it up, but the interrupt never comes because
|
||||||
* the vCPU isn't running any insns and thus doesn't advance the
|
* the vCPU isn't running any insns and thus doesn't advance the
|
||||||
* QEMU_CLOCK_VIRTUAL.
|
* QEMU_CLOCK_VIRTUAL.
|
||||||
*
|
|
||||||
* An extreme solution for this problem would be to never let VCPUs
|
|
||||||
* sleep in icount mode if there is a pending QEMU_CLOCK_VIRTUAL
|
|
||||||
* timer; rather time could just advance to the next QEMU_CLOCK_VIRTUAL
|
|
||||||
* event. Instead, we do stop VCPUs and only advance QEMU_CLOCK_VIRTUAL
|
|
||||||
* after some "real" time, (related to the time left until the next
|
|
||||||
* event) has passed. The QEMU_CLOCK_VIRTUAL_RT clock will do this.
|
|
||||||
* This avoids that the warps are visible externally; for example,
|
|
||||||
* you will not be sending network packets continuously instead of
|
|
||||||
* every 100ms.
|
|
||||||
*/
|
*/
|
||||||
seqlock_write_lock(&timers_state.vm_clock_seqlock);
|
if (!icount_sleep) {
|
||||||
if (vm_clock_warp_start == -1 || vm_clock_warp_start > clock) {
|
/*
|
||||||
vm_clock_warp_start = clock;
|
* We never let VCPUs sleep in no sleep icount mode.
|
||||||
|
* If there is a pending QEMU_CLOCK_VIRTUAL timer we just advance
|
||||||
|
* to the next QEMU_CLOCK_VIRTUAL event and notify it.
|
||||||
|
* It is useful when we want a deterministic execution time,
|
||||||
|
* isolated from host latencies.
|
||||||
|
*/
|
||||||
|
seqlock_write_lock(&timers_state.vm_clock_seqlock);
|
||||||
|
timers_state.qemu_icount_bias += deadline;
|
||||||
|
seqlock_write_unlock(&timers_state.vm_clock_seqlock);
|
||||||
|
qemu_clock_notify(QEMU_CLOCK_VIRTUAL);
|
||||||
|
} else {
|
||||||
|
/*
|
||||||
|
* We do stop VCPUs and only advance QEMU_CLOCK_VIRTUAL after some
|
||||||
|
* "real" time, (related to the time left until the next event) has
|
||||||
|
* passed. The QEMU_CLOCK_VIRTUAL_RT clock will do this.
|
||||||
|
* This avoids that the warps are visible externally; for example,
|
||||||
|
* you will not be sending network packets continuously instead of
|
||||||
|
* every 100ms.
|
||||||
|
*/
|
||||||
|
seqlock_write_lock(&timers_state.vm_clock_seqlock);
|
||||||
|
if (vm_clock_warp_start == -1 || vm_clock_warp_start > clock) {
|
||||||
|
vm_clock_warp_start = clock;
|
||||||
|
}
|
||||||
|
seqlock_write_unlock(&timers_state.vm_clock_seqlock);
|
||||||
|
timer_mod_anticipate(icount_warp_timer, clock + deadline);
|
||||||
}
|
}
|
||||||
seqlock_write_unlock(&timers_state.vm_clock_seqlock);
|
|
||||||
timer_mod_anticipate(icount_warp_timer, clock + deadline);
|
|
||||||
} else if (deadline == 0) {
|
} else if (deadline == 0) {
|
||||||
qemu_clock_notify(QEMU_CLOCK_VIRTUAL);
|
qemu_clock_notify(QEMU_CLOCK_VIRTUAL);
|
||||||
}
|
}
|
||||||
@@ -504,9 +525,18 @@ void configure_icount(QemuOpts *opts, Error **errp)
|
|||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
icount_sleep = qemu_opt_get_bool(opts, "sleep", true);
|
||||||
|
if (icount_sleep) {
|
||||||
|
icount_warp_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL_RT,
|
||||||
|
icount_warp_rt, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
icount_align_option = qemu_opt_get_bool(opts, "align", false);
|
icount_align_option = qemu_opt_get_bool(opts, "align", false);
|
||||||
icount_warp_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL_RT,
|
|
||||||
icount_warp_rt, NULL);
|
if (icount_align_option && !icount_sleep) {
|
||||||
|
error_setg(errp, "align=on and sleep=no are incompatible");
|
||||||
|
}
|
||||||
if (strcmp(option, "auto") != 0) {
|
if (strcmp(option, "auto") != 0) {
|
||||||
errno = 0;
|
errno = 0;
|
||||||
icount_time_shift = strtol(option, &rem_str, 0);
|
icount_time_shift = strtol(option, &rem_str, 0);
|
||||||
@@ -517,6 +547,8 @@ void configure_icount(QemuOpts *opts, Error **errp)
|
|||||||
return;
|
return;
|
||||||
} else if (icount_align_option) {
|
} else if (icount_align_option) {
|
||||||
error_setg(errp, "shift=auto and align=on are incompatible");
|
error_setg(errp, "shift=auto and align=on are incompatible");
|
||||||
|
} else if (!icount_sleep) {
|
||||||
|
error_setg(errp, "shift=auto and sleep=no are incompatible");
|
||||||
}
|
}
|
||||||
|
|
||||||
use_icount = 2;
|
use_icount = 2;
|
||||||
|
|||||||
7
cputlb.c
7
cputlb.c
@@ -125,14 +125,13 @@ void tlb_flush_page(CPUState *cpu, target_ulong addr)
|
|||||||
can be detected */
|
can be detected */
|
||||||
void tlb_protect_code(ram_addr_t ram_addr)
|
void tlb_protect_code(ram_addr_t ram_addr)
|
||||||
{
|
{
|
||||||
cpu_physical_memory_reset_dirty(ram_addr, TARGET_PAGE_SIZE,
|
cpu_physical_memory_test_and_clear_dirty(ram_addr, TARGET_PAGE_SIZE,
|
||||||
DIRTY_MEMORY_CODE);
|
DIRTY_MEMORY_CODE);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* update the TLB so that writes in physical page 'phys_addr' are no longer
|
/* update the TLB so that writes in physical page 'phys_addr' are no longer
|
||||||
tested for self modifying code */
|
tested for self modifying code */
|
||||||
void tlb_unprotect_code_phys(CPUState *cpu, ram_addr_t ram_addr,
|
void tlb_unprotect_code(ram_addr_t ram_addr)
|
||||||
target_ulong vaddr)
|
|
||||||
{
|
{
|
||||||
cpu_physical_memory_set_dirty_flag(ram_addr, DIRTY_MEMORY_CODE);
|
cpu_physical_memory_set_dirty_flag(ram_addr, DIRTY_MEMORY_CODE);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -101,3 +101,4 @@ CONFIG_ALLWINNER_A10=y
|
|||||||
CONFIG_XIO3130=y
|
CONFIG_XIO3130=y
|
||||||
CONFIG_IOH3420=y
|
CONFIG_IOH3420=y
|
||||||
CONFIG_I82801B11=y
|
CONFIG_I82801B11=y
|
||||||
|
CONFIG_ACPI=y
|
||||||
|
|||||||
@@ -15,6 +15,9 @@ CONFIG_PCSPK=y
|
|||||||
CONFIG_PCKBD=y
|
CONFIG_PCKBD=y
|
||||||
CONFIG_FDC=y
|
CONFIG_FDC=y
|
||||||
CONFIG_ACPI=y
|
CONFIG_ACPI=y
|
||||||
|
CONFIG_ACPI_X86=y
|
||||||
|
CONFIG_ACPI_MEMORY_HOTPLUG=y
|
||||||
|
CONFIG_ACPI_CPU_HOTPLUG=y
|
||||||
CONFIG_APM=y
|
CONFIG_APM=y
|
||||||
CONFIG_I8257=y
|
CONFIG_I8257=y
|
||||||
CONFIG_IDE_ISA=y
|
CONFIG_IDE_ISA=y
|
||||||
|
|||||||
@@ -15,6 +15,9 @@ CONFIG_PCSPK=y
|
|||||||
CONFIG_PCKBD=y
|
CONFIG_PCKBD=y
|
||||||
CONFIG_FDC=y
|
CONFIG_FDC=y
|
||||||
CONFIG_ACPI=y
|
CONFIG_ACPI=y
|
||||||
|
CONFIG_ACPI_X86=y
|
||||||
|
CONFIG_ACPI_MEMORY_HOTPLUG=y
|
||||||
|
CONFIG_ACPI_CPU_HOTPLUG=y
|
||||||
CONFIG_APM=y
|
CONFIG_APM=y
|
||||||
CONFIG_I8257=y
|
CONFIG_I8257=y
|
||||||
CONFIG_PIIX4=y
|
CONFIG_PIIX4=y
|
||||||
|
|||||||
@@ -15,6 +15,9 @@ CONFIG_PCSPK=y
|
|||||||
CONFIG_PCKBD=y
|
CONFIG_PCKBD=y
|
||||||
CONFIG_FDC=y
|
CONFIG_FDC=y
|
||||||
CONFIG_ACPI=y
|
CONFIG_ACPI=y
|
||||||
|
CONFIG_ACPI_X86=y
|
||||||
|
CONFIG_ACPI_MEMORY_HOTPLUG=y
|
||||||
|
CONFIG_ACPI_CPU_HOTPLUG=y
|
||||||
CONFIG_APM=y
|
CONFIG_APM=y
|
||||||
CONFIG_I8257=y
|
CONFIG_I8257=y
|
||||||
CONFIG_PIIX4=y
|
CONFIG_PIIX4=y
|
||||||
|
|||||||
@@ -15,6 +15,9 @@ CONFIG_PCSPK=y
|
|||||||
CONFIG_PCKBD=y
|
CONFIG_PCKBD=y
|
||||||
CONFIG_FDC=y
|
CONFIG_FDC=y
|
||||||
CONFIG_ACPI=y
|
CONFIG_ACPI=y
|
||||||
|
CONFIG_ACPI_X86=y
|
||||||
|
CONFIG_ACPI_MEMORY_HOTPLUG=y
|
||||||
|
CONFIG_ACPI_CPU_HOTPLUG=y
|
||||||
CONFIG_APM=y
|
CONFIG_APM=y
|
||||||
CONFIG_I8257=y
|
CONFIG_I8257=y
|
||||||
CONFIG_PIIX4=y
|
CONFIG_PIIX4=y
|
||||||
|
|||||||
@@ -15,6 +15,9 @@ CONFIG_PCSPK=y
|
|||||||
CONFIG_PCKBD=y
|
CONFIG_PCKBD=y
|
||||||
CONFIG_FDC=y
|
CONFIG_FDC=y
|
||||||
CONFIG_ACPI=y
|
CONFIG_ACPI=y
|
||||||
|
CONFIG_ACPI_X86=y
|
||||||
|
CONFIG_ACPI_MEMORY_HOTPLUG=y
|
||||||
|
CONFIG_ACPI_CPU_HOTPLUG=y
|
||||||
CONFIG_APM=y
|
CONFIG_APM=y
|
||||||
CONFIG_I8257=y
|
CONFIG_I8257=y
|
||||||
CONFIG_PIIX4=y
|
CONFIG_PIIX4=y
|
||||||
|
|||||||
@@ -15,6 +15,9 @@ CONFIG_PCSPK=y
|
|||||||
CONFIG_PCKBD=y
|
CONFIG_PCKBD=y
|
||||||
CONFIG_FDC=y
|
CONFIG_FDC=y
|
||||||
CONFIG_ACPI=y
|
CONFIG_ACPI=y
|
||||||
|
CONFIG_ACPI_X86=y
|
||||||
|
CONFIG_ACPI_MEMORY_HOTPLUG=y
|
||||||
|
CONFIG_ACPI_CPU_HOTPLUG=y
|
||||||
CONFIG_APM=y
|
CONFIG_APM=y
|
||||||
CONFIG_I8257=y
|
CONFIG_I8257=y
|
||||||
CONFIG_IDE_ISA=y
|
CONFIG_IDE_ISA=y
|
||||||
|
|||||||
@@ -18,7 +18,6 @@
|
|||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
|
||||||
#include "config.h"
|
|
||||||
#include "qemu-common.h"
|
#include "qemu-common.h"
|
||||||
#include "qemu/error-report.h"
|
#include "qemu/error-report.h"
|
||||||
#include "sysemu/device_tree.h"
|
#include "sysemu/device_tree.h"
|
||||||
|
|||||||
58
docs/pci_expander_bridge.txt
Normal file
58
docs/pci_expander_bridge.txt
Normal file
@@ -0,0 +1,58 @@
|
|||||||
|
PCI EXPANDER BRIDGE (PXB)
|
||||||
|
=========================
|
||||||
|
|
||||||
|
Description
|
||||||
|
===========
|
||||||
|
PXB is a "light-weight" host bridge in the same PCI domain
|
||||||
|
as the main host bridge whose purpose is to enable
|
||||||
|
the main host bridge to support multiple PCI root buses.
|
||||||
|
It is implemented only for i440fx and can be placed only
|
||||||
|
on bus 0 (pci.0).
|
||||||
|
|
||||||
|
As opposed to PCI-2-PCI bridge's secondary bus, PXB's bus
|
||||||
|
is a primary bus and can be associated with a NUMA node
|
||||||
|
(different from the main host bridge) allowing the guest OS
|
||||||
|
to recognize the proximity of a pass-through device to
|
||||||
|
other resources as RAM and CPUs.
|
||||||
|
|
||||||
|
Usage
|
||||||
|
=====
|
||||||
|
A detailed command line would be:
|
||||||
|
|
||||||
|
[qemu-bin + storage options]
|
||||||
|
-m 2G
|
||||||
|
-object memory-backend-ram,size=1024M,policy=bind,host-nodes=0,id=ram-node0 -numa node,nodeid=0,cpus=0,memdev=ram-node0
|
||||||
|
-object memory-backend-ram,size=1024M,policy=bind,host-nodes=1,id=ram-node1 -numa node,nodeid=1,cpus=1,memdev=ram-node1
|
||||||
|
-device pxb,id=bridge1,bus=pci.0,numa_node=1,bus_nr=4 -netdev user,id=nd-device e1000,bus=bridge1,addr=0x4,netdev=nd
|
||||||
|
-device pxb,id=bridge2,bus=pci.0,numa_node=0,bus_nr=8,bus=pci.0 -device e1000,bus=bridge2,addr=0x3
|
||||||
|
-device pxb,id=bridge3,bus=pci.0,bus_nr=40,bus=pci.0 -drive if=none,id=drive0,file=[img] -device virtio-blk-pci,drive=drive0,scsi=off,bus=bridge3,addr=1
|
||||||
|
|
||||||
|
Here you have:
|
||||||
|
- 2 NUMA nodes for the guest, 0 and 1. (both mapped to the same NUMA node in host, but you can and should put it in different host NUMA nodes)
|
||||||
|
- a pxb host bridge attached to NUMA 1 with an e1000 behind it
|
||||||
|
- a pxb host bridge attached to NUMA 0 with an e1000 behind it
|
||||||
|
- a pxb host bridge not attached to any NUMA with a hard drive behind it.
|
||||||
|
|
||||||
|
Limitations
|
||||||
|
===========
|
||||||
|
Please observe that we specified the bus "pci.0" for the second and third pxb.
|
||||||
|
This is because when no bus is given, another pxb can be selected by QEMU as default bus,
|
||||||
|
however, PXBs can be placed only under the root bus.
|
||||||
|
|
||||||
|
Implementation
|
||||||
|
==============
|
||||||
|
The PXB is composed by:
|
||||||
|
- HostBridge (TYPE_PXB_HOST)
|
||||||
|
The host bridge allows to register and query the PXB's rPCI root bus in QEMU.
|
||||||
|
- PXBDev(TYPE_PXB_DEVICE)
|
||||||
|
It is a regular PCI Device that resides on the piix host-bridge bus and its bus uses the same PCI domain.
|
||||||
|
However, the bus behind is exposed through ACPI as a primary PCI bus and starts a new PCI hierarchy.
|
||||||
|
The interrupts from devices behind the PXB are routed through this device the same as if it were a
|
||||||
|
PCI-2-PCI bridge. The _PRT follows the i440fx model.
|
||||||
|
- PCIBridgeDev(TYPE_PCI_BRIDGE_DEV)
|
||||||
|
Created automatically as part of init sequence.
|
||||||
|
When adding a device to PXB it is attached to the bridge for two reasons:
|
||||||
|
- Using the bridge will enable hotplug support
|
||||||
|
- All the devices behind the bridge will use bridge's IO/MEM windows compacting
|
||||||
|
the PCI address space.
|
||||||
|
|
||||||
287
docs/specs/ppc-spapr-hotplug.txt
Normal file
287
docs/specs/ppc-spapr-hotplug.txt
Normal file
@@ -0,0 +1,287 @@
|
|||||||
|
= sPAPR Dynamic Reconfiguration =
|
||||||
|
|
||||||
|
sPAPR/"pseries" guests make use of a facility called dynamic-reconfiguration
|
||||||
|
to handle hotplugging of dynamic "physical" resources like PCI cards, or
|
||||||
|
"logical"/paravirtual resources like memory, CPUs, and "physical"
|
||||||
|
host-bridges, which are generally managed by the host/hypervisor and provided
|
||||||
|
to guests as virtualized resources. The specifics of dynamic-reconfiguration
|
||||||
|
are documented extensively in PAPR+ v2.7, Section 13.1. This document
|
||||||
|
provides a summary of that information as it applies to the implementation
|
||||||
|
within QEMU.
|
||||||
|
|
||||||
|
== Dynamic-reconfiguration Connectors ==
|
||||||
|
|
||||||
|
To manage hotplug/unplug of these resources, a firmware abstraction known as
|
||||||
|
a Dynamic Resource Connector (DRC) is used to assign a particular dynamic
|
||||||
|
resource to the guest, and provide an interface for the guest to manage
|
||||||
|
configuration/removal of the resource associated with it.
|
||||||
|
|
||||||
|
== Device-tree description of DRCs ==
|
||||||
|
|
||||||
|
A set of 4 Open Firmware device tree array properties are used to describe
|
||||||
|
the name/index/power-domain/type of each DRC allocated to a guest at
|
||||||
|
boot-time. There may be multiple sets of these arrays, rooted at different
|
||||||
|
paths in the device tree depending on the type of resource the DRCs manage.
|
||||||
|
|
||||||
|
In some cases, the DRCs themselves may be provided by a dynamic resource,
|
||||||
|
such as the DRCs managing PCI slots on a hotplugged PHB. In this case the
|
||||||
|
arrays would be fetched as part of the device tree retrieval interfaces
|
||||||
|
for hotplugged resources described under "Guest->Host interface".
|
||||||
|
|
||||||
|
The array properties are described below. Each entry/element in an array
|
||||||
|
describes the DRC identified by the element in the corresponding position
|
||||||
|
of ibm,drc-indexes:
|
||||||
|
|
||||||
|
ibm,drc-names:
|
||||||
|
first 4-bytes: BE-encoded integer denoting the number of entries
|
||||||
|
each entry: a NULL-terminated <name> string encoded as a byte array
|
||||||
|
|
||||||
|
<name> values for logical/virtual resources are defined in PAPR+ v2.7,
|
||||||
|
Section 13.5.2.4, and basically consist of the type of the resource
|
||||||
|
followed by a space and a numerical value that's unique across resources
|
||||||
|
of that type.
|
||||||
|
|
||||||
|
<name> values for "physical" resources such as PCI or VIO devices are
|
||||||
|
defined as being "location codes", which are the "location labels" of
|
||||||
|
each encapsulating device, starting from the chassis down to the
|
||||||
|
individual slot for the device, concatenated by a hyphen. This provides
|
||||||
|
a mapping of resources to a physical location in a chassis for debugging
|
||||||
|
purposes. For QEMU, this mapping is less important, so we assign a
|
||||||
|
location code that conforms to naming specifications, but is simply a
|
||||||
|
location label for the slot by itself to simplify the implementation.
|
||||||
|
The naming convention for location labels is documented in detail in
|
||||||
|
PAPR+ v2.7, Section 12.3.1.5, and in our case amounts to using "C<n>"
|
||||||
|
for PCI/VIO device slots, where <n> is unique across all PCI/VIO
|
||||||
|
device slots.
|
||||||
|
|
||||||
|
ibm,drc-indexes:
|
||||||
|
first 4-bytes: BE-encoded integer denoting the number of entries
|
||||||
|
each 4-byte entry: BE-encoded <index> integer that is unique across all DRCs
|
||||||
|
in the machine
|
||||||
|
|
||||||
|
<index> is arbitrary, but in the case of QEMU we try to maintain the
|
||||||
|
convention used to assign them to pSeries guests on pHyp:
|
||||||
|
|
||||||
|
bit[31:28]: integer encoding of <type>, where <type> is:
|
||||||
|
1 for CPU resource
|
||||||
|
2 for PHB resource
|
||||||
|
3 for VIO resource
|
||||||
|
4 for PCI resource
|
||||||
|
8 for Memory resource
|
||||||
|
bit[27:0]: integer encoding of <id>, where <id> is unique across
|
||||||
|
all resources of specified type
|
||||||
|
|
||||||
|
ibm,drc-power-domains:
|
||||||
|
first 4-bytes: BE-encoded integer denoting the number of entries
|
||||||
|
each 4-byte entry: 32-bit, BE-encoded <index> integer that specifies the
|
||||||
|
power domain the resource will be assigned to. In the case of QEMU
|
||||||
|
we associated all resources with a "live insertion" domain, where the
|
||||||
|
power is assumed to be managed automatically. The integer value for
|
||||||
|
this domain is a special value of -1.
|
||||||
|
|
||||||
|
|
||||||
|
ibm,drc-types:
|
||||||
|
first 4-bytes: BE-encoded integer denoting the number of entries
|
||||||
|
each entry: a NULL-terminated <type> string encoded as a byte array
|
||||||
|
|
||||||
|
<type> is assigned as follows:
|
||||||
|
"CPU" for a CPU
|
||||||
|
"PHB" for a physical host-bridge
|
||||||
|
"SLOT" for a VIO slot
|
||||||
|
"28" for a PCI slot
|
||||||
|
"MEM" for memory resource
|
||||||
|
|
||||||
|
== Guest->Host interface to manage dynamic resources ==
|
||||||
|
|
||||||
|
Each DRC is given a globally unique DRC Index, and resources associated with
|
||||||
|
a particular DRC are configured/managed by the guest via a number of RTAS
|
||||||
|
calls which reference individual DRCs based on the DRC index. This can be
|
||||||
|
considered the guest->host interface.
|
||||||
|
|
||||||
|
rtas-set-power-level:
|
||||||
|
arg[0]: integer identifying power domain
|
||||||
|
arg[1]: new power level for the domain, 0-100
|
||||||
|
output[0]: status, 0 on success
|
||||||
|
output[1]: power level after command
|
||||||
|
|
||||||
|
Set the power level for a specified power domain
|
||||||
|
|
||||||
|
rtas-get-power-level:
|
||||||
|
arg[0]: integer identifying power domain
|
||||||
|
output[0]: status, 0 on success
|
||||||
|
output[1]: current power level
|
||||||
|
|
||||||
|
Get the power level for a specified power domain
|
||||||
|
|
||||||
|
rtas-set-indicator:
|
||||||
|
arg[0]: integer identifying sensor/indicator type
|
||||||
|
arg[1]: index of sensor, for DR-related sensors this is generally the
|
||||||
|
DRC index
|
||||||
|
arg[2]: desired sensor value
|
||||||
|
output[0]: status, 0 on success
|
||||||
|
|
||||||
|
Set the state of an indicator or sensor. For the purpose of this document we
|
||||||
|
focus on the indicator/sensor types associated with a DRC. The types are:
|
||||||
|
|
||||||
|
9001: isolation-state, controls/indicates whether a device has been made
|
||||||
|
accessible to a guest
|
||||||
|
|
||||||
|
supported sensor values:
|
||||||
|
0: isolate, device is made unaccessible by guest OS
|
||||||
|
1: unisolate, device is made available to guest OS
|
||||||
|
|
||||||
|
9002: dr-indicator, controls "visual" indicator associated with device
|
||||||
|
|
||||||
|
supported sensor values:
|
||||||
|
0: inactive, resource may be safely removed
|
||||||
|
1: active, resource is in use and cannot be safely removed
|
||||||
|
2: identify, used to visually identify slot for interactive hotplug
|
||||||
|
3: action, in most cases, used in the same manner as identify
|
||||||
|
|
||||||
|
9003: allocation-state, generally only used for "logical" DR resources to
|
||||||
|
request the allocation/deallocation of a resource prior to acquiring
|
||||||
|
it via isolation-state->unisolate, or after releasing it via
|
||||||
|
isolation-state->isolate, respectively. for "physical" DR (like PCI
|
||||||
|
hotplug/unplug) the pre-allocation of the resource is implied and
|
||||||
|
this sensor is unused.
|
||||||
|
|
||||||
|
supported sensor values:
|
||||||
|
0: unusable, tell firmware/system the resource can be
|
||||||
|
unallocated/reclaimed and added back to the system resource pool
|
||||||
|
1: usable, request the resource be allocated/reserved for use by
|
||||||
|
guest OS
|
||||||
|
2: exchange, used to allocate a spare resource to use for fail-over
|
||||||
|
in certain situations. unused in QEMU
|
||||||
|
3: recover, used to reclaim a previously allocated resource that's
|
||||||
|
not currently allocated to the guest OS. unused in QEMU
|
||||||
|
|
||||||
|
rtas-get-sensor-state:
|
||||||
|
arg[0]: integer identifying sensor/indicator type
|
||||||
|
arg[1]: index of sensor, for DR-related sensors this is generally the
|
||||||
|
DRC index
|
||||||
|
output[0]: status, 0 on success
|
||||||
|
|
||||||
|
Used to read an indicator or sensor value.
|
||||||
|
|
||||||
|
For DR-related operations, the only noteworthy sensor is dr-entity-sense,
|
||||||
|
which has a type value of 9003, as allocation-state does in the case of
|
||||||
|
rtas-set-indicator. The semantics/encodings of the sensor values are distinct
|
||||||
|
however:
|
||||||
|
|
||||||
|
supported sensor values for dr-entity-sense (9003) sensor:
|
||||||
|
0: empty,
|
||||||
|
for physical resources: DRC/slot is empty
|
||||||
|
for logical resources: unused
|
||||||
|
1: present,
|
||||||
|
for physical resources: DRC/slot is populated with a device/resource
|
||||||
|
for logical resources: resource has been allocated to the DRC
|
||||||
|
2: unusable,
|
||||||
|
for physical resources: unused
|
||||||
|
for logical resources: DRC has no resource allocated to it
|
||||||
|
3: exchange,
|
||||||
|
for physical resources: unused
|
||||||
|
for logical resources: resource available for exchange (see
|
||||||
|
allocation-state sensor semantics above)
|
||||||
|
4: recovery,
|
||||||
|
for physical resources: unused
|
||||||
|
for logical resources: resource available for recovery (see
|
||||||
|
allocation-state sensor semantics above)
|
||||||
|
|
||||||
|
rtas-ibm-configure-connector:
|
||||||
|
arg[0]: guest physical address of 4096-byte work area buffer
|
||||||
|
arg[1]: 0, or address of additional 4096-byte work area buffer. only non-zero
|
||||||
|
if a prior RTAS response indicated a need for additional memory
|
||||||
|
output[0]: status:
|
||||||
|
0: completed transmittal of device-tree node
|
||||||
|
1: instruct guest to prepare for next DT sibling node
|
||||||
|
2: instruct guest to prepare for next DT child node
|
||||||
|
3: instruct guest to prepare for next DT property
|
||||||
|
4: instruct guest to ascend to parent DT node
|
||||||
|
5: instruct guest to provide additional work-area buffer
|
||||||
|
via arg[1]
|
||||||
|
990x: instruct guest that operation took too long and to try
|
||||||
|
again later
|
||||||
|
|
||||||
|
Used to fetch an OF device-tree description of the resource associated with
|
||||||
|
a particular DRC. The DRC index is encoded in the first 4-bytes of the first
|
||||||
|
work area buffer.
|
||||||
|
|
||||||
|
Work area layout, using 4-byte offsets:
|
||||||
|
wa[0]: DRC index of the DRC to fetch device-tree nodes from
|
||||||
|
wa[1]: 0 (hard-coded)
|
||||||
|
wa[2]: for next-sibling/next-child response:
|
||||||
|
wa offset of null-terminated string denoting the new node's name
|
||||||
|
for next-property response:
|
||||||
|
wa offset of null-terminated string denoting new property's name
|
||||||
|
wa[3]: for next-property response (unused otherwise):
|
||||||
|
byte-length of new property's value
|
||||||
|
wa[4]: for next-property response (unused otherwise):
|
||||||
|
new property's value, encoded as an OFDT-compatible byte array
|
||||||
|
|
||||||
|
== hotplug/unplug events ==
|
||||||
|
|
||||||
|
For most DR operations, the hypervisor will issue host->guest add/remove events
|
||||||
|
using the EPOW/check-exception notification framework, where the host issues a
|
||||||
|
check-exception interrupt, then provides an RTAS event log via an
|
||||||
|
rtas-check-exception call issued by the guest in response. This framework is
|
||||||
|
documented by PAPR+ v2.7, and already use in by QEMU for generating powerdown
|
||||||
|
requests via EPOW events.
|
||||||
|
|
||||||
|
For DR, this framework has been extended to include hotplug events, which were
|
||||||
|
previously unneeded due to direct manipulation of DR-related guest userspace
|
||||||
|
tools by host-level management such as an HMC. This level of management is not
|
||||||
|
applicable to PowerKVM, hence the reason for extending the notification
|
||||||
|
framework to support hotplug events.
|
||||||
|
|
||||||
|
Note that these events are not yet formally part of the PAPR+ specification,
|
||||||
|
but support for this format has already been implemented in DR-related
|
||||||
|
guest tools such as powerpc-utils/librtas, as well as kernel patches that have
|
||||||
|
been submitted to handle in-kernel processing of memory/cpu-related hotplug
|
||||||
|
events[1], and is planned for formal inclusion is PAPR+ specification. The
|
||||||
|
hotplug-specific payload is QEMU implemented as follows (with all values
|
||||||
|
encoded in big-endian format):
|
||||||
|
|
||||||
|
struct rtas_event_log_v6_hp {
|
||||||
|
#define SECTION_ID_HOTPLUG 0x4850 /* HP */
|
||||||
|
struct section_header {
|
||||||
|
uint16_t section_id; /* set to SECTION_ID_HOTPLUG */
|
||||||
|
uint16_t section_length; /* sizeof(rtas_event_log_v6_hp),
|
||||||
|
* plus the length of the DRC name
|
||||||
|
* if a DRC name identifier is
|
||||||
|
* specified for hotplug_identifier
|
||||||
|
*/
|
||||||
|
uint8_t section_version; /* version 1 */
|
||||||
|
uint8_t section_subtype; /* unused */
|
||||||
|
uint16_t creator_component_id; /* unused */
|
||||||
|
} hdr;
|
||||||
|
#define RTAS_LOG_V6_HP_TYPE_CPU 1
|
||||||
|
#define RTAS_LOG_V6_HP_TYPE_MEMORY 2
|
||||||
|
#define RTAS_LOG_V6_HP_TYPE_SLOT 3
|
||||||
|
#define RTAS_LOG_V6_HP_TYPE_PHB 4
|
||||||
|
#define RTAS_LOG_V6_HP_TYPE_PCI 5
|
||||||
|
uint8_t hotplug_type; /* type of resource/device */
|
||||||
|
#define RTAS_LOG_V6_HP_ACTION_ADD 1
|
||||||
|
#define RTAS_LOG_V6_HP_ACTION_REMOVE 2
|
||||||
|
uint8_t hotplug_action; /* action (add/remove) */
|
||||||
|
#define RTAS_LOG_V6_HP_ID_DRC_NAME 1
|
||||||
|
#define RTAS_LOG_V6_HP_ID_DRC_INDEX 2
|
||||||
|
#define RTAS_LOG_V6_HP_ID_DRC_COUNT 3
|
||||||
|
uint8_t hotplug_identifier; /* type of the resource identifier,
|
||||||
|
* which serves as the discriminator
|
||||||
|
* for the 'drc' union field below
|
||||||
|
*/
|
||||||
|
uint8_t reserved;
|
||||||
|
union {
|
||||||
|
uint32_t index; /* DRC index of resource to take action
|
||||||
|
* on
|
||||||
|
*/
|
||||||
|
uint32_t count; /* number of DR resources to take
|
||||||
|
* action on (guest chooses which)
|
||||||
|
*/
|
||||||
|
char name[1]; /* string representing the name of the
|
||||||
|
* DRC to take action on
|
||||||
|
*/
|
||||||
|
} drc;
|
||||||
|
} QEMU_PACKED;
|
||||||
|
|
||||||
|
[1] http://thread.gmane.org/gmane.linux.ports.ppc.embedded/75350/focus=106867
|
||||||
@@ -127,6 +127,11 @@ in the ancillary data:
|
|||||||
If Master is unable to send the full message or receives a wrong reply it will
|
If Master is unable to send the full message or receives a wrong reply it will
|
||||||
close the connection. An optional reconnection mechanism can be implemented.
|
close the connection. An optional reconnection mechanism can be implemented.
|
||||||
|
|
||||||
|
Multi queue support
|
||||||
|
-------------------
|
||||||
|
The protocol supports multiple queues by setting all index fields in the sent
|
||||||
|
messages to a properly calculated value.
|
||||||
|
|
||||||
Message types
|
Message types
|
||||||
-------------
|
-------------
|
||||||
|
|
||||||
|
|||||||
@@ -598,7 +598,7 @@ stored in its "value" member. In our example, the "value" member is a pointer
|
|||||||
to an TimerAlarmMethod instance.
|
to an TimerAlarmMethod instance.
|
||||||
|
|
||||||
Notice that the "current" variable is used as "true" only in the first
|
Notice that the "current" variable is used as "true" only in the first
|
||||||
interation of the loop. That's because the alarm timer method in use is the
|
iteration of the loop. That's because the alarm timer method in use is the
|
||||||
first element of the alarm_timers array. Also notice that QAPI lists are handled
|
first element of the alarm_timers array. Also notice that QAPI lists are handled
|
||||||
by hand and we return the head of the list.
|
by hand and we return the head of the list.
|
||||||
|
|
||||||
|
|||||||
2
dtc
2
dtc
Submodule dtc updated: bc895d6d09...65cc4d2748
123
exec.c
123
exec.c
@@ -59,8 +59,6 @@
|
|||||||
//#define DEBUG_SUBPAGE
|
//#define DEBUG_SUBPAGE
|
||||||
|
|
||||||
#if !defined(CONFIG_USER_ONLY)
|
#if !defined(CONFIG_USER_ONLY)
|
||||||
static bool in_migration;
|
|
||||||
|
|
||||||
/* ram_list is read under rcu_read_lock()/rcu_read_unlock(). Writes
|
/* ram_list is read under rcu_read_lock()/rcu_read_unlock(). Writes
|
||||||
* are protected by the ramlist lock.
|
* are protected by the ramlist lock.
|
||||||
*/
|
*/
|
||||||
@@ -173,17 +171,22 @@ static void phys_map_node_reserve(PhysPageMap *map, unsigned nodes)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static uint32_t phys_map_node_alloc(PhysPageMap *map)
|
static uint32_t phys_map_node_alloc(PhysPageMap *map, bool leaf)
|
||||||
{
|
{
|
||||||
unsigned i;
|
unsigned i;
|
||||||
uint32_t ret;
|
uint32_t ret;
|
||||||
|
PhysPageEntry e;
|
||||||
|
PhysPageEntry *p;
|
||||||
|
|
||||||
ret = map->nodes_nb++;
|
ret = map->nodes_nb++;
|
||||||
|
p = map->nodes[ret];
|
||||||
assert(ret != PHYS_MAP_NODE_NIL);
|
assert(ret != PHYS_MAP_NODE_NIL);
|
||||||
assert(ret != map->nodes_nb_alloc);
|
assert(ret != map->nodes_nb_alloc);
|
||||||
|
|
||||||
|
e.skip = leaf ? 0 : 1;
|
||||||
|
e.ptr = leaf ? PHYS_SECTION_UNASSIGNED : PHYS_MAP_NODE_NIL;
|
||||||
for (i = 0; i < P_L2_SIZE; ++i) {
|
for (i = 0; i < P_L2_SIZE; ++i) {
|
||||||
map->nodes[ret][i].skip = 1;
|
memcpy(&p[i], &e, sizeof(e));
|
||||||
map->nodes[ret][i].ptr = PHYS_MAP_NODE_NIL;
|
|
||||||
}
|
}
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
@@ -193,21 +196,12 @@ static void phys_page_set_level(PhysPageMap *map, PhysPageEntry *lp,
|
|||||||
int level)
|
int level)
|
||||||
{
|
{
|
||||||
PhysPageEntry *p;
|
PhysPageEntry *p;
|
||||||
int i;
|
|
||||||
hwaddr step = (hwaddr)1 << (level * P_L2_BITS);
|
hwaddr step = (hwaddr)1 << (level * P_L2_BITS);
|
||||||
|
|
||||||
if (lp->skip && lp->ptr == PHYS_MAP_NODE_NIL) {
|
if (lp->skip && lp->ptr == PHYS_MAP_NODE_NIL) {
|
||||||
lp->ptr = phys_map_node_alloc(map);
|
lp->ptr = phys_map_node_alloc(map, level == 0);
|
||||||
p = map->nodes[lp->ptr];
|
|
||||||
if (level == 0) {
|
|
||||||
for (i = 0; i < P_L2_SIZE; i++) {
|
|
||||||
p[i].skip = 0;
|
|
||||||
p[i].ptr = PHYS_SECTION_UNASSIGNED;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
p = map->nodes[lp->ptr];
|
|
||||||
}
|
}
|
||||||
|
p = map->nodes[lp->ptr];
|
||||||
lp = &p[(*index >> (level * P_L2_BITS)) & (P_L2_SIZE - 1)];
|
lp = &p[(*index >> (level * P_L2_BITS)) & (P_L2_SIZE - 1)];
|
||||||
|
|
||||||
while (*nb && lp < &p[P_L2_SIZE]) {
|
while (*nb && lp < &p[P_L2_SIZE]) {
|
||||||
@@ -858,21 +852,27 @@ static void tlb_reset_dirty_range_all(ram_addr_t start, ram_addr_t length)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Note: start and end must be within the same ram block. */
|
/* Note: start and end must be within the same ram block. */
|
||||||
void cpu_physical_memory_reset_dirty(ram_addr_t start, ram_addr_t length,
|
bool cpu_physical_memory_test_and_clear_dirty(ram_addr_t start,
|
||||||
unsigned client)
|
ram_addr_t length,
|
||||||
|
unsigned client)
|
||||||
{
|
{
|
||||||
if (length == 0)
|
unsigned long end, page;
|
||||||
return;
|
bool dirty;
|
||||||
cpu_physical_memory_clear_dirty_range_type(start, length, client);
|
|
||||||
|
|
||||||
if (tcg_enabled()) {
|
if (length == 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
end = TARGET_PAGE_ALIGN(start + length) >> TARGET_PAGE_BITS;
|
||||||
|
page = start >> TARGET_PAGE_BITS;
|
||||||
|
dirty = bitmap_test_and_clear_atomic(ram_list.dirty_memory[client],
|
||||||
|
page, end - page);
|
||||||
|
|
||||||
|
if (dirty && tcg_enabled()) {
|
||||||
tlb_reset_dirty_range_all(start, length);
|
tlb_reset_dirty_range_all(start, length);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
static void cpu_physical_memory_set_dirty_tracking(bool enable)
|
return dirty;
|
||||||
{
|
|
||||||
in_migration = enable;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Called from RCU critical section */
|
/* Called from RCU critical section */
|
||||||
@@ -1362,7 +1362,8 @@ int qemu_ram_resize(ram_addr_t base, ram_addr_t newsize, Error **errp)
|
|||||||
|
|
||||||
cpu_physical_memory_clear_dirty_range(block->offset, block->used_length);
|
cpu_physical_memory_clear_dirty_range(block->offset, block->used_length);
|
||||||
block->used_length = newsize;
|
block->used_length = newsize;
|
||||||
cpu_physical_memory_set_dirty_range(block->offset, block->used_length);
|
cpu_physical_memory_set_dirty_range(block->offset, block->used_length,
|
||||||
|
DIRTY_CLIENTS_ALL);
|
||||||
memory_region_set_size(block->mr, newsize);
|
memory_region_set_size(block->mr, newsize);
|
||||||
if (block->resized) {
|
if (block->resized) {
|
||||||
block->resized(block->idstr, newsize, block->host);
|
block->resized(block->idstr, newsize, block->host);
|
||||||
@@ -1436,7 +1437,8 @@ static ram_addr_t ram_block_add(RAMBlock *new_block, Error **errp)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
cpu_physical_memory_set_dirty_range(new_block->offset,
|
cpu_physical_memory_set_dirty_range(new_block->offset,
|
||||||
new_block->used_length);
|
new_block->used_length,
|
||||||
|
DIRTY_CLIENTS_ALL);
|
||||||
|
|
||||||
if (new_block->host) {
|
if (new_block->host) {
|
||||||
qemu_ram_setup_dump(new_block->host, new_block->max_length);
|
qemu_ram_setup_dump(new_block->host, new_block->max_length);
|
||||||
@@ -1824,7 +1826,11 @@ static void notdirty_mem_write(void *opaque, hwaddr ram_addr,
|
|||||||
default:
|
default:
|
||||||
abort();
|
abort();
|
||||||
}
|
}
|
||||||
cpu_physical_memory_set_dirty_range_nocode(ram_addr, size);
|
/* Set both VGA and migration bits for simplicity and to remove
|
||||||
|
* the notdirty callback faster.
|
||||||
|
*/
|
||||||
|
cpu_physical_memory_set_dirty_range(ram_addr, size,
|
||||||
|
DIRTY_CLIENTS_NOCODE);
|
||||||
/* we remove the notdirty callback only if the code has been
|
/* we remove the notdirty callback only if the code has been
|
||||||
flushed */
|
flushed */
|
||||||
if (!cpu_physical_memory_is_clean(ram_addr)) {
|
if (!cpu_physical_memory_is_clean(ram_addr)) {
|
||||||
@@ -2165,22 +2171,6 @@ static void tcg_commit(MemoryListener *listener)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void core_log_global_start(MemoryListener *listener)
|
|
||||||
{
|
|
||||||
cpu_physical_memory_set_dirty_tracking(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void core_log_global_stop(MemoryListener *listener)
|
|
||||||
{
|
|
||||||
cpu_physical_memory_set_dirty_tracking(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
static MemoryListener core_memory_listener = {
|
|
||||||
.log_global_start = core_log_global_start,
|
|
||||||
.log_global_stop = core_log_global_stop,
|
|
||||||
.priority = 1,
|
|
||||||
};
|
|
||||||
|
|
||||||
void address_space_init_dispatch(AddressSpace *as)
|
void address_space_init_dispatch(AddressSpace *as)
|
||||||
{
|
{
|
||||||
as->dispatch = NULL;
|
as->dispatch = NULL;
|
||||||
@@ -2220,8 +2210,6 @@ static void memory_map_init(void)
|
|||||||
memory_region_init_io(system_io, NULL, &unassigned_io_ops, NULL, "io",
|
memory_region_init_io(system_io, NULL, &unassigned_io_ops, NULL, "io",
|
||||||
65536);
|
65536);
|
||||||
address_space_init(&address_space_io, system_io, "I/O");
|
address_space_init(&address_space_io, system_io, "I/O");
|
||||||
|
|
||||||
memory_listener_register(&core_memory_listener, &address_space_memory);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
MemoryRegion *get_system_memory(void)
|
MemoryRegion *get_system_memory(void)
|
||||||
@@ -2279,14 +2267,23 @@ int cpu_memory_rw_debug(CPUState *cpu, target_ulong addr,
|
|||||||
|
|
||||||
#else
|
#else
|
||||||
|
|
||||||
static void invalidate_and_set_dirty(hwaddr addr,
|
static void invalidate_and_set_dirty(MemoryRegion *mr, hwaddr addr,
|
||||||
hwaddr length)
|
hwaddr length)
|
||||||
{
|
{
|
||||||
if (cpu_physical_memory_range_includes_clean(addr, length)) {
|
uint8_t dirty_log_mask = memory_region_get_dirty_log_mask(mr);
|
||||||
tb_invalidate_phys_range(addr, addr + length, 0);
|
/* No early return if dirty_log_mask is or becomes 0, because
|
||||||
cpu_physical_memory_set_dirty_range_nocode(addr, length);
|
* cpu_physical_memory_set_dirty_range will still call
|
||||||
|
* xen_modified_memory.
|
||||||
|
*/
|
||||||
|
if (dirty_log_mask) {
|
||||||
|
dirty_log_mask =
|
||||||
|
cpu_physical_memory_range_includes_clean(addr, length, dirty_log_mask);
|
||||||
}
|
}
|
||||||
xen_modified_memory(addr, length);
|
if (dirty_log_mask & (1 << DIRTY_MEMORY_CODE)) {
|
||||||
|
tb_invalidate_phys_range(addr, addr + length);
|
||||||
|
dirty_log_mask &= ~(1 << DIRTY_MEMORY_CODE);
|
||||||
|
}
|
||||||
|
cpu_physical_memory_set_dirty_range(addr, length, dirty_log_mask);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int memory_access_size(MemoryRegion *mr, unsigned l, hwaddr addr)
|
static int memory_access_size(MemoryRegion *mr, unsigned l, hwaddr addr)
|
||||||
@@ -2371,7 +2368,7 @@ MemTxResult address_space_rw(AddressSpace *as, hwaddr addr, MemTxAttrs attrs,
|
|||||||
/* RAM case */
|
/* RAM case */
|
||||||
ptr = qemu_get_ram_ptr(addr1);
|
ptr = qemu_get_ram_ptr(addr1);
|
||||||
memcpy(ptr, buf, l);
|
memcpy(ptr, buf, l);
|
||||||
invalidate_and_set_dirty(addr1, l);
|
invalidate_and_set_dirty(mr, addr1, l);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (!memory_access_is_direct(mr, is_write)) {
|
if (!memory_access_is_direct(mr, is_write)) {
|
||||||
@@ -2468,7 +2465,7 @@ static inline void cpu_physical_memory_write_rom_internal(AddressSpace *as,
|
|||||||
switch (type) {
|
switch (type) {
|
||||||
case WRITE_DATA:
|
case WRITE_DATA:
|
||||||
memcpy(ptr, buf, l);
|
memcpy(ptr, buf, l);
|
||||||
invalidate_and_set_dirty(addr1, l);
|
invalidate_and_set_dirty(mr, addr1, l);
|
||||||
break;
|
break;
|
||||||
case FLUSH_CACHE:
|
case FLUSH_CACHE:
|
||||||
flush_icache_range((uintptr_t)ptr, (uintptr_t)ptr + l);
|
flush_icache_range((uintptr_t)ptr, (uintptr_t)ptr + l);
|
||||||
@@ -2693,7 +2690,7 @@ void address_space_unmap(AddressSpace *as, void *buffer, hwaddr len,
|
|||||||
mr = qemu_ram_addr_from_host(buffer, &addr1);
|
mr = qemu_ram_addr_from_host(buffer, &addr1);
|
||||||
assert(mr != NULL);
|
assert(mr != NULL);
|
||||||
if (is_write) {
|
if (is_write) {
|
||||||
invalidate_and_set_dirty(addr1, access_len);
|
invalidate_and_set_dirty(mr, addr1, access_len);
|
||||||
}
|
}
|
||||||
if (xen_enabled()) {
|
if (xen_enabled()) {
|
||||||
xen_invalidate_map_cache_entry(buffer);
|
xen_invalidate_map_cache_entry(buffer);
|
||||||
@@ -3022,6 +3019,7 @@ void address_space_stl_notdirty(AddressSpace *as, hwaddr addr, uint32_t val,
|
|||||||
hwaddr l = 4;
|
hwaddr l = 4;
|
||||||
hwaddr addr1;
|
hwaddr addr1;
|
||||||
MemTxResult r;
|
MemTxResult r;
|
||||||
|
uint8_t dirty_log_mask;
|
||||||
|
|
||||||
rcu_read_lock();
|
rcu_read_lock();
|
||||||
mr = address_space_translate(as, addr, &addr1, &l,
|
mr = address_space_translate(as, addr, &addr1, &l,
|
||||||
@@ -3033,14 +3031,9 @@ void address_space_stl_notdirty(AddressSpace *as, hwaddr addr, uint32_t val,
|
|||||||
ptr = qemu_get_ram_ptr(addr1);
|
ptr = qemu_get_ram_ptr(addr1);
|
||||||
stl_p(ptr, val);
|
stl_p(ptr, val);
|
||||||
|
|
||||||
if (unlikely(in_migration)) {
|
dirty_log_mask = memory_region_get_dirty_log_mask(mr);
|
||||||
if (cpu_physical_memory_is_clean(addr1)) {
|
dirty_log_mask &= ~(1 << DIRTY_MEMORY_CODE);
|
||||||
/* invalidate code */
|
cpu_physical_memory_set_dirty_range(addr1, 4, dirty_log_mask);
|
||||||
tb_invalidate_phys_page_range(addr1, addr1 + 4, 0);
|
|
||||||
/* set dirty bit */
|
|
||||||
cpu_physical_memory_set_dirty_range_nocode(addr1, 4);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
r = MEMTX_OK;
|
r = MEMTX_OK;
|
||||||
}
|
}
|
||||||
if (result) {
|
if (result) {
|
||||||
@@ -3096,7 +3089,7 @@ static inline void address_space_stl_internal(AddressSpace *as,
|
|||||||
stl_p(ptr, val);
|
stl_p(ptr, val);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
invalidate_and_set_dirty(addr1, 4);
|
invalidate_and_set_dirty(mr, addr1, 4);
|
||||||
r = MEMTX_OK;
|
r = MEMTX_OK;
|
||||||
}
|
}
|
||||||
if (result) {
|
if (result) {
|
||||||
@@ -3200,7 +3193,7 @@ static inline void address_space_stw_internal(AddressSpace *as,
|
|||||||
stw_p(ptr, val);
|
stw_p(ptr, val);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
invalidate_and_set_dirty(addr1, 2);
|
invalidate_and_set_dirty(mr, addr1, 2);
|
||||||
r = MEMTX_OK;
|
r = MEMTX_OK;
|
||||||
}
|
}
|
||||||
if (result) {
|
if (result) {
|
||||||
|
|||||||
@@ -113,7 +113,7 @@ const float16 float16_default_nan = const_float16(0xFE00);
|
|||||||
#if defined(TARGET_SPARC)
|
#if defined(TARGET_SPARC)
|
||||||
const float32 float32_default_nan = const_float32(0x7FFFFFFF);
|
const float32 float32_default_nan = const_float32(0x7FFFFFFF);
|
||||||
#elif defined(TARGET_PPC) || defined(TARGET_ARM) || defined(TARGET_ALPHA) || \
|
#elif defined(TARGET_PPC) || defined(TARGET_ARM) || defined(TARGET_ALPHA) || \
|
||||||
defined(TARGET_XTENSA)
|
defined(TARGET_XTENSA) || defined(TARGET_S390X)
|
||||||
const float32 float32_default_nan = const_float32(0x7FC00000);
|
const float32 float32_default_nan = const_float32(0x7FC00000);
|
||||||
#elif SNAN_BIT_IS_ONE
|
#elif SNAN_BIT_IS_ONE
|
||||||
const float32 float32_default_nan = const_float32(0x7FBFFFFF);
|
const float32 float32_default_nan = const_float32(0x7FBFFFFF);
|
||||||
@@ -126,7 +126,8 @@ const float32 float32_default_nan = const_float32(0xFFC00000);
|
|||||||
*----------------------------------------------------------------------------*/
|
*----------------------------------------------------------------------------*/
|
||||||
#if defined(TARGET_SPARC)
|
#if defined(TARGET_SPARC)
|
||||||
const float64 float64_default_nan = const_float64(LIT64( 0x7FFFFFFFFFFFFFFF ));
|
const float64 float64_default_nan = const_float64(LIT64( 0x7FFFFFFFFFFFFFFF ));
|
||||||
#elif defined(TARGET_PPC) || defined(TARGET_ARM) || defined(TARGET_ALPHA)
|
#elif defined(TARGET_PPC) || defined(TARGET_ARM) || defined(TARGET_ALPHA) || \
|
||||||
|
defined(TARGET_S390X)
|
||||||
const float64 float64_default_nan = const_float64(LIT64( 0x7FF8000000000000 ));
|
const float64 float64_default_nan = const_float64(LIT64( 0x7FF8000000000000 ));
|
||||||
#elif SNAN_BIT_IS_ONE
|
#elif SNAN_BIT_IS_ONE
|
||||||
const float64 float64_default_nan = const_float64(LIT64(0x7FF7FFFFFFFFFFFF));
|
const float64 float64_default_nan = const_float64(LIT64(0x7FF7FFFFFFFFFFFF));
|
||||||
@@ -155,6 +156,9 @@ const floatx80 floatx80_default_nan
|
|||||||
#if SNAN_BIT_IS_ONE
|
#if SNAN_BIT_IS_ONE
|
||||||
#define float128_default_nan_high LIT64(0x7FFF7FFFFFFFFFFF)
|
#define float128_default_nan_high LIT64(0x7FFF7FFFFFFFFFFF)
|
||||||
#define float128_default_nan_low LIT64(0xFFFFFFFFFFFFFFFF)
|
#define float128_default_nan_low LIT64(0xFFFFFFFFFFFFFFFF)
|
||||||
|
#elif defined(TARGET_S390X)
|
||||||
|
#define float128_default_nan_high LIT64( 0x7FFF800000000000 )
|
||||||
|
#define float128_default_nan_low LIT64( 0x0000000000000000 )
|
||||||
#else
|
#else
|
||||||
#define float128_default_nan_high LIT64( 0xFFFF800000000000 )
|
#define float128_default_nan_high LIT64( 0xFFFF800000000000 )
|
||||||
#define float128_default_nan_low LIT64( 0x0000000000000000 )
|
#define float128_default_nan_low LIT64( 0x0000000000000000 )
|
||||||
|
|||||||
@@ -178,8 +178,7 @@ ETEXI
|
|||||||
.args_type = "id:B",
|
.args_type = "id:B",
|
||||||
.params = "device",
|
.params = "device",
|
||||||
.help = "remove host block device",
|
.help = "remove host block device",
|
||||||
.user_print = monitor_user_noop,
|
.mhandler.cmd = hmp_drive_del,
|
||||||
.mhandler.cmd_new = hmp_drive_del,
|
|
||||||
},
|
},
|
||||||
|
|
||||||
STEXI
|
STEXI
|
||||||
@@ -654,8 +653,7 @@ ETEXI
|
|||||||
.args_type = "device:O",
|
.args_type = "device:O",
|
||||||
.params = "driver[,prop=value][,...]",
|
.params = "driver[,prop=value][,...]",
|
||||||
.help = "add device, like -device on the command line",
|
.help = "add device, like -device on the command line",
|
||||||
.user_print = monitor_user_noop,
|
.mhandler.cmd = hmp_device_add,
|
||||||
.mhandler.cmd_new = do_device_add,
|
|
||||||
.command_completion = device_add_completion,
|
.command_completion = device_add_completion,
|
||||||
},
|
},
|
||||||
|
|
||||||
@@ -1011,17 +1009,16 @@ ETEXI
|
|||||||
.name = "client_migrate_info",
|
.name = "client_migrate_info",
|
||||||
.args_type = "protocol:s,hostname:s,port:i?,tls-port:i?,cert-subject:s?",
|
.args_type = "protocol:s,hostname:s,port:i?,tls-port:i?,cert-subject:s?",
|
||||||
.params = "protocol hostname port tls-port cert-subject",
|
.params = "protocol hostname port tls-port cert-subject",
|
||||||
.help = "send migration info to spice/vnc client",
|
.help = "set migration information for remote display",
|
||||||
.user_print = monitor_user_noop,
|
.mhandler.cmd = hmp_client_migrate_info,
|
||||||
.mhandler.cmd_new = client_migrate_info,
|
|
||||||
},
|
},
|
||||||
|
|
||||||
STEXI
|
STEXI
|
||||||
@item client_migrate_info @var{protocol} @var{hostname} @var{port} @var{tls-port} @var{cert-subject}
|
@item client_migrate_info @var{protocol} @var{hostname} @var{port} @var{tls-port} @var{cert-subject}
|
||||||
@findex client_migrate_info
|
@findex client_migrate_info
|
||||||
Set the spice/vnc connection info for the migration target. The spice/vnc
|
Set migration information for remote display. This makes the server
|
||||||
server will ask the spice/vnc client to automatically reconnect using the
|
ask the client to automatically reconnect using the new parameters
|
||||||
new parameters (if specified) once the vm migration finished successfully.
|
once migration finished successfully. Only implemented for SPICE.
|
||||||
ETEXI
|
ETEXI
|
||||||
|
|
||||||
{
|
{
|
||||||
@@ -1186,8 +1183,7 @@ ETEXI
|
|||||||
"<error_status> = error string or 32bit\n\t\t\t"
|
"<error_status> = error string or 32bit\n\t\t\t"
|
||||||
"<tlb header> = 32bit x 4\n\t\t\t"
|
"<tlb header> = 32bit x 4\n\t\t\t"
|
||||||
"<tlb header prefix> = 32bit x 4",
|
"<tlb header prefix> = 32bit x 4",
|
||||||
.user_print = pcie_aer_inject_error_print,
|
.mhandler.cmd = hmp_pcie_aer_inject_error,
|
||||||
.mhandler.cmd_new = hmp_pcie_aer_inject_error,
|
|
||||||
},
|
},
|
||||||
|
|
||||||
STEXI
|
STEXI
|
||||||
|
|||||||
23
hmp.c
23
hmp.c
@@ -22,6 +22,7 @@
|
|||||||
#include "qmp-commands.h"
|
#include "qmp-commands.h"
|
||||||
#include "qemu/sockets.h"
|
#include "qemu/sockets.h"
|
||||||
#include "monitor/monitor.h"
|
#include "monitor/monitor.h"
|
||||||
|
#include "monitor/qdev.h"
|
||||||
#include "qapi/opts-visitor.h"
|
#include "qapi/opts-visitor.h"
|
||||||
#include "qapi/string-output-visitor.h"
|
#include "qapi/string-output-visitor.h"
|
||||||
#include "qapi-visit.h"
|
#include "qapi-visit.h"
|
||||||
@@ -1250,6 +1251,23 @@ void hmp_migrate_set_parameter(Monitor *mon, const QDict *qdict)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void hmp_client_migrate_info(Monitor *mon, const QDict *qdict)
|
||||||
|
{
|
||||||
|
Error *err = NULL;
|
||||||
|
const char *protocol = qdict_get_str(qdict, "protocol");
|
||||||
|
const char *hostname = qdict_get_str(qdict, "hostname");
|
||||||
|
bool has_port = qdict_haskey(qdict, "port");
|
||||||
|
int port = qdict_get_try_int(qdict, "port", -1);
|
||||||
|
bool has_tls_port = qdict_haskey(qdict, "tls-port");
|
||||||
|
int tls_port = qdict_get_try_int(qdict, "tls-port", -1);
|
||||||
|
const char *cert_subject = qdict_get_try_str(qdict, "cert-subject");
|
||||||
|
|
||||||
|
qmp_client_migrate_info(protocol, hostname,
|
||||||
|
has_port, port, has_tls_port, tls_port,
|
||||||
|
!!cert_subject, cert_subject, &err);
|
||||||
|
hmp_handle_error(mon, &err);
|
||||||
|
}
|
||||||
|
|
||||||
void hmp_set_password(Monitor *mon, const QDict *qdict)
|
void hmp_set_password(Monitor *mon, const QDict *qdict)
|
||||||
{
|
{
|
||||||
const char *protocol = qdict_get_str(qdict, "protocol");
|
const char *protocol = qdict_get_str(qdict, "protocol");
|
||||||
@@ -1482,6 +1500,11 @@ void hmp_migrate(Monitor *mon, const QDict *qdict)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void hmp_device_add(Monitor *mon, const QDict *qdict)
|
||||||
|
{
|
||||||
|
do_device_add(mon, qdict, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
void hmp_device_del(Monitor *mon, const QDict *qdict)
|
void hmp_device_del(Monitor *mon, const QDict *qdict)
|
||||||
{
|
{
|
||||||
const char *id = qdict_get_str(qdict, "id");
|
const char *id = qdict_get_str(qdict, "id");
|
||||||
|
|||||||
2
hmp.h
2
hmp.h
@@ -67,6 +67,7 @@ void hmp_migrate_set_speed(Monitor *mon, const QDict *qdict);
|
|||||||
void hmp_migrate_set_capability(Monitor *mon, const QDict *qdict);
|
void hmp_migrate_set_capability(Monitor *mon, const QDict *qdict);
|
||||||
void hmp_migrate_set_parameter(Monitor *mon, const QDict *qdict);
|
void hmp_migrate_set_parameter(Monitor *mon, const QDict *qdict);
|
||||||
void hmp_migrate_set_cache_size(Monitor *mon, const QDict *qdict);
|
void hmp_migrate_set_cache_size(Monitor *mon, const QDict *qdict);
|
||||||
|
void hmp_client_migrate_info(Monitor *mon, const QDict *qdict);
|
||||||
void hmp_set_password(Monitor *mon, const QDict *qdict);
|
void hmp_set_password(Monitor *mon, const QDict *qdict);
|
||||||
void hmp_expire_password(Monitor *mon, const QDict *qdict);
|
void hmp_expire_password(Monitor *mon, const QDict *qdict);
|
||||||
void hmp_eject(Monitor *mon, const QDict *qdict);
|
void hmp_eject(Monitor *mon, const QDict *qdict);
|
||||||
@@ -79,6 +80,7 @@ void hmp_block_job_pause(Monitor *mon, const QDict *qdict);
|
|||||||
void hmp_block_job_resume(Monitor *mon, const QDict *qdict);
|
void hmp_block_job_resume(Monitor *mon, const QDict *qdict);
|
||||||
void hmp_block_job_complete(Monitor *mon, const QDict *qdict);
|
void hmp_block_job_complete(Monitor *mon, const QDict *qdict);
|
||||||
void hmp_migrate(Monitor *mon, const QDict *qdict);
|
void hmp_migrate(Monitor *mon, const QDict *qdict);
|
||||||
|
void hmp_device_add(Monitor *mon, const QDict *qdict);
|
||||||
void hmp_device_del(Monitor *mon, const QDict *qdict);
|
void hmp_device_del(Monitor *mon, const QDict *qdict);
|
||||||
void hmp_dump_guest_memory(Monitor *mon, const QDict *qdict);
|
void hmp_dump_guest_memory(Monitor *mon, const QDict *qdict);
|
||||||
void hmp_netdev_add(Monitor *mon, const QDict *qdict);
|
void hmp_netdev_add(Monitor *mon, const QDict *qdict);
|
||||||
|
|||||||
@@ -21,7 +21,7 @@
|
|||||||
#include "virtio-9p-coth.h"
|
#include "virtio-9p-coth.h"
|
||||||
#include "hw/virtio/virtio-access.h"
|
#include "hw/virtio/virtio-access.h"
|
||||||
|
|
||||||
static uint32_t virtio_9p_get_features(VirtIODevice *vdev, uint32_t features)
|
static uint64_t virtio_9p_get_features(VirtIODevice *vdev, uint64_t features)
|
||||||
{
|
{
|
||||||
virtio_add_feature(&features, VIRTIO_9P_MOUNT_TAG);
|
virtio_add_feature(&features, VIRTIO_9P_MOUNT_TAG);
|
||||||
return features;
|
return features;
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
common-obj-$(CONFIG_ACPI) += core.o piix4.o ich9.o pcihp.o cpu_hotplug.o
|
common-obj-$(CONFIG_ACPI_X86) += core.o piix4.o ich9.o pcihp.o
|
||||||
common-obj-$(CONFIG_ACPI) += memory_hotplug.o
|
common-obj-$(CONFIG_ACPI_CPU_HOTPLUG) += cpu_hotplug.o
|
||||||
|
common-obj-$(CONFIG_ACPI_MEMORY_HOTPLUG) += memory_hotplug.o
|
||||||
common-obj-$(CONFIG_ACPI) += acpi_interface.o
|
common-obj-$(CONFIG_ACPI) += acpi_interface.o
|
||||||
common-obj-$(CONFIG_ACPI) += bios-linker-loader.o
|
common-obj-$(CONFIG_ACPI) += bios-linker-loader.o
|
||||||
common-obj-$(CONFIG_ACPI) += aml-build.o
|
common-obj-$(CONFIG_ACPI) += aml-build.o
|
||||||
|
|||||||
@@ -19,6 +19,7 @@
|
|||||||
* with this program; if not, see <http://www.gnu.org/licenses/>.
|
* with this program; if not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include <glib/gprintf.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdarg.h>
|
#include <stdarg.h>
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
@@ -26,6 +27,7 @@
|
|||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include "hw/acpi/aml-build.h"
|
#include "hw/acpi/aml-build.h"
|
||||||
#include "qemu/bswap.h"
|
#include "qemu/bswap.h"
|
||||||
|
#include "qemu/bitops.h"
|
||||||
#include "hw/acpi/bios-linker-loader.h"
|
#include "hw/acpi/bios-linker-loader.h"
|
||||||
|
|
||||||
static GArray *build_alloc_array(void)
|
static GArray *build_alloc_array(void)
|
||||||
@@ -58,7 +60,6 @@ static void build_append_array(GArray *array, GArray *val)
|
|||||||
static void
|
static void
|
||||||
build_append_nameseg(GArray *array, const char *seg)
|
build_append_nameseg(GArray *array, const char *seg)
|
||||||
{
|
{
|
||||||
/* It would be nicer to use g_string_vprintf but it's only there in 2.22 */
|
|
||||||
int len;
|
int len;
|
||||||
|
|
||||||
len = strlen(seg);
|
len = strlen(seg);
|
||||||
@@ -72,22 +73,12 @@ build_append_nameseg(GArray *array, const char *seg)
|
|||||||
static void GCC_FMT_ATTR(2, 0)
|
static void GCC_FMT_ATTR(2, 0)
|
||||||
build_append_namestringv(GArray *array, const char *format, va_list ap)
|
build_append_namestringv(GArray *array, const char *format, va_list ap)
|
||||||
{
|
{
|
||||||
/* It would be nicer to use g_string_vprintf but it's only there in 2.22 */
|
|
||||||
char *s;
|
char *s;
|
||||||
int len;
|
|
||||||
va_list va_len;
|
|
||||||
char **segs;
|
char **segs;
|
||||||
char **segs_iter;
|
char **segs_iter;
|
||||||
int seg_count = 0;
|
int seg_count = 0;
|
||||||
|
|
||||||
va_copy(va_len, ap);
|
s = g_strdup_vprintf(format, ap);
|
||||||
len = vsnprintf(NULL, 0, format, va_len);
|
|
||||||
va_end(va_len);
|
|
||||||
len += 1;
|
|
||||||
s = g_new(typeof(*s), len);
|
|
||||||
|
|
||||||
len = vsnprintf(s, len, format, ap);
|
|
||||||
|
|
||||||
segs = g_strsplit(s, ".", 0);
|
segs = g_strsplit(s, ".", 0);
|
||||||
g_free(s);
|
g_free(s);
|
||||||
|
|
||||||
@@ -305,6 +296,7 @@ static void aml_free(gpointer data, gpointer user_data)
|
|||||||
{
|
{
|
||||||
Aml *var = data;
|
Aml *var = data;
|
||||||
build_free_array(var->buf);
|
build_free_array(var->buf);
|
||||||
|
g_free(var);
|
||||||
}
|
}
|
||||||
|
|
||||||
Aml *init_aml_allocator(void)
|
Aml *init_aml_allocator(void)
|
||||||
@@ -454,6 +446,73 @@ Aml *aml_and(Aml *arg1, Aml *arg2)
|
|||||||
return var;
|
return var;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* ACPI 1.0b: 16.2.5.4 Type 2 Opcodes Encoding: DefOr */
|
||||||
|
Aml *aml_or(Aml *arg1, Aml *arg2)
|
||||||
|
{
|
||||||
|
Aml *var = aml_opcode(0x7D /* OrOp */);
|
||||||
|
aml_append(var, arg1);
|
||||||
|
aml_append(var, arg2);
|
||||||
|
build_append_byte(var->buf, 0x00 /* NullNameOp */);
|
||||||
|
return var;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ACPI 1.0b: 16.2.5.4 Type 2 Opcodes Encoding: DefShiftLeft */
|
||||||
|
Aml *aml_shiftleft(Aml *arg1, Aml *count)
|
||||||
|
{
|
||||||
|
Aml *var = aml_opcode(0x79 /* ShiftLeftOp */);
|
||||||
|
aml_append(var, arg1);
|
||||||
|
aml_append(var, count);
|
||||||
|
build_append_byte(var->buf, 0x00); /* NullNameOp */
|
||||||
|
return var;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ACPI 1.0b: 16.2.5.4 Type 2 Opcodes Encoding: DefShiftRight */
|
||||||
|
Aml *aml_shiftright(Aml *arg1, Aml *count)
|
||||||
|
{
|
||||||
|
Aml *var = aml_opcode(0x7A /* ShiftRightOp */);
|
||||||
|
aml_append(var, arg1);
|
||||||
|
aml_append(var, count);
|
||||||
|
build_append_byte(var->buf, 0x00); /* NullNameOp */
|
||||||
|
return var;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ACPI 1.0b: 16.2.5.4 Type 2 Opcodes Encoding: DefLLess */
|
||||||
|
Aml *aml_lless(Aml *arg1, Aml *arg2)
|
||||||
|
{
|
||||||
|
Aml *var = aml_opcode(0x95 /* LLessOp */);
|
||||||
|
aml_append(var, arg1);
|
||||||
|
aml_append(var, arg2);
|
||||||
|
return var;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ACPI 1.0b: 16.2.5.4 Type 2 Opcodes Encoding: DefAdd */
|
||||||
|
Aml *aml_add(Aml *arg1, Aml *arg2)
|
||||||
|
{
|
||||||
|
Aml *var = aml_opcode(0x72 /* AddOp */);
|
||||||
|
aml_append(var, arg1);
|
||||||
|
aml_append(var, arg2);
|
||||||
|
build_append_byte(var->buf, 0x00 /* NullNameOp */);
|
||||||
|
return var;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ACPI 1.0b: 16.2.5.4 Type 2 Opcodes Encoding: DefIncrement */
|
||||||
|
Aml *aml_increment(Aml *arg)
|
||||||
|
{
|
||||||
|
Aml *var = aml_opcode(0x75 /* IncrementOp */);
|
||||||
|
aml_append(var, arg);
|
||||||
|
return var;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ACPI 1.0b: 16.2.5.4 Type 2 Opcodes Encoding: DefIndex */
|
||||||
|
Aml *aml_index(Aml *arg1, Aml *idx)
|
||||||
|
{
|
||||||
|
Aml *var = aml_opcode(0x88 /* IndexOp */);
|
||||||
|
aml_append(var, arg1);
|
||||||
|
aml_append(var, idx);
|
||||||
|
build_append_byte(var->buf, 0x00 /* NullNameOp */);
|
||||||
|
return var;
|
||||||
|
}
|
||||||
|
|
||||||
/* ACPI 1.0b: 16.2.5.3 Type 1 Opcodes Encoding: DefNotify */
|
/* ACPI 1.0b: 16.2.5.3 Type 1 Opcodes Encoding: DefNotify */
|
||||||
Aml *aml_notify(Aml *arg1, Aml *arg2)
|
Aml *aml_notify(Aml *arg1, Aml *arg2)
|
||||||
{
|
{
|
||||||
@@ -505,6 +564,60 @@ Aml *aml_call4(const char *method, Aml *arg1, Aml *arg2, Aml *arg3, Aml *arg4)
|
|||||||
return var;
|
return var;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* ACPI 1.0b: 6.4.3.4 32-Bit Fixed Location Memory Range Descriptor
|
||||||
|
* (Type 1, Large Item Name 0x6)
|
||||||
|
*/
|
||||||
|
Aml *aml_memory32_fixed(uint32_t addr, uint32_t size,
|
||||||
|
AmlReadAndWrite read_and_write)
|
||||||
|
{
|
||||||
|
Aml *var = aml_alloc();
|
||||||
|
build_append_byte(var->buf, 0x86); /* Memory32Fixed Resource Descriptor */
|
||||||
|
build_append_byte(var->buf, 9); /* Length, bits[7:0] value = 9 */
|
||||||
|
build_append_byte(var->buf, 0); /* Length, bits[15:8] value = 0 */
|
||||||
|
build_append_byte(var->buf, read_and_write); /* Write status, 1 rw 0 ro */
|
||||||
|
|
||||||
|
/* Range base address */
|
||||||
|
build_append_byte(var->buf, extract32(addr, 0, 8)); /* bits[7:0] */
|
||||||
|
build_append_byte(var->buf, extract32(addr, 8, 8)); /* bits[15:8] */
|
||||||
|
build_append_byte(var->buf, extract32(addr, 16, 8)); /* bits[23:16] */
|
||||||
|
build_append_byte(var->buf, extract32(addr, 24, 8)); /* bits[31:24] */
|
||||||
|
|
||||||
|
/* Range length */
|
||||||
|
build_append_byte(var->buf, extract32(size, 0, 8)); /* bits[7:0] */
|
||||||
|
build_append_byte(var->buf, extract32(size, 8, 8)); /* bits[15:8] */
|
||||||
|
build_append_byte(var->buf, extract32(size, 16, 8)); /* bits[23:16] */
|
||||||
|
build_append_byte(var->buf, extract32(size, 24, 8)); /* bits[31:24] */
|
||||||
|
return var;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* ACPI 5.0: 6.4.3.6 Extended Interrupt Descriptor
|
||||||
|
* Type 1, Large Item Name 0x9
|
||||||
|
*/
|
||||||
|
Aml *aml_interrupt(AmlConsumerAndProducer con_and_pro,
|
||||||
|
AmlLevelAndEdge level_and_edge,
|
||||||
|
AmlActiveHighAndLow high_and_low, AmlShared shared,
|
||||||
|
uint32_t irq)
|
||||||
|
{
|
||||||
|
Aml *var = aml_alloc();
|
||||||
|
uint8_t irq_flags = con_and_pro | (level_and_edge << 1)
|
||||||
|
| (high_and_low << 2) | (shared << 3);
|
||||||
|
|
||||||
|
build_append_byte(var->buf, 0x89); /* Extended irq descriptor */
|
||||||
|
build_append_byte(var->buf, 6); /* Length, bits[7:0] minimum value = 6 */
|
||||||
|
build_append_byte(var->buf, 0); /* Length, bits[15:8] minimum value = 0 */
|
||||||
|
build_append_byte(var->buf, irq_flags); /* Interrupt Vector Information. */
|
||||||
|
build_append_byte(var->buf, 0x01); /* Interrupt table length = 1 */
|
||||||
|
|
||||||
|
/* Interrupt Number */
|
||||||
|
build_append_byte(var->buf, extract32(irq, 0, 8)); /* bits[7:0] */
|
||||||
|
build_append_byte(var->buf, extract32(irq, 8, 8)); /* bits[15:8] */
|
||||||
|
build_append_byte(var->buf, extract32(irq, 16, 8)); /* bits[23:16] */
|
||||||
|
build_append_byte(var->buf, extract32(irq, 24, 8)); /* bits[31:24] */
|
||||||
|
return var;
|
||||||
|
}
|
||||||
|
|
||||||
/* ACPI 1.0b: 6.4.2.5 I/O Port Descriptor */
|
/* ACPI 1.0b: 6.4.2.5 I/O Port Descriptor */
|
||||||
Aml *aml_io(AmlIODecode dec, uint16_t min_base, uint16_t max_base,
|
Aml *aml_io(AmlIODecode dec, uint16_t min_base, uint16_t max_base,
|
||||||
uint8_t aln, uint8_t len)
|
uint8_t aln, uint8_t len)
|
||||||
@@ -542,6 +655,14 @@ Aml *aml_irq_no_flags(uint8_t irq)
|
|||||||
return var;
|
return var;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* ACPI 1.0b: 16.2.5.4 Type 2 Opcodes Encoding: DefLNot */
|
||||||
|
Aml *aml_lnot(Aml *arg)
|
||||||
|
{
|
||||||
|
Aml *var = aml_opcode(0x92 /* LNotOp */);
|
||||||
|
aml_append(var, arg);
|
||||||
|
return var;
|
||||||
|
}
|
||||||
|
|
||||||
/* ACPI 1.0b: 16.2.5.4 Type 2 Opcodes Encoding: DefLEqual */
|
/* ACPI 1.0b: 16.2.5.4 Type 2 Opcodes Encoding: DefLEqual */
|
||||||
Aml *aml_equal(Aml *arg1, Aml *arg2)
|
Aml *aml_equal(Aml *arg1, Aml *arg2)
|
||||||
{
|
{
|
||||||
@@ -559,6 +680,21 @@ Aml *aml_if(Aml *predicate)
|
|||||||
return var;
|
return var;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* ACPI 1.0b: 16.2.5.3 Type 1 Opcodes Encoding: DefElse */
|
||||||
|
Aml *aml_else(void)
|
||||||
|
{
|
||||||
|
Aml *var = aml_bundle(0xA1 /* ElseOp */, AML_PACKAGE);
|
||||||
|
return var;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ACPI 1.0b: 16.2.5.3 Type 1 Opcodes Encoding: DefWhile */
|
||||||
|
Aml *aml_while(Aml *predicate)
|
||||||
|
{
|
||||||
|
Aml *var = aml_bundle(0xA2 /* WhileOp */, AML_PACKAGE);
|
||||||
|
aml_append(var, predicate);
|
||||||
|
return var;
|
||||||
|
}
|
||||||
|
|
||||||
/* ACPI 1.0b: 16.2.5.2 Named Objects Encoding: DefMethod */
|
/* ACPI 1.0b: 16.2.5.2 Named Objects Encoding: DefMethod */
|
||||||
Aml *aml_method(const char *name, int arg_count)
|
Aml *aml_method(const char *name, int arg_count)
|
||||||
{
|
{
|
||||||
@@ -587,10 +723,22 @@ Aml *aml_resource_template(void)
|
|||||||
return var;
|
return var;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ACPI 1.0b: 16.2.5.4 Type 2 Opcodes Encoding: DefBuffer */
|
/* ACPI 1.0b: 16.2.5.4 Type 2 Opcodes Encoding: DefBuffer
|
||||||
Aml *aml_buffer(void)
|
* Pass byte_list as NULL to request uninitialized buffer to reserve space.
|
||||||
|
*/
|
||||||
|
Aml *aml_buffer(int buffer_size, uint8_t *byte_list)
|
||||||
{
|
{
|
||||||
|
int i;
|
||||||
Aml *var = aml_bundle(0x11 /* BufferOp */, AML_BUFFER);
|
Aml *var = aml_bundle(0x11 /* BufferOp */, AML_BUFFER);
|
||||||
|
|
||||||
|
for (i = 0; i < buffer_size; i++) {
|
||||||
|
if (byte_list == NULL) {
|
||||||
|
build_append_byte(var->buf, 0x0);
|
||||||
|
} else {
|
||||||
|
build_append_byte(var->buf, byte_list[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return var;
|
return var;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -646,26 +794,30 @@ Aml *aml_field(const char *name, AmlAccessType type, AmlUpdateRule rule)
|
|||||||
return var;
|
return var;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* ACPI 1.0b: 16.2.5.2 Named Objects Encoding: DefCreateDWordField */
|
||||||
|
Aml *aml_create_dword_field(Aml *srcbuf, Aml *index, const char *name)
|
||||||
|
{
|
||||||
|
Aml *var = aml_alloc();
|
||||||
|
build_append_byte(var->buf, 0x8A); /* CreateDWordFieldOp */
|
||||||
|
aml_append(var, srcbuf);
|
||||||
|
aml_append(var, index);
|
||||||
|
build_append_namestring(var->buf, "%s", name);
|
||||||
|
return var;
|
||||||
|
}
|
||||||
|
|
||||||
/* ACPI 1.0b: 16.2.3 Data Objects Encoding: String */
|
/* ACPI 1.0b: 16.2.3 Data Objects Encoding: String */
|
||||||
Aml *aml_string(const char *name_format, ...)
|
Aml *aml_string(const char *name_format, ...)
|
||||||
{
|
{
|
||||||
Aml *var = aml_opcode(0x0D /* StringPrefix */);
|
Aml *var = aml_opcode(0x0D /* StringPrefix */);
|
||||||
va_list ap, va_len;
|
va_list ap;
|
||||||
char *s;
|
char *s;
|
||||||
int len;
|
int len;
|
||||||
|
|
||||||
va_start(ap, name_format);
|
va_start(ap, name_format);
|
||||||
va_copy(va_len, ap);
|
len = g_vasprintf(&s, name_format, ap);
|
||||||
len = vsnprintf(NULL, 0, name_format, va_len);
|
|
||||||
va_end(va_len);
|
|
||||||
len += 1;
|
|
||||||
s = g_new0(typeof(*s), len);
|
|
||||||
|
|
||||||
len = vsnprintf(s, len, name_format, ap);
|
|
||||||
va_end(ap);
|
va_end(ap);
|
||||||
|
|
||||||
g_array_append_vals(var->buf, s, len);
|
g_array_append_vals(var->buf, s, len + 1);
|
||||||
build_append_byte(var->buf, 0x0); /* NullChar */
|
|
||||||
g_free(s);
|
g_free(s);
|
||||||
|
|
||||||
return var;
|
return var;
|
||||||
@@ -833,7 +985,7 @@ Aml *aml_word_bus_number(AmlMinFixed min_fixed, AmlMaxFixed max_fixed,
|
|||||||
uint16_t addr_trans, uint16_t len)
|
uint16_t addr_trans, uint16_t len)
|
||||||
|
|
||||||
{
|
{
|
||||||
return aml_word_as_desc(aml_bus_number_range, min_fixed, max_fixed, dec,
|
return aml_word_as_desc(AML_BUS_NUMBER_RANGE, min_fixed, max_fixed, dec,
|
||||||
addr_gran, addr_min, addr_max, addr_trans, len, 0);
|
addr_gran, addr_min, addr_max, addr_trans, len, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -850,7 +1002,25 @@ Aml *aml_word_io(AmlMinFixed min_fixed, AmlMaxFixed max_fixed,
|
|||||||
uint16_t len)
|
uint16_t len)
|
||||||
|
|
||||||
{
|
{
|
||||||
return aml_word_as_desc(aml_io_range, min_fixed, max_fixed, dec,
|
return aml_word_as_desc(AML_IO_RANGE, min_fixed, max_fixed, dec,
|
||||||
|
addr_gran, addr_min, addr_max, addr_trans, len,
|
||||||
|
isa_ranges);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* ACPI 1.0b: 6.4.3.5.4 ASL Macros for DWORD Address Descriptor
|
||||||
|
*
|
||||||
|
* More verbose description at:
|
||||||
|
* ACPI 5.0: 19.5.33 DWordIO (DWord IO Resource Descriptor Macro)
|
||||||
|
*/
|
||||||
|
Aml *aml_dword_io(AmlMinFixed min_fixed, AmlMaxFixed max_fixed,
|
||||||
|
AmlDecode dec, AmlISARanges isa_ranges,
|
||||||
|
uint32_t addr_gran, uint32_t addr_min,
|
||||||
|
uint32_t addr_max, uint32_t addr_trans,
|
||||||
|
uint32_t len)
|
||||||
|
|
||||||
|
{
|
||||||
|
return aml_dword_as_desc(AML_IO_RANGE, min_fixed, max_fixed, dec,
|
||||||
addr_gran, addr_min, addr_max, addr_trans, len,
|
addr_gran, addr_min, addr_max, addr_trans, len,
|
||||||
isa_ranges);
|
isa_ranges);
|
||||||
}
|
}
|
||||||
@@ -862,7 +1032,7 @@ Aml *aml_word_io(AmlMinFixed min_fixed, AmlMaxFixed max_fixed,
|
|||||||
* ACPI 5.0: 19.5.34 DWordMemory (DWord Memory Resource Descriptor Macro)
|
* ACPI 5.0: 19.5.34 DWordMemory (DWord Memory Resource Descriptor Macro)
|
||||||
*/
|
*/
|
||||||
Aml *aml_dword_memory(AmlDecode dec, AmlMinFixed min_fixed,
|
Aml *aml_dword_memory(AmlDecode dec, AmlMinFixed min_fixed,
|
||||||
AmlMaxFixed max_fixed, AmlCacheble cacheable,
|
AmlMaxFixed max_fixed, AmlCacheable cacheable,
|
||||||
AmlReadAndWrite read_and_write,
|
AmlReadAndWrite read_and_write,
|
||||||
uint32_t addr_gran, uint32_t addr_min,
|
uint32_t addr_gran, uint32_t addr_min,
|
||||||
uint32_t addr_max, uint32_t addr_trans,
|
uint32_t addr_max, uint32_t addr_trans,
|
||||||
@@ -870,7 +1040,7 @@ Aml *aml_dword_memory(AmlDecode dec, AmlMinFixed min_fixed,
|
|||||||
{
|
{
|
||||||
uint8_t flags = read_and_write | (cacheable << 1);
|
uint8_t flags = read_and_write | (cacheable << 1);
|
||||||
|
|
||||||
return aml_dword_as_desc(aml_memory_range, min_fixed, max_fixed,
|
return aml_dword_as_desc(AML_MEMORY_RANGE, min_fixed, max_fixed,
|
||||||
dec, addr_gran, addr_min, addr_max,
|
dec, addr_gran, addr_min, addr_max,
|
||||||
addr_trans, len, flags);
|
addr_trans, len, flags);
|
||||||
}
|
}
|
||||||
@@ -882,7 +1052,7 @@ Aml *aml_dword_memory(AmlDecode dec, AmlMinFixed min_fixed,
|
|||||||
* ACPI 5.0: 19.5.102 QWordMemory (QWord Memory Resource Descriptor Macro)
|
* ACPI 5.0: 19.5.102 QWordMemory (QWord Memory Resource Descriptor Macro)
|
||||||
*/
|
*/
|
||||||
Aml *aml_qword_memory(AmlDecode dec, AmlMinFixed min_fixed,
|
Aml *aml_qword_memory(AmlDecode dec, AmlMinFixed min_fixed,
|
||||||
AmlMaxFixed max_fixed, AmlCacheble cacheable,
|
AmlMaxFixed max_fixed, AmlCacheable cacheable,
|
||||||
AmlReadAndWrite read_and_write,
|
AmlReadAndWrite read_and_write,
|
||||||
uint64_t addr_gran, uint64_t addr_min,
|
uint64_t addr_gran, uint64_t addr_min,
|
||||||
uint64_t addr_max, uint64_t addr_trans,
|
uint64_t addr_max, uint64_t addr_trans,
|
||||||
@@ -890,11 +1060,81 @@ Aml *aml_qword_memory(AmlDecode dec, AmlMinFixed min_fixed,
|
|||||||
{
|
{
|
||||||
uint8_t flags = read_and_write | (cacheable << 1);
|
uint8_t flags = read_and_write | (cacheable << 1);
|
||||||
|
|
||||||
return aml_qword_as_desc(aml_memory_range, min_fixed, max_fixed,
|
return aml_qword_as_desc(AML_MEMORY_RANGE, min_fixed, max_fixed,
|
||||||
dec, addr_gran, addr_min, addr_max,
|
dec, addr_gran, addr_min, addr_max,
|
||||||
addr_trans, len, flags);
|
addr_trans, len, flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static uint8_t Hex2Byte(const char *src)
|
||||||
|
{
|
||||||
|
int hi, lo;
|
||||||
|
|
||||||
|
hi = Hex2Digit(src[0]);
|
||||||
|
assert(hi >= 0);
|
||||||
|
assert(hi <= 15);
|
||||||
|
|
||||||
|
lo = Hex2Digit(src[1]);
|
||||||
|
assert(lo >= 0);
|
||||||
|
assert(lo <= 15);
|
||||||
|
return (hi << 4) | lo;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* ACPI 3.0: 17.5.124 ToUUID (Convert String to UUID Macro)
|
||||||
|
* e.g. UUID: aabbccdd-eeff-gghh-iijj-kkllmmnnoopp
|
||||||
|
* call aml_touuid("aabbccdd-eeff-gghh-iijj-kkllmmnnoopp");
|
||||||
|
*/
|
||||||
|
Aml *aml_touuid(const char *uuid)
|
||||||
|
{
|
||||||
|
Aml *var = aml_bundle(0x11 /* BufferOp */, AML_BUFFER);
|
||||||
|
|
||||||
|
assert(strlen(uuid) == 36);
|
||||||
|
assert(uuid[8] == '-');
|
||||||
|
assert(uuid[13] == '-');
|
||||||
|
assert(uuid[18] == '-');
|
||||||
|
assert(uuid[23] == '-');
|
||||||
|
|
||||||
|
build_append_byte(var->buf, Hex2Byte(uuid + 6)); /* dd - at offset 00 */
|
||||||
|
build_append_byte(var->buf, Hex2Byte(uuid + 4)); /* cc - at offset 01 */
|
||||||
|
build_append_byte(var->buf, Hex2Byte(uuid + 2)); /* bb - at offset 02 */
|
||||||
|
build_append_byte(var->buf, Hex2Byte(uuid + 0)); /* aa - at offset 03 */
|
||||||
|
|
||||||
|
build_append_byte(var->buf, Hex2Byte(uuid + 11)); /* ff - at offset 04 */
|
||||||
|
build_append_byte(var->buf, Hex2Byte(uuid + 9)); /* ee - at offset 05 */
|
||||||
|
|
||||||
|
build_append_byte(var->buf, Hex2Byte(uuid + 16)); /* hh - at offset 06 */
|
||||||
|
build_append_byte(var->buf, Hex2Byte(uuid + 14)); /* gg - at offset 07 */
|
||||||
|
|
||||||
|
build_append_byte(var->buf, Hex2Byte(uuid + 19)); /* ii - at offset 08 */
|
||||||
|
build_append_byte(var->buf, Hex2Byte(uuid + 21)); /* jj - at offset 09 */
|
||||||
|
|
||||||
|
build_append_byte(var->buf, Hex2Byte(uuid + 24)); /* kk - at offset 10 */
|
||||||
|
build_append_byte(var->buf, Hex2Byte(uuid + 26)); /* ll - at offset 11 */
|
||||||
|
build_append_byte(var->buf, Hex2Byte(uuid + 28)); /* mm - at offset 12 */
|
||||||
|
build_append_byte(var->buf, Hex2Byte(uuid + 30)); /* nn - at offset 13 */
|
||||||
|
build_append_byte(var->buf, Hex2Byte(uuid + 32)); /* oo - at offset 14 */
|
||||||
|
build_append_byte(var->buf, Hex2Byte(uuid + 34)); /* pp - at offset 15 */
|
||||||
|
|
||||||
|
return var;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* ACPI 2.0b: 16.2.3.6.4.3 Unicode Macro (Convert Ascii String To Unicode)
|
||||||
|
*/
|
||||||
|
Aml *aml_unicode(const char *str)
|
||||||
|
{
|
||||||
|
int i = 0;
|
||||||
|
Aml *var = aml_bundle(0x11 /* BufferOp */, AML_BUFFER);
|
||||||
|
|
||||||
|
do {
|
||||||
|
build_append_byte(var->buf, str[i]);
|
||||||
|
build_append_byte(var->buf, 0);
|
||||||
|
i++;
|
||||||
|
} while (i <= strlen(str));
|
||||||
|
|
||||||
|
return var;
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
build_header(GArray *linker, GArray *table_data,
|
build_header(GArray *linker, GArray *table_data,
|
||||||
AcpiTableHeader *h, const char *sig, int len, uint8_t rev)
|
AcpiTableHeader *h, const char *sig, int len, uint8_t rev)
|
||||||
@@ -951,3 +1191,27 @@ void acpi_build_tables_cleanup(AcpiBuildTables *tables, bool mfre)
|
|||||||
g_array_free(tables->table_data, true);
|
g_array_free(tables->table_data, true);
|
||||||
g_array_free(tables->tcpalog, mfre);
|
g_array_free(tables->tcpalog, mfre);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Build rsdt table */
|
||||||
|
void
|
||||||
|
build_rsdt(GArray *table_data, GArray *linker, GArray *table_offsets)
|
||||||
|
{
|
||||||
|
AcpiRsdtDescriptorRev1 *rsdt;
|
||||||
|
size_t rsdt_len;
|
||||||
|
int i;
|
||||||
|
const int table_data_len = (sizeof(uint32_t) * table_offsets->len);
|
||||||
|
|
||||||
|
rsdt_len = sizeof(*rsdt) + table_data_len;
|
||||||
|
rsdt = acpi_data_push(table_data, rsdt_len);
|
||||||
|
memcpy(rsdt->table_offset_entry, table_offsets->data, table_data_len);
|
||||||
|
for (i = 0; i < table_offsets->len; ++i) {
|
||||||
|
/* rsdt->table_offset_entry to be filled by Guest linker */
|
||||||
|
bios_linker_loader_add_pointer(linker,
|
||||||
|
ACPI_BUILD_TABLE_FILE,
|
||||||
|
ACPI_BUILD_TABLE_FILE,
|
||||||
|
table_data, &rsdt->table_offset_entry[i],
|
||||||
|
sizeof(uint32_t));
|
||||||
|
}
|
||||||
|
build_header(linker, table_data,
|
||||||
|
(void *)rsdt, "RSDT", rsdt_len, 1);
|
||||||
|
}
|
||||||
|
|||||||
@@ -22,6 +22,7 @@
|
|||||||
#include "hw/hw.h"
|
#include "hw/hw.h"
|
||||||
#include "hw/i386/pc.h"
|
#include "hw/i386/pc.h"
|
||||||
#include "hw/acpi/acpi.h"
|
#include "hw/acpi/acpi.h"
|
||||||
|
#include "hw/nvram/fw_cfg.h"
|
||||||
#include "qemu/config-file.h"
|
#include "qemu/config-file.h"
|
||||||
#include "qapi/opts-visitor.h"
|
#include "qapi/opts-visitor.h"
|
||||||
#include "qapi/dealloc-visitor.h"
|
#include "qapi/dealloc-visitor.h"
|
||||||
@@ -592,14 +593,26 @@ static const MemoryRegionOps acpi_pm_cnt_ops = {
|
|||||||
.endianness = DEVICE_LITTLE_ENDIAN,
|
.endianness = DEVICE_LITTLE_ENDIAN,
|
||||||
};
|
};
|
||||||
|
|
||||||
void acpi_pm1_cnt_init(ACPIREGS *ar, MemoryRegion *parent, uint8_t s4_val)
|
void acpi_pm1_cnt_init(ACPIREGS *ar, MemoryRegion *parent,
|
||||||
|
bool disable_s3, bool disable_s4, uint8_t s4_val)
|
||||||
{
|
{
|
||||||
|
FWCfgState *fw_cfg;
|
||||||
|
|
||||||
ar->pm1.cnt.s4_val = s4_val;
|
ar->pm1.cnt.s4_val = s4_val;
|
||||||
ar->wakeup.notify = acpi_notify_wakeup;
|
ar->wakeup.notify = acpi_notify_wakeup;
|
||||||
qemu_register_wakeup_notifier(&ar->wakeup);
|
qemu_register_wakeup_notifier(&ar->wakeup);
|
||||||
memory_region_init_io(&ar->pm1.cnt.io, memory_region_owner(parent),
|
memory_region_init_io(&ar->pm1.cnt.io, memory_region_owner(parent),
|
||||||
&acpi_pm_cnt_ops, ar, "acpi-cnt", 2);
|
&acpi_pm_cnt_ops, ar, "acpi-cnt", 2);
|
||||||
memory_region_add_subregion(parent, 4, &ar->pm1.cnt.io);
|
memory_region_add_subregion(parent, 4, &ar->pm1.cnt.io);
|
||||||
|
|
||||||
|
fw_cfg = fw_cfg_find();
|
||||||
|
if (fw_cfg) {
|
||||||
|
uint8_t suspend[6] = {128, 0, 0, 129, 128, 128};
|
||||||
|
suspend[3] = 1 | ((!disable_s3) << 7);
|
||||||
|
suspend[4] = s4_val | ((!disable_s4) << 7);
|
||||||
|
|
||||||
|
fw_cfg_add_file(fw_cfg, "etc/system-states", g_memdup(suspend, 6), 6);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void acpi_pm1_cnt_reset(ACPIREGS *ar)
|
void acpi_pm1_cnt_reset(ACPIREGS *ar)
|
||||||
@@ -666,6 +679,13 @@ uint32_t acpi_gpe_ioport_readb(ACPIREGS *ar, uint32_t addr)
|
|||||||
return val;
|
return val;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void acpi_send_gpe_event(ACPIREGS *ar, qemu_irq irq,
|
||||||
|
AcpiGPEStatusBits status)
|
||||||
|
{
|
||||||
|
ar->gpe.sts[0] |= status;
|
||||||
|
acpi_update_sci(ar, irq);
|
||||||
|
}
|
||||||
|
|
||||||
void acpi_update_sci(ACPIREGS *regs, qemu_irq irq)
|
void acpi_update_sci(ACPIREGS *regs, qemu_irq irq)
|
||||||
{
|
{
|
||||||
int sci_level, pm1a_sts;
|
int sci_level, pm1a_sts;
|
||||||
|
|||||||
@@ -59,8 +59,7 @@ void acpi_cpu_plug_cb(ACPIREGS *ar, qemu_irq irq,
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
ar->gpe.sts[0] |= ACPI_CPU_HOTPLUG_STATUS;
|
acpi_send_gpe_event(ar, irq, ACPI_CPU_HOTPLUG_STATUS);
|
||||||
acpi_update_sci(ar, irq);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void acpi_cpu_hotplug_init(MemoryRegion *parent, Object *owner,
|
void acpi_cpu_hotplug_init(MemoryRegion *parent, Object *owner,
|
||||||
|
|||||||
@@ -94,7 +94,8 @@ static void ich9_smi_writel(void *opaque, hwaddr addr, uint64_t val,
|
|||||||
ICH9LPCPMRegs *pm = opaque;
|
ICH9LPCPMRegs *pm = opaque;
|
||||||
switch (addr) {
|
switch (addr) {
|
||||||
case 0:
|
case 0:
|
||||||
pm->smi_en = val;
|
pm->smi_en &= ~pm->smi_en_wmask;
|
||||||
|
pm->smi_en |= (val & pm->smi_en_wmask);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -198,6 +199,7 @@ static void pm_reset(void *opaque)
|
|||||||
* support SMM mode. */
|
* support SMM mode. */
|
||||||
pm->smi_en |= ICH9_PMIO_SMI_EN_APMC_EN;
|
pm->smi_en |= ICH9_PMIO_SMI_EN_APMC_EN;
|
||||||
}
|
}
|
||||||
|
pm->smi_en_wmask = ~0;
|
||||||
|
|
||||||
acpi_update_sci(&pm->acpi_regs, pm->irq);
|
acpi_update_sci(&pm->acpi_regs, pm->irq);
|
||||||
}
|
}
|
||||||
@@ -219,7 +221,8 @@ void ich9_pm_init(PCIDevice *lpc_pci, ICH9LPCPMRegs *pm,
|
|||||||
|
|
||||||
acpi_pm_tmr_init(&pm->acpi_regs, ich9_pm_update_sci_fn, &pm->io);
|
acpi_pm_tmr_init(&pm->acpi_regs, ich9_pm_update_sci_fn, &pm->io);
|
||||||
acpi_pm1_evt_init(&pm->acpi_regs, ich9_pm_update_sci_fn, &pm->io);
|
acpi_pm1_evt_init(&pm->acpi_regs, ich9_pm_update_sci_fn, &pm->io);
|
||||||
acpi_pm1_cnt_init(&pm->acpi_regs, &pm->io, pm->s4_val);
|
acpi_pm1_cnt_init(&pm->acpi_regs, &pm->io, pm->disable_s3, pm->disable_s4,
|
||||||
|
pm->s4_val);
|
||||||
|
|
||||||
acpi_gpe_init(&pm->acpi_regs, ICH9_PMIO_GPE0_LEN);
|
acpi_gpe_init(&pm->acpi_regs, ICH9_PMIO_GPE0_LEN);
|
||||||
memory_region_init_io(&pm->io_gpe, OBJECT(lpc_pci), &ich9_gpe_ops, pm,
|
memory_region_init_io(&pm->io_gpe, OBJECT(lpc_pci), &ich9_gpe_ops, pm,
|
||||||
|
|||||||
@@ -241,8 +241,7 @@ void acpi_memory_plug_cb(ACPIREGS *ar, qemu_irq irq, MemHotplugState *mem_st,
|
|||||||
mdev->is_inserting = true;
|
mdev->is_inserting = true;
|
||||||
|
|
||||||
/* do ACPI magic */
|
/* do ACPI magic */
|
||||||
ar->gpe.sts[0] |= ACPI_MEMORY_HOTPLUG_STATUS;
|
acpi_send_gpe_event(ar, irq, ACPI_MEMORY_HOTPLUG_STATUS);
|
||||||
acpi_update_sci(ar, irq);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -260,8 +259,7 @@ void acpi_memory_unplug_request_cb(ACPIREGS *ar, qemu_irq irq,
|
|||||||
mdev->is_removing = true;
|
mdev->is_removing = true;
|
||||||
|
|
||||||
/* Do ACPI magic */
|
/* Do ACPI magic */
|
||||||
ar->gpe.sts[0] |= ACPI_MEMORY_HOTPLUG_STATUS;
|
acpi_send_gpe_event(ar, irq, ACPI_MEMORY_HOTPLUG_STATUS);
|
||||||
acpi_update_sci(ar, irq);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void acpi_memory_unplug_cb(MemHotplugState *mem_st,
|
void acpi_memory_unplug_cb(MemHotplugState *mem_st,
|
||||||
|
|||||||
@@ -45,7 +45,6 @@
|
|||||||
# define ACPI_PCIHP_DPRINTF(format, ...) do { } while (0)
|
# define ACPI_PCIHP_DPRINTF(format, ...) do { } while (0)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define ACPI_PCI_HOTPLUG_STATUS 2
|
|
||||||
#define ACPI_PCIHP_ADDR 0xae00
|
#define ACPI_PCIHP_ADDR 0xae00
|
||||||
#define ACPI_PCIHP_SIZE 0x0014
|
#define ACPI_PCIHP_SIZE 0x0014
|
||||||
#define ACPI_PCIHP_LEGACY_SIZE 0x000f
|
#define ACPI_PCIHP_LEGACY_SIZE 0x000f
|
||||||
@@ -202,8 +201,7 @@ void acpi_pcihp_device_plug_cb(ACPIREGS *ar, qemu_irq irq, AcpiPciHpState *s,
|
|||||||
|
|
||||||
s->acpi_pcihp_pci_status[bsel].up |= (1U << slot);
|
s->acpi_pcihp_pci_status[bsel].up |= (1U << slot);
|
||||||
|
|
||||||
ar->gpe.sts[0] |= ACPI_PCI_HOTPLUG_STATUS;
|
acpi_send_gpe_event(ar, irq, ACPI_PCI_HOTPLUG_STATUS);
|
||||||
acpi_update_sci(ar, irq);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void acpi_pcihp_device_unplug_cb(ACPIREGS *ar, qemu_irq irq, AcpiPciHpState *s,
|
void acpi_pcihp_device_unplug_cb(ACPIREGS *ar, qemu_irq irq, AcpiPciHpState *s,
|
||||||
@@ -220,8 +218,7 @@ void acpi_pcihp_device_unplug_cb(ACPIREGS *ar, qemu_irq irq, AcpiPciHpState *s,
|
|||||||
|
|
||||||
s->acpi_pcihp_pci_status[bsel].down |= (1U << slot);
|
s->acpi_pcihp_pci_status[bsel].down |= (1U << slot);
|
||||||
|
|
||||||
ar->gpe.sts[0] |= ACPI_PCI_HOTPLUG_STATUS;
|
acpi_send_gpe_event(ar, irq, ACPI_PCI_HOTPLUG_STATUS);
|
||||||
acpi_update_sci(ar, irq);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static uint64_t pci_read(void *opaque, hwaddr addr, unsigned int size)
|
static uint64_t pci_read(void *opaque, hwaddr addr, unsigned int size)
|
||||||
|
|||||||
@@ -475,7 +475,7 @@ static void piix4_pm_realize(PCIDevice *dev, Error **errp)
|
|||||||
|
|
||||||
acpi_pm_tmr_init(&s->ar, pm_tmr_timer, &s->io);
|
acpi_pm_tmr_init(&s->ar, pm_tmr_timer, &s->io);
|
||||||
acpi_pm1_evt_init(&s->ar, pm_tmr_timer, &s->io);
|
acpi_pm1_evt_init(&s->ar, pm_tmr_timer, &s->io);
|
||||||
acpi_pm1_cnt_init(&s->ar, &s->io, s->s4_val);
|
acpi_pm1_cnt_init(&s->ar, &s->io, s->disable_s3, s->disable_s4, s->s4_val);
|
||||||
acpi_gpe_init(&s->ar, GPE_LEN);
|
acpi_gpe_init(&s->ar, GPE_LEN);
|
||||||
|
|
||||||
s->powerdown_notifier.notify = piix4_pm_powerdown_req;
|
s->powerdown_notifier.notify = piix4_pm_powerdown_req;
|
||||||
@@ -503,8 +503,7 @@ Object *piix4_pm_find(void)
|
|||||||
|
|
||||||
I2CBus *piix4_pm_init(PCIBus *bus, int devfn, uint32_t smb_io_base,
|
I2CBus *piix4_pm_init(PCIBus *bus, int devfn, uint32_t smb_io_base,
|
||||||
qemu_irq sci_irq, qemu_irq smi_irq,
|
qemu_irq sci_irq, qemu_irq smi_irq,
|
||||||
int kvm_enabled, FWCfgState *fw_cfg,
|
int kvm_enabled, DeviceState **piix4_pm)
|
||||||
DeviceState **piix4_pm)
|
|
||||||
{
|
{
|
||||||
DeviceState *dev;
|
DeviceState *dev;
|
||||||
PIIX4PMState *s;
|
PIIX4PMState *s;
|
||||||
@@ -525,14 +524,6 @@ I2CBus *piix4_pm_init(PCIBus *bus, int devfn, uint32_t smb_io_base,
|
|||||||
|
|
||||||
qdev_init_nofail(dev);
|
qdev_init_nofail(dev);
|
||||||
|
|
||||||
if (fw_cfg) {
|
|
||||||
uint8_t suspend[6] = {128, 0, 0, 129, 128, 128};
|
|
||||||
suspend[3] = 1 | ((!s->disable_s3) << 7);
|
|
||||||
suspend[4] = s->s4_val | ((!s->disable_s4) << 7);
|
|
||||||
|
|
||||||
fw_cfg_add_file(fw_cfg, "etc/system-states", g_memdup(suspend, 6), 6);
|
|
||||||
}
|
|
||||||
|
|
||||||
return s->smb.smbus;
|
return s->smb.smbus;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -55,7 +55,7 @@ static void clipper_init(MachineState *machine)
|
|||||||
ISABus *isa_bus;
|
ISABus *isa_bus;
|
||||||
qemu_irq rtc_irq;
|
qemu_irq rtc_irq;
|
||||||
long size, i;
|
long size, i;
|
||||||
const char *palcode_filename;
|
char *palcode_filename;
|
||||||
uint64_t palcode_entry, palcode_low, palcode_high;
|
uint64_t palcode_entry, palcode_low, palcode_high;
|
||||||
uint64_t kernel_entry, kernel_low, kernel_high;
|
uint64_t kernel_entry, kernel_low, kernel_high;
|
||||||
|
|
||||||
@@ -101,8 +101,8 @@ static void clipper_init(MachineState *machine)
|
|||||||
/* Load PALcode. Given that this is not "real" cpu palcode,
|
/* Load PALcode. Given that this is not "real" cpu palcode,
|
||||||
but one explicitly written for the emulation, we might as
|
but one explicitly written for the emulation, we might as
|
||||||
well load it directly from and ELF image. */
|
well load it directly from and ELF image. */
|
||||||
palcode_filename = (bios_name ? bios_name : "palcode-clipper");
|
palcode_filename = qemu_find_file(QEMU_FILE_TYPE_BIOS,
|
||||||
palcode_filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, palcode_filename);
|
bios_name ? bios_name : "palcode-clipper");
|
||||||
if (palcode_filename == NULL) {
|
if (palcode_filename == NULL) {
|
||||||
hw_error("no palcode provided\n");
|
hw_error("no palcode provided\n");
|
||||||
exit(1);
|
exit(1);
|
||||||
@@ -114,6 +114,7 @@ static void clipper_init(MachineState *machine)
|
|||||||
hw_error("could not load palcode '%s'\n", palcode_filename);
|
hw_error("could not load palcode '%s'\n", palcode_filename);
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
g_free(palcode_filename);
|
||||||
|
|
||||||
/* Start all cpus at the PALcode RESET entry point. */
|
/* Start all cpus at the PALcode RESET entry point. */
|
||||||
for (i = 0; i < smp_cpus; ++i) {
|
for (i = 0; i < smp_cpus; ++i) {
|
||||||
|
|||||||
@@ -841,7 +841,7 @@ PCIBus *typhoon_init(ram_addr_t ram_size, ISABus **isa_bus,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
*p_rtc_irq = *qemu_allocate_irqs(typhoon_set_timer_irq, s, 1);
|
*p_rtc_irq = qemu_allocate_irq(typhoon_set_timer_irq, s, 0);
|
||||||
|
|
||||||
/* Main memory region, 0x00.0000.0000. Real hardware supports 32GB,
|
/* Main memory region, 0x00.0000.0000. Real hardware supports 32GB,
|
||||||
but the address space hole reserved at this point is 8TB. */
|
but the address space hole reserved at this point is 8TB. */
|
||||||
@@ -918,11 +918,11 @@ PCIBus *typhoon_init(ram_addr_t ram_size, ISABus **isa_bus,
|
|||||||
/* Init the ISA bus. */
|
/* Init the ISA bus. */
|
||||||
/* ??? Technically there should be a cy82c693ub pci-isa bridge. */
|
/* ??? Technically there should be a cy82c693ub pci-isa bridge. */
|
||||||
{
|
{
|
||||||
qemu_irq isa_pci_irq, *isa_irqs;
|
qemu_irq *isa_irqs;
|
||||||
|
|
||||||
*isa_bus = isa_bus_new(NULL, get_system_memory(), &s->pchip.reg_io);
|
*isa_bus = isa_bus_new(NULL, get_system_memory(), &s->pchip.reg_io);
|
||||||
isa_pci_irq = *qemu_allocate_irqs(typhoon_set_isa_irq, s, 1);
|
isa_irqs = i8259_init(*isa_bus,
|
||||||
isa_irqs = i8259_init(*isa_bus, isa_pci_irq);
|
qemu_allocate_irq(typhoon_set_isa_irq, s, 0));
|
||||||
isa_bus_irqs(*isa_bus, isa_irqs);
|
isa_bus_irqs(*isa_bus, isa_irqs);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -3,7 +3,9 @@ obj-$(CONFIG_DIGIC) += digic_boards.o
|
|||||||
obj-y += integratorcp.o kzm.o mainstone.o musicpal.o nseries.o
|
obj-y += integratorcp.o kzm.o mainstone.o musicpal.o nseries.o
|
||||||
obj-y += omap_sx1.o palm.o realview.o spitz.o stellaris.o
|
obj-y += omap_sx1.o palm.o realview.o spitz.o stellaris.o
|
||||||
obj-y += tosa.o versatilepb.o vexpress.o virt.o xilinx_zynq.o z2.o
|
obj-y += tosa.o versatilepb.o vexpress.o virt.o xilinx_zynq.o z2.o
|
||||||
|
obj-$(CONFIG_ACPI) += virt-acpi-build.o
|
||||||
obj-y += netduino2.o
|
obj-y += netduino2.o
|
||||||
|
obj-y += sysbus-fdt.o
|
||||||
|
|
||||||
obj-y += armv7m.o exynos4210.o pxa2xx.o pxa2xx_gpio.o pxa2xx_pic.o
|
obj-y += armv7m.o exynos4210.o pxa2xx.o pxa2xx_gpio.o pxa2xx_pic.o
|
||||||
obj-$(CONFIG_DIGIC) += digic.o
|
obj-$(CONFIG_DIGIC) += digic.o
|
||||||
|
|||||||
@@ -557,7 +557,7 @@ static void load_image_to_fw_cfg(FWCfgState *fw_cfg, uint16_t size_key,
|
|||||||
fw_cfg_add_bytes(fw_cfg, data_key, data, size);
|
fw_cfg_add_bytes(fw_cfg, data_key, data, size);
|
||||||
}
|
}
|
||||||
|
|
||||||
void arm_load_kernel(ARMCPU *cpu, struct arm_boot_info *info)
|
static void arm_load_kernel_notify(Notifier *notifier, void *data)
|
||||||
{
|
{
|
||||||
CPUState *cs;
|
CPUState *cs;
|
||||||
int kernel_size;
|
int kernel_size;
|
||||||
@@ -568,6 +568,11 @@ void arm_load_kernel(ARMCPU *cpu, struct arm_boot_info *info)
|
|||||||
hwaddr entry, kernel_load_offset;
|
hwaddr entry, kernel_load_offset;
|
||||||
int big_endian;
|
int big_endian;
|
||||||
static const ARMInsnFixup *primary_loader;
|
static const ARMInsnFixup *primary_loader;
|
||||||
|
ArmLoadKernelNotifier *n = DO_UPCAST(ArmLoadKernelNotifier,
|
||||||
|
notifier, notifier);
|
||||||
|
ARMCPU *cpu = n->cpu;
|
||||||
|
struct arm_boot_info *info =
|
||||||
|
container_of(n, struct arm_boot_info, load_kernel_notifier);
|
||||||
|
|
||||||
/* CPU objects (unlike devices) are not automatically reset on system
|
/* CPU objects (unlike devices) are not automatically reset on system
|
||||||
* reset, so we must always register a handler to do so. If we're
|
* reset, so we must always register a handler to do so. If we're
|
||||||
@@ -775,3 +780,10 @@ void arm_load_kernel(ARMCPU *cpu, struct arm_boot_info *info)
|
|||||||
ARM_CPU(cs)->env.boot_info = info;
|
ARM_CPU(cs)->env.boot_info = info;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void arm_load_kernel(ARMCPU *cpu, struct arm_boot_info *info)
|
||||||
|
{
|
||||||
|
info->load_kernel_notifier.cpu = cpu;
|
||||||
|
info->load_kernel_notifier.notifier.notify = arm_load_kernel_notify;
|
||||||
|
qemu_add_machine_init_done_notifier(&info->load_kernel_notifier.notifier);
|
||||||
|
}
|
||||||
|
|||||||
@@ -133,9 +133,8 @@ static void n800_mmc_cs_cb(void *opaque, int line, int level)
|
|||||||
|
|
||||||
static void n8x0_gpio_setup(struct n800_s *s)
|
static void n8x0_gpio_setup(struct n800_s *s)
|
||||||
{
|
{
|
||||||
qemu_irq *mmc_cs = qemu_allocate_irqs(n800_mmc_cs_cb, s->mpu->mmc, 1);
|
qdev_connect_gpio_out(s->mpu->gpio, N8X0_MMC_CS_GPIO,
|
||||||
qdev_connect_gpio_out(s->mpu->gpio, N8X0_MMC_CS_GPIO, mmc_cs[0]);
|
qemu_allocate_irq(n800_mmc_cs_cb, s->mpu->mmc, 0));
|
||||||
|
|
||||||
qemu_irq_lower(qdev_get_gpio_in(s->mpu->gpio, N800_BAT_COVER_GPIO));
|
qemu_irq_lower(qdev_get_gpio_in(s->mpu->gpio, N800_BAT_COVER_GPIO));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -103,7 +103,6 @@ static void sx1_init(MachineState *machine, const int version)
|
|||||||
struct omap_mpu_state_s *mpu;
|
struct omap_mpu_state_s *mpu;
|
||||||
MemoryRegion *address_space = get_system_memory();
|
MemoryRegion *address_space = get_system_memory();
|
||||||
MemoryRegion *flash = g_new(MemoryRegion, 1);
|
MemoryRegion *flash = g_new(MemoryRegion, 1);
|
||||||
MemoryRegion *flash_1 = g_new(MemoryRegion, 1);
|
|
||||||
MemoryRegion *cs = g_new(MemoryRegion, 4);
|
MemoryRegion *cs = g_new(MemoryRegion, 4);
|
||||||
static uint32_t cs0val = 0x00213090;
|
static uint32_t cs0val = 0x00213090;
|
||||||
static uint32_t cs1val = 0x00215070;
|
static uint32_t cs1val = 0x00215070;
|
||||||
@@ -165,6 +164,7 @@ static void sx1_init(MachineState *machine, const int version)
|
|||||||
|
|
||||||
if ((version == 1) &&
|
if ((version == 1) &&
|
||||||
(dinfo = drive_get(IF_PFLASH, 0, fl_idx)) != NULL) {
|
(dinfo = drive_get(IF_PFLASH, 0, fl_idx)) != NULL) {
|
||||||
|
MemoryRegion *flash_1 = g_new(MemoryRegion, 1);
|
||||||
memory_region_init_ram(flash_1, NULL, "omap_sx1.flash1-0", flash1_size,
|
memory_region_init_ram(flash_1, NULL, "omap_sx1.flash1-0", flash1_size,
|
||||||
&error_abort);
|
&error_abort);
|
||||||
vmstate_register_ram_global(flash_1);
|
vmstate_register_ram_global(flash_1);
|
||||||
|
|||||||
174
hw/arm/sysbus-fdt.c
Normal file
174
hw/arm/sysbus-fdt.c
Normal file
@@ -0,0 +1,174 @@
|
|||||||
|
/*
|
||||||
|
* ARM Platform Bus device tree generation helpers
|
||||||
|
*
|
||||||
|
* Copyright (c) 2014 Linaro Limited
|
||||||
|
*
|
||||||
|
* Authors:
|
||||||
|
* Alex Graf <agraf@suse.de>
|
||||||
|
* Eric Auger <eric.auger@linaro.org>
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms and conditions of the GNU General Public License,
|
||||||
|
* version 2 or later, as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||||
|
* more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License along with
|
||||||
|
* this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "hw/arm/sysbus-fdt.h"
|
||||||
|
#include "qemu/error-report.h"
|
||||||
|
#include "sysemu/device_tree.h"
|
||||||
|
#include "hw/platform-bus.h"
|
||||||
|
#include "sysemu/sysemu.h"
|
||||||
|
|
||||||
|
/*
|
||||||
|
* internal struct that contains the information to create dynamic
|
||||||
|
* sysbus device node
|
||||||
|
*/
|
||||||
|
typedef struct PlatformBusFDTData {
|
||||||
|
void *fdt; /* device tree handle */
|
||||||
|
int irq_start; /* index of the first IRQ usable by platform bus devices */
|
||||||
|
const char *pbus_node_name; /* name of the platform bus node */
|
||||||
|
PlatformBusDevice *pbus;
|
||||||
|
} PlatformBusFDTData;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* struct used when calling the machine init done notifier
|
||||||
|
* that constructs the fdt nodes of platform bus devices
|
||||||
|
*/
|
||||||
|
typedef struct PlatformBusFDTNotifierParams {
|
||||||
|
Notifier notifier;
|
||||||
|
ARMPlatformBusFDTParams *fdt_params;
|
||||||
|
} PlatformBusFDTNotifierParams;
|
||||||
|
|
||||||
|
/* struct that associates a device type name and a node creation function */
|
||||||
|
typedef struct NodeCreationPair {
|
||||||
|
const char *typename;
|
||||||
|
int (*add_fdt_node_fn)(SysBusDevice *sbdev, void *opaque);
|
||||||
|
} NodeCreationPair;
|
||||||
|
|
||||||
|
/* list of supported dynamic sysbus devices */
|
||||||
|
static const NodeCreationPair add_fdt_node_functions[] = {
|
||||||
|
{"", NULL}, /* last element */
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* add_fdt_node - add the device tree node of a dynamic sysbus device
|
||||||
|
*
|
||||||
|
* @sbdev: handle to the sysbus device
|
||||||
|
* @opaque: handle to the PlatformBusFDTData
|
||||||
|
*
|
||||||
|
* Checks the sysbus type belongs to the list of device types that
|
||||||
|
* are dynamically instantiable and if so call the node creation
|
||||||
|
* function.
|
||||||
|
*/
|
||||||
|
static int add_fdt_node(SysBusDevice *sbdev, void *opaque)
|
||||||
|
{
|
||||||
|
int i, ret;
|
||||||
|
|
||||||
|
for (i = 0; i < ARRAY_SIZE(add_fdt_node_functions); i++) {
|
||||||
|
if (!strcmp(object_get_typename(OBJECT(sbdev)),
|
||||||
|
add_fdt_node_functions[i].typename)) {
|
||||||
|
ret = add_fdt_node_functions[i].add_fdt_node_fn(sbdev, opaque);
|
||||||
|
assert(!ret);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
error_report("Device %s can not be dynamically instantiated",
|
||||||
|
qdev_fw_name(DEVICE(sbdev)));
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* add_all_platform_bus_fdt_nodes - create all the platform bus nodes
|
||||||
|
*
|
||||||
|
* builds the parent platform bus node and all the nodes of dynamic
|
||||||
|
* sysbus devices attached to it.
|
||||||
|
*/
|
||||||
|
static void add_all_platform_bus_fdt_nodes(ARMPlatformBusFDTParams *fdt_params)
|
||||||
|
{
|
||||||
|
const char platcomp[] = "qemu,platform\0simple-bus";
|
||||||
|
PlatformBusDevice *pbus;
|
||||||
|
DeviceState *dev;
|
||||||
|
gchar *node;
|
||||||
|
uint64_t addr, size;
|
||||||
|
int irq_start, dtb_size;
|
||||||
|
struct arm_boot_info *info = fdt_params->binfo;
|
||||||
|
const ARMPlatformBusSystemParams *params = fdt_params->system_params;
|
||||||
|
const char *intc = fdt_params->intc;
|
||||||
|
void *fdt = info->get_dtb(info, &dtb_size);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If the user provided a dtb, we assume the dynamic sysbus nodes
|
||||||
|
* already are integrated there. This corresponds to a use case where
|
||||||
|
* the dynamic sysbus nodes are complex and their generation is not yet
|
||||||
|
* supported. In that case the user can take charge of the guest dt
|
||||||
|
* while qemu takes charge of the qom stuff.
|
||||||
|
*/
|
||||||
|
if (info->dtb_filename) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
assert(fdt);
|
||||||
|
|
||||||
|
node = g_strdup_printf("/platform@%"PRIx64, params->platform_bus_base);
|
||||||
|
addr = params->platform_bus_base;
|
||||||
|
size = params->platform_bus_size;
|
||||||
|
irq_start = params->platform_bus_first_irq;
|
||||||
|
|
||||||
|
/* Create a /platform node that we can put all devices into */
|
||||||
|
qemu_fdt_add_subnode(fdt, node);
|
||||||
|
qemu_fdt_setprop(fdt, node, "compatible", platcomp, sizeof(platcomp));
|
||||||
|
|
||||||
|
/* Our platform bus region is less than 32bits, so 1 cell is enough for
|
||||||
|
* address and size
|
||||||
|
*/
|
||||||
|
qemu_fdt_setprop_cells(fdt, node, "#size-cells", 1);
|
||||||
|
qemu_fdt_setprop_cells(fdt, node, "#address-cells", 1);
|
||||||
|
qemu_fdt_setprop_cells(fdt, node, "ranges", 0, addr >> 32, addr, size);
|
||||||
|
|
||||||
|
qemu_fdt_setprop_phandle(fdt, node, "interrupt-parent", intc);
|
||||||
|
|
||||||
|
dev = qdev_find_recursive(sysbus_get_default(), TYPE_PLATFORM_BUS_DEVICE);
|
||||||
|
pbus = PLATFORM_BUS_DEVICE(dev);
|
||||||
|
|
||||||
|
/* We can only create dt nodes for dynamic devices when they're ready */
|
||||||
|
assert(pbus->done_gathering);
|
||||||
|
|
||||||
|
PlatformBusFDTData data = {
|
||||||
|
.fdt = fdt,
|
||||||
|
.irq_start = irq_start,
|
||||||
|
.pbus_node_name = node,
|
||||||
|
.pbus = pbus,
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Loop through all dynamic sysbus devices and create their node */
|
||||||
|
foreach_dynamic_sysbus_device(add_fdt_node, &data);
|
||||||
|
|
||||||
|
g_free(node);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void platform_bus_fdt_notify(Notifier *notifier, void *data)
|
||||||
|
{
|
||||||
|
PlatformBusFDTNotifierParams *p = DO_UPCAST(PlatformBusFDTNotifierParams,
|
||||||
|
notifier, notifier);
|
||||||
|
|
||||||
|
add_all_platform_bus_fdt_nodes(p->fdt_params);
|
||||||
|
g_free(p->fdt_params);
|
||||||
|
g_free(p);
|
||||||
|
}
|
||||||
|
|
||||||
|
void arm_register_platform_bus_fdt_creator(ARMPlatformBusFDTParams *fdt_params)
|
||||||
|
{
|
||||||
|
PlatformBusFDTNotifierParams *p = g_new(PlatformBusFDTNotifierParams, 1);
|
||||||
|
|
||||||
|
p->fdt_params = fdt_params;
|
||||||
|
p->notifier.notify = platform_bus_fdt_notify;
|
||||||
|
qemu_add_machine_init_done_notifier(&p->notifier);
|
||||||
|
}
|
||||||
@@ -525,7 +525,7 @@ static pflash_t *ve_pflash_cfi01_register(hwaddr base, const char *name,
|
|||||||
qdev_prop_set_uint64(dev, "sector-length", VEXPRESS_FLASH_SECT_SIZE);
|
qdev_prop_set_uint64(dev, "sector-length", VEXPRESS_FLASH_SECT_SIZE);
|
||||||
qdev_prop_set_uint8(dev, "width", 4);
|
qdev_prop_set_uint8(dev, "width", 4);
|
||||||
qdev_prop_set_uint8(dev, "device-width", 2);
|
qdev_prop_set_uint8(dev, "device-width", 2);
|
||||||
qdev_prop_set_uint8(dev, "big-endian", 0);
|
qdev_prop_set_bit(dev, "big-endian", false);
|
||||||
qdev_prop_set_uint16(dev, "id0", 0x89);
|
qdev_prop_set_uint16(dev, "id0", 0x89);
|
||||||
qdev_prop_set_uint16(dev, "id1", 0x18);
|
qdev_prop_set_uint16(dev, "id1", 0x18);
|
||||||
qdev_prop_set_uint16(dev, "id2", 0x00);
|
qdev_prop_set_uint16(dev, "id2", 0x00);
|
||||||
|
|||||||
644
hw/arm/virt-acpi-build.c
Normal file
644
hw/arm/virt-acpi-build.c
Normal file
@@ -0,0 +1,644 @@
|
|||||||
|
/* Support for generating ACPI tables and passing them to Guests
|
||||||
|
*
|
||||||
|
* ARM virt ACPI generation
|
||||||
|
*
|
||||||
|
* Copyright (C) 2008-2010 Kevin O'Connor <kevin@koconnor.net>
|
||||||
|
* Copyright (C) 2006 Fabrice Bellard
|
||||||
|
* Copyright (C) 2013 Red Hat Inc
|
||||||
|
*
|
||||||
|
* Author: Michael S. Tsirkin <mst@redhat.com>
|
||||||
|
*
|
||||||
|
* Copyright (c) 2015 HUAWEI TECHNOLOGIES CO.,LTD.
|
||||||
|
*
|
||||||
|
* Author: Shannon Zhao <zhaoshenglong@huawei.com>
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
|
||||||
|
* You should have received a copy of the GNU General Public License along
|
||||||
|
* with this program; if not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "qemu-common.h"
|
||||||
|
#include "hw/arm/virt-acpi-build.h"
|
||||||
|
#include "qemu/bitmap.h"
|
||||||
|
#include "trace.h"
|
||||||
|
#include "qom/cpu.h"
|
||||||
|
#include "target-arm/cpu.h"
|
||||||
|
#include "hw/acpi/acpi-defs.h"
|
||||||
|
#include "hw/acpi/acpi.h"
|
||||||
|
#include "hw/nvram/fw_cfg.h"
|
||||||
|
#include "hw/acpi/bios-linker-loader.h"
|
||||||
|
#include "hw/loader.h"
|
||||||
|
#include "hw/hw.h"
|
||||||
|
#include "hw/acpi/aml-build.h"
|
||||||
|
#include "hw/pci/pcie_host.h"
|
||||||
|
#include "hw/pci/pci.h"
|
||||||
|
|
||||||
|
#define ARM_SPI_BASE 32
|
||||||
|
|
||||||
|
typedef struct VirtAcpiCpuInfo {
|
||||||
|
DECLARE_BITMAP(found_cpus, VIRT_ACPI_CPU_ID_LIMIT);
|
||||||
|
} VirtAcpiCpuInfo;
|
||||||
|
|
||||||
|
static void virt_acpi_get_cpu_info(VirtAcpiCpuInfo *cpuinfo)
|
||||||
|
{
|
||||||
|
CPUState *cpu;
|
||||||
|
|
||||||
|
memset(cpuinfo->found_cpus, 0, sizeof cpuinfo->found_cpus);
|
||||||
|
CPU_FOREACH(cpu) {
|
||||||
|
set_bit(cpu->cpu_index, cpuinfo->found_cpus);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void acpi_dsdt_add_cpus(Aml *scope, int smp_cpus)
|
||||||
|
{
|
||||||
|
uint16_t i;
|
||||||
|
|
||||||
|
for (i = 0; i < smp_cpus; i++) {
|
||||||
|
Aml *dev = aml_device("C%03x", i);
|
||||||
|
aml_append(dev, aml_name_decl("_HID", aml_string("ACPI0007")));
|
||||||
|
aml_append(dev, aml_name_decl("_UID", aml_int(i)));
|
||||||
|
aml_append(scope, dev);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void acpi_dsdt_add_uart(Aml *scope, const MemMapEntry *uart_memmap,
|
||||||
|
int uart_irq)
|
||||||
|
{
|
||||||
|
Aml *dev = aml_device("COM0");
|
||||||
|
aml_append(dev, aml_name_decl("_HID", aml_string("ARMH0011")));
|
||||||
|
aml_append(dev, aml_name_decl("_UID", aml_int(0)));
|
||||||
|
|
||||||
|
Aml *crs = aml_resource_template();
|
||||||
|
aml_append(crs, aml_memory32_fixed(uart_memmap->base,
|
||||||
|
uart_memmap->size, AML_READ_WRITE));
|
||||||
|
aml_append(crs,
|
||||||
|
aml_interrupt(AML_CONSUMER, AML_LEVEL, AML_ACTIVE_HIGH,
|
||||||
|
AML_EXCLUSIVE, uart_irq));
|
||||||
|
aml_append(dev, aml_name_decl("_CRS", crs));
|
||||||
|
aml_append(scope, dev);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void acpi_dsdt_add_rtc(Aml *scope, const MemMapEntry *rtc_memmap,
|
||||||
|
int rtc_irq)
|
||||||
|
{
|
||||||
|
Aml *dev = aml_device("RTC0");
|
||||||
|
aml_append(dev, aml_name_decl("_HID", aml_string("LNRO0013")));
|
||||||
|
aml_append(dev, aml_name_decl("_UID", aml_int(0)));
|
||||||
|
|
||||||
|
Aml *crs = aml_resource_template();
|
||||||
|
aml_append(crs, aml_memory32_fixed(rtc_memmap->base,
|
||||||
|
rtc_memmap->size, AML_READ_WRITE));
|
||||||
|
aml_append(crs,
|
||||||
|
aml_interrupt(AML_CONSUMER, AML_LEVEL, AML_ACTIVE_HIGH,
|
||||||
|
AML_EXCLUSIVE, rtc_irq));
|
||||||
|
aml_append(dev, aml_name_decl("_CRS", crs));
|
||||||
|
aml_append(scope, dev);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void acpi_dsdt_add_flash(Aml *scope, const MemMapEntry *flash_memmap)
|
||||||
|
{
|
||||||
|
Aml *dev, *crs;
|
||||||
|
hwaddr base = flash_memmap->base;
|
||||||
|
hwaddr size = flash_memmap->size;
|
||||||
|
|
||||||
|
dev = aml_device("FLS0");
|
||||||
|
aml_append(dev, aml_name_decl("_HID", aml_string("LNRO0015")));
|
||||||
|
aml_append(dev, aml_name_decl("_UID", aml_int(0)));
|
||||||
|
|
||||||
|
crs = aml_resource_template();
|
||||||
|
aml_append(crs, aml_memory32_fixed(base, size, AML_READ_WRITE));
|
||||||
|
aml_append(dev, aml_name_decl("_CRS", crs));
|
||||||
|
aml_append(scope, dev);
|
||||||
|
|
||||||
|
dev = aml_device("FLS1");
|
||||||
|
aml_append(dev, aml_name_decl("_HID", aml_string("LNRO0015")));
|
||||||
|
aml_append(dev, aml_name_decl("_UID", aml_int(1)));
|
||||||
|
crs = aml_resource_template();
|
||||||
|
aml_append(crs, aml_memory32_fixed(base + size, size, AML_READ_WRITE));
|
||||||
|
aml_append(dev, aml_name_decl("_CRS", crs));
|
||||||
|
aml_append(scope, dev);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void acpi_dsdt_add_virtio(Aml *scope,
|
||||||
|
const MemMapEntry *virtio_mmio_memmap,
|
||||||
|
int mmio_irq, int num)
|
||||||
|
{
|
||||||
|
hwaddr base = virtio_mmio_memmap->base;
|
||||||
|
hwaddr size = virtio_mmio_memmap->size;
|
||||||
|
int irq = mmio_irq;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i = 0; i < num; i++) {
|
||||||
|
Aml *dev = aml_device("VR%02u", i);
|
||||||
|
aml_append(dev, aml_name_decl("_HID", aml_string("LNRO0005")));
|
||||||
|
aml_append(dev, aml_name_decl("_UID", aml_int(i)));
|
||||||
|
|
||||||
|
Aml *crs = aml_resource_template();
|
||||||
|
aml_append(crs, aml_memory32_fixed(base, size, AML_READ_WRITE));
|
||||||
|
aml_append(crs,
|
||||||
|
aml_interrupt(AML_CONSUMER, AML_LEVEL, AML_ACTIVE_HIGH,
|
||||||
|
AML_EXCLUSIVE, irq + i));
|
||||||
|
aml_append(dev, aml_name_decl("_CRS", crs));
|
||||||
|
aml_append(scope, dev);
|
||||||
|
base += size;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void acpi_dsdt_add_pci(Aml *scope, const MemMapEntry *memmap, int irq)
|
||||||
|
{
|
||||||
|
Aml *method, *crs, *ifctx, *UUID, *ifctx1, *elsectx, *buf;
|
||||||
|
int i, bus_no;
|
||||||
|
hwaddr base_mmio = memmap[VIRT_PCIE_MMIO].base;
|
||||||
|
hwaddr size_mmio = memmap[VIRT_PCIE_MMIO].size;
|
||||||
|
hwaddr base_pio = memmap[VIRT_PCIE_PIO].base;
|
||||||
|
hwaddr size_pio = memmap[VIRT_PCIE_PIO].size;
|
||||||
|
hwaddr base_ecam = memmap[VIRT_PCIE_ECAM].base;
|
||||||
|
hwaddr size_ecam = memmap[VIRT_PCIE_ECAM].size;
|
||||||
|
int nr_pcie_buses = size_ecam / PCIE_MMCFG_SIZE_MIN;
|
||||||
|
|
||||||
|
Aml *dev = aml_device("%s", "PCI0");
|
||||||
|
aml_append(dev, aml_name_decl("_HID", aml_string("PNP0A08")));
|
||||||
|
aml_append(dev, aml_name_decl("_CID", aml_string("PNP0A03")));
|
||||||
|
aml_append(dev, aml_name_decl("_SEG", aml_int(0)));
|
||||||
|
aml_append(dev, aml_name_decl("_BBN", aml_int(0)));
|
||||||
|
aml_append(dev, aml_name_decl("_ADR", aml_int(0)));
|
||||||
|
aml_append(dev, aml_name_decl("_UID", aml_string("PCI0")));
|
||||||
|
aml_append(dev, aml_name_decl("_STR", aml_unicode("PCIe 0 Device")));
|
||||||
|
|
||||||
|
/* Declare the PCI Routing Table. */
|
||||||
|
Aml *rt_pkg = aml_package(nr_pcie_buses * PCI_NUM_PINS);
|
||||||
|
for (bus_no = 0; bus_no < nr_pcie_buses; bus_no++) {
|
||||||
|
for (i = 0; i < PCI_NUM_PINS; i++) {
|
||||||
|
int gsi = (i + bus_no) % PCI_NUM_PINS;
|
||||||
|
Aml *pkg = aml_package(4);
|
||||||
|
aml_append(pkg, aml_int((bus_no << 16) | 0xFFFF));
|
||||||
|
aml_append(pkg, aml_int(i));
|
||||||
|
aml_append(pkg, aml_name("GSI%d", gsi));
|
||||||
|
aml_append(pkg, aml_int(0));
|
||||||
|
aml_append(rt_pkg, pkg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
aml_append(dev, aml_name_decl("_PRT", rt_pkg));
|
||||||
|
|
||||||
|
/* Create GSI link device */
|
||||||
|
for (i = 0; i < PCI_NUM_PINS; i++) {
|
||||||
|
Aml *dev_gsi = aml_device("GSI%d", i);
|
||||||
|
aml_append(dev_gsi, aml_name_decl("_HID", aml_string("PNP0C0F")));
|
||||||
|
aml_append(dev_gsi, aml_name_decl("_UID", aml_int(0)));
|
||||||
|
crs = aml_resource_template();
|
||||||
|
aml_append(crs,
|
||||||
|
aml_interrupt(AML_CONSUMER, AML_LEVEL, AML_ACTIVE_HIGH,
|
||||||
|
AML_EXCLUSIVE, irq + i));
|
||||||
|
aml_append(dev_gsi, aml_name_decl("_PRS", crs));
|
||||||
|
crs = aml_resource_template();
|
||||||
|
aml_append(crs,
|
||||||
|
aml_interrupt(AML_CONSUMER, AML_LEVEL, AML_ACTIVE_HIGH,
|
||||||
|
AML_EXCLUSIVE, irq + i));
|
||||||
|
aml_append(dev_gsi, aml_name_decl("_CRS", crs));
|
||||||
|
method = aml_method("_SRS", 1);
|
||||||
|
aml_append(dev_gsi, method);
|
||||||
|
aml_append(dev, dev_gsi);
|
||||||
|
}
|
||||||
|
|
||||||
|
method = aml_method("_CBA", 0);
|
||||||
|
aml_append(method, aml_return(aml_int(base_ecam)));
|
||||||
|
aml_append(dev, method);
|
||||||
|
|
||||||
|
method = aml_method("_CRS", 0);
|
||||||
|
Aml *rbuf = aml_resource_template();
|
||||||
|
aml_append(rbuf,
|
||||||
|
aml_word_bus_number(AML_MIN_FIXED, AML_MAX_FIXED, AML_POS_DECODE,
|
||||||
|
0x0000, 0x0000, nr_pcie_buses - 1, 0x0000,
|
||||||
|
nr_pcie_buses));
|
||||||
|
aml_append(rbuf,
|
||||||
|
aml_dword_memory(AML_POS_DECODE, AML_MIN_FIXED, AML_MAX_FIXED,
|
||||||
|
AML_NON_CACHEABLE, AML_READ_WRITE, 0x0000, base_mmio,
|
||||||
|
base_mmio + size_mmio - 1, 0x0000, size_mmio));
|
||||||
|
aml_append(rbuf,
|
||||||
|
aml_dword_io(AML_MIN_FIXED, AML_MAX_FIXED, AML_POS_DECODE,
|
||||||
|
AML_ENTIRE_RANGE, 0x0000, 0x0000, size_pio - 1, base_pio,
|
||||||
|
size_pio));
|
||||||
|
|
||||||
|
aml_append(method, aml_name_decl("RBUF", rbuf));
|
||||||
|
aml_append(method, aml_return(rbuf));
|
||||||
|
aml_append(dev, method);
|
||||||
|
|
||||||
|
/* Declare an _OSC (OS Control Handoff) method */
|
||||||
|
aml_append(dev, aml_name_decl("SUPP", aml_int(0)));
|
||||||
|
aml_append(dev, aml_name_decl("CTRL", aml_int(0)));
|
||||||
|
method = aml_method("_OSC", 4);
|
||||||
|
aml_append(method,
|
||||||
|
aml_create_dword_field(aml_arg(3), aml_int(0), "CDW1"));
|
||||||
|
|
||||||
|
/* PCI Firmware Specification 3.0
|
||||||
|
* 4.5.1. _OSC Interface for PCI Host Bridge Devices
|
||||||
|
* The _OSC interface for a PCI/PCI-X/PCI Express hierarchy is
|
||||||
|
* identified by the Universal Unique IDentifier (UUID)
|
||||||
|
* 33DB4D5B-1FF7-401C-9657-7441C03DD766
|
||||||
|
*/
|
||||||
|
UUID = aml_touuid("33DB4D5B-1FF7-401C-9657-7441C03DD766");
|
||||||
|
ifctx = aml_if(aml_equal(aml_arg(0), UUID));
|
||||||
|
aml_append(ifctx,
|
||||||
|
aml_create_dword_field(aml_arg(3), aml_int(4), "CDW2"));
|
||||||
|
aml_append(ifctx,
|
||||||
|
aml_create_dword_field(aml_arg(3), aml_int(8), "CDW3"));
|
||||||
|
aml_append(ifctx, aml_store(aml_name("CDW2"), aml_name("SUPP")));
|
||||||
|
aml_append(ifctx, aml_store(aml_name("CDW3"), aml_name("CTRL")));
|
||||||
|
aml_append(ifctx, aml_store(aml_and(aml_name("CTRL"), aml_int(0x1D)),
|
||||||
|
aml_name("CTRL")));
|
||||||
|
|
||||||
|
ifctx1 = aml_if(aml_lnot(aml_equal(aml_arg(1), aml_int(0x1))));
|
||||||
|
aml_append(ifctx1, aml_store(aml_or(aml_name("CDW1"), aml_int(0x08)),
|
||||||
|
aml_name("CDW1")));
|
||||||
|
aml_append(ifctx, ifctx1);
|
||||||
|
|
||||||
|
ifctx1 = aml_if(aml_lnot(aml_equal(aml_name("CDW3"), aml_name("CTRL"))));
|
||||||
|
aml_append(ifctx1, aml_store(aml_or(aml_name("CDW1"), aml_int(0x10)),
|
||||||
|
aml_name("CDW1")));
|
||||||
|
aml_append(ifctx, ifctx1);
|
||||||
|
|
||||||
|
aml_append(ifctx, aml_store(aml_name("CTRL"), aml_name("CDW3")));
|
||||||
|
aml_append(ifctx, aml_return(aml_arg(3)));
|
||||||
|
aml_append(method, ifctx);
|
||||||
|
|
||||||
|
elsectx = aml_else();
|
||||||
|
aml_append(elsectx, aml_store(aml_or(aml_name("CDW1"), aml_int(4)),
|
||||||
|
aml_name("CDW1")));
|
||||||
|
aml_append(elsectx, aml_return(aml_arg(3)));
|
||||||
|
aml_append(method, elsectx);
|
||||||
|
aml_append(dev, method);
|
||||||
|
|
||||||
|
method = aml_method("_DSM", 4);
|
||||||
|
|
||||||
|
/* PCI Firmware Specification 3.0
|
||||||
|
* 4.6.1. _DSM for PCI Express Slot Information
|
||||||
|
* The UUID in _DSM in this context is
|
||||||
|
* {E5C937D0-3553-4D7A-9117-EA4D19C3434D}
|
||||||
|
*/
|
||||||
|
UUID = aml_touuid("E5C937D0-3553-4D7A-9117-EA4D19C3434D");
|
||||||
|
ifctx = aml_if(aml_equal(aml_arg(0), UUID));
|
||||||
|
ifctx1 = aml_if(aml_equal(aml_arg(2), aml_int(0)));
|
||||||
|
uint8_t byte_list[1] = {1};
|
||||||
|
buf = aml_buffer(1, byte_list);
|
||||||
|
aml_append(ifctx1, aml_return(buf));
|
||||||
|
aml_append(ifctx, ifctx1);
|
||||||
|
aml_append(method, ifctx);
|
||||||
|
|
||||||
|
byte_list[0] = 0;
|
||||||
|
buf = aml_buffer(1, byte_list);
|
||||||
|
aml_append(method, aml_return(buf));
|
||||||
|
aml_append(dev, method);
|
||||||
|
|
||||||
|
Aml *dev_rp0 = aml_device("%s", "RP0");
|
||||||
|
aml_append(dev_rp0, aml_name_decl("_ADR", aml_int(0)));
|
||||||
|
aml_append(dev, dev_rp0);
|
||||||
|
aml_append(scope, dev);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* RSDP */
|
||||||
|
static GArray *
|
||||||
|
build_rsdp(GArray *rsdp_table, GArray *linker, unsigned rsdt)
|
||||||
|
{
|
||||||
|
AcpiRsdpDescriptor *rsdp = acpi_data_push(rsdp_table, sizeof *rsdp);
|
||||||
|
|
||||||
|
bios_linker_loader_alloc(linker, ACPI_BUILD_RSDP_FILE, 16,
|
||||||
|
true /* fseg memory */);
|
||||||
|
|
||||||
|
memcpy(&rsdp->signature, "RSD PTR ", sizeof(rsdp->signature));
|
||||||
|
memcpy(rsdp->oem_id, ACPI_BUILD_APPNAME6, sizeof(rsdp->oem_id));
|
||||||
|
rsdp->length = cpu_to_le32(sizeof(*rsdp));
|
||||||
|
rsdp->revision = 0x02;
|
||||||
|
|
||||||
|
/* Point to RSDT */
|
||||||
|
rsdp->rsdt_physical_address = cpu_to_le32(rsdt);
|
||||||
|
/* Address to be filled by Guest linker */
|
||||||
|
bios_linker_loader_add_pointer(linker, ACPI_BUILD_RSDP_FILE,
|
||||||
|
ACPI_BUILD_TABLE_FILE,
|
||||||
|
rsdp_table, &rsdp->rsdt_physical_address,
|
||||||
|
sizeof rsdp->rsdt_physical_address);
|
||||||
|
rsdp->checksum = 0;
|
||||||
|
/* Checksum to be filled by Guest linker */
|
||||||
|
bios_linker_loader_add_checksum(linker, ACPI_BUILD_RSDP_FILE,
|
||||||
|
rsdp, rsdp, sizeof *rsdp, &rsdp->checksum);
|
||||||
|
|
||||||
|
return rsdp_table;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
build_mcfg(GArray *table_data, GArray *linker, VirtGuestInfo *guest_info)
|
||||||
|
{
|
||||||
|
AcpiTableMcfg *mcfg;
|
||||||
|
const MemMapEntry *memmap = guest_info->memmap;
|
||||||
|
int len = sizeof(*mcfg) + sizeof(mcfg->allocation[0]);
|
||||||
|
|
||||||
|
mcfg = acpi_data_push(table_data, len);
|
||||||
|
mcfg->allocation[0].address = cpu_to_le64(memmap[VIRT_PCIE_ECAM].base);
|
||||||
|
|
||||||
|
/* Only a single allocation so no need to play with segments */
|
||||||
|
mcfg->allocation[0].pci_segment = cpu_to_le16(0);
|
||||||
|
mcfg->allocation[0].start_bus_number = 0;
|
||||||
|
mcfg->allocation[0].end_bus_number = (memmap[VIRT_PCIE_ECAM].size
|
||||||
|
/ PCIE_MMCFG_SIZE_MIN) - 1;
|
||||||
|
|
||||||
|
build_header(linker, table_data, (void *)mcfg, "MCFG", len, 5);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* GTDT */
|
||||||
|
static void
|
||||||
|
build_gtdt(GArray *table_data, GArray *linker)
|
||||||
|
{
|
||||||
|
int gtdt_start = table_data->len;
|
||||||
|
AcpiGenericTimerTable *gtdt;
|
||||||
|
|
||||||
|
gtdt = acpi_data_push(table_data, sizeof *gtdt);
|
||||||
|
/* The interrupt values are the same with the device tree when adding 16 */
|
||||||
|
gtdt->secure_el1_interrupt = ARCH_TIMER_S_EL1_IRQ + 16;
|
||||||
|
gtdt->secure_el1_flags = ACPI_EDGE_SENSITIVE;
|
||||||
|
|
||||||
|
gtdt->non_secure_el1_interrupt = ARCH_TIMER_NS_EL1_IRQ + 16;
|
||||||
|
gtdt->non_secure_el1_flags = ACPI_EDGE_SENSITIVE;
|
||||||
|
|
||||||
|
gtdt->virtual_timer_interrupt = ARCH_TIMER_VIRT_IRQ + 16;
|
||||||
|
gtdt->virtual_timer_flags = ACPI_EDGE_SENSITIVE;
|
||||||
|
|
||||||
|
gtdt->non_secure_el2_interrupt = ARCH_TIMER_NS_EL2_IRQ + 16;
|
||||||
|
gtdt->non_secure_el2_flags = ACPI_EDGE_SENSITIVE;
|
||||||
|
|
||||||
|
build_header(linker, table_data,
|
||||||
|
(void *)(table_data->data + gtdt_start), "GTDT",
|
||||||
|
table_data->len - gtdt_start, 5);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* MADT */
|
||||||
|
static void
|
||||||
|
build_madt(GArray *table_data, GArray *linker, VirtGuestInfo *guest_info,
|
||||||
|
VirtAcpiCpuInfo *cpuinfo)
|
||||||
|
{
|
||||||
|
int madt_start = table_data->len;
|
||||||
|
const MemMapEntry *memmap = guest_info->memmap;
|
||||||
|
AcpiMultipleApicTable *madt;
|
||||||
|
AcpiMadtGenericDistributor *gicd;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
madt = acpi_data_push(table_data, sizeof *madt);
|
||||||
|
|
||||||
|
for (i = 0; i < guest_info->smp_cpus; i++) {
|
||||||
|
AcpiMadtGenericInterrupt *gicc = acpi_data_push(table_data,
|
||||||
|
sizeof *gicc);
|
||||||
|
gicc->type = ACPI_APIC_GENERIC_INTERRUPT;
|
||||||
|
gicc->length = sizeof(*gicc);
|
||||||
|
gicc->base_address = memmap[VIRT_GIC_CPU].base;
|
||||||
|
gicc->cpu_interface_number = i;
|
||||||
|
gicc->arm_mpidr = i;
|
||||||
|
gicc->uid = i;
|
||||||
|
if (test_bit(i, cpuinfo->found_cpus)) {
|
||||||
|
gicc->flags = cpu_to_le32(ACPI_GICC_ENABLED);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
gicd = acpi_data_push(table_data, sizeof *gicd);
|
||||||
|
gicd->type = ACPI_APIC_GENERIC_DISTRIBUTOR;
|
||||||
|
gicd->length = sizeof(*gicd);
|
||||||
|
gicd->base_address = memmap[VIRT_GIC_DIST].base;
|
||||||
|
|
||||||
|
build_header(linker, table_data,
|
||||||
|
(void *)(table_data->data + madt_start), "APIC",
|
||||||
|
table_data->len - madt_start, 5);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* FADT */
|
||||||
|
static void
|
||||||
|
build_fadt(GArray *table_data, GArray *linker, unsigned dsdt)
|
||||||
|
{
|
||||||
|
AcpiFadtDescriptorRev5_1 *fadt = acpi_data_push(table_data, sizeof(*fadt));
|
||||||
|
|
||||||
|
/* Hardware Reduced = 1 and use PSCI 0.2+ and with HVC */
|
||||||
|
fadt->flags = cpu_to_le32(1 << ACPI_FADT_F_HW_REDUCED_ACPI);
|
||||||
|
fadt->arm_boot_flags = cpu_to_le16((1 << ACPI_FADT_ARM_USE_PSCI_G_0_2) |
|
||||||
|
(1 << ACPI_FADT_ARM_PSCI_USE_HVC));
|
||||||
|
|
||||||
|
/* ACPI v5.1 (fadt->revision.fadt->minor_revision) */
|
||||||
|
fadt->minor_revision = 0x1;
|
||||||
|
|
||||||
|
fadt->dsdt = cpu_to_le32(dsdt);
|
||||||
|
/* DSDT address to be filled by Guest linker */
|
||||||
|
bios_linker_loader_add_pointer(linker, ACPI_BUILD_TABLE_FILE,
|
||||||
|
ACPI_BUILD_TABLE_FILE,
|
||||||
|
table_data, &fadt->dsdt,
|
||||||
|
sizeof fadt->dsdt);
|
||||||
|
|
||||||
|
build_header(linker, table_data,
|
||||||
|
(void *)fadt, "FACP", sizeof(*fadt), 5);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* DSDT */
|
||||||
|
static void
|
||||||
|
build_dsdt(GArray *table_data, GArray *linker, VirtGuestInfo *guest_info)
|
||||||
|
{
|
||||||
|
Aml *scope, *dsdt;
|
||||||
|
const MemMapEntry *memmap = guest_info->memmap;
|
||||||
|
const int *irqmap = guest_info->irqmap;
|
||||||
|
|
||||||
|
dsdt = init_aml_allocator();
|
||||||
|
/* Reserve space for header */
|
||||||
|
acpi_data_push(dsdt->buf, sizeof(AcpiTableHeader));
|
||||||
|
|
||||||
|
scope = aml_scope("\\_SB");
|
||||||
|
acpi_dsdt_add_cpus(scope, guest_info->smp_cpus);
|
||||||
|
acpi_dsdt_add_uart(scope, &memmap[VIRT_UART],
|
||||||
|
(irqmap[VIRT_UART] + ARM_SPI_BASE));
|
||||||
|
acpi_dsdt_add_rtc(scope, &memmap[VIRT_RTC],
|
||||||
|
(irqmap[VIRT_RTC] + ARM_SPI_BASE));
|
||||||
|
acpi_dsdt_add_flash(scope, &memmap[VIRT_FLASH]);
|
||||||
|
acpi_dsdt_add_virtio(scope, &memmap[VIRT_MMIO],
|
||||||
|
(irqmap[VIRT_MMIO] + ARM_SPI_BASE), NUM_VIRTIO_TRANSPORTS);
|
||||||
|
acpi_dsdt_add_pci(scope, memmap, (irqmap[VIRT_PCIE] + ARM_SPI_BASE));
|
||||||
|
|
||||||
|
aml_append(dsdt, scope);
|
||||||
|
|
||||||
|
/* copy AML table into ACPI tables blob and patch header there */
|
||||||
|
g_array_append_vals(table_data, dsdt->buf->data, dsdt->buf->len);
|
||||||
|
build_header(linker, table_data,
|
||||||
|
(void *)(table_data->data + table_data->len - dsdt->buf->len),
|
||||||
|
"DSDT", dsdt->buf->len, 5);
|
||||||
|
free_aml_allocator();
|
||||||
|
}
|
||||||
|
|
||||||
|
typedef
|
||||||
|
struct AcpiBuildState {
|
||||||
|
/* Copy of table in RAM (for patching). */
|
||||||
|
MemoryRegion *table_mr;
|
||||||
|
MemoryRegion *rsdp_mr;
|
||||||
|
MemoryRegion *linker_mr;
|
||||||
|
/* Is table patched? */
|
||||||
|
bool patched;
|
||||||
|
VirtGuestInfo *guest_info;
|
||||||
|
} AcpiBuildState;
|
||||||
|
|
||||||
|
static
|
||||||
|
void virt_acpi_build(VirtGuestInfo *guest_info, AcpiBuildTables *tables)
|
||||||
|
{
|
||||||
|
GArray *table_offsets;
|
||||||
|
unsigned dsdt, rsdt;
|
||||||
|
VirtAcpiCpuInfo cpuinfo;
|
||||||
|
GArray *tables_blob = tables->table_data;
|
||||||
|
|
||||||
|
virt_acpi_get_cpu_info(&cpuinfo);
|
||||||
|
|
||||||
|
table_offsets = g_array_new(false, true /* clear */,
|
||||||
|
sizeof(uint32_t));
|
||||||
|
|
||||||
|
bios_linker_loader_alloc(tables->linker, ACPI_BUILD_TABLE_FILE,
|
||||||
|
64, false /* high memory */);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The ACPI v5.1 tables for Hardware-reduced ACPI platform are:
|
||||||
|
* RSDP
|
||||||
|
* RSDT
|
||||||
|
* FADT
|
||||||
|
* GTDT
|
||||||
|
* MADT
|
||||||
|
* DSDT
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* DSDT is pointed to by FADT */
|
||||||
|
dsdt = tables_blob->len;
|
||||||
|
build_dsdt(tables_blob, tables->linker, guest_info);
|
||||||
|
|
||||||
|
/* FADT MADT GTDT pointed to by RSDT */
|
||||||
|
acpi_add_table(table_offsets, tables_blob);
|
||||||
|
build_fadt(tables_blob, tables->linker, dsdt);
|
||||||
|
|
||||||
|
acpi_add_table(table_offsets, tables_blob);
|
||||||
|
build_madt(tables_blob, tables->linker, guest_info, &cpuinfo);
|
||||||
|
|
||||||
|
acpi_add_table(table_offsets, tables_blob);
|
||||||
|
build_gtdt(tables_blob, tables->linker);
|
||||||
|
|
||||||
|
acpi_add_table(table_offsets, tables_blob);
|
||||||
|
build_mcfg(tables_blob, tables->linker, guest_info);
|
||||||
|
|
||||||
|
/* RSDT is pointed to by RSDP */
|
||||||
|
rsdt = tables_blob->len;
|
||||||
|
build_rsdt(tables_blob, tables->linker, table_offsets);
|
||||||
|
|
||||||
|
/* RSDP is in FSEG memory, so allocate it separately */
|
||||||
|
build_rsdp(tables->rsdp, tables->linker, rsdt);
|
||||||
|
|
||||||
|
/* Cleanup memory that's no longer used. */
|
||||||
|
g_array_free(table_offsets, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void acpi_ram_update(MemoryRegion *mr, GArray *data)
|
||||||
|
{
|
||||||
|
uint32_t size = acpi_data_len(data);
|
||||||
|
|
||||||
|
/* Make sure RAM size is correct - in case it got changed
|
||||||
|
* e.g. by migration */
|
||||||
|
memory_region_ram_resize(mr, size, &error_abort);
|
||||||
|
|
||||||
|
memcpy(memory_region_get_ram_ptr(mr), data->data, size);
|
||||||
|
memory_region_set_dirty(mr, 0, size);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void virt_acpi_build_update(void *build_opaque, uint32_t offset)
|
||||||
|
{
|
||||||
|
AcpiBuildState *build_state = build_opaque;
|
||||||
|
AcpiBuildTables tables;
|
||||||
|
|
||||||
|
/* No state to update or already patched? Nothing to do. */
|
||||||
|
if (!build_state || build_state->patched) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
build_state->patched = true;
|
||||||
|
|
||||||
|
acpi_build_tables_init(&tables);
|
||||||
|
|
||||||
|
virt_acpi_build(build_state->guest_info, &tables);
|
||||||
|
|
||||||
|
acpi_ram_update(build_state->table_mr, tables.table_data);
|
||||||
|
acpi_ram_update(build_state->rsdp_mr, tables.rsdp);
|
||||||
|
acpi_ram_update(build_state->linker_mr, tables.linker);
|
||||||
|
|
||||||
|
|
||||||
|
acpi_build_tables_cleanup(&tables, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void virt_acpi_build_reset(void *build_opaque)
|
||||||
|
{
|
||||||
|
AcpiBuildState *build_state = build_opaque;
|
||||||
|
build_state->patched = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
static MemoryRegion *acpi_add_rom_blob(AcpiBuildState *build_state,
|
||||||
|
GArray *blob, const char *name,
|
||||||
|
uint64_t max_size)
|
||||||
|
{
|
||||||
|
return rom_add_blob(name, blob->data, acpi_data_len(blob), max_size, -1,
|
||||||
|
name, virt_acpi_build_update, build_state);
|
||||||
|
}
|
||||||
|
|
||||||
|
static const VMStateDescription vmstate_virt_acpi_build = {
|
||||||
|
.name = "virt_acpi_build",
|
||||||
|
.version_id = 1,
|
||||||
|
.minimum_version_id = 1,
|
||||||
|
.fields = (VMStateField[]) {
|
||||||
|
VMSTATE_BOOL(patched, AcpiBuildState),
|
||||||
|
VMSTATE_END_OF_LIST()
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
void virt_acpi_setup(VirtGuestInfo *guest_info)
|
||||||
|
{
|
||||||
|
AcpiBuildTables tables;
|
||||||
|
AcpiBuildState *build_state;
|
||||||
|
|
||||||
|
if (!guest_info->fw_cfg) {
|
||||||
|
trace_virt_acpi_setup();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!acpi_enabled) {
|
||||||
|
trace_virt_acpi_setup();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
build_state = g_malloc0(sizeof *build_state);
|
||||||
|
build_state->guest_info = guest_info;
|
||||||
|
|
||||||
|
acpi_build_tables_init(&tables);
|
||||||
|
virt_acpi_build(build_state->guest_info, &tables);
|
||||||
|
|
||||||
|
/* Now expose it all to Guest */
|
||||||
|
build_state->table_mr = acpi_add_rom_blob(build_state, tables.table_data,
|
||||||
|
ACPI_BUILD_TABLE_FILE,
|
||||||
|
ACPI_BUILD_TABLE_MAX_SIZE);
|
||||||
|
assert(build_state->table_mr != NULL);
|
||||||
|
|
||||||
|
build_state->linker_mr =
|
||||||
|
acpi_add_rom_blob(build_state, tables.linker, "etc/table-loader", 0);
|
||||||
|
|
||||||
|
fw_cfg_add_file(guest_info->fw_cfg, ACPI_BUILD_TPMLOG_FILE,
|
||||||
|
tables.tcpalog->data, acpi_data_len(tables.tcpalog));
|
||||||
|
|
||||||
|
build_state->rsdp_mr = acpi_add_rom_blob(build_state, tables.rsdp,
|
||||||
|
ACPI_BUILD_RSDP_FILE, 0);
|
||||||
|
|
||||||
|
qemu_register_reset(virt_acpi_build_reset, build_state);
|
||||||
|
virt_acpi_build_reset(build_state);
|
||||||
|
vmstate_register(NULL, 0, &vmstate_virt_acpi_build, build_state);
|
||||||
|
|
||||||
|
/* Cleanup tables but don't free the memory: we track it
|
||||||
|
* in build_state.
|
||||||
|
*/
|
||||||
|
acpi_build_tables_cleanup(&tables, false);
|
||||||
|
}
|
||||||
236
hw/arm/virt.c
236
hw/arm/virt.c
@@ -31,6 +31,7 @@
|
|||||||
#include "hw/sysbus.h"
|
#include "hw/sysbus.h"
|
||||||
#include "hw/arm/arm.h"
|
#include "hw/arm/arm.h"
|
||||||
#include "hw/arm/primecell.h"
|
#include "hw/arm/primecell.h"
|
||||||
|
#include "hw/arm/virt.h"
|
||||||
#include "hw/devices.h"
|
#include "hw/devices.h"
|
||||||
#include "net/net.h"
|
#include "net/net.h"
|
||||||
#include "sysemu/block-backend.h"
|
#include "sysemu/block-backend.h"
|
||||||
@@ -43,11 +44,12 @@
|
|||||||
#include "qemu/bitops.h"
|
#include "qemu/bitops.h"
|
||||||
#include "qemu/error-report.h"
|
#include "qemu/error-report.h"
|
||||||
#include "hw/pci-host/gpex.h"
|
#include "hw/pci-host/gpex.h"
|
||||||
|
#include "hw/arm/virt-acpi-build.h"
|
||||||
#define NUM_VIRTIO_TRANSPORTS 32
|
#include "hw/arm/sysbus-fdt.h"
|
||||||
|
#include "hw/platform-bus.h"
|
||||||
|
|
||||||
/* Number of external interrupt lines to configure the GIC with */
|
/* Number of external interrupt lines to configure the GIC with */
|
||||||
#define NUM_IRQS 128
|
#define NUM_IRQS 256
|
||||||
|
|
||||||
#define GIC_FDT_IRQ_TYPE_SPI 0
|
#define GIC_FDT_IRQ_TYPE_SPI 0
|
||||||
#define GIC_FDT_IRQ_TYPE_PPI 1
|
#define GIC_FDT_IRQ_TYPE_PPI 1
|
||||||
@@ -60,23 +62,9 @@
|
|||||||
#define GIC_FDT_IRQ_PPI_CPU_START 8
|
#define GIC_FDT_IRQ_PPI_CPU_START 8
|
||||||
#define GIC_FDT_IRQ_PPI_CPU_WIDTH 8
|
#define GIC_FDT_IRQ_PPI_CPU_WIDTH 8
|
||||||
|
|
||||||
enum {
|
#define PLATFORM_BUS_NUM_IRQS 64
|
||||||
VIRT_FLASH,
|
|
||||||
VIRT_MEM,
|
|
||||||
VIRT_CPUPERIPHS,
|
|
||||||
VIRT_GIC_DIST,
|
|
||||||
VIRT_GIC_CPU,
|
|
||||||
VIRT_UART,
|
|
||||||
VIRT_MMIO,
|
|
||||||
VIRT_RTC,
|
|
||||||
VIRT_FW_CFG,
|
|
||||||
VIRT_PCIE,
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef struct MemMapEntry {
|
static ARMPlatformBusSystemParams platform_bus_params;
|
||||||
hwaddr base;
|
|
||||||
hwaddr size;
|
|
||||||
} MemMapEntry;
|
|
||||||
|
|
||||||
typedef struct VirtBoardInfo {
|
typedef struct VirtBoardInfo {
|
||||||
struct arm_boot_info bootinfo;
|
struct arm_boot_info bootinfo;
|
||||||
@@ -87,6 +75,8 @@ typedef struct VirtBoardInfo {
|
|||||||
void *fdt;
|
void *fdt;
|
||||||
int fdt_size;
|
int fdt_size;
|
||||||
uint32_t clock_phandle;
|
uint32_t clock_phandle;
|
||||||
|
uint32_t gic_phandle;
|
||||||
|
uint32_t v2m_phandle;
|
||||||
} VirtBoardInfo;
|
} VirtBoardInfo;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
@@ -121,25 +111,22 @@ typedef struct {
|
|||||||
*/
|
*/
|
||||||
static const MemMapEntry a15memmap[] = {
|
static const MemMapEntry a15memmap[] = {
|
||||||
/* Space up to 0x8000000 is reserved for a boot ROM */
|
/* Space up to 0x8000000 is reserved for a boot ROM */
|
||||||
[VIRT_FLASH] = { 0, 0x08000000 },
|
[VIRT_FLASH] = { 0, 0x08000000 },
|
||||||
[VIRT_CPUPERIPHS] = { 0x08000000, 0x00020000 },
|
[VIRT_CPUPERIPHS] = { 0x08000000, 0x00020000 },
|
||||||
/* GIC distributor and CPU interfaces sit inside the CPU peripheral space */
|
/* GIC distributor and CPU interfaces sit inside the CPU peripheral space */
|
||||||
[VIRT_GIC_DIST] = { 0x08000000, 0x00010000 },
|
[VIRT_GIC_DIST] = { 0x08000000, 0x00010000 },
|
||||||
[VIRT_GIC_CPU] = { 0x08010000, 0x00010000 },
|
[VIRT_GIC_CPU] = { 0x08010000, 0x00010000 },
|
||||||
[VIRT_UART] = { 0x09000000, 0x00001000 },
|
[VIRT_GIC_V2M] = { 0x08020000, 0x00001000 },
|
||||||
[VIRT_RTC] = { 0x09010000, 0x00001000 },
|
[VIRT_UART] = { 0x09000000, 0x00001000 },
|
||||||
[VIRT_FW_CFG] = { 0x09020000, 0x0000000a },
|
[VIRT_RTC] = { 0x09010000, 0x00001000 },
|
||||||
[VIRT_MMIO] = { 0x0a000000, 0x00000200 },
|
[VIRT_FW_CFG] = { 0x09020000, 0x0000000a },
|
||||||
|
[VIRT_MMIO] = { 0x0a000000, 0x00000200 },
|
||||||
/* ...repeating for a total of NUM_VIRTIO_TRANSPORTS, each of that size */
|
/* ...repeating for a total of NUM_VIRTIO_TRANSPORTS, each of that size */
|
||||||
/*
|
[VIRT_PLATFORM_BUS] = { 0x0c000000, 0x02000000 },
|
||||||
* PCIE verbose map:
|
[VIRT_PCIE_MMIO] = { 0x10000000, 0x2eff0000 },
|
||||||
*
|
[VIRT_PCIE_PIO] = { 0x3eff0000, 0x00010000 },
|
||||||
* MMIO window { 0x10000000, 0x2eff0000 },
|
[VIRT_PCIE_ECAM] = { 0x3f000000, 0x01000000 },
|
||||||
* PIO window { 0x3eff0000, 0x00010000 },
|
[VIRT_MEM] = { 0x40000000, 30ULL * 1024 * 1024 * 1024 },
|
||||||
* ECAM { 0x3f000000, 0x01000000 },
|
|
||||||
*/
|
|
||||||
[VIRT_PCIE] = { 0x10000000, 0x30000000 },
|
|
||||||
[VIRT_MEM] = { 0x40000000, 30ULL * 1024 * 1024 * 1024 },
|
|
||||||
};
|
};
|
||||||
|
|
||||||
static const int a15irqmap[] = {
|
static const int a15irqmap[] = {
|
||||||
@@ -147,6 +134,8 @@ static const int a15irqmap[] = {
|
|||||||
[VIRT_RTC] = 2,
|
[VIRT_RTC] = 2,
|
||||||
[VIRT_PCIE] = 3, /* ... to 6 */
|
[VIRT_PCIE] = 3, /* ... to 6 */
|
||||||
[VIRT_MMIO] = 16, /* ...to 16 + NUM_VIRTIO_TRANSPORTS - 1 */
|
[VIRT_MMIO] = 16, /* ...to 16 + NUM_VIRTIO_TRANSPORTS - 1 */
|
||||||
|
[VIRT_GIC_V2M] = 48, /* ...to 48 + NUM_GICV2M_SPIS - 1 */
|
||||||
|
[VIRT_PLATFORM_BUS] = 112, /* ...to 112 + PLATFORM_BUS_NUM_IRQS -1 */
|
||||||
};
|
};
|
||||||
|
|
||||||
static VirtBoardInfo machines[] = {
|
static VirtBoardInfo machines[] = {
|
||||||
@@ -289,10 +278,10 @@ static void fdt_add_timer_nodes(const VirtBoardInfo *vbi)
|
|||||||
"arm,armv7-timer");
|
"arm,armv7-timer");
|
||||||
}
|
}
|
||||||
qemu_fdt_setprop_cells(vbi->fdt, "/timer", "interrupts",
|
qemu_fdt_setprop_cells(vbi->fdt, "/timer", "interrupts",
|
||||||
GIC_FDT_IRQ_TYPE_PPI, 13, irqflags,
|
GIC_FDT_IRQ_TYPE_PPI, ARCH_TIMER_S_EL1_IRQ, irqflags,
|
||||||
GIC_FDT_IRQ_TYPE_PPI, 14, irqflags,
|
GIC_FDT_IRQ_TYPE_PPI, ARCH_TIMER_NS_EL1_IRQ, irqflags,
|
||||||
GIC_FDT_IRQ_TYPE_PPI, 11, irqflags,
|
GIC_FDT_IRQ_TYPE_PPI, ARCH_TIMER_VIRT_IRQ, irqflags,
|
||||||
GIC_FDT_IRQ_TYPE_PPI, 10, irqflags);
|
GIC_FDT_IRQ_TYPE_PPI, ARCH_TIMER_NS_EL2_IRQ, irqflags);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void fdt_add_cpu_nodes(const VirtBoardInfo *vbi)
|
static void fdt_add_cpu_nodes(const VirtBoardInfo *vbi)
|
||||||
@@ -322,12 +311,23 @@ static void fdt_add_cpu_nodes(const VirtBoardInfo *vbi)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static uint32_t fdt_add_gic_node(const VirtBoardInfo *vbi)
|
static void fdt_add_v2m_gic_node(VirtBoardInfo *vbi)
|
||||||
{
|
{
|
||||||
uint32_t gic_phandle;
|
vbi->v2m_phandle = qemu_fdt_alloc_phandle(vbi->fdt);
|
||||||
|
qemu_fdt_add_subnode(vbi->fdt, "/intc/v2m");
|
||||||
|
qemu_fdt_setprop_string(vbi->fdt, "/intc/v2m", "compatible",
|
||||||
|
"arm,gic-v2m-frame");
|
||||||
|
qemu_fdt_setprop(vbi->fdt, "/intc/v2m", "msi-controller", NULL, 0);
|
||||||
|
qemu_fdt_setprop_sized_cells(vbi->fdt, "/intc/v2m", "reg",
|
||||||
|
2, vbi->memmap[VIRT_GIC_V2M].base,
|
||||||
|
2, vbi->memmap[VIRT_GIC_V2M].size);
|
||||||
|
qemu_fdt_setprop_cell(vbi->fdt, "/intc/v2m", "phandle", vbi->v2m_phandle);
|
||||||
|
}
|
||||||
|
|
||||||
gic_phandle = qemu_fdt_alloc_phandle(vbi->fdt);
|
static void fdt_add_gic_node(VirtBoardInfo *vbi)
|
||||||
qemu_fdt_setprop_cell(vbi->fdt, "/", "interrupt-parent", gic_phandle);
|
{
|
||||||
|
vbi->gic_phandle = qemu_fdt_alloc_phandle(vbi->fdt);
|
||||||
|
qemu_fdt_setprop_cell(vbi->fdt, "/", "interrupt-parent", vbi->gic_phandle);
|
||||||
|
|
||||||
qemu_fdt_add_subnode(vbi->fdt, "/intc");
|
qemu_fdt_add_subnode(vbi->fdt, "/intc");
|
||||||
/* 'cortex-a15-gic' means 'GIC v2' */
|
/* 'cortex-a15-gic' means 'GIC v2' */
|
||||||
@@ -340,12 +340,32 @@ static uint32_t fdt_add_gic_node(const VirtBoardInfo *vbi)
|
|||||||
2, vbi->memmap[VIRT_GIC_DIST].size,
|
2, vbi->memmap[VIRT_GIC_DIST].size,
|
||||||
2, vbi->memmap[VIRT_GIC_CPU].base,
|
2, vbi->memmap[VIRT_GIC_CPU].base,
|
||||||
2, vbi->memmap[VIRT_GIC_CPU].size);
|
2, vbi->memmap[VIRT_GIC_CPU].size);
|
||||||
qemu_fdt_setprop_cell(vbi->fdt, "/intc", "phandle", gic_phandle);
|
qemu_fdt_setprop_cell(vbi->fdt, "/intc", "#address-cells", 0x2);
|
||||||
|
qemu_fdt_setprop_cell(vbi->fdt, "/intc", "#size-cells", 0x2);
|
||||||
return gic_phandle;
|
qemu_fdt_setprop(vbi->fdt, "/intc", "ranges", NULL, 0);
|
||||||
|
qemu_fdt_setprop_cell(vbi->fdt, "/intc", "phandle", vbi->gic_phandle);
|
||||||
}
|
}
|
||||||
|
|
||||||
static uint32_t create_gic(const VirtBoardInfo *vbi, qemu_irq *pic)
|
static void create_v2m(VirtBoardInfo *vbi, qemu_irq *pic)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
int irq = vbi->irqmap[VIRT_GIC_V2M];
|
||||||
|
DeviceState *dev;
|
||||||
|
|
||||||
|
dev = qdev_create(NULL, "arm-gicv2m");
|
||||||
|
sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, vbi->memmap[VIRT_GIC_V2M].base);
|
||||||
|
qdev_prop_set_uint32(dev, "base-spi", irq);
|
||||||
|
qdev_prop_set_uint32(dev, "num-spi", NUM_GICV2M_SPIS);
|
||||||
|
qdev_init_nofail(dev);
|
||||||
|
|
||||||
|
for (i = 0; i < NUM_GICV2M_SPIS; i++) {
|
||||||
|
sysbus_connect_irq(SYS_BUS_DEVICE(dev), i, pic[irq + i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
fdt_add_v2m_gic_node(vbi);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void create_gic(VirtBoardInfo *vbi, qemu_irq *pic)
|
||||||
{
|
{
|
||||||
/* We create a standalone GIC v2 */
|
/* We create a standalone GIC v2 */
|
||||||
DeviceState *gicdev;
|
DeviceState *gicdev;
|
||||||
@@ -394,7 +414,9 @@ static uint32_t create_gic(const VirtBoardInfo *vbi, qemu_irq *pic)
|
|||||||
pic[i] = qdev_get_gpio_in(gicdev, i);
|
pic[i] = qdev_get_gpio_in(gicdev, i);
|
||||||
}
|
}
|
||||||
|
|
||||||
return fdt_add_gic_node(vbi);
|
fdt_add_gic_node(vbi);
|
||||||
|
|
||||||
|
create_v2m(vbi, pic);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void create_uart(const VirtBoardInfo *vbi, qemu_irq *pic)
|
static void create_uart(const VirtBoardInfo *vbi, qemu_irq *pic)
|
||||||
@@ -533,7 +555,7 @@ static void create_one_flash(const char *name, hwaddr flashbase,
|
|||||||
qdev_prop_set_uint64(dev, "sector-length", sectorlength);
|
qdev_prop_set_uint64(dev, "sector-length", sectorlength);
|
||||||
qdev_prop_set_uint8(dev, "width", 4);
|
qdev_prop_set_uint8(dev, "width", 4);
|
||||||
qdev_prop_set_uint8(dev, "device-width", 2);
|
qdev_prop_set_uint8(dev, "device-width", 2);
|
||||||
qdev_prop_set_uint8(dev, "big-endian", 0);
|
qdev_prop_set_bit(dev, "big-endian", false);
|
||||||
qdev_prop_set_uint16(dev, "id0", 0x89);
|
qdev_prop_set_uint16(dev, "id0", 0x89);
|
||||||
qdev_prop_set_uint16(dev, "id1", 0x18);
|
qdev_prop_set_uint16(dev, "id1", 0x18);
|
||||||
qdev_prop_set_uint16(dev, "id2", 0x00);
|
qdev_prop_set_uint16(dev, "id2", 0x00);
|
||||||
@@ -610,7 +632,7 @@ static void create_pcie_irq_map(const VirtBoardInfo *vbi, uint32_t gic_phandle,
|
|||||||
int first_irq, const char *nodename)
|
int first_irq, const char *nodename)
|
||||||
{
|
{
|
||||||
int devfn, pin;
|
int devfn, pin;
|
||||||
uint32_t full_irq_map[4 * 4 * 8] = { 0 };
|
uint32_t full_irq_map[4 * 4 * 10] = { 0 };
|
||||||
uint32_t *irq_map = full_irq_map;
|
uint32_t *irq_map = full_irq_map;
|
||||||
|
|
||||||
for (devfn = 0; devfn <= 0x18; devfn += 0x8) {
|
for (devfn = 0; devfn <= 0x18; devfn += 0x8) {
|
||||||
@@ -623,13 +645,13 @@ static void create_pcie_irq_map(const VirtBoardInfo *vbi, uint32_t gic_phandle,
|
|||||||
uint32_t map[] = {
|
uint32_t map[] = {
|
||||||
devfn << 8, 0, 0, /* devfn */
|
devfn << 8, 0, 0, /* devfn */
|
||||||
pin + 1, /* PCI pin */
|
pin + 1, /* PCI pin */
|
||||||
gic_phandle, irq_type, irq_nr, irq_level }; /* GIC irq */
|
gic_phandle, 0, 0, irq_type, irq_nr, irq_level }; /* GIC irq */
|
||||||
|
|
||||||
/* Convert map to big endian */
|
/* Convert map to big endian */
|
||||||
for (i = 0; i < 8; i++) {
|
for (i = 0; i < 10; i++) {
|
||||||
irq_map[i] = cpu_to_be32(map[i]);
|
irq_map[i] = cpu_to_be32(map[i]);
|
||||||
}
|
}
|
||||||
irq_map += 8;
|
irq_map += 10;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -641,19 +663,16 @@ static void create_pcie_irq_map(const VirtBoardInfo *vbi, uint32_t gic_phandle,
|
|||||||
0x7 /* PCI irq */);
|
0x7 /* PCI irq */);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void create_pcie(const VirtBoardInfo *vbi, qemu_irq *pic,
|
static void create_pcie(const VirtBoardInfo *vbi, qemu_irq *pic)
|
||||||
uint32_t gic_phandle)
|
|
||||||
{
|
{
|
||||||
hwaddr base = vbi->memmap[VIRT_PCIE].base;
|
hwaddr base_mmio = vbi->memmap[VIRT_PCIE_MMIO].base;
|
||||||
hwaddr size = vbi->memmap[VIRT_PCIE].size;
|
hwaddr size_mmio = vbi->memmap[VIRT_PCIE_MMIO].size;
|
||||||
hwaddr end = base + size;
|
hwaddr base_pio = vbi->memmap[VIRT_PCIE_PIO].base;
|
||||||
hwaddr size_mmio;
|
hwaddr size_pio = vbi->memmap[VIRT_PCIE_PIO].size;
|
||||||
hwaddr size_ioport = 64 * 1024;
|
hwaddr base_ecam = vbi->memmap[VIRT_PCIE_ECAM].base;
|
||||||
int nr_pcie_buses = 16;
|
hwaddr size_ecam = vbi->memmap[VIRT_PCIE_ECAM].size;
|
||||||
hwaddr size_ecam = PCIE_MMCFG_SIZE_MIN * nr_pcie_buses;
|
hwaddr base = base_mmio;
|
||||||
hwaddr base_mmio = base;
|
int nr_pcie_buses = size_ecam / PCIE_MMCFG_SIZE_MIN;
|
||||||
hwaddr base_ioport;
|
|
||||||
hwaddr base_ecam;
|
|
||||||
int irq = vbi->irqmap[VIRT_PCIE];
|
int irq = vbi->irqmap[VIRT_PCIE];
|
||||||
MemoryRegion *mmio_alias;
|
MemoryRegion *mmio_alias;
|
||||||
MemoryRegion *mmio_reg;
|
MemoryRegion *mmio_reg;
|
||||||
@@ -663,10 +682,6 @@ static void create_pcie(const VirtBoardInfo *vbi, qemu_irq *pic,
|
|||||||
char *nodename;
|
char *nodename;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
base_ecam = QEMU_ALIGN_DOWN(end - size_ecam, size_ecam);
|
|
||||||
base_ioport = QEMU_ALIGN_DOWN(base_ecam - size_ioport, size_ioport);
|
|
||||||
size_mmio = base_ioport - base;
|
|
||||||
|
|
||||||
dev = qdev_create(NULL, TYPE_GPEX_HOST);
|
dev = qdev_create(NULL, TYPE_GPEX_HOST);
|
||||||
qdev_init_nofail(dev);
|
qdev_init_nofail(dev);
|
||||||
|
|
||||||
@@ -689,7 +704,7 @@ static void create_pcie(const VirtBoardInfo *vbi, qemu_irq *pic,
|
|||||||
memory_region_add_subregion(get_system_memory(), base_mmio, mmio_alias);
|
memory_region_add_subregion(get_system_memory(), base_mmio, mmio_alias);
|
||||||
|
|
||||||
/* Map IO port space */
|
/* Map IO port space */
|
||||||
sysbus_mmio_map(SYS_BUS_DEVICE(dev), 2, base_ioport);
|
sysbus_mmio_map(SYS_BUS_DEVICE(dev), 2, base_pio);
|
||||||
|
|
||||||
for (i = 0; i < GPEX_NUM_IRQS; i++) {
|
for (i = 0; i < GPEX_NUM_IRQS; i++) {
|
||||||
sysbus_connect_irq(SYS_BUS_DEVICE(dev), i, pic[irq + i]);
|
sysbus_connect_irq(SYS_BUS_DEVICE(dev), i, pic[irq + i]);
|
||||||
@@ -705,20 +720,63 @@ static void create_pcie(const VirtBoardInfo *vbi, qemu_irq *pic,
|
|||||||
qemu_fdt_setprop_cells(vbi->fdt, nodename, "bus-range", 0,
|
qemu_fdt_setprop_cells(vbi->fdt, nodename, "bus-range", 0,
|
||||||
nr_pcie_buses - 1);
|
nr_pcie_buses - 1);
|
||||||
|
|
||||||
|
qemu_fdt_setprop_cells(vbi->fdt, nodename, "msi-parent", vbi->v2m_phandle);
|
||||||
|
|
||||||
qemu_fdt_setprop_sized_cells(vbi->fdt, nodename, "reg",
|
qemu_fdt_setprop_sized_cells(vbi->fdt, nodename, "reg",
|
||||||
2, base_ecam, 2, size_ecam);
|
2, base_ecam, 2, size_ecam);
|
||||||
qemu_fdt_setprop_sized_cells(vbi->fdt, nodename, "ranges",
|
qemu_fdt_setprop_sized_cells(vbi->fdt, nodename, "ranges",
|
||||||
1, FDT_PCI_RANGE_IOPORT, 2, 0,
|
1, FDT_PCI_RANGE_IOPORT, 2, 0,
|
||||||
2, base_ioport, 2, size_ioport,
|
2, base_pio, 2, size_pio,
|
||||||
1, FDT_PCI_RANGE_MMIO, 2, base_mmio,
|
1, FDT_PCI_RANGE_MMIO, 2, base_mmio,
|
||||||
2, base_mmio, 2, size_mmio);
|
2, base_mmio, 2, size_mmio);
|
||||||
|
|
||||||
qemu_fdt_setprop_cell(vbi->fdt, nodename, "#interrupt-cells", 1);
|
qemu_fdt_setprop_cell(vbi->fdt, nodename, "#interrupt-cells", 1);
|
||||||
create_pcie_irq_map(vbi, gic_phandle, irq, nodename);
|
create_pcie_irq_map(vbi, vbi->gic_phandle, irq, nodename);
|
||||||
|
|
||||||
g_free(nodename);
|
g_free(nodename);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void create_platform_bus(VirtBoardInfo *vbi, qemu_irq *pic)
|
||||||
|
{
|
||||||
|
DeviceState *dev;
|
||||||
|
SysBusDevice *s;
|
||||||
|
int i;
|
||||||
|
ARMPlatformBusFDTParams *fdt_params = g_new(ARMPlatformBusFDTParams, 1);
|
||||||
|
MemoryRegion *sysmem = get_system_memory();
|
||||||
|
|
||||||
|
platform_bus_params.platform_bus_base = vbi->memmap[VIRT_PLATFORM_BUS].base;
|
||||||
|
platform_bus_params.platform_bus_size = vbi->memmap[VIRT_PLATFORM_BUS].size;
|
||||||
|
platform_bus_params.platform_bus_first_irq = vbi->irqmap[VIRT_PLATFORM_BUS];
|
||||||
|
platform_bus_params.platform_bus_num_irqs = PLATFORM_BUS_NUM_IRQS;
|
||||||
|
|
||||||
|
fdt_params->system_params = &platform_bus_params;
|
||||||
|
fdt_params->binfo = &vbi->bootinfo;
|
||||||
|
fdt_params->intc = "/intc";
|
||||||
|
/*
|
||||||
|
* register a machine init done notifier that creates the device tree
|
||||||
|
* nodes of the platform bus and its children dynamic sysbus devices
|
||||||
|
*/
|
||||||
|
arm_register_platform_bus_fdt_creator(fdt_params);
|
||||||
|
|
||||||
|
dev = qdev_create(NULL, TYPE_PLATFORM_BUS_DEVICE);
|
||||||
|
dev->id = TYPE_PLATFORM_BUS_DEVICE;
|
||||||
|
qdev_prop_set_uint32(dev, "num_irqs",
|
||||||
|
platform_bus_params.platform_bus_num_irqs);
|
||||||
|
qdev_prop_set_uint32(dev, "mmio_size",
|
||||||
|
platform_bus_params.platform_bus_size);
|
||||||
|
qdev_init_nofail(dev);
|
||||||
|
s = SYS_BUS_DEVICE(dev);
|
||||||
|
|
||||||
|
for (i = 0; i < platform_bus_params.platform_bus_num_irqs; i++) {
|
||||||
|
int irqn = platform_bus_params.platform_bus_first_irq + i;
|
||||||
|
sysbus_connect_irq(s, i, pic[irqn]);
|
||||||
|
}
|
||||||
|
|
||||||
|
memory_region_add_subregion(sysmem,
|
||||||
|
platform_bus_params.platform_bus_base,
|
||||||
|
sysbus_mmio_get_region(s, 0));
|
||||||
|
}
|
||||||
|
|
||||||
static void *machvirt_dtb(const struct arm_boot_info *binfo, int *fdt_size)
|
static void *machvirt_dtb(const struct arm_boot_info *binfo, int *fdt_size)
|
||||||
{
|
{
|
||||||
const VirtBoardInfo *board = (const VirtBoardInfo *)binfo;
|
const VirtBoardInfo *board = (const VirtBoardInfo *)binfo;
|
||||||
@@ -727,6 +785,14 @@ static void *machvirt_dtb(const struct arm_boot_info *binfo, int *fdt_size)
|
|||||||
return board->fdt;
|
return board->fdt;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
void virt_guest_info_machine_done(Notifier *notifier, void *data)
|
||||||
|
{
|
||||||
|
VirtGuestInfoState *guest_info_state = container_of(notifier,
|
||||||
|
VirtGuestInfoState, machine_done);
|
||||||
|
virt_acpi_setup(&guest_info_state->info);
|
||||||
|
}
|
||||||
|
|
||||||
static void machvirt_init(MachineState *machine)
|
static void machvirt_init(MachineState *machine)
|
||||||
{
|
{
|
||||||
VirtMachineState *vms = VIRT_MACHINE(machine);
|
VirtMachineState *vms = VIRT_MACHINE(machine);
|
||||||
@@ -736,7 +802,8 @@ static void machvirt_init(MachineState *machine)
|
|||||||
MemoryRegion *ram = g_new(MemoryRegion, 1);
|
MemoryRegion *ram = g_new(MemoryRegion, 1);
|
||||||
const char *cpu_model = machine->cpu_model;
|
const char *cpu_model = machine->cpu_model;
|
||||||
VirtBoardInfo *vbi;
|
VirtBoardInfo *vbi;
|
||||||
uint32_t gic_phandle;
|
VirtGuestInfoState *guest_info_state = g_malloc0(sizeof *guest_info_state);
|
||||||
|
VirtGuestInfo *guest_info = &guest_info_state->info;
|
||||||
char **cpustr;
|
char **cpustr;
|
||||||
|
|
||||||
if (!cpu_model) {
|
if (!cpu_model) {
|
||||||
@@ -813,13 +880,13 @@ static void machvirt_init(MachineState *machine)
|
|||||||
|
|
||||||
create_flash(vbi);
|
create_flash(vbi);
|
||||||
|
|
||||||
gic_phandle = create_gic(vbi, pic);
|
create_gic(vbi, pic);
|
||||||
|
|
||||||
create_uart(vbi, pic);
|
create_uart(vbi, pic);
|
||||||
|
|
||||||
create_rtc(vbi, pic);
|
create_rtc(vbi, pic);
|
||||||
|
|
||||||
create_pcie(vbi, pic, gic_phandle);
|
create_pcie(vbi, pic);
|
||||||
|
|
||||||
/* Create mmio transports, so the user can create virtio backends
|
/* Create mmio transports, so the user can create virtio backends
|
||||||
* (which will be automatically plugged in to the transports). If
|
* (which will be automatically plugged in to the transports). If
|
||||||
@@ -828,6 +895,14 @@ static void machvirt_init(MachineState *machine)
|
|||||||
create_virtio_devices(vbi, pic);
|
create_virtio_devices(vbi, pic);
|
||||||
|
|
||||||
create_fw_cfg(vbi);
|
create_fw_cfg(vbi);
|
||||||
|
rom_set_fw(fw_cfg_find());
|
||||||
|
|
||||||
|
guest_info->smp_cpus = smp_cpus;
|
||||||
|
guest_info->fw_cfg = fw_cfg_find();
|
||||||
|
guest_info->memmap = vbi->memmap;
|
||||||
|
guest_info->irqmap = vbi->irqmap;
|
||||||
|
guest_info_state->machine_done.notify = virt_guest_info_machine_done;
|
||||||
|
qemu_add_machine_init_done_notifier(&guest_info_state->machine_done);
|
||||||
|
|
||||||
vbi->bootinfo.ram_size = machine->ram_size;
|
vbi->bootinfo.ram_size = machine->ram_size;
|
||||||
vbi->bootinfo.kernel_filename = machine->kernel_filename;
|
vbi->bootinfo.kernel_filename = machine->kernel_filename;
|
||||||
@@ -839,6 +914,14 @@ static void machvirt_init(MachineState *machine)
|
|||||||
vbi->bootinfo.get_dtb = machvirt_dtb;
|
vbi->bootinfo.get_dtb = machvirt_dtb;
|
||||||
vbi->bootinfo.firmware_loaded = bios_name || drive_get(IF_PFLASH, 0, 0);
|
vbi->bootinfo.firmware_loaded = bios_name || drive_get(IF_PFLASH, 0, 0);
|
||||||
arm_load_kernel(ARM_CPU(first_cpu), &vbi->bootinfo);
|
arm_load_kernel(ARM_CPU(first_cpu), &vbi->bootinfo);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* arm_load_kernel machine init done notifier registration must
|
||||||
|
* happen before the platform_bus_create call. In this latter,
|
||||||
|
* another notifier is registered which adds platform bus nodes.
|
||||||
|
* Notifiers are executed in registration reverse order.
|
||||||
|
*/
|
||||||
|
create_platform_bus(vbi, pic);
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool virt_get_secure(Object *obj, Error **errp)
|
static bool virt_get_secure(Object *obj, Error **errp)
|
||||||
@@ -877,6 +960,7 @@ static void virt_class_init(ObjectClass *oc, void *data)
|
|||||||
mc->desc = "ARM Virtual Machine",
|
mc->desc = "ARM Virtual Machine",
|
||||||
mc->init = machvirt_init;
|
mc->init = machvirt_init;
|
||||||
mc->max_cpus = 8;
|
mc->max_cpus = 8;
|
||||||
|
mc->has_dynamic_sysbus = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static const TypeInfo machvirt_info = {
|
static const TypeInfo machvirt_info = {
|
||||||
|
|||||||
298
hw/block/fdc.c
298
hw/block/fdc.c
@@ -324,7 +324,7 @@ static void fd_revalidate(FDrive *drv)
|
|||||||
/* Intel 82078 floppy disk controller emulation */
|
/* Intel 82078 floppy disk controller emulation */
|
||||||
|
|
||||||
static void fdctrl_reset(FDCtrl *fdctrl, int do_irq);
|
static void fdctrl_reset(FDCtrl *fdctrl, int do_irq);
|
||||||
static void fdctrl_reset_fifo(FDCtrl *fdctrl);
|
static void fdctrl_to_command_phase(FDCtrl *fdctrl);
|
||||||
static int fdctrl_transfer_handler (void *opaque, int nchan,
|
static int fdctrl_transfer_handler (void *opaque, int nchan,
|
||||||
int dma_pos, int dma_len);
|
int dma_pos, int dma_len);
|
||||||
static void fdctrl_raise_irq(FDCtrl *fdctrl);
|
static void fdctrl_raise_irq(FDCtrl *fdctrl);
|
||||||
@@ -495,6 +495,33 @@ enum {
|
|||||||
FD_DIR_DSKCHG = 0x80,
|
FD_DIR_DSKCHG = 0x80,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* See chapter 5.0 "Controller phases" of the spec:
|
||||||
|
*
|
||||||
|
* Command phase:
|
||||||
|
* The host writes a command and its parameters into the FIFO. The command
|
||||||
|
* phase is completed when all parameters for the command have been supplied,
|
||||||
|
* and execution phase is entered.
|
||||||
|
*
|
||||||
|
* Execution phase:
|
||||||
|
* Data transfers, either DMA or non-DMA. For non-DMA transfers, the FIFO
|
||||||
|
* contains the payload now, otherwise it's unused. When all bytes of the
|
||||||
|
* required data have been transferred, the state is switched to either result
|
||||||
|
* phase (if the command produces status bytes) or directly back into the
|
||||||
|
* command phase for the next command.
|
||||||
|
*
|
||||||
|
* Result phase:
|
||||||
|
* The host reads out the FIFO, which contains one or more result bytes now.
|
||||||
|
*/
|
||||||
|
enum {
|
||||||
|
/* Only for migration: reconstruct phase from registers like qemu 2.3 */
|
||||||
|
FD_PHASE_RECONSTRUCT = 0,
|
||||||
|
|
||||||
|
FD_PHASE_COMMAND = 1,
|
||||||
|
FD_PHASE_EXECUTION = 2,
|
||||||
|
FD_PHASE_RESULT = 3,
|
||||||
|
};
|
||||||
|
|
||||||
#define FD_MULTI_TRACK(state) ((state) & FD_STATE_MULTI)
|
#define FD_MULTI_TRACK(state) ((state) & FD_STATE_MULTI)
|
||||||
#define FD_FORMAT_CMD(state) ((state) & FD_STATE_FORMAT)
|
#define FD_FORMAT_CMD(state) ((state) & FD_STATE_FORMAT)
|
||||||
|
|
||||||
@@ -504,6 +531,7 @@ struct FDCtrl {
|
|||||||
/* Controller state */
|
/* Controller state */
|
||||||
QEMUTimer *result_timer;
|
QEMUTimer *result_timer;
|
||||||
int dma_chann;
|
int dma_chann;
|
||||||
|
uint8_t phase;
|
||||||
/* Controller's identification */
|
/* Controller's identification */
|
||||||
uint8_t version;
|
uint8_t version;
|
||||||
/* HW */
|
/* HW */
|
||||||
@@ -744,6 +772,28 @@ static const VMStateDescription vmstate_fdrive = {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Reconstructs the phase from register values according to the logic that was
|
||||||
|
* implemented in qemu 2.3. This is the default value that is used if the phase
|
||||||
|
* subsection is not present on migration.
|
||||||
|
*
|
||||||
|
* Don't change this function to reflect newer qemu versions, it is part of
|
||||||
|
* the migration ABI.
|
||||||
|
*/
|
||||||
|
static int reconstruct_phase(FDCtrl *fdctrl)
|
||||||
|
{
|
||||||
|
if (fdctrl->msr & FD_MSR_NONDMA) {
|
||||||
|
return FD_PHASE_EXECUTION;
|
||||||
|
} else if ((fdctrl->msr & FD_MSR_RQM) == 0) {
|
||||||
|
/* qemu 2.3 disabled RQM only during DMA transfers */
|
||||||
|
return FD_PHASE_EXECUTION;
|
||||||
|
} else if (fdctrl->msr & FD_MSR_DIO) {
|
||||||
|
return FD_PHASE_RESULT;
|
||||||
|
} else {
|
||||||
|
return FD_PHASE_COMMAND;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static void fdc_pre_save(void *opaque)
|
static void fdc_pre_save(void *opaque)
|
||||||
{
|
{
|
||||||
FDCtrl *s = opaque;
|
FDCtrl *s = opaque;
|
||||||
@@ -751,12 +801,24 @@ static void fdc_pre_save(void *opaque)
|
|||||||
s->dor_vmstate = s->dor | GET_CUR_DRV(s);
|
s->dor_vmstate = s->dor | GET_CUR_DRV(s);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int fdc_pre_load(void *opaque)
|
||||||
|
{
|
||||||
|
FDCtrl *s = opaque;
|
||||||
|
s->phase = FD_PHASE_RECONSTRUCT;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static int fdc_post_load(void *opaque, int version_id)
|
static int fdc_post_load(void *opaque, int version_id)
|
||||||
{
|
{
|
||||||
FDCtrl *s = opaque;
|
FDCtrl *s = opaque;
|
||||||
|
|
||||||
SET_CUR_DRV(s, s->dor_vmstate & FD_DOR_SELMASK);
|
SET_CUR_DRV(s, s->dor_vmstate & FD_DOR_SELMASK);
|
||||||
s->dor = s->dor_vmstate & ~FD_DOR_SELMASK;
|
s->dor = s->dor_vmstate & ~FD_DOR_SELMASK;
|
||||||
|
|
||||||
|
if (s->phase == FD_PHASE_RECONSTRUCT) {
|
||||||
|
s->phase = reconstruct_phase(s);
|
||||||
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -794,11 +856,29 @@ static const VMStateDescription vmstate_fdc_result_timer = {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static bool fdc_phase_needed(void *opaque)
|
||||||
|
{
|
||||||
|
FDCtrl *fdctrl = opaque;
|
||||||
|
|
||||||
|
return reconstruct_phase(fdctrl) != fdctrl->phase;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const VMStateDescription vmstate_fdc_phase = {
|
||||||
|
.name = "fdc/phase",
|
||||||
|
.version_id = 1,
|
||||||
|
.minimum_version_id = 1,
|
||||||
|
.fields = (VMStateField[]) {
|
||||||
|
VMSTATE_UINT8(phase, FDCtrl),
|
||||||
|
VMSTATE_END_OF_LIST()
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
static const VMStateDescription vmstate_fdc = {
|
static const VMStateDescription vmstate_fdc = {
|
||||||
.name = "fdc",
|
.name = "fdc",
|
||||||
.version_id = 2,
|
.version_id = 2,
|
||||||
.minimum_version_id = 2,
|
.minimum_version_id = 2,
|
||||||
.pre_save = fdc_pre_save,
|
.pre_save = fdc_pre_save,
|
||||||
|
.pre_load = fdc_pre_load,
|
||||||
.post_load = fdc_post_load,
|
.post_load = fdc_post_load,
|
||||||
.fields = (VMStateField[]) {
|
.fields = (VMStateField[]) {
|
||||||
/* Controller State */
|
/* Controller State */
|
||||||
@@ -838,6 +918,9 @@ static const VMStateDescription vmstate_fdc = {
|
|||||||
} , {
|
} , {
|
||||||
.vmsd = &vmstate_fdc_result_timer,
|
.vmsd = &vmstate_fdc_result_timer,
|
||||||
.needed = fdc_result_timer_needed,
|
.needed = fdc_result_timer_needed,
|
||||||
|
} , {
|
||||||
|
.vmsd = &vmstate_fdc_phase,
|
||||||
|
.needed = fdc_phase_needed,
|
||||||
} , {
|
} , {
|
||||||
/* empty */
|
/* empty */
|
||||||
}
|
}
|
||||||
@@ -918,7 +1001,7 @@ static void fdctrl_reset(FDCtrl *fdctrl, int do_irq)
|
|||||||
fdctrl->data_dir = FD_DIR_WRITE;
|
fdctrl->data_dir = FD_DIR_WRITE;
|
||||||
for (i = 0; i < MAX_FD; i++)
|
for (i = 0; i < MAX_FD; i++)
|
||||||
fd_recalibrate(&fdctrl->drives[i]);
|
fd_recalibrate(&fdctrl->drives[i]);
|
||||||
fdctrl_reset_fifo(fdctrl);
|
fdctrl_to_command_phase(fdctrl);
|
||||||
if (do_irq) {
|
if (do_irq) {
|
||||||
fdctrl->status0 |= FD_SR0_RDYCHG;
|
fdctrl->status0 |= FD_SR0_RDYCHG;
|
||||||
fdctrl_raise_irq(fdctrl);
|
fdctrl_raise_irq(fdctrl);
|
||||||
@@ -1134,17 +1217,22 @@ static uint32_t fdctrl_read_dir(FDCtrl *fdctrl)
|
|||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* FIFO state control */
|
/* Clear the FIFO and update the state for receiving the next command */
|
||||||
static void fdctrl_reset_fifo(FDCtrl *fdctrl)
|
static void fdctrl_to_command_phase(FDCtrl *fdctrl)
|
||||||
{
|
{
|
||||||
|
fdctrl->phase = FD_PHASE_COMMAND;
|
||||||
fdctrl->data_dir = FD_DIR_WRITE;
|
fdctrl->data_dir = FD_DIR_WRITE;
|
||||||
fdctrl->data_pos = 0;
|
fdctrl->data_pos = 0;
|
||||||
|
fdctrl->data_len = 1; /* Accept command byte, adjust for params later */
|
||||||
fdctrl->msr &= ~(FD_MSR_CMDBUSY | FD_MSR_DIO);
|
fdctrl->msr &= ~(FD_MSR_CMDBUSY | FD_MSR_DIO);
|
||||||
|
fdctrl->msr |= FD_MSR_RQM;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Set FIFO status for the host to read */
|
/* Update the state to allow the guest to read out the command status.
|
||||||
static void fdctrl_set_fifo(FDCtrl *fdctrl, int fifo_len)
|
* @fifo_len is the number of result bytes to be read out. */
|
||||||
|
static void fdctrl_to_result_phase(FDCtrl *fdctrl, int fifo_len)
|
||||||
{
|
{
|
||||||
|
fdctrl->phase = FD_PHASE_RESULT;
|
||||||
fdctrl->data_dir = FD_DIR_READ;
|
fdctrl->data_dir = FD_DIR_READ;
|
||||||
fdctrl->data_len = fifo_len;
|
fdctrl->data_len = fifo_len;
|
||||||
fdctrl->data_pos = 0;
|
fdctrl->data_pos = 0;
|
||||||
@@ -1157,7 +1245,7 @@ static void fdctrl_unimplemented(FDCtrl *fdctrl, int direction)
|
|||||||
qemu_log_mask(LOG_UNIMP, "fdc: unimplemented command 0x%02x\n",
|
qemu_log_mask(LOG_UNIMP, "fdc: unimplemented command 0x%02x\n",
|
||||||
fdctrl->fifo[0]);
|
fdctrl->fifo[0]);
|
||||||
fdctrl->fifo[0] = FD_SR0_INVCMD;
|
fdctrl->fifo[0] = FD_SR0_INVCMD;
|
||||||
fdctrl_set_fifo(fdctrl, 1);
|
fdctrl_to_result_phase(fdctrl, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Seek to next sector
|
/* Seek to next sector
|
||||||
@@ -1238,7 +1326,7 @@ static void fdctrl_stop_transfer(FDCtrl *fdctrl, uint8_t status0,
|
|||||||
fdctrl->msr |= FD_MSR_RQM | FD_MSR_DIO;
|
fdctrl->msr |= FD_MSR_RQM | FD_MSR_DIO;
|
||||||
fdctrl->msr &= ~FD_MSR_NONDMA;
|
fdctrl->msr &= ~FD_MSR_NONDMA;
|
||||||
|
|
||||||
fdctrl_set_fifo(fdctrl, 7);
|
fdctrl_to_result_phase(fdctrl, 7);
|
||||||
fdctrl_raise_irq(fdctrl);
|
fdctrl_raise_irq(fdctrl);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1352,7 +1440,7 @@ static void fdctrl_start_transfer(FDCtrl *fdctrl, int direction)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
FLOPPY_DPRINTF("start non-DMA transfer\n");
|
FLOPPY_DPRINTF("start non-DMA transfer\n");
|
||||||
fdctrl->msr |= FD_MSR_NONDMA;
|
fdctrl->msr |= FD_MSR_NONDMA | FD_MSR_RQM;
|
||||||
if (direction != FD_DIR_WRITE)
|
if (direction != FD_DIR_WRITE)
|
||||||
fdctrl->msr |= FD_MSR_DIO;
|
fdctrl->msr |= FD_MSR_DIO;
|
||||||
/* IO based transfer: calculate len */
|
/* IO based transfer: calculate len */
|
||||||
@@ -1505,9 +1593,16 @@ static uint32_t fdctrl_read_data(FDCtrl *fdctrl)
|
|||||||
FLOPPY_DPRINTF("error: controller not ready for reading\n");
|
FLOPPY_DPRINTF("error: controller not ready for reading\n");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* If data_len spans multiple sectors, the current position in the FIFO
|
||||||
|
* wraps around while fdctrl->data_pos is the real position in the whole
|
||||||
|
* request. */
|
||||||
pos = fdctrl->data_pos;
|
pos = fdctrl->data_pos;
|
||||||
pos %= FD_SECTOR_LEN;
|
pos %= FD_SECTOR_LEN;
|
||||||
if (fdctrl->msr & FD_MSR_NONDMA) {
|
|
||||||
|
switch (fdctrl->phase) {
|
||||||
|
case FD_PHASE_EXECUTION:
|
||||||
|
assert(fdctrl->msr & FD_MSR_NONDMA);
|
||||||
if (pos == 0) {
|
if (pos == 0) {
|
||||||
if (fdctrl->data_pos != 0)
|
if (fdctrl->data_pos != 0)
|
||||||
if (!fdctrl_seek_to_next_sect(fdctrl, cur_drv)) {
|
if (!fdctrl_seek_to_next_sect(fdctrl, cur_drv)) {
|
||||||
@@ -1523,20 +1618,28 @@ static uint32_t fdctrl_read_data(FDCtrl *fdctrl)
|
|||||||
memset(fdctrl->fifo, 0, FD_SECTOR_LEN);
|
memset(fdctrl->fifo, 0, FD_SECTOR_LEN);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
retval = fdctrl->fifo[pos];
|
if (++fdctrl->data_pos == fdctrl->data_len) {
|
||||||
if (++fdctrl->data_pos == fdctrl->data_len) {
|
fdctrl->msr &= ~FD_MSR_RQM;
|
||||||
fdctrl->data_pos = 0;
|
|
||||||
/* Switch from transfer mode to status mode
|
|
||||||
* then from status mode to command mode
|
|
||||||
*/
|
|
||||||
if (fdctrl->msr & FD_MSR_NONDMA) {
|
|
||||||
fdctrl_stop_transfer(fdctrl, 0x00, 0x00, 0x00);
|
fdctrl_stop_transfer(fdctrl, 0x00, 0x00, 0x00);
|
||||||
} else {
|
}
|
||||||
fdctrl_reset_fifo(fdctrl);
|
break;
|
||||||
|
|
||||||
|
case FD_PHASE_RESULT:
|
||||||
|
assert(!(fdctrl->msr & FD_MSR_NONDMA));
|
||||||
|
if (++fdctrl->data_pos == fdctrl->data_len) {
|
||||||
|
fdctrl->msr &= ~FD_MSR_RQM;
|
||||||
|
fdctrl_to_command_phase(fdctrl);
|
||||||
fdctrl_reset_irq(fdctrl);
|
fdctrl_reset_irq(fdctrl);
|
||||||
}
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case FD_PHASE_COMMAND:
|
||||||
|
default:
|
||||||
|
abort();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
retval = fdctrl->fifo[pos];
|
||||||
FLOPPY_DPRINTF("data register: 0x%02x\n", retval);
|
FLOPPY_DPRINTF("data register: 0x%02x\n", retval);
|
||||||
|
|
||||||
return retval;
|
return retval;
|
||||||
@@ -1606,7 +1709,7 @@ static void fdctrl_handle_lock(FDCtrl *fdctrl, int direction)
|
|||||||
{
|
{
|
||||||
fdctrl->lock = (fdctrl->fifo[0] & 0x80) ? 1 : 0;
|
fdctrl->lock = (fdctrl->fifo[0] & 0x80) ? 1 : 0;
|
||||||
fdctrl->fifo[0] = fdctrl->lock << 4;
|
fdctrl->fifo[0] = fdctrl->lock << 4;
|
||||||
fdctrl_set_fifo(fdctrl, 1);
|
fdctrl_to_result_phase(fdctrl, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void fdctrl_handle_dumpreg(FDCtrl *fdctrl, int direction)
|
static void fdctrl_handle_dumpreg(FDCtrl *fdctrl, int direction)
|
||||||
@@ -1631,20 +1734,20 @@ static void fdctrl_handle_dumpreg(FDCtrl *fdctrl, int direction)
|
|||||||
(cur_drv->perpendicular << 2);
|
(cur_drv->perpendicular << 2);
|
||||||
fdctrl->fifo[8] = fdctrl->config;
|
fdctrl->fifo[8] = fdctrl->config;
|
||||||
fdctrl->fifo[9] = fdctrl->precomp_trk;
|
fdctrl->fifo[9] = fdctrl->precomp_trk;
|
||||||
fdctrl_set_fifo(fdctrl, 10);
|
fdctrl_to_result_phase(fdctrl, 10);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void fdctrl_handle_version(FDCtrl *fdctrl, int direction)
|
static void fdctrl_handle_version(FDCtrl *fdctrl, int direction)
|
||||||
{
|
{
|
||||||
/* Controller's version */
|
/* Controller's version */
|
||||||
fdctrl->fifo[0] = fdctrl->version;
|
fdctrl->fifo[0] = fdctrl->version;
|
||||||
fdctrl_set_fifo(fdctrl, 1);
|
fdctrl_to_result_phase(fdctrl, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void fdctrl_handle_partid(FDCtrl *fdctrl, int direction)
|
static void fdctrl_handle_partid(FDCtrl *fdctrl, int direction)
|
||||||
{
|
{
|
||||||
fdctrl->fifo[0] = 0x41; /* Stepping 1 */
|
fdctrl->fifo[0] = 0x41; /* Stepping 1 */
|
||||||
fdctrl_set_fifo(fdctrl, 1);
|
fdctrl_to_result_phase(fdctrl, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void fdctrl_handle_restore(FDCtrl *fdctrl, int direction)
|
static void fdctrl_handle_restore(FDCtrl *fdctrl, int direction)
|
||||||
@@ -1667,7 +1770,7 @@ static void fdctrl_handle_restore(FDCtrl *fdctrl, int direction)
|
|||||||
fdctrl->config = fdctrl->fifo[11];
|
fdctrl->config = fdctrl->fifo[11];
|
||||||
fdctrl->precomp_trk = fdctrl->fifo[12];
|
fdctrl->precomp_trk = fdctrl->fifo[12];
|
||||||
fdctrl->pwrd = fdctrl->fifo[13];
|
fdctrl->pwrd = fdctrl->fifo[13];
|
||||||
fdctrl_reset_fifo(fdctrl);
|
fdctrl_to_command_phase(fdctrl);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void fdctrl_handle_save(FDCtrl *fdctrl, int direction)
|
static void fdctrl_handle_save(FDCtrl *fdctrl, int direction)
|
||||||
@@ -1697,7 +1800,7 @@ static void fdctrl_handle_save(FDCtrl *fdctrl, int direction)
|
|||||||
fdctrl->fifo[12] = fdctrl->pwrd;
|
fdctrl->fifo[12] = fdctrl->pwrd;
|
||||||
fdctrl->fifo[13] = 0;
|
fdctrl->fifo[13] = 0;
|
||||||
fdctrl->fifo[14] = 0;
|
fdctrl->fifo[14] = 0;
|
||||||
fdctrl_set_fifo(fdctrl, 15);
|
fdctrl_to_result_phase(fdctrl, 15);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void fdctrl_handle_readid(FDCtrl *fdctrl, int direction)
|
static void fdctrl_handle_readid(FDCtrl *fdctrl, int direction)
|
||||||
@@ -1746,7 +1849,7 @@ static void fdctrl_handle_specify(FDCtrl *fdctrl, int direction)
|
|||||||
else
|
else
|
||||||
fdctrl->dor |= FD_DOR_DMAEN;
|
fdctrl->dor |= FD_DOR_DMAEN;
|
||||||
/* No result back */
|
/* No result back */
|
||||||
fdctrl_reset_fifo(fdctrl);
|
fdctrl_to_command_phase(fdctrl);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void fdctrl_handle_sense_drive_status(FDCtrl *fdctrl, int direction)
|
static void fdctrl_handle_sense_drive_status(FDCtrl *fdctrl, int direction)
|
||||||
@@ -1762,7 +1865,7 @@ static void fdctrl_handle_sense_drive_status(FDCtrl *fdctrl, int direction)
|
|||||||
(cur_drv->head << 2) |
|
(cur_drv->head << 2) |
|
||||||
GET_CUR_DRV(fdctrl) |
|
GET_CUR_DRV(fdctrl) |
|
||||||
0x28;
|
0x28;
|
||||||
fdctrl_set_fifo(fdctrl, 1);
|
fdctrl_to_result_phase(fdctrl, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void fdctrl_handle_recalibrate(FDCtrl *fdctrl, int direction)
|
static void fdctrl_handle_recalibrate(FDCtrl *fdctrl, int direction)
|
||||||
@@ -1772,7 +1875,7 @@ static void fdctrl_handle_recalibrate(FDCtrl *fdctrl, int direction)
|
|||||||
SET_CUR_DRV(fdctrl, fdctrl->fifo[1] & FD_DOR_SELMASK);
|
SET_CUR_DRV(fdctrl, fdctrl->fifo[1] & FD_DOR_SELMASK);
|
||||||
cur_drv = get_cur_drv(fdctrl);
|
cur_drv = get_cur_drv(fdctrl);
|
||||||
fd_recalibrate(cur_drv);
|
fd_recalibrate(cur_drv);
|
||||||
fdctrl_reset_fifo(fdctrl);
|
fdctrl_to_command_phase(fdctrl);
|
||||||
/* Raise Interrupt */
|
/* Raise Interrupt */
|
||||||
fdctrl->status0 |= FD_SR0_SEEK;
|
fdctrl->status0 |= FD_SR0_SEEK;
|
||||||
fdctrl_raise_irq(fdctrl);
|
fdctrl_raise_irq(fdctrl);
|
||||||
@@ -1788,7 +1891,7 @@ static void fdctrl_handle_sense_interrupt_status(FDCtrl *fdctrl, int direction)
|
|||||||
fdctrl->reset_sensei--;
|
fdctrl->reset_sensei--;
|
||||||
} else if (!(fdctrl->sra & FD_SRA_INTPEND)) {
|
} else if (!(fdctrl->sra & FD_SRA_INTPEND)) {
|
||||||
fdctrl->fifo[0] = FD_SR0_INVCMD;
|
fdctrl->fifo[0] = FD_SR0_INVCMD;
|
||||||
fdctrl_set_fifo(fdctrl, 1);
|
fdctrl_to_result_phase(fdctrl, 1);
|
||||||
return;
|
return;
|
||||||
} else {
|
} else {
|
||||||
fdctrl->fifo[0] =
|
fdctrl->fifo[0] =
|
||||||
@@ -1797,7 +1900,7 @@ static void fdctrl_handle_sense_interrupt_status(FDCtrl *fdctrl, int direction)
|
|||||||
}
|
}
|
||||||
|
|
||||||
fdctrl->fifo[1] = cur_drv->track;
|
fdctrl->fifo[1] = cur_drv->track;
|
||||||
fdctrl_set_fifo(fdctrl, 2);
|
fdctrl_to_result_phase(fdctrl, 2);
|
||||||
fdctrl_reset_irq(fdctrl);
|
fdctrl_reset_irq(fdctrl);
|
||||||
fdctrl->status0 = FD_SR0_RDYCHG;
|
fdctrl->status0 = FD_SR0_RDYCHG;
|
||||||
}
|
}
|
||||||
@@ -1808,7 +1911,7 @@ static void fdctrl_handle_seek(FDCtrl *fdctrl, int direction)
|
|||||||
|
|
||||||
SET_CUR_DRV(fdctrl, fdctrl->fifo[1] & FD_DOR_SELMASK);
|
SET_CUR_DRV(fdctrl, fdctrl->fifo[1] & FD_DOR_SELMASK);
|
||||||
cur_drv = get_cur_drv(fdctrl);
|
cur_drv = get_cur_drv(fdctrl);
|
||||||
fdctrl_reset_fifo(fdctrl);
|
fdctrl_to_command_phase(fdctrl);
|
||||||
/* The seek command just sends step pulses to the drive and doesn't care if
|
/* The seek command just sends step pulses to the drive and doesn't care if
|
||||||
* there is a medium inserted of if it's banging the head against the drive.
|
* there is a medium inserted of if it's banging the head against the drive.
|
||||||
*/
|
*/
|
||||||
@@ -1825,7 +1928,7 @@ static void fdctrl_handle_perpendicular_mode(FDCtrl *fdctrl, int direction)
|
|||||||
if (fdctrl->fifo[1] & 0x80)
|
if (fdctrl->fifo[1] & 0x80)
|
||||||
cur_drv->perpendicular = fdctrl->fifo[1] & 0x7;
|
cur_drv->perpendicular = fdctrl->fifo[1] & 0x7;
|
||||||
/* No result back */
|
/* No result back */
|
||||||
fdctrl_reset_fifo(fdctrl);
|
fdctrl_to_command_phase(fdctrl);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void fdctrl_handle_configure(FDCtrl *fdctrl, int direction)
|
static void fdctrl_handle_configure(FDCtrl *fdctrl, int direction)
|
||||||
@@ -1833,20 +1936,20 @@ static void fdctrl_handle_configure(FDCtrl *fdctrl, int direction)
|
|||||||
fdctrl->config = fdctrl->fifo[2];
|
fdctrl->config = fdctrl->fifo[2];
|
||||||
fdctrl->precomp_trk = fdctrl->fifo[3];
|
fdctrl->precomp_trk = fdctrl->fifo[3];
|
||||||
/* No result back */
|
/* No result back */
|
||||||
fdctrl_reset_fifo(fdctrl);
|
fdctrl_to_command_phase(fdctrl);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void fdctrl_handle_powerdown_mode(FDCtrl *fdctrl, int direction)
|
static void fdctrl_handle_powerdown_mode(FDCtrl *fdctrl, int direction)
|
||||||
{
|
{
|
||||||
fdctrl->pwrd = fdctrl->fifo[1];
|
fdctrl->pwrd = fdctrl->fifo[1];
|
||||||
fdctrl->fifo[0] = fdctrl->fifo[1];
|
fdctrl->fifo[0] = fdctrl->fifo[1];
|
||||||
fdctrl_set_fifo(fdctrl, 1);
|
fdctrl_to_result_phase(fdctrl, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void fdctrl_handle_option(FDCtrl *fdctrl, int direction)
|
static void fdctrl_handle_option(FDCtrl *fdctrl, int direction)
|
||||||
{
|
{
|
||||||
/* No result back */
|
/* No result back */
|
||||||
fdctrl_reset_fifo(fdctrl);
|
fdctrl_to_command_phase(fdctrl);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void fdctrl_handle_drive_specification_command(FDCtrl *fdctrl, int direction)
|
static void fdctrl_handle_drive_specification_command(FDCtrl *fdctrl, int direction)
|
||||||
@@ -1862,15 +1965,15 @@ static void fdctrl_handle_drive_specification_command(FDCtrl *fdctrl, int direct
|
|||||||
fdctrl->fifo[0] = fdctrl->fifo[1];
|
fdctrl->fifo[0] = fdctrl->fifo[1];
|
||||||
fdctrl->fifo[2] = 0;
|
fdctrl->fifo[2] = 0;
|
||||||
fdctrl->fifo[3] = 0;
|
fdctrl->fifo[3] = 0;
|
||||||
fdctrl_set_fifo(fdctrl, 4);
|
fdctrl_to_result_phase(fdctrl, 4);
|
||||||
} else {
|
} else {
|
||||||
fdctrl_reset_fifo(fdctrl);
|
fdctrl_to_command_phase(fdctrl);
|
||||||
}
|
}
|
||||||
} else if (fdctrl->data_len > 7) {
|
} else if (fdctrl->data_len > 7) {
|
||||||
/* ERROR */
|
/* ERROR */
|
||||||
fdctrl->fifo[0] = 0x80 |
|
fdctrl->fifo[0] = 0x80 |
|
||||||
(cur_drv->head << 2) | GET_CUR_DRV(fdctrl);
|
(cur_drv->head << 2) | GET_CUR_DRV(fdctrl);
|
||||||
fdctrl_set_fifo(fdctrl, 1);
|
fdctrl_to_result_phase(fdctrl, 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1887,7 +1990,7 @@ static void fdctrl_handle_relative_seek_in(FDCtrl *fdctrl, int direction)
|
|||||||
fd_seek(cur_drv, cur_drv->head,
|
fd_seek(cur_drv, cur_drv->head,
|
||||||
cur_drv->track + fdctrl->fifo[2], cur_drv->sect, 1);
|
cur_drv->track + fdctrl->fifo[2], cur_drv->sect, 1);
|
||||||
}
|
}
|
||||||
fdctrl_reset_fifo(fdctrl);
|
fdctrl_to_command_phase(fdctrl);
|
||||||
/* Raise Interrupt */
|
/* Raise Interrupt */
|
||||||
fdctrl->status0 |= FD_SR0_SEEK;
|
fdctrl->status0 |= FD_SR0_SEEK;
|
||||||
fdctrl_raise_irq(fdctrl);
|
fdctrl_raise_irq(fdctrl);
|
||||||
@@ -1905,20 +2008,25 @@ static void fdctrl_handle_relative_seek_out(FDCtrl *fdctrl, int direction)
|
|||||||
fd_seek(cur_drv, cur_drv->head,
|
fd_seek(cur_drv, cur_drv->head,
|
||||||
cur_drv->track - fdctrl->fifo[2], cur_drv->sect, 1);
|
cur_drv->track - fdctrl->fifo[2], cur_drv->sect, 1);
|
||||||
}
|
}
|
||||||
fdctrl_reset_fifo(fdctrl);
|
fdctrl_to_command_phase(fdctrl);
|
||||||
/* Raise Interrupt */
|
/* Raise Interrupt */
|
||||||
fdctrl->status0 |= FD_SR0_SEEK;
|
fdctrl->status0 |= FD_SR0_SEEK;
|
||||||
fdctrl_raise_irq(fdctrl);
|
fdctrl_raise_irq(fdctrl);
|
||||||
}
|
}
|
||||||
|
|
||||||
static const struct {
|
/*
|
||||||
|
* Handlers for the execution phase of each command
|
||||||
|
*/
|
||||||
|
typedef struct FDCtrlCommand {
|
||||||
uint8_t value;
|
uint8_t value;
|
||||||
uint8_t mask;
|
uint8_t mask;
|
||||||
const char* name;
|
const char* name;
|
||||||
int parameters;
|
int parameters;
|
||||||
void (*handler)(FDCtrl *fdctrl, int direction);
|
void (*handler)(FDCtrl *fdctrl, int direction);
|
||||||
int direction;
|
int direction;
|
||||||
} handlers[] = {
|
} FDCtrlCommand;
|
||||||
|
|
||||||
|
static const FDCtrlCommand handlers[] = {
|
||||||
{ FD_CMD_READ, 0x1f, "READ", 8, fdctrl_start_transfer, FD_DIR_READ },
|
{ FD_CMD_READ, 0x1f, "READ", 8, fdctrl_start_transfer, FD_DIR_READ },
|
||||||
{ FD_CMD_WRITE, 0x3f, "WRITE", 8, fdctrl_start_transfer, FD_DIR_WRITE },
|
{ FD_CMD_WRITE, 0x3f, "WRITE", 8, fdctrl_start_transfer, FD_DIR_WRITE },
|
||||||
{ FD_CMD_SEEK, 0xff, "SEEK", 2, fdctrl_handle_seek },
|
{ FD_CMD_SEEK, 0xff, "SEEK", 2, fdctrl_handle_seek },
|
||||||
@@ -1955,9 +2063,19 @@ static const struct {
|
|||||||
/* Associate command to an index in the 'handlers' array */
|
/* Associate command to an index in the 'handlers' array */
|
||||||
static uint8_t command_to_handler[256];
|
static uint8_t command_to_handler[256];
|
||||||
|
|
||||||
|
static const FDCtrlCommand *get_command(uint8_t cmd)
|
||||||
|
{
|
||||||
|
int idx;
|
||||||
|
|
||||||
|
idx = command_to_handler[cmd];
|
||||||
|
FLOPPY_DPRINTF("%s command\n", handlers[idx].name);
|
||||||
|
return &handlers[idx];
|
||||||
|
}
|
||||||
|
|
||||||
static void fdctrl_write_data(FDCtrl *fdctrl, uint32_t value)
|
static void fdctrl_write_data(FDCtrl *fdctrl, uint32_t value)
|
||||||
{
|
{
|
||||||
FDrive *cur_drv;
|
FDrive *cur_drv;
|
||||||
|
const FDCtrlCommand *cmd;
|
||||||
uint32_t pos;
|
uint32_t pos;
|
||||||
|
|
||||||
/* Reset mode */
|
/* Reset mode */
|
||||||
@@ -1970,12 +2088,27 @@ static void fdctrl_write_data(FDCtrl *fdctrl, uint32_t value)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
fdctrl->dsr &= ~FD_DSR_PWRDOWN;
|
fdctrl->dsr &= ~FD_DSR_PWRDOWN;
|
||||||
/* Is it write command time ? */
|
|
||||||
if (fdctrl->msr & FD_MSR_NONDMA) {
|
FLOPPY_DPRINTF("%s: %02x\n", __func__, value);
|
||||||
|
|
||||||
|
/* If data_len spans multiple sectors, the current position in the FIFO
|
||||||
|
* wraps around while fdctrl->data_pos is the real position in the whole
|
||||||
|
* request. */
|
||||||
|
pos = fdctrl->data_pos++;
|
||||||
|
pos %= FD_SECTOR_LEN;
|
||||||
|
fdctrl->fifo[pos] = value;
|
||||||
|
|
||||||
|
if (fdctrl->data_pos == fdctrl->data_len) {
|
||||||
|
fdctrl->msr &= ~FD_MSR_RQM;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (fdctrl->phase) {
|
||||||
|
case FD_PHASE_EXECUTION:
|
||||||
|
/* For DMA requests, RQM should be cleared during execution phase, so
|
||||||
|
* we would have errored out above. */
|
||||||
|
assert(fdctrl->msr & FD_MSR_NONDMA);
|
||||||
|
|
||||||
/* FIFO data write */
|
/* FIFO data write */
|
||||||
pos = fdctrl->data_pos++;
|
|
||||||
pos %= FD_SECTOR_LEN;
|
|
||||||
fdctrl->fifo[pos] = value;
|
|
||||||
if (pos == FD_SECTOR_LEN - 1 ||
|
if (pos == FD_SECTOR_LEN - 1 ||
|
||||||
fdctrl->data_pos == fdctrl->data_len) {
|
fdctrl->data_pos == fdctrl->data_len) {
|
||||||
cur_drv = get_cur_drv(fdctrl);
|
cur_drv = get_cur_drv(fdctrl);
|
||||||
@@ -1983,45 +2116,54 @@ static void fdctrl_write_data(FDCtrl *fdctrl, uint32_t value)
|
|||||||
< 0) {
|
< 0) {
|
||||||
FLOPPY_DPRINTF("error writing sector %d\n",
|
FLOPPY_DPRINTF("error writing sector %d\n",
|
||||||
fd_sector(cur_drv));
|
fd_sector(cur_drv));
|
||||||
return;
|
break;
|
||||||
}
|
}
|
||||||
if (!fdctrl_seek_to_next_sect(fdctrl, cur_drv)) {
|
if (!fdctrl_seek_to_next_sect(fdctrl, cur_drv)) {
|
||||||
FLOPPY_DPRINTF("error seeking to next sector %d\n",
|
FLOPPY_DPRINTF("error seeking to next sector %d\n",
|
||||||
fd_sector(cur_drv));
|
fd_sector(cur_drv));
|
||||||
return;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/* Switch from transfer mode to status mode
|
|
||||||
* then from status mode to command mode
|
|
||||||
*/
|
|
||||||
if (fdctrl->data_pos == fdctrl->data_len)
|
|
||||||
fdctrl_stop_transfer(fdctrl, 0x00, 0x00, 0x00);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (fdctrl->data_pos == 0) {
|
|
||||||
/* Command */
|
|
||||||
pos = command_to_handler[value & 0xff];
|
|
||||||
FLOPPY_DPRINTF("%s command\n", handlers[pos].name);
|
|
||||||
fdctrl->data_len = handlers[pos].parameters + 1;
|
|
||||||
fdctrl->msr |= FD_MSR_CMDBUSY;
|
|
||||||
}
|
|
||||||
|
|
||||||
FLOPPY_DPRINTF("%s: %02x\n", __func__, value);
|
/* Switch to result phase when done with the transfer */
|
||||||
pos = fdctrl->data_pos++;
|
if (fdctrl->data_pos == fdctrl->data_len) {
|
||||||
pos %= FD_SECTOR_LEN;
|
fdctrl_stop_transfer(fdctrl, 0x00, 0x00, 0x00);
|
||||||
fdctrl->fifo[pos] = value;
|
}
|
||||||
if (fdctrl->data_pos == fdctrl->data_len) {
|
break;
|
||||||
/* We now have all parameters
|
|
||||||
* and will be able to treat the command
|
case FD_PHASE_COMMAND:
|
||||||
*/
|
assert(!(fdctrl->msr & FD_MSR_NONDMA));
|
||||||
if (fdctrl->data_state & FD_STATE_FORMAT) {
|
assert(fdctrl->data_pos < FD_SECTOR_LEN);
|
||||||
fdctrl_format_sector(fdctrl);
|
|
||||||
return;
|
if (pos == 0) {
|
||||||
|
/* The first byte specifies the command. Now we start reading
|
||||||
|
* as many parameters as this command requires. */
|
||||||
|
cmd = get_command(value);
|
||||||
|
fdctrl->data_len = cmd->parameters + 1;
|
||||||
|
if (cmd->parameters) {
|
||||||
|
fdctrl->msr |= FD_MSR_RQM;
|
||||||
|
}
|
||||||
|
fdctrl->msr |= FD_MSR_CMDBUSY;
|
||||||
}
|
}
|
||||||
|
|
||||||
pos = command_to_handler[fdctrl->fifo[0] & 0xff];
|
if (fdctrl->data_pos == fdctrl->data_len) {
|
||||||
FLOPPY_DPRINTF("treat %s command\n", handlers[pos].name);
|
/* We have all parameters now, execute the command */
|
||||||
(*handlers[pos].handler)(fdctrl, handlers[pos].direction);
|
fdctrl->phase = FD_PHASE_EXECUTION;
|
||||||
|
|
||||||
|
if (fdctrl->data_state & FD_STATE_FORMAT) {
|
||||||
|
fdctrl_format_sector(fdctrl);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
cmd = get_command(fdctrl->fifo[0]);
|
||||||
|
FLOPPY_DPRINTF("Calling handler for '%s'\n", cmd->name);
|
||||||
|
cmd->handler(fdctrl, cmd->direction);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case FD_PHASE_RESULT:
|
||||||
|
default:
|
||||||
|
abort();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -64,6 +64,9 @@ do { \
|
|||||||
#define TYPE_CFI_PFLASH01 "cfi.pflash01"
|
#define TYPE_CFI_PFLASH01 "cfi.pflash01"
|
||||||
#define CFI_PFLASH01(obj) OBJECT_CHECK(pflash_t, (obj), TYPE_CFI_PFLASH01)
|
#define CFI_PFLASH01(obj) OBJECT_CHECK(pflash_t, (obj), TYPE_CFI_PFLASH01)
|
||||||
|
|
||||||
|
#define PFLASH_BE 0
|
||||||
|
#define PFLASH_SECURE 1
|
||||||
|
|
||||||
struct pflash_t {
|
struct pflash_t {
|
||||||
/*< private >*/
|
/*< private >*/
|
||||||
SysBusDevice parent_obj;
|
SysBusDevice parent_obj;
|
||||||
@@ -75,7 +78,7 @@ struct pflash_t {
|
|||||||
uint8_t bank_width;
|
uint8_t bank_width;
|
||||||
uint8_t device_width; /* If 0, device width not specified. */
|
uint8_t device_width; /* If 0, device width not specified. */
|
||||||
uint8_t max_device_width; /* max device width in bytes */
|
uint8_t max_device_width; /* max device width in bytes */
|
||||||
uint8_t be;
|
uint32_t features;
|
||||||
uint8_t wcycle; /* if 0, the flash is read normally */
|
uint8_t wcycle; /* if 0, the flash is read normally */
|
||||||
int ro;
|
int ro;
|
||||||
uint8_t cmd;
|
uint8_t cmd;
|
||||||
@@ -235,12 +238,57 @@ static uint32_t pflash_devid_query(pflash_t *pfl, hwaddr offset)
|
|||||||
return resp;
|
return resp;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static uint32_t pflash_data_read(pflash_t *pfl, hwaddr offset,
|
||||||
|
int width, int be)
|
||||||
|
{
|
||||||
|
uint8_t *p;
|
||||||
|
uint32_t ret;
|
||||||
|
|
||||||
|
p = pfl->storage;
|
||||||
|
switch (width) {
|
||||||
|
case 1:
|
||||||
|
ret = p[offset];
|
||||||
|
DPRINTF("%s: data offset " TARGET_FMT_plx " %02x\n",
|
||||||
|
__func__, offset, ret);
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
if (be) {
|
||||||
|
ret = p[offset] << 8;
|
||||||
|
ret |= p[offset + 1];
|
||||||
|
} else {
|
||||||
|
ret = p[offset];
|
||||||
|
ret |= p[offset + 1] << 8;
|
||||||
|
}
|
||||||
|
DPRINTF("%s: data offset " TARGET_FMT_plx " %04x\n",
|
||||||
|
__func__, offset, ret);
|
||||||
|
break;
|
||||||
|
case 4:
|
||||||
|
if (be) {
|
||||||
|
ret = p[offset] << 24;
|
||||||
|
ret |= p[offset + 1] << 16;
|
||||||
|
ret |= p[offset + 2] << 8;
|
||||||
|
ret |= p[offset + 3];
|
||||||
|
} else {
|
||||||
|
ret = p[offset];
|
||||||
|
ret |= p[offset + 1] << 8;
|
||||||
|
ret |= p[offset + 2] << 16;
|
||||||
|
ret |= p[offset + 3] << 24;
|
||||||
|
}
|
||||||
|
DPRINTF("%s: data offset " TARGET_FMT_plx " %08x\n",
|
||||||
|
__func__, offset, ret);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
DPRINTF("BUG in %s\n", __func__);
|
||||||
|
abort();
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
static uint32_t pflash_read (pflash_t *pfl, hwaddr offset,
|
static uint32_t pflash_read (pflash_t *pfl, hwaddr offset,
|
||||||
int width, int be)
|
int width, int be)
|
||||||
{
|
{
|
||||||
hwaddr boff;
|
hwaddr boff;
|
||||||
uint32_t ret;
|
uint32_t ret;
|
||||||
uint8_t *p;
|
|
||||||
|
|
||||||
ret = -1;
|
ret = -1;
|
||||||
|
|
||||||
@@ -257,43 +305,7 @@ static uint32_t pflash_read (pflash_t *pfl, hwaddr offset,
|
|||||||
/* fall through to read code */
|
/* fall through to read code */
|
||||||
case 0x00:
|
case 0x00:
|
||||||
/* Flash area read */
|
/* Flash area read */
|
||||||
p = pfl->storage;
|
ret = pflash_data_read(pfl, offset, width, be);
|
||||||
switch (width) {
|
|
||||||
case 1:
|
|
||||||
ret = p[offset];
|
|
||||||
DPRINTF("%s: data offset " TARGET_FMT_plx " %02x\n",
|
|
||||||
__func__, offset, ret);
|
|
||||||
break;
|
|
||||||
case 2:
|
|
||||||
if (be) {
|
|
||||||
ret = p[offset] << 8;
|
|
||||||
ret |= p[offset + 1];
|
|
||||||
} else {
|
|
||||||
ret = p[offset];
|
|
||||||
ret |= p[offset + 1] << 8;
|
|
||||||
}
|
|
||||||
DPRINTF("%s: data offset " TARGET_FMT_plx " %04x\n",
|
|
||||||
__func__, offset, ret);
|
|
||||||
break;
|
|
||||||
case 4:
|
|
||||||
if (be) {
|
|
||||||
ret = p[offset] << 24;
|
|
||||||
ret |= p[offset + 1] << 16;
|
|
||||||
ret |= p[offset + 2] << 8;
|
|
||||||
ret |= p[offset + 3];
|
|
||||||
} else {
|
|
||||||
ret = p[offset];
|
|
||||||
ret |= p[offset + 1] << 8;
|
|
||||||
ret |= p[offset + 2] << 16;
|
|
||||||
ret |= p[offset + 3] << 24;
|
|
||||||
}
|
|
||||||
DPRINTF("%s: data offset " TARGET_FMT_plx " %08x\n",
|
|
||||||
__func__, offset, ret);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
DPRINTF("BUG in %s\n", __func__);
|
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
break;
|
||||||
case 0x10: /* Single byte program */
|
case 0x10: /* Single byte program */
|
||||||
case 0x20: /* Block erase */
|
case 0x20: /* Block erase */
|
||||||
@@ -648,101 +660,37 @@ static void pflash_write(pflash_t *pfl, hwaddr offset,
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static uint32_t pflash_readb_be(void *opaque, hwaddr addr)
|
static MemTxResult pflash_mem_read_with_attrs(void *opaque, hwaddr addr, uint64_t *value,
|
||||||
{
|
unsigned len, MemTxAttrs attrs)
|
||||||
return pflash_read(opaque, addr, 1, 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
static uint32_t pflash_readb_le(void *opaque, hwaddr addr)
|
|
||||||
{
|
|
||||||
return pflash_read(opaque, addr, 1, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
static uint32_t pflash_readw_be(void *opaque, hwaddr addr)
|
|
||||||
{
|
{
|
||||||
pflash_t *pfl = opaque;
|
pflash_t *pfl = opaque;
|
||||||
|
bool be = !!(pfl->features & (1 << PFLASH_BE));
|
||||||
|
|
||||||
return pflash_read(pfl, addr, 2, 1);
|
if ((pfl->features & (1 << PFLASH_SECURE)) && !attrs.secure) {
|
||||||
|
*value = pflash_data_read(opaque, addr, len, be);
|
||||||
|
} else {
|
||||||
|
*value = pflash_read(opaque, addr, len, be);
|
||||||
|
}
|
||||||
|
return MEMTX_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
static uint32_t pflash_readw_le(void *opaque, hwaddr addr)
|
static MemTxResult pflash_mem_write_with_attrs(void *opaque, hwaddr addr, uint64_t value,
|
||||||
|
unsigned len, MemTxAttrs attrs)
|
||||||
{
|
{
|
||||||
pflash_t *pfl = opaque;
|
pflash_t *pfl = opaque;
|
||||||
|
bool be = !!(pfl->features & (1 << PFLASH_BE));
|
||||||
|
|
||||||
return pflash_read(pfl, addr, 2, 0);
|
if ((pfl->features & (1 << PFLASH_SECURE)) && !attrs.secure) {
|
||||||
|
return MEMTX_ERROR;
|
||||||
|
} else {
|
||||||
|
pflash_write(opaque, addr, value, len, be);
|
||||||
|
return MEMTX_OK;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static uint32_t pflash_readl_be(void *opaque, hwaddr addr)
|
static const MemoryRegionOps pflash_cfi01_ops = {
|
||||||
{
|
.read_with_attrs = pflash_mem_read_with_attrs,
|
||||||
pflash_t *pfl = opaque;
|
.write_with_attrs = pflash_mem_write_with_attrs,
|
||||||
|
|
||||||
return pflash_read(pfl, addr, 4, 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
static uint32_t pflash_readl_le(void *opaque, hwaddr addr)
|
|
||||||
{
|
|
||||||
pflash_t *pfl = opaque;
|
|
||||||
|
|
||||||
return pflash_read(pfl, addr, 4, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void pflash_writeb_be(void *opaque, hwaddr addr,
|
|
||||||
uint32_t value)
|
|
||||||
{
|
|
||||||
pflash_write(opaque, addr, value, 1, 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void pflash_writeb_le(void *opaque, hwaddr addr,
|
|
||||||
uint32_t value)
|
|
||||||
{
|
|
||||||
pflash_write(opaque, addr, value, 1, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void pflash_writew_be(void *opaque, hwaddr addr,
|
|
||||||
uint32_t value)
|
|
||||||
{
|
|
||||||
pflash_t *pfl = opaque;
|
|
||||||
|
|
||||||
pflash_write(pfl, addr, value, 2, 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void pflash_writew_le(void *opaque, hwaddr addr,
|
|
||||||
uint32_t value)
|
|
||||||
{
|
|
||||||
pflash_t *pfl = opaque;
|
|
||||||
|
|
||||||
pflash_write(pfl, addr, value, 2, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void pflash_writel_be(void *opaque, hwaddr addr,
|
|
||||||
uint32_t value)
|
|
||||||
{
|
|
||||||
pflash_t *pfl = opaque;
|
|
||||||
|
|
||||||
pflash_write(pfl, addr, value, 4, 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void pflash_writel_le(void *opaque, hwaddr addr,
|
|
||||||
uint32_t value)
|
|
||||||
{
|
|
||||||
pflash_t *pfl = opaque;
|
|
||||||
|
|
||||||
pflash_write(pfl, addr, value, 4, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
static const MemoryRegionOps pflash_cfi01_ops_be = {
|
|
||||||
.old_mmio = {
|
|
||||||
.read = { pflash_readb_be, pflash_readw_be, pflash_readl_be, },
|
|
||||||
.write = { pflash_writeb_be, pflash_writew_be, pflash_writel_be, },
|
|
||||||
},
|
|
||||||
.endianness = DEVICE_NATIVE_ENDIAN,
|
|
||||||
};
|
|
||||||
|
|
||||||
static const MemoryRegionOps pflash_cfi01_ops_le = {
|
|
||||||
.old_mmio = {
|
|
||||||
.read = { pflash_readb_le, pflash_readw_le, pflash_readl_le, },
|
|
||||||
.write = { pflash_writeb_le, pflash_writew_le, pflash_writel_le, },
|
|
||||||
},
|
|
||||||
.endianness = DEVICE_NATIVE_ENDIAN,
|
.endianness = DEVICE_NATIVE_ENDIAN,
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -773,7 +721,8 @@ static void pflash_cfi01_realize(DeviceState *dev, Error **errp)
|
|||||||
|
|
||||||
memory_region_init_rom_device(
|
memory_region_init_rom_device(
|
||||||
&pfl->mem, OBJECT(dev),
|
&pfl->mem, OBJECT(dev),
|
||||||
pfl->be ? &pflash_cfi01_ops_be : &pflash_cfi01_ops_le, pfl,
|
&pflash_cfi01_ops,
|
||||||
|
pfl,
|
||||||
pfl->name, total_len, &local_err);
|
pfl->name, total_len, &local_err);
|
||||||
if (local_err) {
|
if (local_err) {
|
||||||
error_propagate(errp, local_err);
|
error_propagate(errp, local_err);
|
||||||
@@ -925,7 +874,8 @@ static Property pflash_cfi01_properties[] = {
|
|||||||
DEFINE_PROP_UINT8("width", struct pflash_t, bank_width, 0),
|
DEFINE_PROP_UINT8("width", struct pflash_t, bank_width, 0),
|
||||||
DEFINE_PROP_UINT8("device-width", struct pflash_t, device_width, 0),
|
DEFINE_PROP_UINT8("device-width", struct pflash_t, device_width, 0),
|
||||||
DEFINE_PROP_UINT8("max-device-width", struct pflash_t, max_device_width, 0),
|
DEFINE_PROP_UINT8("max-device-width", struct pflash_t, max_device_width, 0),
|
||||||
DEFINE_PROP_UINT8("big-endian", struct pflash_t, be, 0),
|
DEFINE_PROP_BIT("big-endian", struct pflash_t, features, PFLASH_BE, 0),
|
||||||
|
DEFINE_PROP_BIT("secure", struct pflash_t, features, PFLASH_SECURE, 0),
|
||||||
DEFINE_PROP_UINT16("id0", struct pflash_t, ident0, 0),
|
DEFINE_PROP_UINT16("id0", struct pflash_t, ident0, 0),
|
||||||
DEFINE_PROP_UINT16("id1", struct pflash_t, ident1, 0),
|
DEFINE_PROP_UINT16("id1", struct pflash_t, ident1, 0),
|
||||||
DEFINE_PROP_UINT16("id2", struct pflash_t, ident2, 0),
|
DEFINE_PROP_UINT16("id2", struct pflash_t, ident2, 0),
|
||||||
@@ -975,7 +925,7 @@ pflash_t *pflash_cfi01_register(hwaddr base,
|
|||||||
qdev_prop_set_uint32(dev, "num-blocks", nb_blocs);
|
qdev_prop_set_uint32(dev, "num-blocks", nb_blocs);
|
||||||
qdev_prop_set_uint64(dev, "sector-length", sector_len);
|
qdev_prop_set_uint64(dev, "sector-length", sector_len);
|
||||||
qdev_prop_set_uint8(dev, "width", bank_width);
|
qdev_prop_set_uint8(dev, "width", bank_width);
|
||||||
qdev_prop_set_uint8(dev, "big-endian", !!be);
|
qdev_prop_set_bit(dev, "big-endian", !!be);
|
||||||
qdev_prop_set_uint16(dev, "id0", id0);
|
qdev_prop_set_uint16(dev, "id0", id0);
|
||||||
qdev_prop_set_uint16(dev, "id1", id1);
|
qdev_prop_set_uint16(dev, "id1", id1);
|
||||||
qdev_prop_set_uint16(dev, "id2", id2);
|
qdev_prop_set_uint16(dev, "id2", id2);
|
||||||
|
|||||||
@@ -718,7 +718,7 @@ static void virtio_blk_set_config(VirtIODevice *vdev, const uint8_t *config)
|
|||||||
aio_context_release(blk_get_aio_context(s->blk));
|
aio_context_release(blk_get_aio_context(s->blk));
|
||||||
}
|
}
|
||||||
|
|
||||||
static uint32_t virtio_blk_get_features(VirtIODevice *vdev, uint32_t features)
|
static uint64_t virtio_blk_get_features(VirtIODevice *vdev, uint64_t features)
|
||||||
{
|
{
|
||||||
VirtIOBlock *s = VIRTIO_BLK(vdev);
|
VirtIOBlock *s = VIRTIO_BLK(vdev);
|
||||||
|
|
||||||
|
|||||||
@@ -641,28 +641,3 @@ static void parallel_register_types(void)
|
|||||||
}
|
}
|
||||||
|
|
||||||
type_init(parallel_register_types)
|
type_init(parallel_register_types)
|
||||||
|
|
||||||
static void parallel_init(ISABus *bus, int index, CharDriverState *chr)
|
|
||||||
{
|
|
||||||
DeviceState *dev;
|
|
||||||
ISADevice *isadev;
|
|
||||||
|
|
||||||
isadev = isa_create(bus, "isa-parallel");
|
|
||||||
dev = DEVICE(isadev);
|
|
||||||
qdev_prop_set_uint32(dev, "index", index);
|
|
||||||
qdev_prop_set_chr(dev, "chardev", chr);
|
|
||||||
qdev_init_nofail(dev);
|
|
||||||
}
|
|
||||||
|
|
||||||
void parallel_hds_isa_init(ISABus *bus, int n)
|
|
||||||
{
|
|
||||||
int i;
|
|
||||||
|
|
||||||
assert(n <= MAX_PARALLEL_PORTS);
|
|
||||||
|
|
||||||
for (i = 0; i < n; i++) {
|
|
||||||
if (parallel_hds[i]) {
|
|
||||||
parallel_init(bus, i, parallel_hds[i]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -95,6 +95,15 @@ static void set_guest_connected(VirtIOSerialPort *port, int guest_connected)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void guest_writable(VirtIOSerialPort *port)
|
||||||
|
{
|
||||||
|
VirtConsole *vcon = VIRTIO_CONSOLE(port);
|
||||||
|
|
||||||
|
if (vcon->chr) {
|
||||||
|
qemu_chr_accept_input(vcon->chr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* Readiness of the guest to accept data on a port */
|
/* Readiness of the guest to accept data on a port */
|
||||||
static int chr_can_read(void *opaque)
|
static int chr_can_read(void *opaque)
|
||||||
{
|
{
|
||||||
@@ -188,6 +197,7 @@ static void virtserialport_class_init(ObjectClass *klass, void *data)
|
|||||||
k->unrealize = virtconsole_unrealize;
|
k->unrealize = virtconsole_unrealize;
|
||||||
k->have_data = flush_buf;
|
k->have_data = flush_buf;
|
||||||
k->set_guest_connected = set_guest_connected;
|
k->set_guest_connected = set_guest_connected;
|
||||||
|
k->guest_writable = guest_writable;
|
||||||
dc->props = virtserialport_properties;
|
dc->props = virtserialport_properties;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -498,7 +498,7 @@ static void handle_input(VirtIODevice *vdev, VirtQueue *vq)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static uint32_t get_features(VirtIODevice *vdev, uint32_t features)
|
static uint64_t get_features(VirtIODevice *vdev, uint64_t features)
|
||||||
{
|
{
|
||||||
VirtIOSerial *vser;
|
VirtIOSerial *vser;
|
||||||
|
|
||||||
@@ -973,7 +973,7 @@ static void virtio_serial_device_realize(DeviceState *dev, Error **errp)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Each port takes 2 queues, and one pair is for the control queue */
|
/* Each port takes 2 queues, and one pair is for the control queue */
|
||||||
max_supported_ports = VIRTIO_PCI_QUEUE_MAX / 2 - 1;
|
max_supported_ports = VIRTIO_QUEUE_MAX / 2 - 1;
|
||||||
|
|
||||||
if (vser->serial.max_virtserial_ports > max_supported_ports) {
|
if (vser->serial.max_virtserial_ports > max_supported_ports) {
|
||||||
error_setg(errp, "maximum ports supported: %u", max_supported_ports);
|
error_setg(errp, "maximum ports supported: %u", max_supported_ports);
|
||||||
|
|||||||
@@ -294,6 +294,14 @@ static void machine_init_notify(Notifier *notifier, void *data)
|
|||||||
foreach_dynamic_sysbus_device(error_on_sysbus_device, NULL);
|
foreach_dynamic_sysbus_device(error_on_sysbus_device, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void machine_class_init(ObjectClass *oc, void *data)
|
||||||
|
{
|
||||||
|
MachineClass *mc = MACHINE_CLASS(oc);
|
||||||
|
|
||||||
|
/* Default 128 MB as guest ram size */
|
||||||
|
mc->default_ram_size = 128 * M_BYTE;
|
||||||
|
}
|
||||||
|
|
||||||
static void machine_initfn(Object *obj)
|
static void machine_initfn(Object *obj)
|
||||||
{
|
{
|
||||||
MachineState *ms = MACHINE(obj);
|
MachineState *ms = MACHINE(obj);
|
||||||
@@ -463,6 +471,7 @@ static const TypeInfo machine_info = {
|
|||||||
.parent = TYPE_OBJECT,
|
.parent = TYPE_OBJECT,
|
||||||
.abstract = true,
|
.abstract = true,
|
||||||
.class_size = sizeof(MachineClass),
|
.class_size = sizeof(MachineClass),
|
||||||
|
.class_init = machine_class_init,
|
||||||
.instance_size = sizeof(MachineState),
|
.instance_size = sizeof(MachineState),
|
||||||
.instance_init = machine_initfn,
|
.instance_init = machine_initfn,
|
||||||
.instance_finalize = machine_finalize,
|
.instance_finalize = machine_finalize,
|
||||||
|
|||||||
@@ -389,7 +389,7 @@ void qdev_set_nic_properties(DeviceState *dev, NICInfo *nd)
|
|||||||
nd->instantiated = 1;
|
nd->instantiated = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int qdev_add_one_global(QemuOpts *opts, void *opaque)
|
static int qdev_add_one_global(void *opaque, QemuOpts *opts, Error **errp)
|
||||||
{
|
{
|
||||||
GlobalProperty *g;
|
GlobalProperty *g;
|
||||||
|
|
||||||
@@ -404,5 +404,6 @@ static int qdev_add_one_global(QemuOpts *opts, void *opaque)
|
|||||||
|
|
||||||
void qemu_add_globals(void)
|
void qemu_add_globals(void)
|
||||||
{
|
{
|
||||||
qemu_opts_foreach(qemu_find_opts("global"), qdev_add_one_global, NULL, 0);
|
qemu_opts_foreach(qemu_find_opts("global"),
|
||||||
|
qdev_add_one_global, NULL, NULL);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -125,6 +125,64 @@ PropertyInfo qdev_prop_bit = {
|
|||||||
.set = prop_set_bit,
|
.set = prop_set_bit,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/* Bit64 */
|
||||||
|
|
||||||
|
static uint64_t qdev_get_prop_mask64(Property *prop)
|
||||||
|
{
|
||||||
|
assert(prop->info == &qdev_prop_bit);
|
||||||
|
return 0x1 << prop->bitnr;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void bit64_prop_set(DeviceState *dev, Property *props, bool val)
|
||||||
|
{
|
||||||
|
uint64_t *p = qdev_get_prop_ptr(dev, props);
|
||||||
|
uint64_t mask = qdev_get_prop_mask64(props);
|
||||||
|
if (val) {
|
||||||
|
*p |= mask;
|
||||||
|
} else {
|
||||||
|
*p &= ~mask;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void prop_get_bit64(Object *obj, Visitor *v, void *opaque,
|
||||||
|
const char *name, Error **errp)
|
||||||
|
{
|
||||||
|
DeviceState *dev = DEVICE(obj);
|
||||||
|
Property *prop = opaque;
|
||||||
|
uint64_t *p = qdev_get_prop_ptr(dev, prop);
|
||||||
|
bool value = (*p & qdev_get_prop_mask64(prop)) != 0;
|
||||||
|
|
||||||
|
visit_type_bool(v, &value, name, errp);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void prop_set_bit64(Object *obj, Visitor *v, void *opaque,
|
||||||
|
const char *name, Error **errp)
|
||||||
|
{
|
||||||
|
DeviceState *dev = DEVICE(obj);
|
||||||
|
Property *prop = opaque;
|
||||||
|
Error *local_err = NULL;
|
||||||
|
bool value;
|
||||||
|
|
||||||
|
if (dev->realized) {
|
||||||
|
qdev_prop_set_after_realize(dev, name, errp);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
visit_type_bool(v, &value, name, &local_err);
|
||||||
|
if (local_err) {
|
||||||
|
error_propagate(errp, local_err);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
bit64_prop_set(dev, prop, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
PropertyInfo qdev_prop_bit64 = {
|
||||||
|
.name = "bool",
|
||||||
|
.description = "on/off",
|
||||||
|
.get = prop_get_bit64,
|
||||||
|
.set = prop_set_bit64,
|
||||||
|
};
|
||||||
|
|
||||||
/* --- bool --- */
|
/* --- bool --- */
|
||||||
|
|
||||||
static void get_bool(Object *obj, Visitor *v, void *opaque,
|
static void get_bool(Object *obj, Visitor *v, void *opaque,
|
||||||
|
|||||||
@@ -34,3 +34,5 @@ obj-$(CONFIG_CG3) += cg3.o
|
|||||||
obj-$(CONFIG_VGA) += vga.o
|
obj-$(CONFIG_VGA) += vga.o
|
||||||
|
|
||||||
common-obj-$(CONFIG_QXL) += qxl.o qxl-logger.o qxl-render.o
|
common-obj-$(CONFIG_QXL) += qxl.o qxl-logger.o qxl-render.o
|
||||||
|
|
||||||
|
obj-$(CONFIG_VIRTIO) += virtio-gpu.o
|
||||||
|
|||||||
@@ -106,6 +106,7 @@ static void cg3_update_display(void *opaque)
|
|||||||
pix = memory_region_get_ram_ptr(&s->vram_mem);
|
pix = memory_region_get_ram_ptr(&s->vram_mem);
|
||||||
data = (uint32_t *)surface_data(surface);
|
data = (uint32_t *)surface_data(surface);
|
||||||
|
|
||||||
|
memory_region_sync_dirty_bitmap(&s->vram_mem);
|
||||||
for (y = 0; y < height; y++) {
|
for (y = 0; y < height; y++) {
|
||||||
int update = s->full_update;
|
int update = s->full_update;
|
||||||
|
|
||||||
@@ -309,6 +310,7 @@ static void cg3_realizefn(DeviceState *dev, Error **errp)
|
|||||||
|
|
||||||
memory_region_init_ram(&s->vram_mem, NULL, "cg3.vram", s->vram_size,
|
memory_region_init_ram(&s->vram_mem, NULL, "cg3.vram", s->vram_size,
|
||||||
&error_abort);
|
&error_abort);
|
||||||
|
memory_region_set_log(&s->vram_mem, true, DIRTY_MEMORY_VGA);
|
||||||
vmstate_register_ram_global(&s->vram_mem);
|
vmstate_register_ram_global(&s->vram_mem);
|
||||||
sysbus_init_mmio(sbd, &s->vram_mem);
|
sysbus_init_mmio(sbd, &s->vram_mem);
|
||||||
|
|
||||||
|
|||||||
@@ -1109,6 +1109,12 @@ static inline int fimd_get_buffer_id(Exynos4210fimdWindow *w)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void exynos4210_fimd_invalidate(void *opaque)
|
||||||
|
{
|
||||||
|
Exynos4210fimdState *s = (Exynos4210fimdState *)opaque;
|
||||||
|
s->invalidate = true;
|
||||||
|
}
|
||||||
|
|
||||||
/* Updates specified window's MemorySection based on values of WINCON,
|
/* Updates specified window's MemorySection based on values of WINCON,
|
||||||
* VIDOSDA, VIDOSDB, VIDWADDx and SHADOWCON registers */
|
* VIDOSDA, VIDOSDB, VIDWADDx and SHADOWCON registers */
|
||||||
static void fimd_update_memory_section(Exynos4210fimdState *s, unsigned win)
|
static void fimd_update_memory_section(Exynos4210fimdState *s, unsigned win)
|
||||||
@@ -1136,7 +1142,11 @@ static void fimd_update_memory_section(Exynos4210fimdState *s, unsigned win)
|
|||||||
/* TODO: add .exit and unref the region there. Not needed yet since sysbus
|
/* TODO: add .exit and unref the region there. Not needed yet since sysbus
|
||||||
* does not support hot-unplug.
|
* does not support hot-unplug.
|
||||||
*/
|
*/
|
||||||
memory_region_unref(w->mem_section.mr);
|
if (w->mem_section.mr) {
|
||||||
|
memory_region_set_log(w->mem_section.mr, false, DIRTY_MEMORY_VGA);
|
||||||
|
memory_region_unref(w->mem_section.mr);
|
||||||
|
}
|
||||||
|
|
||||||
w->mem_section = memory_region_find(sysbus_address_space(sbd),
|
w->mem_section = memory_region_find(sysbus_address_space(sbd),
|
||||||
fb_start_addr, w->fb_len);
|
fb_start_addr, w->fb_len);
|
||||||
assert(w->mem_section.mr);
|
assert(w->mem_section.mr);
|
||||||
@@ -1162,6 +1172,8 @@ static void fimd_update_memory_section(Exynos4210fimdState *s, unsigned win)
|
|||||||
cpu_physical_memory_unmap(w->host_fb_addr, fb_mapped_len, 0, 0);
|
cpu_physical_memory_unmap(w->host_fb_addr, fb_mapped_len, 0, 0);
|
||||||
goto error_return;
|
goto error_return;
|
||||||
}
|
}
|
||||||
|
memory_region_set_log(w->mem_section.mr, true, DIRTY_MEMORY_VGA);
|
||||||
|
exynos4210_fimd_invalidate(s);
|
||||||
return;
|
return;
|
||||||
|
|
||||||
error_return:
|
error_return:
|
||||||
@@ -1224,12 +1236,6 @@ static void exynos4210_fimd_update_irq(Exynos4210fimdState *s)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void exynos4210_fimd_invalidate(void *opaque)
|
|
||||||
{
|
|
||||||
Exynos4210fimdState *s = (Exynos4210fimdState *)opaque;
|
|
||||||
s->invalidate = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void exynos4210_update_resolution(Exynos4210fimdState *s)
|
static void exynos4210_update_resolution(Exynos4210fimdState *s)
|
||||||
{
|
{
|
||||||
DisplaySurface *surface = qemu_console_surface(s->console);
|
DisplaySurface *surface = qemu_console_surface(s->console);
|
||||||
|
|||||||
@@ -63,6 +63,10 @@ void framebuffer_update_display(
|
|||||||
assert(mem_section.offset_within_address_space == base);
|
assert(mem_section.offset_within_address_space == base);
|
||||||
|
|
||||||
memory_region_sync_dirty_bitmap(mem);
|
memory_region_sync_dirty_bitmap(mem);
|
||||||
|
if (!memory_region_is_logging(mem, DIRTY_MEMORY_VGA)) {
|
||||||
|
invalidate = true;
|
||||||
|
}
|
||||||
|
|
||||||
src_base = cpu_physical_memory_map(base, &src_len, 0);
|
src_base = cpu_physical_memory_map(base, &src_len, 0);
|
||||||
/* If we can't map the framebuffer then bail. We could try harder,
|
/* If we can't map the framebuffer then bail. We could try harder,
|
||||||
but it's not really worth it as dirty flag tracking will probably
|
but it's not really worth it as dirty flag tracking will probably
|
||||||
|
|||||||
@@ -260,6 +260,7 @@ static void g364fb_update_display(void *opaque)
|
|||||||
qemu_console_resize(s->con, s->width, s->height);
|
qemu_console_resize(s->con, s->width, s->height);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
memory_region_sync_dirty_bitmap(&s->mem_vram);
|
||||||
if (s->ctla & CTLA_FORCE_BLANK) {
|
if (s->ctla & CTLA_FORCE_BLANK) {
|
||||||
g364fb_draw_blank(s);
|
g364fb_draw_blank(s);
|
||||||
} else if (s->depth == 8) {
|
} else if (s->depth == 8) {
|
||||||
@@ -489,7 +490,7 @@ static void g364fb_init(DeviceState *dev, G364State *s)
|
|||||||
memory_region_init_ram_ptr(&s->mem_vram, NULL, "vram",
|
memory_region_init_ram_ptr(&s->mem_vram, NULL, "vram",
|
||||||
s->vram_size, s->vram);
|
s->vram_size, s->vram);
|
||||||
vmstate_register_ram(&s->mem_vram, dev);
|
vmstate_register_ram(&s->mem_vram, dev);
|
||||||
memory_region_set_coalescing(&s->mem_vram);
|
memory_region_set_log(&s->mem_vram, true, DIRTY_MEMORY_VGA);
|
||||||
}
|
}
|
||||||
|
|
||||||
#define TYPE_G364 "sysbus-g364"
|
#define TYPE_G364 "sysbus-g364"
|
||||||
|
|||||||
@@ -504,6 +504,10 @@ static void interface_set_mm_time(QXLInstance *sin, uint32_t mm_time)
|
|||||||
{
|
{
|
||||||
PCIQXLDevice *qxl = container_of(sin, PCIQXLDevice, ssd.qxl);
|
PCIQXLDevice *qxl = container_of(sin, PCIQXLDevice, ssd.qxl);
|
||||||
|
|
||||||
|
if (!qemu_spice_display_is_running(&qxl->ssd)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
trace_qxl_interface_set_mm_time(qxl->id, mm_time);
|
trace_qxl_interface_set_mm_time(qxl->id, mm_time);
|
||||||
qxl->shadow_rom.mm_clock = cpu_to_le32(mm_time);
|
qxl->shadow_rom.mm_clock = cpu_to_le32(mm_time);
|
||||||
qxl->rom->mm_clock = cpu_to_le32(mm_time);
|
qxl->rom->mm_clock = cpu_to_le32(mm_time);
|
||||||
|
|||||||
@@ -1322,6 +1322,7 @@ static void sm501_draw_crt(SM501State * s)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* draw each line according to conditions */
|
/* draw each line according to conditions */
|
||||||
|
memory_region_sync_dirty_bitmap(&s->local_mem_region);
|
||||||
for (y = 0; y < height; y++) {
|
for (y = 0; y < height; y++) {
|
||||||
int update_hwc = draw_hwc_line ? within_hwc_y_range(s, y, 1) : 0;
|
int update_hwc = draw_hwc_line ? within_hwc_y_range(s, y, 1) : 0;
|
||||||
int update = full_update || update_hwc;
|
int update = full_update || update_hwc;
|
||||||
@@ -1412,6 +1413,7 @@ void sm501_init(MemoryRegion *address_space_mem, uint32_t base,
|
|||||||
memory_region_init_ram(&s->local_mem_region, NULL, "sm501.local",
|
memory_region_init_ram(&s->local_mem_region, NULL, "sm501.local",
|
||||||
local_mem_bytes, &error_abort);
|
local_mem_bytes, &error_abort);
|
||||||
vmstate_register_ram_global(&s->local_mem_region);
|
vmstate_register_ram_global(&s->local_mem_region);
|
||||||
|
memory_region_set_log(&s->local_mem_region, true, DIRTY_MEMORY_VGA);
|
||||||
s->local_mem = memory_region_get_ram_ptr(&s->local_mem_region);
|
s->local_mem = memory_region_get_ram_ptr(&s->local_mem_region);
|
||||||
memory_region_add_subregion(address_space_mem, base, &s->local_mem_region);
|
memory_region_add_subregion(address_space_mem, base, &s->local_mem_region);
|
||||||
|
|
||||||
|
|||||||
@@ -571,7 +571,7 @@ TC6393xbState *tc6393xb_init(MemoryRegion *sysmem, uint32_t base, qemu_irq irq)
|
|||||||
s->irq = irq;
|
s->irq = irq;
|
||||||
s->gpio_in = qemu_allocate_irqs(tc6393xb_gpio_set, s, TC6393XB_GPIOS);
|
s->gpio_in = qemu_allocate_irqs(tc6393xb_gpio_set, s, TC6393XB_GPIOS);
|
||||||
|
|
||||||
s->l3v = *qemu_allocate_irqs(tc6393xb_l3v, s, 1);
|
s->l3v = qemu_allocate_irq(tc6393xb_l3v, s, 0);
|
||||||
s->blanked = 1;
|
s->blanked = 1;
|
||||||
|
|
||||||
s->sub_irqs = qemu_allocate_irqs(tc6393xb_sub_irq, s, TC6393XB_NR_IRQS);
|
s->sub_irqs = qemu_allocate_irqs(tc6393xb_sub_irq, s, TC6393XB_NR_IRQS);
|
||||||
|
|||||||
@@ -353,6 +353,7 @@ static void tcx_update_display(void *opaque)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
memory_region_sync_dirty_bitmap(&ts->vram_mem);
|
||||||
for (y = 0; y < ts->height; page += TARGET_PAGE_SIZE) {
|
for (y = 0; y < ts->height; page += TARGET_PAGE_SIZE) {
|
||||||
if (memory_region_get_dirty(&ts->vram_mem, page, TARGET_PAGE_SIZE,
|
if (memory_region_get_dirty(&ts->vram_mem, page, TARGET_PAGE_SIZE,
|
||||||
DIRTY_MEMORY_VGA)) {
|
DIRTY_MEMORY_VGA)) {
|
||||||
@@ -446,6 +447,7 @@ static void tcx24_update_display(void *opaque)
|
|||||||
dd = surface_stride(surface);
|
dd = surface_stride(surface);
|
||||||
ds = 1024;
|
ds = 1024;
|
||||||
|
|
||||||
|
memory_region_sync_dirty_bitmap(&ts->vram_mem);
|
||||||
for (y = 0; y < ts->height; page += TARGET_PAGE_SIZE,
|
for (y = 0; y < ts->height; page += TARGET_PAGE_SIZE,
|
||||||
page24 += TARGET_PAGE_SIZE, cpage += TARGET_PAGE_SIZE) {
|
page24 += TARGET_PAGE_SIZE, cpage += TARGET_PAGE_SIZE) {
|
||||||
if (tcx24_check_dirty(ts, page, page24, cpage)) {
|
if (tcx24_check_dirty(ts, page, page24, cpage)) {
|
||||||
@@ -1006,6 +1008,7 @@ static void tcx_realizefn(DeviceState *dev, Error **errp)
|
|||||||
memory_region_init_ram(&s->vram_mem, OBJECT(s), "tcx.vram",
|
memory_region_init_ram(&s->vram_mem, OBJECT(s), "tcx.vram",
|
||||||
s->vram_size * (1 + 4 + 4), &error_abort);
|
s->vram_size * (1 + 4 + 4), &error_abort);
|
||||||
vmstate_register_ram_global(&s->vram_mem);
|
vmstate_register_ram_global(&s->vram_mem);
|
||||||
|
memory_region_set_log(&s->vram_mem, true, DIRTY_MEMORY_VGA);
|
||||||
vram_base = memory_region_get_ram_ptr(&s->vram_mem);
|
vram_base = memory_region_get_ram_ptr(&s->vram_mem);
|
||||||
|
|
||||||
/* 10/ROM : FCode ROM */
|
/* 10/ROM : FCode ROM */
|
||||||
|
|||||||
@@ -54,9 +54,7 @@ typedef struct PCIVGAState {
|
|||||||
VGACommonState vga;
|
VGACommonState vga;
|
||||||
uint32_t flags;
|
uint32_t flags;
|
||||||
MemoryRegion mmio;
|
MemoryRegion mmio;
|
||||||
MemoryRegion ioport;
|
MemoryRegion mrs[3];
|
||||||
MemoryRegion bochs;
|
|
||||||
MemoryRegion qext;
|
|
||||||
} PCIVGAState;
|
} PCIVGAState;
|
||||||
|
|
||||||
#define TYPE_PCI_VGA "pci-vga"
|
#define TYPE_PCI_VGA "pci-vga"
|
||||||
@@ -76,16 +74,16 @@ static const VMStateDescription vmstate_vga_pci = {
|
|||||||
static uint64_t pci_vga_ioport_read(void *ptr, hwaddr addr,
|
static uint64_t pci_vga_ioport_read(void *ptr, hwaddr addr,
|
||||||
unsigned size)
|
unsigned size)
|
||||||
{
|
{
|
||||||
PCIVGAState *d = ptr;
|
VGACommonState *s = ptr;
|
||||||
uint64_t ret = 0;
|
uint64_t ret = 0;
|
||||||
|
|
||||||
switch (size) {
|
switch (size) {
|
||||||
case 1:
|
case 1:
|
||||||
ret = vga_ioport_read(&d->vga, addr);
|
ret = vga_ioport_read(s, addr + 0x3c0);
|
||||||
break;
|
break;
|
||||||
case 2:
|
case 2:
|
||||||
ret = vga_ioport_read(&d->vga, addr);
|
ret = vga_ioport_read(s, addr + 0x3c0);
|
||||||
ret |= vga_ioport_read(&d->vga, addr+1) << 8;
|
ret |= vga_ioport_read(s, addr + 0x3c1) << 8;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
return ret;
|
return ret;
|
||||||
@@ -94,11 +92,11 @@ static uint64_t pci_vga_ioport_read(void *ptr, hwaddr addr,
|
|||||||
static void pci_vga_ioport_write(void *ptr, hwaddr addr,
|
static void pci_vga_ioport_write(void *ptr, hwaddr addr,
|
||||||
uint64_t val, unsigned size)
|
uint64_t val, unsigned size)
|
||||||
{
|
{
|
||||||
PCIVGAState *d = ptr;
|
VGACommonState *s = ptr;
|
||||||
|
|
||||||
switch (size) {
|
switch (size) {
|
||||||
case 1:
|
case 1:
|
||||||
vga_ioport_write(&d->vga, addr + 0x3c0, val);
|
vga_ioport_write(s, addr + 0x3c0, val);
|
||||||
break;
|
break;
|
||||||
case 2:
|
case 2:
|
||||||
/*
|
/*
|
||||||
@@ -106,8 +104,8 @@ static void pci_vga_ioport_write(void *ptr, hwaddr addr,
|
|||||||
* indexed registers with a single word write because the
|
* indexed registers with a single word write because the
|
||||||
* index byte is updated first.
|
* index byte is updated first.
|
||||||
*/
|
*/
|
||||||
vga_ioport_write(&d->vga, addr + 0x3c0, val & 0xff);
|
vga_ioport_write(s, addr + 0x3c0, val & 0xff);
|
||||||
vga_ioport_write(&d->vga, addr + 0x3c1, (val >> 8) & 0xff);
|
vga_ioport_write(s, addr + 0x3c1, (val >> 8) & 0xff);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -125,21 +123,21 @@ static const MemoryRegionOps pci_vga_ioport_ops = {
|
|||||||
static uint64_t pci_vga_bochs_read(void *ptr, hwaddr addr,
|
static uint64_t pci_vga_bochs_read(void *ptr, hwaddr addr,
|
||||||
unsigned size)
|
unsigned size)
|
||||||
{
|
{
|
||||||
PCIVGAState *d = ptr;
|
VGACommonState *s = ptr;
|
||||||
int index = addr >> 1;
|
int index = addr >> 1;
|
||||||
|
|
||||||
vbe_ioport_write_index(&d->vga, 0, index);
|
vbe_ioport_write_index(s, 0, index);
|
||||||
return vbe_ioport_read_data(&d->vga, 0);
|
return vbe_ioport_read_data(s, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void pci_vga_bochs_write(void *ptr, hwaddr addr,
|
static void pci_vga_bochs_write(void *ptr, hwaddr addr,
|
||||||
uint64_t val, unsigned size)
|
uint64_t val, unsigned size)
|
||||||
{
|
{
|
||||||
PCIVGAState *d = ptr;
|
VGACommonState *s = ptr;
|
||||||
int index = addr >> 1;
|
int index = addr >> 1;
|
||||||
|
|
||||||
vbe_ioport_write_index(&d->vga, 0, index);
|
vbe_ioport_write_index(s, 0, index);
|
||||||
vbe_ioport_write_data(&d->vga, 0, val);
|
vbe_ioport_write_data(s, 0, val);
|
||||||
}
|
}
|
||||||
|
|
||||||
static const MemoryRegionOps pci_vga_bochs_ops = {
|
static const MemoryRegionOps pci_vga_bochs_ops = {
|
||||||
@@ -154,13 +152,13 @@ static const MemoryRegionOps pci_vga_bochs_ops = {
|
|||||||
|
|
||||||
static uint64_t pci_vga_qext_read(void *ptr, hwaddr addr, unsigned size)
|
static uint64_t pci_vga_qext_read(void *ptr, hwaddr addr, unsigned size)
|
||||||
{
|
{
|
||||||
PCIVGAState *d = ptr;
|
VGACommonState *s = ptr;
|
||||||
|
|
||||||
switch (addr) {
|
switch (addr) {
|
||||||
case PCI_VGA_QEXT_REG_SIZE:
|
case PCI_VGA_QEXT_REG_SIZE:
|
||||||
return PCI_VGA_QEXT_SIZE;
|
return PCI_VGA_QEXT_SIZE;
|
||||||
case PCI_VGA_QEXT_REG_BYTEORDER:
|
case PCI_VGA_QEXT_REG_BYTEORDER:
|
||||||
return d->vga.big_endian_fb ?
|
return s->big_endian_fb ?
|
||||||
PCI_VGA_QEXT_BIG_ENDIAN : PCI_VGA_QEXT_LITTLE_ENDIAN;
|
PCI_VGA_QEXT_BIG_ENDIAN : PCI_VGA_QEXT_LITTLE_ENDIAN;
|
||||||
default:
|
default:
|
||||||
return 0;
|
return 0;
|
||||||
@@ -170,15 +168,15 @@ static uint64_t pci_vga_qext_read(void *ptr, hwaddr addr, unsigned size)
|
|||||||
static void pci_vga_qext_write(void *ptr, hwaddr addr,
|
static void pci_vga_qext_write(void *ptr, hwaddr addr,
|
||||||
uint64_t val, unsigned size)
|
uint64_t val, unsigned size)
|
||||||
{
|
{
|
||||||
PCIVGAState *d = ptr;
|
VGACommonState *s = ptr;
|
||||||
|
|
||||||
switch (addr) {
|
switch (addr) {
|
||||||
case PCI_VGA_QEXT_REG_BYTEORDER:
|
case PCI_VGA_QEXT_REG_BYTEORDER:
|
||||||
if (val == PCI_VGA_QEXT_BIG_ENDIAN) {
|
if (val == PCI_VGA_QEXT_BIG_ENDIAN) {
|
||||||
d->vga.big_endian_fb = true;
|
s->big_endian_fb = true;
|
||||||
}
|
}
|
||||||
if (val == PCI_VGA_QEXT_LITTLE_ENDIAN) {
|
if (val == PCI_VGA_QEXT_LITTLE_ENDIAN) {
|
||||||
d->vga.big_endian_fb = false;
|
s->big_endian_fb = false;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -206,10 +204,34 @@ static const MemoryRegionOps pci_vga_qext_ops = {
|
|||||||
.endianness = DEVICE_LITTLE_ENDIAN,
|
.endianness = DEVICE_LITTLE_ENDIAN,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static void pci_std_vga_mmio_region_init(VGACommonState *s,
|
||||||
|
MemoryRegion *parent,
|
||||||
|
MemoryRegion *subs,
|
||||||
|
bool qext)
|
||||||
|
{
|
||||||
|
memory_region_init_io(&subs[0], NULL, &pci_vga_ioport_ops, s,
|
||||||
|
"vga ioports remapped", PCI_VGA_IOPORT_SIZE);
|
||||||
|
memory_region_add_subregion(parent, PCI_VGA_IOPORT_OFFSET,
|
||||||
|
&subs[0]);
|
||||||
|
|
||||||
|
memory_region_init_io(&subs[1], NULL, &pci_vga_bochs_ops, s,
|
||||||
|
"bochs dispi interface", PCI_VGA_BOCHS_SIZE);
|
||||||
|
memory_region_add_subregion(parent, PCI_VGA_BOCHS_OFFSET,
|
||||||
|
&subs[1]);
|
||||||
|
|
||||||
|
if (qext) {
|
||||||
|
memory_region_init_io(&subs[2], NULL, &pci_vga_qext_ops, s,
|
||||||
|
"qemu extended regs", PCI_VGA_QEXT_SIZE);
|
||||||
|
memory_region_add_subregion(parent, PCI_VGA_QEXT_OFFSET,
|
||||||
|
&subs[2]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static void pci_std_vga_realize(PCIDevice *dev, Error **errp)
|
static void pci_std_vga_realize(PCIDevice *dev, Error **errp)
|
||||||
{
|
{
|
||||||
PCIVGAState *d = PCI_VGA(dev);
|
PCIVGAState *d = PCI_VGA(dev);
|
||||||
VGACommonState *s = &d->vga;
|
VGACommonState *s = &d->vga;
|
||||||
|
bool qext = false;
|
||||||
|
|
||||||
/* vga + console init */
|
/* vga + console init */
|
||||||
vga_common_init(s, OBJECT(dev), true);
|
vga_common_init(s, OBJECT(dev), true);
|
||||||
@@ -224,23 +246,12 @@ static void pci_std_vga_realize(PCIDevice *dev, Error **errp)
|
|||||||
/* mmio bar for vga register access */
|
/* mmio bar for vga register access */
|
||||||
if (d->flags & (1 << PCI_VGA_FLAG_ENABLE_MMIO)) {
|
if (d->flags & (1 << PCI_VGA_FLAG_ENABLE_MMIO)) {
|
||||||
memory_region_init(&d->mmio, NULL, "vga.mmio", 4096);
|
memory_region_init(&d->mmio, NULL, "vga.mmio", 4096);
|
||||||
memory_region_init_io(&d->ioport, NULL, &pci_vga_ioport_ops, d,
|
|
||||||
"vga ioports remapped", PCI_VGA_IOPORT_SIZE);
|
|
||||||
memory_region_init_io(&d->bochs, NULL, &pci_vga_bochs_ops, d,
|
|
||||||
"bochs dispi interface", PCI_VGA_BOCHS_SIZE);
|
|
||||||
|
|
||||||
memory_region_add_subregion(&d->mmio, PCI_VGA_IOPORT_OFFSET,
|
|
||||||
&d->ioport);
|
|
||||||
memory_region_add_subregion(&d->mmio, PCI_VGA_BOCHS_OFFSET,
|
|
||||||
&d->bochs);
|
|
||||||
|
|
||||||
if (d->flags & (1 << PCI_VGA_FLAG_ENABLE_QEXT)) {
|
if (d->flags & (1 << PCI_VGA_FLAG_ENABLE_QEXT)) {
|
||||||
memory_region_init_io(&d->qext, NULL, &pci_vga_qext_ops, d,
|
qext = true;
|
||||||
"qemu extended regs", PCI_VGA_QEXT_SIZE);
|
|
||||||
memory_region_add_subregion(&d->mmio, PCI_VGA_QEXT_OFFSET,
|
|
||||||
&d->qext);
|
|
||||||
pci_set_byte(&d->dev.config[PCI_REVISION_ID], 2);
|
pci_set_byte(&d->dev.config[PCI_REVISION_ID], 2);
|
||||||
}
|
}
|
||||||
|
pci_std_vga_mmio_region_init(s, &d->mmio, d->mrs, qext);
|
||||||
|
|
||||||
pci_register_bar(&d->dev, 2, PCI_BASE_ADDRESS_SPACE_MEMORY, &d->mmio);
|
pci_register_bar(&d->dev, 2, PCI_BASE_ADDRESS_SPACE_MEMORY, &d->mmio);
|
||||||
}
|
}
|
||||||
@@ -262,6 +273,7 @@ static void pci_secondary_vga_realize(PCIDevice *dev, Error **errp)
|
|||||||
{
|
{
|
||||||
PCIVGAState *d = PCI_VGA(dev);
|
PCIVGAState *d = PCI_VGA(dev);
|
||||||
VGACommonState *s = &d->vga;
|
VGACommonState *s = &d->vga;
|
||||||
|
bool qext = false;
|
||||||
|
|
||||||
/* vga + console init */
|
/* vga + console init */
|
||||||
vga_common_init(s, OBJECT(dev), false);
|
vga_common_init(s, OBJECT(dev), false);
|
||||||
@@ -269,23 +281,12 @@ static void pci_secondary_vga_realize(PCIDevice *dev, Error **errp)
|
|||||||
|
|
||||||
/* mmio bar */
|
/* mmio bar */
|
||||||
memory_region_init(&d->mmio, OBJECT(dev), "vga.mmio", 4096);
|
memory_region_init(&d->mmio, OBJECT(dev), "vga.mmio", 4096);
|
||||||
memory_region_init_io(&d->ioport, OBJECT(dev), &pci_vga_ioport_ops, d,
|
|
||||||
"vga ioports remapped", PCI_VGA_IOPORT_SIZE);
|
|
||||||
memory_region_init_io(&d->bochs, OBJECT(dev), &pci_vga_bochs_ops, d,
|
|
||||||
"bochs dispi interface", PCI_VGA_BOCHS_SIZE);
|
|
||||||
|
|
||||||
memory_region_add_subregion(&d->mmio, PCI_VGA_IOPORT_OFFSET,
|
|
||||||
&d->ioport);
|
|
||||||
memory_region_add_subregion(&d->mmio, PCI_VGA_BOCHS_OFFSET,
|
|
||||||
&d->bochs);
|
|
||||||
|
|
||||||
if (d->flags & (1 << PCI_VGA_FLAG_ENABLE_QEXT)) {
|
if (d->flags & (1 << PCI_VGA_FLAG_ENABLE_QEXT)) {
|
||||||
memory_region_init_io(&d->qext, NULL, &pci_vga_qext_ops, d,
|
qext = true;
|
||||||
"qemu extended regs", PCI_VGA_QEXT_SIZE);
|
|
||||||
memory_region_add_subregion(&d->mmio, PCI_VGA_QEXT_OFFSET,
|
|
||||||
&d->qext);
|
|
||||||
pci_set_byte(&d->dev.config[PCI_REVISION_ID], 2);
|
pci_set_byte(&d->dev.config[PCI_REVISION_ID], 2);
|
||||||
}
|
}
|
||||||
|
pci_std_vga_mmio_region_init(s, &d->mmio, d->mrs, qext);
|
||||||
|
|
||||||
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);
|
||||||
pci_register_bar(&d->dev, 2, PCI_BASE_ADDRESS_SPACE_MEMORY, &d->mmio);
|
pci_register_bar(&d->dev, 2, PCI_BASE_ADDRESS_SPACE_MEMORY, &d->mmio);
|
||||||
|
|||||||
918
hw/display/virtio-gpu.c
Normal file
918
hw/display/virtio-gpu.c
Normal file
@@ -0,0 +1,918 @@
|
|||||||
|
/*
|
||||||
|
* Virtio GPU Device
|
||||||
|
*
|
||||||
|
* Copyright Red Hat, Inc. 2013-2014
|
||||||
|
*
|
||||||
|
* Authors:
|
||||||
|
* Dave Airlie <airlied@redhat.com>
|
||||||
|
* Gerd Hoffmann <kraxel@redhat.com>
|
||||||
|
*
|
||||||
|
* This work is licensed under the terms of the GNU GPL, version 2.
|
||||||
|
* See the COPYING file in the top-level directory.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "qemu-common.h"
|
||||||
|
#include "qemu/iov.h"
|
||||||
|
#include "ui/console.h"
|
||||||
|
#include "trace.h"
|
||||||
|
#include "hw/virtio/virtio.h"
|
||||||
|
#include "hw/virtio/virtio-gpu.h"
|
||||||
|
#include "hw/virtio/virtio-bus.h"
|
||||||
|
|
||||||
|
static struct virtio_gpu_simple_resource*
|
||||||
|
virtio_gpu_find_resource(VirtIOGPU *g, uint32_t resource_id);
|
||||||
|
|
||||||
|
static void update_cursor_data_simple(VirtIOGPU *g,
|
||||||
|
struct virtio_gpu_scanout *s,
|
||||||
|
uint32_t resource_id)
|
||||||
|
{
|
||||||
|
struct virtio_gpu_simple_resource *res;
|
||||||
|
uint32_t pixels;
|
||||||
|
|
||||||
|
res = virtio_gpu_find_resource(g, resource_id);
|
||||||
|
if (!res) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pixman_image_get_width(res->image) != s->current_cursor->width ||
|
||||||
|
pixman_image_get_height(res->image) != s->current_cursor->height) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
pixels = s->current_cursor->width * s->current_cursor->height;
|
||||||
|
memcpy(s->current_cursor->data,
|
||||||
|
pixman_image_get_data(res->image),
|
||||||
|
pixels * sizeof(uint32_t));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void update_cursor(VirtIOGPU *g, struct virtio_gpu_update_cursor *cursor)
|
||||||
|
{
|
||||||
|
struct virtio_gpu_scanout *s;
|
||||||
|
|
||||||
|
if (cursor->pos.scanout_id >= g->conf.max_outputs) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
s = &g->scanout[cursor->pos.scanout_id];
|
||||||
|
|
||||||
|
if (cursor->hdr.type != VIRTIO_GPU_CMD_MOVE_CURSOR) {
|
||||||
|
if (!s->current_cursor) {
|
||||||
|
s->current_cursor = cursor_alloc(64, 64);
|
||||||
|
}
|
||||||
|
|
||||||
|
s->current_cursor->hot_x = cursor->hot_x;
|
||||||
|
s->current_cursor->hot_y = cursor->hot_y;
|
||||||
|
|
||||||
|
if (cursor->resource_id > 0) {
|
||||||
|
update_cursor_data_simple(g, s, cursor->resource_id);
|
||||||
|
}
|
||||||
|
dpy_cursor_define(s->con, s->current_cursor);
|
||||||
|
}
|
||||||
|
dpy_mouse_set(s->con, cursor->pos.x, cursor->pos.y,
|
||||||
|
cursor->resource_id ? 1 : 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void virtio_gpu_get_config(VirtIODevice *vdev, uint8_t *config)
|
||||||
|
{
|
||||||
|
VirtIOGPU *g = VIRTIO_GPU(vdev);
|
||||||
|
memcpy(config, &g->virtio_config, sizeof(g->virtio_config));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void virtio_gpu_set_config(VirtIODevice *vdev, const uint8_t *config)
|
||||||
|
{
|
||||||
|
VirtIOGPU *g = VIRTIO_GPU(vdev);
|
||||||
|
struct virtio_gpu_config vgconfig;
|
||||||
|
|
||||||
|
memcpy(&vgconfig, config, sizeof(g->virtio_config));
|
||||||
|
|
||||||
|
if (vgconfig.events_clear) {
|
||||||
|
g->virtio_config.events_read &= ~vgconfig.events_clear;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint64_t virtio_gpu_get_features(VirtIODevice *vdev, uint64_t features)
|
||||||
|
{
|
||||||
|
return features;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void virtio_gpu_notify_event(VirtIOGPU *g, uint32_t event_type)
|
||||||
|
{
|
||||||
|
g->virtio_config.events_read |= event_type;
|
||||||
|
virtio_notify_config(&g->parent_obj);
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct virtio_gpu_simple_resource *
|
||||||
|
virtio_gpu_find_resource(VirtIOGPU *g, uint32_t resource_id)
|
||||||
|
{
|
||||||
|
struct virtio_gpu_simple_resource *res;
|
||||||
|
|
||||||
|
QTAILQ_FOREACH(res, &g->reslist, next) {
|
||||||
|
if (res->resource_id == resource_id) {
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
void virtio_gpu_ctrl_response(VirtIOGPU *g,
|
||||||
|
struct virtio_gpu_ctrl_command *cmd,
|
||||||
|
struct virtio_gpu_ctrl_hdr *resp,
|
||||||
|
size_t resp_len)
|
||||||
|
{
|
||||||
|
size_t s;
|
||||||
|
|
||||||
|
if (cmd->cmd_hdr.flags & VIRTIO_GPU_FLAG_FENCE) {
|
||||||
|
resp->flags |= VIRTIO_GPU_FLAG_FENCE;
|
||||||
|
resp->fence_id = cmd->cmd_hdr.fence_id;
|
||||||
|
resp->ctx_id = cmd->cmd_hdr.ctx_id;
|
||||||
|
}
|
||||||
|
s = iov_from_buf(cmd->elem.in_sg, cmd->elem.in_num, 0, resp, resp_len);
|
||||||
|
if (s != resp_len) {
|
||||||
|
qemu_log_mask(LOG_GUEST_ERROR,
|
||||||
|
"%s: response size incorrect %zu vs %zu\n",
|
||||||
|
__func__, s, resp_len);
|
||||||
|
}
|
||||||
|
virtqueue_push(cmd->vq, &cmd->elem, s);
|
||||||
|
virtio_notify(VIRTIO_DEVICE(g), cmd->vq);
|
||||||
|
cmd->finished = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void virtio_gpu_ctrl_response_nodata(VirtIOGPU *g,
|
||||||
|
struct virtio_gpu_ctrl_command *cmd,
|
||||||
|
enum virtio_gpu_ctrl_type type)
|
||||||
|
{
|
||||||
|
struct virtio_gpu_ctrl_hdr resp;
|
||||||
|
|
||||||
|
memset(&resp, 0, sizeof(resp));
|
||||||
|
resp.type = type;
|
||||||
|
virtio_gpu_ctrl_response(g, cmd, &resp, sizeof(resp));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
virtio_gpu_fill_display_info(VirtIOGPU *g,
|
||||||
|
struct virtio_gpu_resp_display_info *dpy_info)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i = 0; i < g->conf.max_outputs; i++) {
|
||||||
|
if (g->enabled_output_bitmask & (1 << i)) {
|
||||||
|
dpy_info->pmodes[i].enabled = 1;
|
||||||
|
dpy_info->pmodes[i].r.width = g->req_state[i].width;
|
||||||
|
dpy_info->pmodes[i].r.height = g->req_state[i].height;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void virtio_gpu_get_display_info(VirtIOGPU *g,
|
||||||
|
struct virtio_gpu_ctrl_command *cmd)
|
||||||
|
{
|
||||||
|
struct virtio_gpu_resp_display_info display_info;
|
||||||
|
|
||||||
|
trace_virtio_gpu_cmd_get_display_info();
|
||||||
|
memset(&display_info, 0, sizeof(display_info));
|
||||||
|
display_info.hdr.type = VIRTIO_GPU_RESP_OK_DISPLAY_INFO;
|
||||||
|
virtio_gpu_fill_display_info(g, &display_info);
|
||||||
|
virtio_gpu_ctrl_response(g, cmd, &display_info.hdr,
|
||||||
|
sizeof(display_info));
|
||||||
|
}
|
||||||
|
|
||||||
|
static pixman_format_code_t get_pixman_format(uint32_t virtio_gpu_format)
|
||||||
|
{
|
||||||
|
switch (virtio_gpu_format) {
|
||||||
|
#ifdef HOST_WORDS_BIGENDIAN
|
||||||
|
case VIRTIO_GPU_FORMAT_B8G8R8X8_UNORM:
|
||||||
|
return PIXMAN_b8g8r8x8;
|
||||||
|
case VIRTIO_GPU_FORMAT_B8G8R8A8_UNORM:
|
||||||
|
return PIXMAN_b8g8r8a8;
|
||||||
|
case VIRTIO_GPU_FORMAT_X8R8G8B8_UNORM:
|
||||||
|
return PIXMAN_x8r8g8b8;
|
||||||
|
case VIRTIO_GPU_FORMAT_A8R8G8B8_UNORM:
|
||||||
|
return PIXMAN_a8r8g8b8;
|
||||||
|
case VIRTIO_GPU_FORMAT_R8G8B8X8_UNORM:
|
||||||
|
return PIXMAN_r8g8b8x8;
|
||||||
|
case VIRTIO_GPU_FORMAT_R8G8B8A8_UNORM:
|
||||||
|
return PIXMAN_r8g8b8a8;
|
||||||
|
case VIRTIO_GPU_FORMAT_X8B8G8R8_UNORM:
|
||||||
|
return PIXMAN_x8b8g8r8;
|
||||||
|
case VIRTIO_GPU_FORMAT_A8B8G8R8_UNORM:
|
||||||
|
return PIXMAN_a8b8g8r8;
|
||||||
|
#else
|
||||||
|
case VIRTIO_GPU_FORMAT_B8G8R8X8_UNORM:
|
||||||
|
return PIXMAN_x8r8g8b8;
|
||||||
|
case VIRTIO_GPU_FORMAT_B8G8R8A8_UNORM:
|
||||||
|
return PIXMAN_a8r8g8b8;
|
||||||
|
case VIRTIO_GPU_FORMAT_X8R8G8B8_UNORM:
|
||||||
|
return PIXMAN_b8g8r8x8;
|
||||||
|
case VIRTIO_GPU_FORMAT_A8R8G8B8_UNORM:
|
||||||
|
return PIXMAN_b8g8r8a8;
|
||||||
|
case VIRTIO_GPU_FORMAT_R8G8B8X8_UNORM:
|
||||||
|
return PIXMAN_x8b8g8r8;
|
||||||
|
case VIRTIO_GPU_FORMAT_R8G8B8A8_UNORM:
|
||||||
|
return PIXMAN_a8b8g8r8;
|
||||||
|
case VIRTIO_GPU_FORMAT_X8B8G8R8_UNORM:
|
||||||
|
return PIXMAN_r8g8b8x8;
|
||||||
|
case VIRTIO_GPU_FORMAT_A8B8G8R8_UNORM:
|
||||||
|
return PIXMAN_r8g8b8a8;
|
||||||
|
#endif
|
||||||
|
default:
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void virtio_gpu_resource_create_2d(VirtIOGPU *g,
|
||||||
|
struct virtio_gpu_ctrl_command *cmd)
|
||||||
|
{
|
||||||
|
pixman_format_code_t pformat;
|
||||||
|
struct virtio_gpu_simple_resource *res;
|
||||||
|
struct virtio_gpu_resource_create_2d c2d;
|
||||||
|
|
||||||
|
VIRTIO_GPU_FILL_CMD(c2d);
|
||||||
|
trace_virtio_gpu_cmd_res_create_2d(c2d.resource_id, c2d.format,
|
||||||
|
c2d.width, c2d.height);
|
||||||
|
|
||||||
|
if (c2d.resource_id == 0) {
|
||||||
|
qemu_log_mask(LOG_GUEST_ERROR, "%s: resource id 0 is not allowed\n",
|
||||||
|
__func__);
|
||||||
|
cmd->error = VIRTIO_GPU_RESP_ERR_INVALID_RESOURCE_ID;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
res = virtio_gpu_find_resource(g, c2d.resource_id);
|
||||||
|
if (res) {
|
||||||
|
qemu_log_mask(LOG_GUEST_ERROR, "%s: resource already exists %d\n",
|
||||||
|
__func__, c2d.resource_id);
|
||||||
|
cmd->error = VIRTIO_GPU_RESP_ERR_INVALID_RESOURCE_ID;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
res = g_new0(struct virtio_gpu_simple_resource, 1);
|
||||||
|
|
||||||
|
res->width = c2d.width;
|
||||||
|
res->height = c2d.height;
|
||||||
|
res->format = c2d.format;
|
||||||
|
res->resource_id = c2d.resource_id;
|
||||||
|
|
||||||
|
pformat = get_pixman_format(c2d.format);
|
||||||
|
if (!pformat) {
|
||||||
|
qemu_log_mask(LOG_GUEST_ERROR,
|
||||||
|
"%s: host couldn't handle guest format %d\n",
|
||||||
|
__func__, c2d.format);
|
||||||
|
cmd->error = VIRTIO_GPU_RESP_ERR_INVALID_PARAMETER;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
res->image = pixman_image_create_bits(pformat,
|
||||||
|
c2d.width,
|
||||||
|
c2d.height,
|
||||||
|
NULL, 0);
|
||||||
|
|
||||||
|
if (!res->image) {
|
||||||
|
qemu_log_mask(LOG_GUEST_ERROR,
|
||||||
|
"%s: resource creation failed %d %d %d\n",
|
||||||
|
__func__, c2d.resource_id, c2d.width, c2d.height);
|
||||||
|
g_free(res);
|
||||||
|
cmd->error = VIRTIO_GPU_RESP_ERR_OUT_OF_MEMORY;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
QTAILQ_INSERT_HEAD(&g->reslist, res, next);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void virtio_gpu_resource_destroy(VirtIOGPU *g,
|
||||||
|
struct virtio_gpu_simple_resource *res)
|
||||||
|
{
|
||||||
|
pixman_image_unref(res->image);
|
||||||
|
QTAILQ_REMOVE(&g->reslist, res, next);
|
||||||
|
g_free(res);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void virtio_gpu_resource_unref(VirtIOGPU *g,
|
||||||
|
struct virtio_gpu_ctrl_command *cmd)
|
||||||
|
{
|
||||||
|
struct virtio_gpu_simple_resource *res;
|
||||||
|
struct virtio_gpu_resource_unref unref;
|
||||||
|
|
||||||
|
VIRTIO_GPU_FILL_CMD(unref);
|
||||||
|
trace_virtio_gpu_cmd_res_unref(unref.resource_id);
|
||||||
|
|
||||||
|
res = virtio_gpu_find_resource(g, unref.resource_id);
|
||||||
|
if (!res) {
|
||||||
|
qemu_log_mask(LOG_GUEST_ERROR, "%s: illegal resource specified %d\n",
|
||||||
|
__func__, unref.resource_id);
|
||||||
|
cmd->error = VIRTIO_GPU_RESP_ERR_INVALID_RESOURCE_ID;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
virtio_gpu_resource_destroy(g, res);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void virtio_gpu_transfer_to_host_2d(VirtIOGPU *g,
|
||||||
|
struct virtio_gpu_ctrl_command *cmd)
|
||||||
|
{
|
||||||
|
struct virtio_gpu_simple_resource *res;
|
||||||
|
int h;
|
||||||
|
uint32_t src_offset, dst_offset, stride;
|
||||||
|
int bpp;
|
||||||
|
pixman_format_code_t format;
|
||||||
|
struct virtio_gpu_transfer_to_host_2d t2d;
|
||||||
|
|
||||||
|
VIRTIO_GPU_FILL_CMD(t2d);
|
||||||
|
trace_virtio_gpu_cmd_res_xfer_toh_2d(t2d.resource_id);
|
||||||
|
|
||||||
|
res = virtio_gpu_find_resource(g, t2d.resource_id);
|
||||||
|
if (!res || !res->iov) {
|
||||||
|
qemu_log_mask(LOG_GUEST_ERROR, "%s: illegal resource specified %d\n",
|
||||||
|
__func__, t2d.resource_id);
|
||||||
|
cmd->error = VIRTIO_GPU_RESP_ERR_INVALID_RESOURCE_ID;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (t2d.r.x > res->width ||
|
||||||
|
t2d.r.y > res->height ||
|
||||||
|
t2d.r.width > res->width ||
|
||||||
|
t2d.r.height > res->height ||
|
||||||
|
t2d.r.x + t2d.r.width > res->width ||
|
||||||
|
t2d.r.y + t2d.r.height > res->height) {
|
||||||
|
qemu_log_mask(LOG_GUEST_ERROR, "%s: transfer bounds outside resource"
|
||||||
|
" bounds for resource %d: %d %d %d %d vs %d %d\n",
|
||||||
|
__func__, t2d.resource_id, t2d.r.x, t2d.r.y,
|
||||||
|
t2d.r.width, t2d.r.height, res->width, res->height);
|
||||||
|
cmd->error = VIRTIO_GPU_RESP_ERR_INVALID_PARAMETER;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
format = pixman_image_get_format(res->image);
|
||||||
|
bpp = (PIXMAN_FORMAT_BPP(format) + 7) / 8;
|
||||||
|
stride = pixman_image_get_stride(res->image);
|
||||||
|
|
||||||
|
if (t2d.offset || t2d.r.x || t2d.r.y ||
|
||||||
|
t2d.r.width != pixman_image_get_width(res->image)) {
|
||||||
|
void *img_data = pixman_image_get_data(res->image);
|
||||||
|
for (h = 0; h < t2d.r.height; h++) {
|
||||||
|
src_offset = t2d.offset + stride * h;
|
||||||
|
dst_offset = (t2d.r.y + h) * stride + (t2d.r.x * bpp);
|
||||||
|
|
||||||
|
iov_to_buf(res->iov, res->iov_cnt, src_offset,
|
||||||
|
(uint8_t *)img_data
|
||||||
|
+ dst_offset, t2d.r.width * bpp);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
iov_to_buf(res->iov, res->iov_cnt, 0,
|
||||||
|
pixman_image_get_data(res->image),
|
||||||
|
pixman_image_get_stride(res->image)
|
||||||
|
* pixman_image_get_height(res->image));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void virtio_gpu_resource_flush(VirtIOGPU *g,
|
||||||
|
struct virtio_gpu_ctrl_command *cmd)
|
||||||
|
{
|
||||||
|
struct virtio_gpu_simple_resource *res;
|
||||||
|
struct virtio_gpu_resource_flush rf;
|
||||||
|
pixman_region16_t flush_region;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
VIRTIO_GPU_FILL_CMD(rf);
|
||||||
|
trace_virtio_gpu_cmd_res_flush(rf.resource_id,
|
||||||
|
rf.r.width, rf.r.height, rf.r.x, rf.r.y);
|
||||||
|
|
||||||
|
res = virtio_gpu_find_resource(g, rf.resource_id);
|
||||||
|
if (!res) {
|
||||||
|
qemu_log_mask(LOG_GUEST_ERROR, "%s: illegal resource specified %d\n",
|
||||||
|
__func__, rf.resource_id);
|
||||||
|
cmd->error = VIRTIO_GPU_RESP_ERR_INVALID_RESOURCE_ID;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (rf.r.x > res->width ||
|
||||||
|
rf.r.y > res->height ||
|
||||||
|
rf.r.width > res->width ||
|
||||||
|
rf.r.height > res->height ||
|
||||||
|
rf.r.x + rf.r.width > res->width ||
|
||||||
|
rf.r.y + rf.r.height > res->height) {
|
||||||
|
qemu_log_mask(LOG_GUEST_ERROR, "%s: flush bounds outside resource"
|
||||||
|
" bounds for resource %d: %d %d %d %d vs %d %d\n",
|
||||||
|
__func__, rf.resource_id, rf.r.x, rf.r.y,
|
||||||
|
rf.r.width, rf.r.height, res->width, res->height);
|
||||||
|
cmd->error = VIRTIO_GPU_RESP_ERR_INVALID_PARAMETER;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
pixman_region_init_rect(&flush_region,
|
||||||
|
rf.r.x, rf.r.y, rf.r.width, rf.r.height);
|
||||||
|
for (i = 0; i < VIRTIO_GPU_MAX_SCANOUT; i++) {
|
||||||
|
struct virtio_gpu_scanout *scanout;
|
||||||
|
pixman_region16_t region, finalregion;
|
||||||
|
pixman_box16_t *extents;
|
||||||
|
|
||||||
|
if (!(res->scanout_bitmask & (1 << i))) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
scanout = &g->scanout[i];
|
||||||
|
|
||||||
|
pixman_region_init(&finalregion);
|
||||||
|
pixman_region_init_rect(®ion, scanout->x, scanout->y,
|
||||||
|
scanout->width, scanout->height);
|
||||||
|
|
||||||
|
pixman_region_intersect(&finalregion, &flush_region, ®ion);
|
||||||
|
pixman_region_translate(&finalregion, -scanout->x, -scanout->y);
|
||||||
|
extents = pixman_region_extents(&finalregion);
|
||||||
|
/* work out the area we need to update for each console */
|
||||||
|
dpy_gfx_update(g->scanout[i].con,
|
||||||
|
extents->x1, extents->y1,
|
||||||
|
extents->x2 - extents->x1,
|
||||||
|
extents->y2 - extents->y1);
|
||||||
|
|
||||||
|
pixman_region_fini(®ion);
|
||||||
|
pixman_region_fini(&finalregion);
|
||||||
|
}
|
||||||
|
pixman_region_fini(&flush_region);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void virtio_gpu_set_scanout(VirtIOGPU *g,
|
||||||
|
struct virtio_gpu_ctrl_command *cmd)
|
||||||
|
{
|
||||||
|
struct virtio_gpu_simple_resource *res;
|
||||||
|
struct virtio_gpu_scanout *scanout;
|
||||||
|
pixman_format_code_t format;
|
||||||
|
uint32_t offset;
|
||||||
|
int bpp;
|
||||||
|
struct virtio_gpu_set_scanout ss;
|
||||||
|
|
||||||
|
VIRTIO_GPU_FILL_CMD(ss);
|
||||||
|
trace_virtio_gpu_cmd_set_scanout(ss.scanout_id, ss.resource_id,
|
||||||
|
ss.r.width, ss.r.height, ss.r.x, ss.r.y);
|
||||||
|
|
||||||
|
g->enable = 1;
|
||||||
|
if (ss.resource_id == 0) {
|
||||||
|
scanout = &g->scanout[ss.scanout_id];
|
||||||
|
if (scanout->resource_id) {
|
||||||
|
res = virtio_gpu_find_resource(g, scanout->resource_id);
|
||||||
|
if (res) {
|
||||||
|
res->scanout_bitmask &= ~(1 << ss.scanout_id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (ss.scanout_id == 0 ||
|
||||||
|
ss.scanout_id >= g->conf.max_outputs) {
|
||||||
|
qemu_log_mask(LOG_GUEST_ERROR,
|
||||||
|
"%s: illegal scanout id specified %d",
|
||||||
|
__func__, ss.scanout_id);
|
||||||
|
cmd->error = VIRTIO_GPU_RESP_ERR_INVALID_SCANOUT_ID;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
dpy_gfx_replace_surface(g->scanout[ss.scanout_id].con, NULL);
|
||||||
|
scanout->ds = NULL;
|
||||||
|
scanout->width = 0;
|
||||||
|
scanout->height = 0;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* create a surface for this scanout */
|
||||||
|
if (ss.scanout_id >= VIRTIO_GPU_MAX_SCANOUT ||
|
||||||
|
ss.scanout_id >= g->conf.max_outputs) {
|
||||||
|
qemu_log_mask(LOG_GUEST_ERROR, "%s: illegal scanout id specified %d",
|
||||||
|
__func__, ss.scanout_id);
|
||||||
|
cmd->error = VIRTIO_GPU_RESP_ERR_INVALID_SCANOUT_ID;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
res = virtio_gpu_find_resource(g, ss.resource_id);
|
||||||
|
if (!res) {
|
||||||
|
qemu_log_mask(LOG_GUEST_ERROR, "%s: illegal resource specified %d\n",
|
||||||
|
__func__, ss.resource_id);
|
||||||
|
cmd->error = VIRTIO_GPU_RESP_ERR_INVALID_RESOURCE_ID;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ss.r.x > res->width ||
|
||||||
|
ss.r.y > res->height ||
|
||||||
|
ss.r.width > res->width ||
|
||||||
|
ss.r.height > res->height ||
|
||||||
|
ss.r.x + ss.r.width > res->width ||
|
||||||
|
ss.r.y + ss.r.height > res->height) {
|
||||||
|
qemu_log_mask(LOG_GUEST_ERROR, "%s: illegal scanout %d bounds for"
|
||||||
|
" resource %d, (%d,%d)+%d,%d vs %d %d\n",
|
||||||
|
__func__, ss.scanout_id, ss.resource_id, ss.r.x, ss.r.y,
|
||||||
|
ss.r.width, ss.r.height, res->width, res->height);
|
||||||
|
cmd->error = VIRTIO_GPU_RESP_ERR_INVALID_PARAMETER;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
scanout = &g->scanout[ss.scanout_id];
|
||||||
|
|
||||||
|
format = pixman_image_get_format(res->image);
|
||||||
|
bpp = (PIXMAN_FORMAT_BPP(format) + 7) / 8;
|
||||||
|
offset = (ss.r.x * bpp) + ss.r.y * pixman_image_get_stride(res->image);
|
||||||
|
if (!scanout->ds || surface_data(scanout->ds)
|
||||||
|
!= ((uint8_t *)pixman_image_get_data(res->image) + offset) ||
|
||||||
|
scanout->width != ss.r.width ||
|
||||||
|
scanout->height != ss.r.height) {
|
||||||
|
/* realloc the surface ptr */
|
||||||
|
scanout->ds = qemu_create_displaysurface_from
|
||||||
|
(ss.r.width, ss.r.height, format,
|
||||||
|
pixman_image_get_stride(res->image),
|
||||||
|
(uint8_t *)pixman_image_get_data(res->image) + offset);
|
||||||
|
if (!scanout->ds) {
|
||||||
|
cmd->error = VIRTIO_GPU_RESP_ERR_UNSPEC;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
dpy_gfx_replace_surface(g->scanout[ss.scanout_id].con, scanout->ds);
|
||||||
|
}
|
||||||
|
|
||||||
|
res->scanout_bitmask |= (1 << ss.scanout_id);
|
||||||
|
scanout->resource_id = ss.resource_id;
|
||||||
|
scanout->x = ss.r.x;
|
||||||
|
scanout->y = ss.r.y;
|
||||||
|
scanout->width = ss.r.width;
|
||||||
|
scanout->height = ss.r.height;
|
||||||
|
}
|
||||||
|
|
||||||
|
int virtio_gpu_create_mapping_iov(struct virtio_gpu_resource_attach_backing *ab,
|
||||||
|
struct virtio_gpu_ctrl_command *cmd,
|
||||||
|
struct iovec **iov)
|
||||||
|
{
|
||||||
|
struct virtio_gpu_mem_entry *ents;
|
||||||
|
size_t esize, s;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
if (ab->nr_entries > 16384) {
|
||||||
|
qemu_log_mask(LOG_GUEST_ERROR,
|
||||||
|
"%s: nr_entries is too big (%d > 1024)\n",
|
||||||
|
__func__, ab->nr_entries);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
esize = sizeof(*ents) * ab->nr_entries;
|
||||||
|
ents = g_malloc(esize);
|
||||||
|
s = iov_to_buf(cmd->elem.out_sg, cmd->elem.out_num,
|
||||||
|
sizeof(*ab), ents, esize);
|
||||||
|
if (s != esize) {
|
||||||
|
qemu_log_mask(LOG_GUEST_ERROR,
|
||||||
|
"%s: command data size incorrect %zu vs %zu\n",
|
||||||
|
__func__, s, esize);
|
||||||
|
g_free(ents);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
*iov = g_malloc0(sizeof(struct iovec) * ab->nr_entries);
|
||||||
|
for (i = 0; i < ab->nr_entries; i++) {
|
||||||
|
hwaddr len = ents[i].length;
|
||||||
|
(*iov)[i].iov_len = ents[i].length;
|
||||||
|
(*iov)[i].iov_base = cpu_physical_memory_map(ents[i].addr, &len, 1);
|
||||||
|
if (!(*iov)[i].iov_base || len != ents[i].length) {
|
||||||
|
qemu_log_mask(LOG_GUEST_ERROR, "%s: failed to map MMIO memory for"
|
||||||
|
" resource %d element %d\n",
|
||||||
|
__func__, ab->resource_id, i);
|
||||||
|
virtio_gpu_cleanup_mapping_iov(*iov, i);
|
||||||
|
g_free(ents);
|
||||||
|
g_free(*iov);
|
||||||
|
*iov = NULL;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
g_free(ents);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void virtio_gpu_cleanup_mapping_iov(struct iovec *iov, uint32_t count)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i = 0; i < count; i++) {
|
||||||
|
cpu_physical_memory_unmap(iov[i].iov_base, iov[i].iov_len, 1,
|
||||||
|
iov[i].iov_len);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void virtio_gpu_cleanup_mapping(struct virtio_gpu_simple_resource *res)
|
||||||
|
{
|
||||||
|
virtio_gpu_cleanup_mapping_iov(res->iov, res->iov_cnt);
|
||||||
|
g_free(res->iov);
|
||||||
|
res->iov = NULL;
|
||||||
|
res->iov_cnt = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
virtio_gpu_resource_attach_backing(VirtIOGPU *g,
|
||||||
|
struct virtio_gpu_ctrl_command *cmd)
|
||||||
|
{
|
||||||
|
struct virtio_gpu_simple_resource *res;
|
||||||
|
struct virtio_gpu_resource_attach_backing ab;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
VIRTIO_GPU_FILL_CMD(ab);
|
||||||
|
trace_virtio_gpu_cmd_res_back_attach(ab.resource_id);
|
||||||
|
|
||||||
|
res = virtio_gpu_find_resource(g, ab.resource_id);
|
||||||
|
if (!res) {
|
||||||
|
qemu_log_mask(LOG_GUEST_ERROR, "%s: illegal resource specified %d\n",
|
||||||
|
__func__, ab.resource_id);
|
||||||
|
cmd->error = VIRTIO_GPU_RESP_ERR_INVALID_RESOURCE_ID;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = virtio_gpu_create_mapping_iov(&ab, cmd, &res->iov);
|
||||||
|
if (ret != 0) {
|
||||||
|
cmd->error = VIRTIO_GPU_RESP_ERR_UNSPEC;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
res->iov_cnt = ab.nr_entries;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
virtio_gpu_resource_detach_backing(VirtIOGPU *g,
|
||||||
|
struct virtio_gpu_ctrl_command *cmd)
|
||||||
|
{
|
||||||
|
struct virtio_gpu_simple_resource *res;
|
||||||
|
struct virtio_gpu_resource_detach_backing detach;
|
||||||
|
|
||||||
|
VIRTIO_GPU_FILL_CMD(detach);
|
||||||
|
trace_virtio_gpu_cmd_res_back_detach(detach.resource_id);
|
||||||
|
|
||||||
|
res = virtio_gpu_find_resource(g, detach.resource_id);
|
||||||
|
if (!res || !res->iov) {
|
||||||
|
qemu_log_mask(LOG_GUEST_ERROR, "%s: illegal resource specified %d\n",
|
||||||
|
__func__, detach.resource_id);
|
||||||
|
cmd->error = VIRTIO_GPU_RESP_ERR_INVALID_RESOURCE_ID;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
virtio_gpu_cleanup_mapping(res);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void virtio_gpu_simple_process_cmd(VirtIOGPU *g,
|
||||||
|
struct virtio_gpu_ctrl_command *cmd)
|
||||||
|
{
|
||||||
|
VIRTIO_GPU_FILL_CMD(cmd->cmd_hdr);
|
||||||
|
|
||||||
|
switch (cmd->cmd_hdr.type) {
|
||||||
|
case VIRTIO_GPU_CMD_GET_DISPLAY_INFO:
|
||||||
|
virtio_gpu_get_display_info(g, cmd);
|
||||||
|
break;
|
||||||
|
case VIRTIO_GPU_CMD_RESOURCE_CREATE_2D:
|
||||||
|
virtio_gpu_resource_create_2d(g, cmd);
|
||||||
|
break;
|
||||||
|
case VIRTIO_GPU_CMD_RESOURCE_UNREF:
|
||||||
|
virtio_gpu_resource_unref(g, cmd);
|
||||||
|
break;
|
||||||
|
case VIRTIO_GPU_CMD_RESOURCE_FLUSH:
|
||||||
|
virtio_gpu_resource_flush(g, cmd);
|
||||||
|
break;
|
||||||
|
case VIRTIO_GPU_CMD_TRANSFER_TO_HOST_2D:
|
||||||
|
virtio_gpu_transfer_to_host_2d(g, cmd);
|
||||||
|
break;
|
||||||
|
case VIRTIO_GPU_CMD_SET_SCANOUT:
|
||||||
|
virtio_gpu_set_scanout(g, cmd);
|
||||||
|
break;
|
||||||
|
case VIRTIO_GPU_CMD_RESOURCE_ATTACH_BACKING:
|
||||||
|
virtio_gpu_resource_attach_backing(g, cmd);
|
||||||
|
break;
|
||||||
|
case VIRTIO_GPU_CMD_RESOURCE_DETACH_BACKING:
|
||||||
|
virtio_gpu_resource_detach_backing(g, cmd);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
cmd->error = VIRTIO_GPU_RESP_ERR_UNSPEC;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (!cmd->finished) {
|
||||||
|
virtio_gpu_ctrl_response_nodata(g, cmd, cmd->error ? cmd->error :
|
||||||
|
VIRTIO_GPU_RESP_OK_NODATA);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void virtio_gpu_handle_ctrl_cb(VirtIODevice *vdev, VirtQueue *vq)
|
||||||
|
{
|
||||||
|
VirtIOGPU *g = VIRTIO_GPU(vdev);
|
||||||
|
qemu_bh_schedule(g->ctrl_bh);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void virtio_gpu_handle_cursor_cb(VirtIODevice *vdev, VirtQueue *vq)
|
||||||
|
{
|
||||||
|
VirtIOGPU *g = VIRTIO_GPU(vdev);
|
||||||
|
qemu_bh_schedule(g->cursor_bh);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void virtio_gpu_handle_ctrl(VirtIODevice *vdev, VirtQueue *vq)
|
||||||
|
{
|
||||||
|
VirtIOGPU *g = VIRTIO_GPU(vdev);
|
||||||
|
struct virtio_gpu_ctrl_command *cmd;
|
||||||
|
|
||||||
|
if (!virtio_queue_ready(vq)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
cmd = g_new(struct virtio_gpu_ctrl_command, 1);
|
||||||
|
while (virtqueue_pop(vq, &cmd->elem)) {
|
||||||
|
cmd->vq = vq;
|
||||||
|
cmd->error = 0;
|
||||||
|
cmd->finished = false;
|
||||||
|
g->stats.requests++;
|
||||||
|
|
||||||
|
virtio_gpu_simple_process_cmd(g, cmd);
|
||||||
|
if (!cmd->finished) {
|
||||||
|
QTAILQ_INSERT_TAIL(&g->fenceq, cmd, next);
|
||||||
|
g->stats.inflight++;
|
||||||
|
if (g->stats.max_inflight < g->stats.inflight) {
|
||||||
|
g->stats.max_inflight = g->stats.inflight;
|
||||||
|
}
|
||||||
|
fprintf(stderr, "inflight: %3d (+)\r", g->stats.inflight);
|
||||||
|
cmd = g_new(struct virtio_gpu_ctrl_command, 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
g_free(cmd);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void virtio_gpu_ctrl_bh(void *opaque)
|
||||||
|
{
|
||||||
|
VirtIOGPU *g = opaque;
|
||||||
|
virtio_gpu_handle_ctrl(&g->parent_obj, g->ctrl_vq);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void virtio_gpu_handle_cursor(VirtIODevice *vdev, VirtQueue *vq)
|
||||||
|
{
|
||||||
|
VirtIOGPU *g = VIRTIO_GPU(vdev);
|
||||||
|
VirtQueueElement elem;
|
||||||
|
size_t s;
|
||||||
|
struct virtio_gpu_update_cursor cursor_info;
|
||||||
|
|
||||||
|
if (!virtio_queue_ready(vq)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
while (virtqueue_pop(vq, &elem)) {
|
||||||
|
s = iov_to_buf(elem.out_sg, elem.out_num, 0,
|
||||||
|
&cursor_info, sizeof(cursor_info));
|
||||||
|
if (s != sizeof(cursor_info)) {
|
||||||
|
qemu_log_mask(LOG_GUEST_ERROR,
|
||||||
|
"%s: cursor size incorrect %zu vs %zu\n",
|
||||||
|
__func__, s, sizeof(cursor_info));
|
||||||
|
} else {
|
||||||
|
update_cursor(g, &cursor_info);
|
||||||
|
}
|
||||||
|
virtqueue_push(vq, &elem, 0);
|
||||||
|
virtio_notify(vdev, vq);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void virtio_gpu_cursor_bh(void *opaque)
|
||||||
|
{
|
||||||
|
VirtIOGPU *g = opaque;
|
||||||
|
virtio_gpu_handle_cursor(&g->parent_obj, g->cursor_vq);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void virtio_gpu_invalidate_display(void *opaque)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
static void virtio_gpu_update_display(void *opaque)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
static void virtio_gpu_text_update(void *opaque, console_ch_t *chardata)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
static int virtio_gpu_ui_info(void *opaque, uint32_t idx, QemuUIInfo *info)
|
||||||
|
{
|
||||||
|
VirtIOGPU *g = opaque;
|
||||||
|
|
||||||
|
if (idx > g->conf.max_outputs) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
g->req_state[idx].x = info->xoff;
|
||||||
|
g->req_state[idx].y = info->yoff;
|
||||||
|
g->req_state[idx].width = info->width;
|
||||||
|
g->req_state[idx].height = info->height;
|
||||||
|
|
||||||
|
if (info->width && info->height) {
|
||||||
|
g->enabled_output_bitmask |= (1 << idx);
|
||||||
|
} else {
|
||||||
|
g->enabled_output_bitmask &= ~(1 << idx);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* send event to guest */
|
||||||
|
virtio_gpu_notify_event(g, VIRTIO_GPU_EVENT_DISPLAY);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
const GraphicHwOps virtio_gpu_ops = {
|
||||||
|
.invalidate = virtio_gpu_invalidate_display,
|
||||||
|
.gfx_update = virtio_gpu_update_display,
|
||||||
|
.text_update = virtio_gpu_text_update,
|
||||||
|
.ui_info = virtio_gpu_ui_info,
|
||||||
|
};
|
||||||
|
|
||||||
|
static void virtio_gpu_device_realize(DeviceState *qdev, Error **errp)
|
||||||
|
{
|
||||||
|
VirtIODevice *vdev = VIRTIO_DEVICE(qdev);
|
||||||
|
VirtIOGPU *g = VIRTIO_GPU(qdev);
|
||||||
|
int i;
|
||||||
|
|
||||||
|
g->config_size = sizeof(struct virtio_gpu_config);
|
||||||
|
g->virtio_config.num_scanouts = g->conf.max_outputs;
|
||||||
|
virtio_init(VIRTIO_DEVICE(g), "virtio-gpu", VIRTIO_ID_GPU,
|
||||||
|
g->config_size);
|
||||||
|
|
||||||
|
g->req_state[0].width = 1024;
|
||||||
|
g->req_state[0].height = 768;
|
||||||
|
|
||||||
|
g->ctrl_vq = virtio_add_queue(vdev, 64, virtio_gpu_handle_ctrl_cb);
|
||||||
|
g->cursor_vq = virtio_add_queue(vdev, 16, virtio_gpu_handle_cursor_cb);
|
||||||
|
|
||||||
|
g->ctrl_bh = qemu_bh_new(virtio_gpu_ctrl_bh, g);
|
||||||
|
g->cursor_bh = qemu_bh_new(virtio_gpu_cursor_bh, g);
|
||||||
|
QTAILQ_INIT(&g->reslist);
|
||||||
|
QTAILQ_INIT(&g->fenceq);
|
||||||
|
|
||||||
|
g->enabled_output_bitmask = 1;
|
||||||
|
g->qdev = qdev;
|
||||||
|
|
||||||
|
for (i = 0; i < g->conf.max_outputs; i++) {
|
||||||
|
g->scanout[i].con =
|
||||||
|
graphic_console_init(DEVICE(g), i, &virtio_gpu_ops, g);
|
||||||
|
if (i > 0) {
|
||||||
|
dpy_gfx_replace_surface(g->scanout[i].con, NULL);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void virtio_gpu_instance_init(Object *obj)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
static void virtio_gpu_reset(VirtIODevice *vdev)
|
||||||
|
{
|
||||||
|
VirtIOGPU *g = VIRTIO_GPU(vdev);
|
||||||
|
struct virtio_gpu_simple_resource *res, *tmp;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
g->enable = 0;
|
||||||
|
|
||||||
|
QTAILQ_FOREACH_SAFE(res, &g->reslist, next, tmp) {
|
||||||
|
virtio_gpu_resource_destroy(g, res);
|
||||||
|
}
|
||||||
|
for (i = 0; i < g->conf.max_outputs; i++) {
|
||||||
|
#if 0
|
||||||
|
g->req_state[i].x = 0;
|
||||||
|
g->req_state[i].y = 0;
|
||||||
|
if (i == 0) {
|
||||||
|
g->req_state[0].width = 1024;
|
||||||
|
g->req_state[0].height = 768;
|
||||||
|
} else {
|
||||||
|
g->req_state[i].width = 0;
|
||||||
|
g->req_state[i].height = 0;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
g->scanout[i].resource_id = 0;
|
||||||
|
g->scanout[i].width = 0;
|
||||||
|
g->scanout[i].height = 0;
|
||||||
|
g->scanout[i].x = 0;
|
||||||
|
g->scanout[i].y = 0;
|
||||||
|
g->scanout[i].ds = NULL;
|
||||||
|
}
|
||||||
|
g->enabled_output_bitmask = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static Property virtio_gpu_properties[] = {
|
||||||
|
DEFINE_VIRTIO_GPU_PROPERTIES(VirtIOGPU, conf),
|
||||||
|
DEFINE_PROP_END_OF_LIST(),
|
||||||
|
};
|
||||||
|
|
||||||
|
static void virtio_gpu_class_init(ObjectClass *klass, void *data)
|
||||||
|
{
|
||||||
|
DeviceClass *dc = DEVICE_CLASS(klass);
|
||||||
|
VirtioDeviceClass *vdc = VIRTIO_DEVICE_CLASS(klass);
|
||||||
|
|
||||||
|
vdc->realize = virtio_gpu_device_realize;
|
||||||
|
vdc->get_config = virtio_gpu_get_config;
|
||||||
|
vdc->set_config = virtio_gpu_set_config;
|
||||||
|
vdc->get_features = virtio_gpu_get_features;
|
||||||
|
|
||||||
|
vdc->reset = virtio_gpu_reset;
|
||||||
|
|
||||||
|
dc->props = virtio_gpu_properties;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const TypeInfo virtio_gpu_info = {
|
||||||
|
.name = TYPE_VIRTIO_GPU,
|
||||||
|
.parent = TYPE_VIRTIO_DEVICE,
|
||||||
|
.instance_size = sizeof(VirtIOGPU),
|
||||||
|
.instance_init = virtio_gpu_instance_init,
|
||||||
|
.class_init = virtio_gpu_class_init,
|
||||||
|
};
|
||||||
|
|
||||||
|
static void virtio_register_types(void)
|
||||||
|
{
|
||||||
|
type_register_static(&virtio_gpu_info);
|
||||||
|
}
|
||||||
|
|
||||||
|
type_init(virtio_register_types)
|
||||||
|
|
||||||
|
QEMU_BUILD_BUG_ON(sizeof(struct virtio_gpu_ctrl_hdr) != 24);
|
||||||
|
QEMU_BUILD_BUG_ON(sizeof(struct virtio_gpu_update_cursor) != 56);
|
||||||
|
QEMU_BUILD_BUG_ON(sizeof(struct virtio_gpu_resource_unref) != 32);
|
||||||
|
QEMU_BUILD_BUG_ON(sizeof(struct virtio_gpu_resource_create_2d) != 40);
|
||||||
|
QEMU_BUILD_BUG_ON(sizeof(struct virtio_gpu_set_scanout) != 48);
|
||||||
|
QEMU_BUILD_BUG_ON(sizeof(struct virtio_gpu_resource_flush) != 48);
|
||||||
|
QEMU_BUILD_BUG_ON(sizeof(struct virtio_gpu_transfer_to_host_2d) != 56);
|
||||||
|
QEMU_BUILD_BUG_ON(sizeof(struct virtio_gpu_mem_entry) != 16);
|
||||||
|
QEMU_BUILD_BUG_ON(sizeof(struct virtio_gpu_resource_attach_backing) != 32);
|
||||||
|
QEMU_BUILD_BUG_ON(sizeof(struct virtio_gpu_resource_detach_backing) != 32);
|
||||||
|
QEMU_BUILD_BUG_ON(sizeof(struct virtio_gpu_resp_display_info) != 408);
|
||||||
@@ -1124,7 +1124,7 @@ static void vmsvga_update_display(void *opaque)
|
|||||||
* Is it more efficient to look at vram VGA-dirty bits or wait
|
* Is it more efficient to look at vram VGA-dirty bits or wait
|
||||||
* for the driver to issue SVGA_CMD_UPDATE?
|
* for the driver to issue SVGA_CMD_UPDATE?
|
||||||
*/
|
*/
|
||||||
if (memory_region_is_logging(&s->vga.vram)) {
|
if (memory_region_is_logging(&s->vga.vram, DIRTY_MEMORY_VGA)) {
|
||||||
vga_sync_dirty_bitmap(&s->vga);
|
vga_sync_dirty_bitmap(&s->vga);
|
||||||
dirty = memory_region_get_dirty(&s->vga.vram, 0,
|
dirty = memory_region_get_dirty(&s->vga.vram, 0,
|
||||||
surface_stride(surface) * surface_height(surface),
|
surface_stride(surface) * surface_height(surface),
|
||||||
|
|||||||
@@ -173,7 +173,7 @@ static uint64_t pl061_read(void *opaque, hwaddr offset,
|
|||||||
case 0x414: /* Raw interrupt status */
|
case 0x414: /* Raw interrupt status */
|
||||||
return s->istate;
|
return s->istate;
|
||||||
case 0x418: /* Masked interrupt status */
|
case 0x418: /* Masked interrupt status */
|
||||||
return s->istate | s->im;
|
return s->istate & s->im;
|
||||||
case 0x420: /* Alternate function select */
|
case 0x420: /* Alternate function select */
|
||||||
return s->afsel;
|
return s->afsel;
|
||||||
case 0x500: /* 2mA drive */
|
case 0x500: /* 2mA drive */
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
common-obj-y += core.o smbus.o smbus_eeprom.o
|
common-obj-y += core.o smbus.o smbus_eeprom.o
|
||||||
common-obj-$(CONFIG_VERSATILE_I2C) += versatile_i2c.o
|
common-obj-$(CONFIG_VERSATILE_I2C) += versatile_i2c.o
|
||||||
common-obj-$(CONFIG_ACPI) += smbus_ich9.o
|
common-obj-$(CONFIG_ACPI_X86) += smbus_ich9.o
|
||||||
common-obj-$(CONFIG_APM) += pm_smbus.o
|
common-obj-$(CONFIG_APM) += pm_smbus.o
|
||||||
common-obj-$(CONFIG_BITBANG_I2C) += bitbang_i2c.o
|
common-obj-$(CONFIG_BITBANG_I2C) += bitbang_i2c.o
|
||||||
common-obj-$(CONFIG_EXYNOS4) += exynos4210_i2c.o
|
common-obj-$(CONFIG_EXYNOS4) += exynos4210_i2c.o
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ obj-y += kvmvapic.o
|
|||||||
obj-y += acpi-build.o
|
obj-y += acpi-build.o
|
||||||
hw/i386/acpi-build.o: hw/i386/acpi-build.c \
|
hw/i386/acpi-build.o: hw/i386/acpi-build.c \
|
||||||
hw/i386/acpi-dsdt.hex hw/i386/q35-acpi-dsdt.hex \
|
hw/i386/acpi-dsdt.hex hw/i386/q35-acpi-dsdt.hex \
|
||||||
hw/i386/ssdt-tpm.hex
|
hw/i386/ssdt-tpm.hex hw/i386/ssdt-tpm2.hex
|
||||||
|
|
||||||
iasl-option=$(shell if test -z "`$(1) $(2) 2>&1 > /dev/null`" \
|
iasl-option=$(shell if test -z "`$(1) $(2) 2>&1 > /dev/null`" \
|
||||||
; then echo "$(2)"; else echo "$(3)"; fi ;)
|
; then echo "$(2)"; else echo "$(3)"; fi ;)
|
||||||
|
|||||||
@@ -41,6 +41,7 @@
|
|||||||
#include "hw/acpi/memory_hotplug.h"
|
#include "hw/acpi/memory_hotplug.h"
|
||||||
#include "sysemu/tpm.h"
|
#include "sysemu/tpm.h"
|
||||||
#include "hw/acpi/tpm.h"
|
#include "hw/acpi/tpm.h"
|
||||||
|
#include "sysemu/tpm_backend.h"
|
||||||
|
|
||||||
/* Supported chipsets: */
|
/* Supported chipsets: */
|
||||||
#include "hw/acpi/piix4.h"
|
#include "hw/acpi/piix4.h"
|
||||||
@@ -106,7 +107,7 @@ typedef struct AcpiPmInfo {
|
|||||||
|
|
||||||
typedef struct AcpiMiscInfo {
|
typedef struct AcpiMiscInfo {
|
||||||
bool has_hpet;
|
bool has_hpet;
|
||||||
bool has_tpm;
|
TPMVersion tpm_version;
|
||||||
const unsigned char *dsdt_code;
|
const unsigned char *dsdt_code;
|
||||||
unsigned dsdt_size;
|
unsigned dsdt_size;
|
||||||
uint16_t pvpanic_port;
|
uint16_t pvpanic_port;
|
||||||
@@ -234,18 +235,37 @@ static void acpi_get_pm_info(AcpiPmInfo *pm)
|
|||||||
static void acpi_get_misc_info(AcpiMiscInfo *info)
|
static void acpi_get_misc_info(AcpiMiscInfo *info)
|
||||||
{
|
{
|
||||||
info->has_hpet = hpet_find();
|
info->has_hpet = hpet_find();
|
||||||
info->has_tpm = tpm_find();
|
info->tpm_version = tpm_get_version();
|
||||||
info->pvpanic_port = pvpanic_port();
|
info->pvpanic_port = pvpanic_port();
|
||||||
info->applesmc_io_base = applesmc_port();
|
info->applesmc_io_base = applesmc_port();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Because of the PXB hosts we cannot simply query TYPE_PCI_HOST_BRIDGE.
|
||||||
|
* On i386 arch we only have two pci hosts, so we can look only for them.
|
||||||
|
*/
|
||||||
|
static Object *acpi_get_i386_pci_host(void)
|
||||||
|
{
|
||||||
|
PCIHostState *host;
|
||||||
|
|
||||||
|
host = OBJECT_CHECK(PCIHostState,
|
||||||
|
object_resolve_path("/machine/i440fx", NULL),
|
||||||
|
TYPE_PCI_HOST_BRIDGE);
|
||||||
|
if (!host) {
|
||||||
|
host = OBJECT_CHECK(PCIHostState,
|
||||||
|
object_resolve_path("/machine/q35", NULL),
|
||||||
|
TYPE_PCI_HOST_BRIDGE);
|
||||||
|
}
|
||||||
|
|
||||||
|
return OBJECT(host);
|
||||||
|
}
|
||||||
|
|
||||||
static void acpi_get_pci_info(PcPciInfo *info)
|
static void acpi_get_pci_info(PcPciInfo *info)
|
||||||
{
|
{
|
||||||
Object *pci_host;
|
Object *pci_host;
|
||||||
bool ambiguous;
|
|
||||||
|
|
||||||
pci_host = object_resolve_path_type("", TYPE_PCI_HOST_BRIDGE, &ambiguous);
|
|
||||||
g_assert(!ambiguous);
|
pci_host = acpi_get_i386_pci_host();
|
||||||
g_assert(pci_host);
|
g_assert(pci_host);
|
||||||
|
|
||||||
info->w32.begin = object_property_get_int(pci_host,
|
info->w32.begin = object_property_get_int(pci_host,
|
||||||
@@ -414,6 +434,7 @@ build_madt(GArray *table_data, GArray *linker, AcpiCpuInfo *cpu,
|
|||||||
}
|
}
|
||||||
|
|
||||||
#include "hw/i386/ssdt-tpm.hex"
|
#include "hw/i386/ssdt-tpm.hex"
|
||||||
|
#include "hw/i386/ssdt-tpm2.hex"
|
||||||
|
|
||||||
/* Assign BSEL property to all buses. In the future, this can be changed
|
/* Assign BSEL property to all buses. In the future, this can be changed
|
||||||
* to only assign to buses that support hotplug.
|
* to only assign to buses that support hotplug.
|
||||||
@@ -594,6 +615,291 @@ static void build_append_pci_bus_devices(Aml *parent_scope, PCIBus *bus,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
aml_append(parent_scope, method);
|
aml_append(parent_scope, method);
|
||||||
|
qobject_decref(bsel);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* initialize_route - Initialize the interrupt routing rule
|
||||||
|
* through a specific LINK:
|
||||||
|
* if (lnk_idx == idx)
|
||||||
|
* route using link 'link_name'
|
||||||
|
*/
|
||||||
|
static Aml *initialize_route(Aml *route, const char *link_name,
|
||||||
|
Aml *lnk_idx, int idx)
|
||||||
|
{
|
||||||
|
Aml *if_ctx = aml_if(aml_equal(lnk_idx, aml_int(idx)));
|
||||||
|
Aml *pkg = aml_package(4);
|
||||||
|
|
||||||
|
aml_append(pkg, aml_int(0));
|
||||||
|
aml_append(pkg, aml_int(0));
|
||||||
|
aml_append(pkg, aml_name("%s", link_name));
|
||||||
|
aml_append(pkg, aml_int(0));
|
||||||
|
aml_append(if_ctx, aml_store(pkg, route));
|
||||||
|
|
||||||
|
return if_ctx;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* build_prt - Define interrupt rounting rules
|
||||||
|
*
|
||||||
|
* Returns an array of 128 routes, one for each device,
|
||||||
|
* based on device location.
|
||||||
|
* The main goal is to equaly distribute the interrupts
|
||||||
|
* over the 4 existing ACPI links (works only for i440fx).
|
||||||
|
* The hash function is (slot + pin) & 3 -> "LNK[D|A|B|C]".
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
static Aml *build_prt(void)
|
||||||
|
{
|
||||||
|
Aml *method, *while_ctx, *pin, *res;
|
||||||
|
|
||||||
|
method = aml_method("_PRT", 0);
|
||||||
|
res = aml_local(0);
|
||||||
|
pin = aml_local(1);
|
||||||
|
aml_append(method, aml_store(aml_package(128), res));
|
||||||
|
aml_append(method, aml_store(aml_int(0), pin));
|
||||||
|
|
||||||
|
/* while (pin < 128) */
|
||||||
|
while_ctx = aml_while(aml_lless(pin, aml_int(128)));
|
||||||
|
{
|
||||||
|
Aml *slot = aml_local(2);
|
||||||
|
Aml *lnk_idx = aml_local(3);
|
||||||
|
Aml *route = aml_local(4);
|
||||||
|
|
||||||
|
/* slot = pin >> 2 */
|
||||||
|
aml_append(while_ctx,
|
||||||
|
aml_store(aml_shiftright(pin, aml_int(2)), slot));
|
||||||
|
/* lnk_idx = (slot + pin) & 3 */
|
||||||
|
aml_append(while_ctx,
|
||||||
|
aml_store(aml_and(aml_add(pin, slot), aml_int(3)), lnk_idx));
|
||||||
|
|
||||||
|
/* route[2] = "LNK[D|A|B|C]", selection based on pin % 3 */
|
||||||
|
aml_append(while_ctx, initialize_route(route, "LNKD", lnk_idx, 0));
|
||||||
|
aml_append(while_ctx, initialize_route(route, "LNKA", lnk_idx, 1));
|
||||||
|
aml_append(while_ctx, initialize_route(route, "LNKB", lnk_idx, 2));
|
||||||
|
aml_append(while_ctx, initialize_route(route, "LNKC", lnk_idx, 3));
|
||||||
|
|
||||||
|
/* route[0] = 0x[slot]FFFF */
|
||||||
|
aml_append(while_ctx,
|
||||||
|
aml_store(aml_or(aml_shiftleft(slot, aml_int(16)), aml_int(0xFFFF)),
|
||||||
|
aml_index(route, aml_int(0))));
|
||||||
|
/* route[1] = pin & 3 */
|
||||||
|
aml_append(while_ctx,
|
||||||
|
aml_store(aml_and(pin, aml_int(3)), aml_index(route, aml_int(1))));
|
||||||
|
/* res[pin] = route */
|
||||||
|
aml_append(while_ctx, aml_store(route, aml_index(res, pin)));
|
||||||
|
/* pin++ */
|
||||||
|
aml_append(while_ctx, aml_increment(pin));
|
||||||
|
}
|
||||||
|
aml_append(method, while_ctx);
|
||||||
|
/* return res*/
|
||||||
|
aml_append(method, aml_return(res));
|
||||||
|
|
||||||
|
return method;
|
||||||
|
}
|
||||||
|
|
||||||
|
typedef struct CrsRangeEntry {
|
||||||
|
uint64_t base;
|
||||||
|
uint64_t limit;
|
||||||
|
} CrsRangeEntry;
|
||||||
|
|
||||||
|
static void crs_range_insert(GPtrArray *ranges, uint64_t base, uint64_t limit)
|
||||||
|
{
|
||||||
|
CrsRangeEntry *entry;
|
||||||
|
|
||||||
|
entry = g_malloc(sizeof(*entry));
|
||||||
|
entry->base = base;
|
||||||
|
entry->limit = limit;
|
||||||
|
|
||||||
|
g_ptr_array_add(ranges, entry);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void crs_range_free(gpointer data)
|
||||||
|
{
|
||||||
|
CrsRangeEntry *entry = (CrsRangeEntry *)data;
|
||||||
|
g_free(entry);
|
||||||
|
}
|
||||||
|
|
||||||
|
static gint crs_range_compare(gconstpointer a, gconstpointer b)
|
||||||
|
{
|
||||||
|
CrsRangeEntry *entry_a = *(CrsRangeEntry **)a;
|
||||||
|
CrsRangeEntry *entry_b = *(CrsRangeEntry **)b;
|
||||||
|
|
||||||
|
return (int64_t)entry_a->base - (int64_t)entry_b->base;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* crs_replace_with_free_ranges - given the 'used' ranges within [start - end]
|
||||||
|
* interval, computes the 'free' ranges from the same interval.
|
||||||
|
* Example: If the input array is { [a1 - a2],[b1 - b2] }, the function
|
||||||
|
* will return { [base - a1], [a2 - b1], [b2 - limit] }.
|
||||||
|
*/
|
||||||
|
static void crs_replace_with_free_ranges(GPtrArray *ranges,
|
||||||
|
uint64_t start, uint64_t end)
|
||||||
|
{
|
||||||
|
GPtrArray *free_ranges = g_ptr_array_new_with_free_func(crs_range_free);
|
||||||
|
uint64_t free_base = start;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
g_ptr_array_sort(ranges, crs_range_compare);
|
||||||
|
for (i = 0; i < ranges->len; i++) {
|
||||||
|
CrsRangeEntry *used = g_ptr_array_index(ranges, i);
|
||||||
|
|
||||||
|
if (free_base < used->base) {
|
||||||
|
crs_range_insert(free_ranges, free_base, used->base - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
free_base = used->limit + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (free_base < end) {
|
||||||
|
crs_range_insert(free_ranges, free_base, end);
|
||||||
|
}
|
||||||
|
|
||||||
|
g_ptr_array_set_size(ranges, 0);
|
||||||
|
for (i = 0; i < free_ranges->len; i++) {
|
||||||
|
g_ptr_array_add(ranges, g_ptr_array_index(free_ranges, i));
|
||||||
|
}
|
||||||
|
|
||||||
|
g_ptr_array_free(free_ranges, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
static Aml *build_crs(PCIHostState *host,
|
||||||
|
GPtrArray *io_ranges, GPtrArray *mem_ranges)
|
||||||
|
{
|
||||||
|
Aml *crs = aml_resource_template();
|
||||||
|
uint8_t max_bus = pci_bus_num(host->bus);
|
||||||
|
uint8_t type;
|
||||||
|
int devfn;
|
||||||
|
|
||||||
|
for (devfn = 0; devfn < ARRAY_SIZE(host->bus->devices); devfn++) {
|
||||||
|
int i;
|
||||||
|
uint64_t range_base, range_limit;
|
||||||
|
PCIDevice *dev = host->bus->devices[devfn];
|
||||||
|
|
||||||
|
if (!dev) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < PCI_NUM_REGIONS; i++) {
|
||||||
|
PCIIORegion *r = &dev->io_regions[i];
|
||||||
|
|
||||||
|
range_base = r->addr;
|
||||||
|
range_limit = r->addr + r->size - 1;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Work-around for old bioses
|
||||||
|
* that do not support multiple root buses
|
||||||
|
*/
|
||||||
|
if (!range_base || range_base > range_limit) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (r->type & PCI_BASE_ADDRESS_SPACE_IO) {
|
||||||
|
aml_append(crs,
|
||||||
|
aml_word_io(AML_MIN_FIXED, AML_MAX_FIXED,
|
||||||
|
AML_POS_DECODE, AML_ENTIRE_RANGE,
|
||||||
|
0,
|
||||||
|
range_base,
|
||||||
|
range_limit,
|
||||||
|
0,
|
||||||
|
range_limit - range_base + 1));
|
||||||
|
crs_range_insert(io_ranges, range_base, range_limit);
|
||||||
|
} else { /* "memory" */
|
||||||
|
aml_append(crs,
|
||||||
|
aml_dword_memory(AML_POS_DECODE, AML_MIN_FIXED,
|
||||||
|
AML_MAX_FIXED, AML_NON_CACHEABLE,
|
||||||
|
AML_READ_WRITE,
|
||||||
|
0,
|
||||||
|
range_base,
|
||||||
|
range_limit,
|
||||||
|
0,
|
||||||
|
range_limit - range_base + 1));
|
||||||
|
crs_range_insert(mem_ranges, range_base, range_limit);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type = dev->config[PCI_HEADER_TYPE] & ~PCI_HEADER_TYPE_MULTI_FUNCTION;
|
||||||
|
if (type == PCI_HEADER_TYPE_BRIDGE) {
|
||||||
|
uint8_t subordinate = dev->config[PCI_SUBORDINATE_BUS];
|
||||||
|
if (subordinate > max_bus) {
|
||||||
|
max_bus = subordinate;
|
||||||
|
}
|
||||||
|
|
||||||
|
range_base = pci_bridge_get_base(dev, PCI_BASE_ADDRESS_SPACE_IO);
|
||||||
|
range_limit = pci_bridge_get_limit(dev, PCI_BASE_ADDRESS_SPACE_IO);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Work-around for old bioses
|
||||||
|
* that do not support multiple root buses
|
||||||
|
*/
|
||||||
|
if (range_base || range_base > range_limit) {
|
||||||
|
aml_append(crs,
|
||||||
|
aml_word_io(AML_MIN_FIXED, AML_MAX_FIXED,
|
||||||
|
AML_POS_DECODE, AML_ENTIRE_RANGE,
|
||||||
|
0,
|
||||||
|
range_base,
|
||||||
|
range_limit,
|
||||||
|
0,
|
||||||
|
range_limit - range_base + 1));
|
||||||
|
crs_range_insert(io_ranges, range_base, range_limit);
|
||||||
|
}
|
||||||
|
|
||||||
|
range_base =
|
||||||
|
pci_bridge_get_base(dev, PCI_BASE_ADDRESS_SPACE_MEMORY);
|
||||||
|
range_limit =
|
||||||
|
pci_bridge_get_limit(dev, PCI_BASE_ADDRESS_SPACE_MEMORY);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Work-around for old bioses
|
||||||
|
* that do not support multiple root buses
|
||||||
|
*/
|
||||||
|
if (range_base || range_base > range_limit) {
|
||||||
|
aml_append(crs,
|
||||||
|
aml_dword_memory(AML_POS_DECODE, AML_MIN_FIXED,
|
||||||
|
AML_MAX_FIXED, AML_NON_CACHEABLE,
|
||||||
|
AML_READ_WRITE,
|
||||||
|
0,
|
||||||
|
range_base,
|
||||||
|
range_limit,
|
||||||
|
0,
|
||||||
|
range_limit - range_base + 1));
|
||||||
|
crs_range_insert(mem_ranges, range_base, range_limit);
|
||||||
|
}
|
||||||
|
|
||||||
|
range_base =
|
||||||
|
pci_bridge_get_base(dev, PCI_BASE_ADDRESS_MEM_PREFETCH);
|
||||||
|
range_limit =
|
||||||
|
pci_bridge_get_limit(dev, PCI_BASE_ADDRESS_MEM_PREFETCH);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Work-around for old bioses
|
||||||
|
* that do not support multiple root buses
|
||||||
|
*/
|
||||||
|
if (range_base || range_base > range_limit) {
|
||||||
|
aml_append(crs,
|
||||||
|
aml_dword_memory(AML_POS_DECODE, AML_MIN_FIXED,
|
||||||
|
AML_MAX_FIXED, AML_NON_CACHEABLE,
|
||||||
|
AML_READ_WRITE,
|
||||||
|
0,
|
||||||
|
range_base,
|
||||||
|
range_limit,
|
||||||
|
0,
|
||||||
|
range_limit - range_base + 1));
|
||||||
|
crs_range_insert(mem_ranges, range_base, range_limit);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
aml_append(crs,
|
||||||
|
aml_word_bus_number(AML_MIN_FIXED, AML_MAX_FIXED, AML_POS_DECODE,
|
||||||
|
0,
|
||||||
|
pci_bus_num(host->bus),
|
||||||
|
max_bus,
|
||||||
|
0,
|
||||||
|
max_bus - pci_bus_num(host->bus) + 1));
|
||||||
|
|
||||||
|
return crs;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
@@ -605,6 +911,11 @@ build_ssdt(GArray *table_data, GArray *linker,
|
|||||||
uint32_t nr_mem = machine->ram_slots;
|
uint32_t nr_mem = machine->ram_slots;
|
||||||
unsigned acpi_cpus = guest_info->apic_id_limit;
|
unsigned acpi_cpus = guest_info->apic_id_limit;
|
||||||
Aml *ssdt, *sb_scope, *scope, *pkg, *dev, *method, *crs, *field, *ifctx;
|
Aml *ssdt, *sb_scope, *scope, *pkg, *dev, *method, *crs, *field, *ifctx;
|
||||||
|
PCIBus *bus = NULL;
|
||||||
|
GPtrArray *io_ranges = g_ptr_array_new_with_free_func(crs_range_free);
|
||||||
|
GPtrArray *mem_ranges = g_ptr_array_new_with_free_func(crs_range_free);
|
||||||
|
CrsRangeEntry *entry;
|
||||||
|
int root_bus_limit = 0xFF;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
ssdt = init_aml_allocator();
|
ssdt = init_aml_allocator();
|
||||||
@@ -616,35 +927,85 @@ build_ssdt(GArray *table_data, GArray *linker,
|
|||||||
/* Reserve space for header */
|
/* Reserve space for header */
|
||||||
acpi_data_push(ssdt->buf, sizeof(AcpiTableHeader));
|
acpi_data_push(ssdt->buf, sizeof(AcpiTableHeader));
|
||||||
|
|
||||||
|
/* Extra PCI root buses are implemented only for i440fx */
|
||||||
|
bus = find_i440fx();
|
||||||
|
if (bus) {
|
||||||
|
QLIST_FOREACH(bus, &bus->child, sibling) {
|
||||||
|
uint8_t bus_num = pci_bus_num(bus);
|
||||||
|
uint8_t numa_node = pci_bus_numa_node(bus);
|
||||||
|
|
||||||
|
/* look only for expander root buses */
|
||||||
|
if (!pci_bus_is_root(bus)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (bus_num < root_bus_limit) {
|
||||||
|
root_bus_limit = bus_num - 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
scope = aml_scope("\\_SB");
|
||||||
|
dev = aml_device("PC%.02X", bus_num);
|
||||||
|
aml_append(dev,
|
||||||
|
aml_name_decl("_UID", aml_string("PC%.02X", bus_num)));
|
||||||
|
aml_append(dev, aml_name_decl("_HID", aml_string("PNP0A03")));
|
||||||
|
aml_append(dev, aml_name_decl("_BBN", aml_int(bus_num)));
|
||||||
|
|
||||||
|
if (numa_node != NUMA_NODE_UNASSIGNED) {
|
||||||
|
aml_append(dev, aml_name_decl("_PXM", aml_int(numa_node)));
|
||||||
|
}
|
||||||
|
|
||||||
|
aml_append(dev, build_prt());
|
||||||
|
crs = build_crs(PCI_HOST_BRIDGE(BUS(bus)->parent),
|
||||||
|
io_ranges, mem_ranges);
|
||||||
|
aml_append(dev, aml_name_decl("_CRS", crs));
|
||||||
|
aml_append(scope, dev);
|
||||||
|
aml_append(ssdt, scope);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
scope = aml_scope("\\_SB.PCI0");
|
scope = aml_scope("\\_SB.PCI0");
|
||||||
/* build PCI0._CRS */
|
/* build PCI0._CRS */
|
||||||
crs = aml_resource_template();
|
crs = aml_resource_template();
|
||||||
aml_append(crs,
|
aml_append(crs,
|
||||||
aml_word_bus_number(aml_min_fixed, aml_max_fixed, aml_pos_decode,
|
aml_word_bus_number(AML_MIN_FIXED, AML_MAX_FIXED, AML_POS_DECODE,
|
||||||
0x0000, 0x0000, 0x00FF, 0x0000, 0x0100));
|
0x0000, 0x0, root_bus_limit,
|
||||||
aml_append(crs, aml_io(aml_decode16, 0x0CF8, 0x0CF8, 0x01, 0x08));
|
0x0000, root_bus_limit + 1));
|
||||||
|
aml_append(crs, aml_io(AML_DECODE16, 0x0CF8, 0x0CF8, 0x01, 0x08));
|
||||||
|
|
||||||
aml_append(crs,
|
aml_append(crs,
|
||||||
aml_word_io(aml_min_fixed, aml_max_fixed,
|
aml_word_io(AML_MIN_FIXED, AML_MAX_FIXED,
|
||||||
aml_pos_decode, aml_entire_range,
|
AML_POS_DECODE, AML_ENTIRE_RANGE,
|
||||||
0x0000, 0x0000, 0x0CF7, 0x0000, 0x0CF8));
|
0x0000, 0x0000, 0x0CF7, 0x0000, 0x0CF8));
|
||||||
|
|
||||||
|
crs_replace_with_free_ranges(io_ranges, 0x0D00, 0xFFFF);
|
||||||
|
for (i = 0; i < io_ranges->len; i++) {
|
||||||
|
entry = g_ptr_array_index(io_ranges, i);
|
||||||
|
aml_append(crs,
|
||||||
|
aml_word_io(AML_MIN_FIXED, AML_MAX_FIXED,
|
||||||
|
AML_POS_DECODE, AML_ENTIRE_RANGE,
|
||||||
|
0x0000, entry->base, entry->limit,
|
||||||
|
0x0000, entry->limit - entry->base + 1));
|
||||||
|
}
|
||||||
|
|
||||||
aml_append(crs,
|
aml_append(crs,
|
||||||
aml_word_io(aml_min_fixed, aml_max_fixed,
|
aml_dword_memory(AML_POS_DECODE, AML_MIN_FIXED, AML_MAX_FIXED,
|
||||||
aml_pos_decode, aml_entire_range,
|
AML_CACHEABLE, AML_READ_WRITE,
|
||||||
0x0000, 0x0D00, 0xFFFF, 0x0000, 0xF300));
|
|
||||||
aml_append(crs,
|
|
||||||
aml_dword_memory(aml_pos_decode, aml_min_fixed, aml_max_fixed,
|
|
||||||
aml_cacheable, aml_ReadWrite,
|
|
||||||
0, 0x000A0000, 0x000BFFFF, 0, 0x00020000));
|
0, 0x000A0000, 0x000BFFFF, 0, 0x00020000));
|
||||||
aml_append(crs,
|
|
||||||
aml_dword_memory(aml_pos_decode, aml_min_fixed, aml_max_fixed,
|
crs_replace_with_free_ranges(mem_ranges, pci->w32.begin, pci->w32.end - 1);
|
||||||
aml_non_cacheable, aml_ReadWrite,
|
for (i = 0; i < mem_ranges->len; i++) {
|
||||||
0, pci->w32.begin, pci->w32.end - 1, 0,
|
entry = g_ptr_array_index(mem_ranges, i);
|
||||||
pci->w32.end - pci->w32.begin));
|
aml_append(crs,
|
||||||
|
aml_dword_memory(AML_POS_DECODE, AML_MIN_FIXED, AML_MAX_FIXED,
|
||||||
|
AML_NON_CACHEABLE, AML_READ_WRITE,
|
||||||
|
0, entry->base, entry->limit,
|
||||||
|
0, entry->limit - entry->base + 1));
|
||||||
|
}
|
||||||
|
|
||||||
if (pci->w64.begin) {
|
if (pci->w64.begin) {
|
||||||
aml_append(crs,
|
aml_append(crs,
|
||||||
aml_qword_memory(aml_pos_decode, aml_min_fixed, aml_max_fixed,
|
aml_qword_memory(AML_POS_DECODE, AML_MIN_FIXED, AML_MAX_FIXED,
|
||||||
aml_cacheable, aml_ReadWrite,
|
AML_CACHEABLE, AML_READ_WRITE,
|
||||||
0, pci->w64.begin, pci->w64.end - 1, 0,
|
0, pci->w64.begin, pci->w64.end - 1, 0,
|
||||||
pci->w64.end - pci->w64.begin));
|
pci->w64.end - pci->w64.begin));
|
||||||
}
|
}
|
||||||
@@ -658,11 +1019,14 @@ build_ssdt(GArray *table_data, GArray *linker,
|
|||||||
aml_append(dev, aml_name_decl("_STA", aml_int(0xB)));
|
aml_append(dev, aml_name_decl("_STA", aml_int(0xB)));
|
||||||
crs = aml_resource_template();
|
crs = aml_resource_template();
|
||||||
aml_append(crs,
|
aml_append(crs,
|
||||||
aml_io(aml_decode16, pm->gpe0_blk, pm->gpe0_blk, 1, pm->gpe0_blk_len)
|
aml_io(AML_DECODE16, pm->gpe0_blk, pm->gpe0_blk, 1, pm->gpe0_blk_len)
|
||||||
);
|
);
|
||||||
aml_append(dev, aml_name_decl("_CRS", crs));
|
aml_append(dev, aml_name_decl("_CRS", crs));
|
||||||
aml_append(scope, dev);
|
aml_append(scope, dev);
|
||||||
|
|
||||||
|
g_ptr_array_free(io_ranges, true);
|
||||||
|
g_ptr_array_free(mem_ranges, true);
|
||||||
|
|
||||||
/* reserve PCIHP resources */
|
/* reserve PCIHP resources */
|
||||||
if (pm->pcihp_io_len) {
|
if (pm->pcihp_io_len) {
|
||||||
dev = aml_device("PHPR");
|
dev = aml_device("PHPR");
|
||||||
@@ -673,7 +1037,7 @@ build_ssdt(GArray *table_data, GArray *linker,
|
|||||||
aml_append(dev, aml_name_decl("_STA", aml_int(0xB)));
|
aml_append(dev, aml_name_decl("_STA", aml_int(0xB)));
|
||||||
crs = aml_resource_template();
|
crs = aml_resource_template();
|
||||||
aml_append(crs,
|
aml_append(crs,
|
||||||
aml_io(aml_decode16, pm->pcihp_io_base, pm->pcihp_io_base, 1,
|
aml_io(AML_DECODE16, pm->pcihp_io_base, pm->pcihp_io_base, 1,
|
||||||
pm->pcihp_io_len)
|
pm->pcihp_io_len)
|
||||||
);
|
);
|
||||||
aml_append(dev, aml_name_decl("_CRS", crs));
|
aml_append(dev, aml_name_decl("_CRS", crs));
|
||||||
@@ -720,7 +1084,7 @@ build_ssdt(GArray *table_data, GArray *linker,
|
|||||||
|
|
||||||
crs = aml_resource_template();
|
crs = aml_resource_template();
|
||||||
aml_append(crs,
|
aml_append(crs,
|
||||||
aml_io(aml_decode16, misc->applesmc_io_base, misc->applesmc_io_base,
|
aml_io(AML_DECODE16, misc->applesmc_io_base, misc->applesmc_io_base,
|
||||||
0x01, APPLESMC_MAX_DATA_LENGTH)
|
0x01, APPLESMC_MAX_DATA_LENGTH)
|
||||||
);
|
);
|
||||||
aml_append(crs, aml_irq_no_flags(6));
|
aml_append(crs, aml_irq_no_flags(6));
|
||||||
@@ -733,21 +1097,24 @@ build_ssdt(GArray *table_data, GArray *linker,
|
|||||||
if (misc->pvpanic_port) {
|
if (misc->pvpanic_port) {
|
||||||
scope = aml_scope("\\_SB.PCI0.ISA");
|
scope = aml_scope("\\_SB.PCI0.ISA");
|
||||||
|
|
||||||
dev = aml_device("PEVR");
|
dev = aml_device("PEVT");
|
||||||
aml_append(dev, aml_name_decl("_HID", aml_string("QEMU0001")));
|
aml_append(dev, aml_name_decl("_HID", aml_string("QEMU0001")));
|
||||||
|
|
||||||
crs = aml_resource_template();
|
crs = aml_resource_template();
|
||||||
aml_append(crs,
|
aml_append(crs,
|
||||||
aml_io(aml_decode16, misc->pvpanic_port, misc->pvpanic_port, 1, 1)
|
aml_io(AML_DECODE16, misc->pvpanic_port, misc->pvpanic_port, 1, 1)
|
||||||
);
|
);
|
||||||
aml_append(dev, aml_name_decl("_CRS", crs));
|
aml_append(dev, aml_name_decl("_CRS", crs));
|
||||||
|
|
||||||
aml_append(dev, aml_operation_region("PEOR", aml_system_io,
|
aml_append(dev, aml_operation_region("PEOR", AML_SYSTEM_IO,
|
||||||
misc->pvpanic_port, 1));
|
misc->pvpanic_port, 1));
|
||||||
field = aml_field("PEOR", aml_byte_acc, aml_preserve);
|
field = aml_field("PEOR", AML_BYTE_ACC, AML_PRESERVE);
|
||||||
aml_append(field, aml_named_field("PEPT", 8));
|
aml_append(field, aml_named_field("PEPT", 8));
|
||||||
aml_append(dev, field);
|
aml_append(dev, field);
|
||||||
|
|
||||||
|
/* device present, functioning, decoding, not shown in UI */
|
||||||
|
aml_append(dev, aml_name_decl("_STA", aml_int(0xB)));
|
||||||
|
|
||||||
method = aml_method("RDPT", 0);
|
method = aml_method("RDPT", 0);
|
||||||
aml_append(method, aml_store(aml_name("PEPT"), aml_local(0)));
|
aml_append(method, aml_store(aml_name("PEPT"), aml_local(0)));
|
||||||
aml_append(method, aml_return(aml_local(0)));
|
aml_append(method, aml_return(aml_local(0)));
|
||||||
@@ -773,15 +1140,15 @@ build_ssdt(GArray *table_data, GArray *linker,
|
|||||||
aml_append(dev, aml_name_decl("_STA", aml_int(0xB)));
|
aml_append(dev, aml_name_decl("_STA", aml_int(0xB)));
|
||||||
crs = aml_resource_template();
|
crs = aml_resource_template();
|
||||||
aml_append(crs,
|
aml_append(crs,
|
||||||
aml_io(aml_decode16, pm->cpu_hp_io_base, pm->cpu_hp_io_base, 1,
|
aml_io(AML_DECODE16, pm->cpu_hp_io_base, pm->cpu_hp_io_base, 1,
|
||||||
pm->cpu_hp_io_len)
|
pm->cpu_hp_io_len)
|
||||||
);
|
);
|
||||||
aml_append(dev, aml_name_decl("_CRS", crs));
|
aml_append(dev, aml_name_decl("_CRS", crs));
|
||||||
aml_append(sb_scope, dev);
|
aml_append(sb_scope, dev);
|
||||||
/* declare CPU hotplug MMIO region and PRS field to access it */
|
/* declare CPU hotplug MMIO region and PRS field to access it */
|
||||||
aml_append(sb_scope, aml_operation_region(
|
aml_append(sb_scope, aml_operation_region(
|
||||||
"PRST", aml_system_io, pm->cpu_hp_io_base, pm->cpu_hp_io_len));
|
"PRST", AML_SYSTEM_IO, pm->cpu_hp_io_base, pm->cpu_hp_io_len));
|
||||||
field = aml_field("PRST", aml_byte_acc, aml_preserve);
|
field = aml_field("PRST", AML_BYTE_ACC, AML_PRESERVE);
|
||||||
aml_append(field, aml_named_field("PRS", 256));
|
aml_append(field, aml_named_field("PRS", 256));
|
||||||
aml_append(sb_scope, field);
|
aml_append(sb_scope, field);
|
||||||
|
|
||||||
@@ -845,18 +1212,18 @@ build_ssdt(GArray *table_data, GArray *linker,
|
|||||||
|
|
||||||
crs = aml_resource_template();
|
crs = aml_resource_template();
|
||||||
aml_append(crs,
|
aml_append(crs,
|
||||||
aml_io(aml_decode16, pm->mem_hp_io_base, pm->mem_hp_io_base, 0,
|
aml_io(AML_DECODE16, pm->mem_hp_io_base, pm->mem_hp_io_base, 0,
|
||||||
pm->mem_hp_io_len)
|
pm->mem_hp_io_len)
|
||||||
);
|
);
|
||||||
aml_append(scope, aml_name_decl("_CRS", crs));
|
aml_append(scope, aml_name_decl("_CRS", crs));
|
||||||
|
|
||||||
aml_append(scope, aml_operation_region(
|
aml_append(scope, aml_operation_region(
|
||||||
stringify(MEMORY_HOTPLUG_IO_REGION), aml_system_io,
|
stringify(MEMORY_HOTPLUG_IO_REGION), AML_SYSTEM_IO,
|
||||||
pm->mem_hp_io_base, pm->mem_hp_io_len)
|
pm->mem_hp_io_base, pm->mem_hp_io_len)
|
||||||
);
|
);
|
||||||
|
|
||||||
field = aml_field(stringify(MEMORY_HOTPLUG_IO_REGION), aml_dword_acc,
|
field = aml_field(stringify(MEMORY_HOTPLUG_IO_REGION), AML_DWORD_ACC,
|
||||||
aml_preserve);
|
AML_PRESERVE);
|
||||||
aml_append(field, /* read only */
|
aml_append(field, /* read only */
|
||||||
aml_named_field(stringify(MEMORY_SLOT_ADDR_LOW), 32));
|
aml_named_field(stringify(MEMORY_SLOT_ADDR_LOW), 32));
|
||||||
aml_append(field, /* read only */
|
aml_append(field, /* read only */
|
||||||
@@ -869,8 +1236,8 @@ build_ssdt(GArray *table_data, GArray *linker,
|
|||||||
aml_named_field(stringify(MEMORY_SLOT_PROXIMITY), 32));
|
aml_named_field(stringify(MEMORY_SLOT_PROXIMITY), 32));
|
||||||
aml_append(scope, field);
|
aml_append(scope, field);
|
||||||
|
|
||||||
field = aml_field(stringify(MEMORY_HOTPLUG_IO_REGION), aml_byte_acc,
|
field = aml_field(stringify(MEMORY_HOTPLUG_IO_REGION), AML_BYTE_ACC,
|
||||||
aml_write_as_zeros);
|
AML_WRITE_AS_ZEROS);
|
||||||
aml_append(field, aml_reserved_field(160 /* bits, Offset(20) */));
|
aml_append(field, aml_reserved_field(160 /* bits, Offset(20) */));
|
||||||
aml_append(field, /* 1 if enabled, read only */
|
aml_append(field, /* 1 if enabled, read only */
|
||||||
aml_named_field(stringify(MEMORY_SLOT_ENABLED), 1));
|
aml_named_field(stringify(MEMORY_SLOT_ENABLED), 1));
|
||||||
@@ -885,8 +1252,8 @@ build_ssdt(GArray *table_data, GArray *linker,
|
|||||||
aml_named_field(stringify(MEMORY_SLOT_EJECT), 1));
|
aml_named_field(stringify(MEMORY_SLOT_EJECT), 1));
|
||||||
aml_append(scope, field);
|
aml_append(scope, field);
|
||||||
|
|
||||||
field = aml_field(stringify(MEMORY_HOTPLUG_IO_REGION), aml_dword_acc,
|
field = aml_field(stringify(MEMORY_HOTPLUG_IO_REGION), AML_DWORD_ACC,
|
||||||
aml_preserve);
|
AML_PRESERVE);
|
||||||
aml_append(field, /* DIMM selector, write only */
|
aml_append(field, /* DIMM selector, write only */
|
||||||
aml_named_field(stringify(MEMORY_SLOT_SLECTOR), 32));
|
aml_named_field(stringify(MEMORY_SLOT_SLECTOR), 32));
|
||||||
aml_append(field, /* _OST event code, write only */
|
aml_append(field, /* _OST event code, write only */
|
||||||
@@ -952,10 +1319,9 @@ build_ssdt(GArray *table_data, GArray *linker,
|
|||||||
{
|
{
|
||||||
Object *pci_host;
|
Object *pci_host;
|
||||||
PCIBus *bus = NULL;
|
PCIBus *bus = NULL;
|
||||||
bool ambiguous;
|
|
||||||
|
|
||||||
pci_host = object_resolve_path_type("", TYPE_PCI_HOST_BRIDGE, &ambiguous);
|
pci_host = acpi_get_i386_pci_host();
|
||||||
if (!ambiguous && pci_host) {
|
if (pci_host) {
|
||||||
bus = PCI_HOST_BRIDGE(pci_host)->bus;
|
bus = PCI_HOST_BRIDGE(pci_host)->bus;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1026,6 +1392,25 @@ build_tpm_ssdt(GArray *table_data, GArray *linker)
|
|||||||
memcpy(tpm_ptr, ssdt_tpm_aml, sizeof(ssdt_tpm_aml));
|
memcpy(tpm_ptr, ssdt_tpm_aml, sizeof(ssdt_tpm_aml));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
build_tpm2(GArray *table_data, GArray *linker)
|
||||||
|
{
|
||||||
|
Acpi20TPM2 *tpm2_ptr;
|
||||||
|
void *tpm_ptr;
|
||||||
|
|
||||||
|
tpm_ptr = acpi_data_push(table_data, sizeof(ssdt_tpm2_aml));
|
||||||
|
memcpy(tpm_ptr, ssdt_tpm2_aml, sizeof(ssdt_tpm2_aml));
|
||||||
|
|
||||||
|
tpm2_ptr = acpi_data_push(table_data, sizeof *tpm2_ptr);
|
||||||
|
|
||||||
|
tpm2_ptr->platform_class = cpu_to_le16(TPM2_ACPI_CLASS_CLIENT);
|
||||||
|
tpm2_ptr->control_area_address = cpu_to_le64(0);
|
||||||
|
tpm2_ptr->start_method = cpu_to_le32(TPM2_START_METHOD_MMIO);
|
||||||
|
|
||||||
|
build_header(linker, table_data,
|
||||||
|
(void *)tpm2_ptr, "TPM2", sizeof(*tpm2_ptr), 4);
|
||||||
|
}
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
MEM_AFFINITY_NOFLAGS = 0,
|
MEM_AFFINITY_NOFLAGS = 0,
|
||||||
MEM_AFFINITY_ENABLED = (1 << 0),
|
MEM_AFFINITY_ENABLED = (1 << 0),
|
||||||
@@ -1208,30 +1593,6 @@ build_dsdt(GArray *table_data, GArray *linker, AcpiMiscInfo *misc)
|
|||||||
misc->dsdt_size, 1);
|
misc->dsdt_size, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Build final rsdt table */
|
|
||||||
static void
|
|
||||||
build_rsdt(GArray *table_data, GArray *linker, GArray *table_offsets)
|
|
||||||
{
|
|
||||||
AcpiRsdtDescriptorRev1 *rsdt;
|
|
||||||
size_t rsdt_len;
|
|
||||||
int i;
|
|
||||||
|
|
||||||
rsdt_len = sizeof(*rsdt) + sizeof(uint32_t) * table_offsets->len;
|
|
||||||
rsdt = acpi_data_push(table_data, rsdt_len);
|
|
||||||
memcpy(rsdt->table_offset_entry, table_offsets->data,
|
|
||||||
sizeof(uint32_t) * table_offsets->len);
|
|
||||||
for (i = 0; i < table_offsets->len; ++i) {
|
|
||||||
/* rsdt->table_offset_entry to be filled by Guest linker */
|
|
||||||
bios_linker_loader_add_pointer(linker,
|
|
||||||
ACPI_BUILD_TABLE_FILE,
|
|
||||||
ACPI_BUILD_TABLE_FILE,
|
|
||||||
table_data, &rsdt->table_offset_entry[i],
|
|
||||||
sizeof(uint32_t));
|
|
||||||
}
|
|
||||||
build_header(linker, table_data,
|
|
||||||
(void *)rsdt, "RSDT", rsdt_len, 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
static GArray *
|
static GArray *
|
||||||
build_rsdp(GArray *rsdp_table, GArray *linker, unsigned rsdt)
|
build_rsdp(GArray *rsdp_table, GArray *linker, unsigned rsdt)
|
||||||
{
|
{
|
||||||
@@ -1272,10 +1633,8 @@ static bool acpi_get_mcfg(AcpiMcfgInfo *mcfg)
|
|||||||
{
|
{
|
||||||
Object *pci_host;
|
Object *pci_host;
|
||||||
QObject *o;
|
QObject *o;
|
||||||
bool ambiguous;
|
|
||||||
|
|
||||||
pci_host = object_resolve_path_type("", TYPE_PCI_HOST_BRIDGE, &ambiguous);
|
pci_host = acpi_get_i386_pci_host();
|
||||||
g_assert(!ambiguous);
|
|
||||||
g_assert(pci_host);
|
g_assert(pci_host);
|
||||||
|
|
||||||
o = object_property_get_qobject(pci_host, PCIE_HOST_MCFG_BASE, NULL);
|
o = object_property_get_qobject(pci_host, PCIE_HOST_MCFG_BASE, NULL);
|
||||||
@@ -1364,12 +1723,21 @@ void acpi_build(PcGuestInfo *guest_info, AcpiBuildTables *tables)
|
|||||||
acpi_add_table(table_offsets, tables_blob);
|
acpi_add_table(table_offsets, tables_blob);
|
||||||
build_hpet(tables_blob, tables->linker);
|
build_hpet(tables_blob, tables->linker);
|
||||||
}
|
}
|
||||||
if (misc.has_tpm) {
|
if (misc.tpm_version != TPM_VERSION_UNSPEC) {
|
||||||
acpi_add_table(table_offsets, tables_blob);
|
acpi_add_table(table_offsets, tables_blob);
|
||||||
build_tpm_tcpa(tables_blob, tables->linker, tables->tcpalog);
|
build_tpm_tcpa(tables_blob, tables->linker, tables->tcpalog);
|
||||||
|
|
||||||
acpi_add_table(table_offsets, tables_blob);
|
acpi_add_table(table_offsets, tables_blob);
|
||||||
build_tpm_ssdt(tables_blob, tables->linker);
|
switch (misc.tpm_version) {
|
||||||
|
case TPM_VERSION_1_2:
|
||||||
|
build_tpm_ssdt(tables_blob, tables->linker);
|
||||||
|
break;
|
||||||
|
case TPM_VERSION_2_0:
|
||||||
|
build_tpm2(tables_blob, tables->linker);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
assert(false);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (guest_info->numa_nodes) {
|
if (guest_info->numa_nodes) {
|
||||||
acpi_add_table(table_offsets, tables_blob);
|
acpi_add_table(table_offsets, tables_blob);
|
||||||
|
|||||||
105
hw/i386/pc.c
105
hw/i386/pc.c
@@ -30,6 +30,7 @@
|
|||||||
#include "hw/block/fdc.h"
|
#include "hw/block/fdc.h"
|
||||||
#include "hw/ide.h"
|
#include "hw/ide.h"
|
||||||
#include "hw/pci/pci.h"
|
#include "hw/pci/pci.h"
|
||||||
|
#include "hw/pci/pci_bus.h"
|
||||||
#include "monitor/monitor.h"
|
#include "monitor/monitor.h"
|
||||||
#include "hw/nvram/fw_cfg.h"
|
#include "hw/nvram/fw_cfg.h"
|
||||||
#include "hw/timer/hpet.h"
|
#include "hw/timer/hpet.h"
|
||||||
@@ -163,27 +164,6 @@ uint64_t cpu_get_tsc(CPUX86State *env)
|
|||||||
return cpu_get_ticks();
|
return cpu_get_ticks();
|
||||||
}
|
}
|
||||||
|
|
||||||
/* SMM support */
|
|
||||||
|
|
||||||
static cpu_set_smm_t smm_set;
|
|
||||||
static void *smm_arg;
|
|
||||||
|
|
||||||
void cpu_smm_register(cpu_set_smm_t callback, void *arg)
|
|
||||||
{
|
|
||||||
assert(smm_set == NULL);
|
|
||||||
assert(smm_arg == NULL);
|
|
||||||
smm_set = callback;
|
|
||||||
smm_arg = arg;
|
|
||||||
}
|
|
||||||
|
|
||||||
void cpu_smm_update(CPUX86State *env)
|
|
||||||
{
|
|
||||||
if (smm_set && smm_arg && CPU(x86_env_get_cpu(env)) == first_cpu) {
|
|
||||||
smm_set(!!(env->hflags & HF_SMM_MASK), smm_arg);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/* IRQ handling */
|
/* IRQ handling */
|
||||||
int cpu_get_pic_interrupt(CPUX86State *env)
|
int cpu_get_pic_interrupt(CPUX86State *env)
|
||||||
{
|
{
|
||||||
@@ -1006,7 +986,6 @@ static X86CPU *pc_new_cpu(const char *cpu_model, int64_t apic_id,
|
|||||||
}
|
}
|
||||||
|
|
||||||
qdev_set_parent_bus(DEVICE(cpu), qdev_get_child_bus(icc_bridge, "icc"));
|
qdev_set_parent_bus(DEVICE(cpu), qdev_get_child_bus(icc_bridge, "icc"));
|
||||||
object_unref(OBJECT(cpu));
|
|
||||||
|
|
||||||
object_property_set_int(OBJECT(cpu), apic_id, "apic-id", &local_err);
|
object_property_set_int(OBJECT(cpu), apic_id, "apic-id", &local_err);
|
||||||
object_property_set_bool(OBJECT(cpu), true, "realized", &local_err);
|
object_property_set_bool(OBJECT(cpu), true, "realized", &local_err);
|
||||||
@@ -1025,7 +1004,9 @@ static const char *current_cpu_model;
|
|||||||
void pc_hot_add_cpu(const int64_t id, Error **errp)
|
void pc_hot_add_cpu(const int64_t id, Error **errp)
|
||||||
{
|
{
|
||||||
DeviceState *icc_bridge;
|
DeviceState *icc_bridge;
|
||||||
|
X86CPU *cpu;
|
||||||
int64_t apic_id = x86_cpu_apic_id_from_index(id);
|
int64_t apic_id = x86_cpu_apic_id_from_index(id);
|
||||||
|
Error *local_err = NULL;
|
||||||
|
|
||||||
if (id < 0) {
|
if (id < 0) {
|
||||||
error_setg(errp, "Invalid CPU id: %" PRIi64, id);
|
error_setg(errp, "Invalid CPU id: %" PRIi64, id);
|
||||||
@@ -1053,7 +1034,12 @@ void pc_hot_add_cpu(const int64_t id, Error **errp)
|
|||||||
|
|
||||||
icc_bridge = DEVICE(object_resolve_path_type("icc-bridge",
|
icc_bridge = DEVICE(object_resolve_path_type("icc-bridge",
|
||||||
TYPE_ICC_BRIDGE, NULL));
|
TYPE_ICC_BRIDGE, NULL));
|
||||||
pc_new_cpu(current_cpu_model, apic_id, icc_bridge, errp);
|
cpu = pc_new_cpu(current_cpu_model, apic_id, icc_bridge, &local_err);
|
||||||
|
if (local_err) {
|
||||||
|
error_propagate(errp, local_err);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
object_unref(OBJECT(cpu));
|
||||||
}
|
}
|
||||||
|
|
||||||
void pc_cpus_init(const char *cpu_model, DeviceState *icc_bridge)
|
void pc_cpus_init(const char *cpu_model, DeviceState *icc_bridge)
|
||||||
@@ -1087,6 +1073,7 @@ void pc_cpus_init(const char *cpu_model, DeviceState *icc_bridge)
|
|||||||
error_report_err(error);
|
error_report_err(error);
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
object_unref(OBJECT(cpu));
|
||||||
}
|
}
|
||||||
|
|
||||||
/* map APIC MMIO area if CPU has APIC */
|
/* map APIC MMIO area if CPU has APIC */
|
||||||
@@ -1119,6 +1106,25 @@ void pc_guest_info_machine_done(Notifier *notifier, void *data)
|
|||||||
PcGuestInfoState *guest_info_state = container_of(notifier,
|
PcGuestInfoState *guest_info_state = container_of(notifier,
|
||||||
PcGuestInfoState,
|
PcGuestInfoState,
|
||||||
machine_done);
|
machine_done);
|
||||||
|
PCIBus *bus = find_i440fx();
|
||||||
|
|
||||||
|
if (bus) {
|
||||||
|
int extra_hosts = 0;
|
||||||
|
|
||||||
|
QLIST_FOREACH(bus, &bus->child, sibling) {
|
||||||
|
/* look for expander root buses */
|
||||||
|
if (pci_bus_is_root(bus)) {
|
||||||
|
extra_hosts++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (extra_hosts && guest_info_state->info.fw_cfg) {
|
||||||
|
uint64_t *val = g_malloc(sizeof(*val));
|
||||||
|
*val = cpu_to_le64(extra_hosts);
|
||||||
|
fw_cfg_add_file(guest_info_state->info.fw_cfg,
|
||||||
|
"etc/extra-pci-roots", val, sizeof(*val));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
acpi_setup(&guest_info_state->info);
|
acpi_setup(&guest_info_state->info);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1345,9 +1351,9 @@ FWCfgState *pc_memory_init(MachineState *machine,
|
|||||||
return fw_cfg;
|
return fw_cfg;
|
||||||
}
|
}
|
||||||
|
|
||||||
qemu_irq *pc_allocate_cpu_irq(void)
|
qemu_irq pc_allocate_cpu_irq(void)
|
||||||
{
|
{
|
||||||
return qemu_allocate_irqs(pic_irq_request, NULL, 1);
|
return qemu_allocate_irq(pic_irq_request, NULL, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
DeviceState *pc_vga_init(ISABus *isa_bus, PCIBus *pci_bus)
|
DeviceState *pc_vga_init(ISABus *isa_bus, PCIBus *pci_bus)
|
||||||
@@ -1395,6 +1401,7 @@ static const MemoryRegionOps ioportF0_io_ops = {
|
|||||||
|
|
||||||
void pc_basic_device_init(ISABus *isa_bus, qemu_irq *gsi,
|
void pc_basic_device_init(ISABus *isa_bus, qemu_irq *gsi,
|
||||||
ISADevice **rtc_state,
|
ISADevice **rtc_state,
|
||||||
|
bool create_fdctrl,
|
||||||
ISADevice **floppy,
|
ISADevice **floppy,
|
||||||
bool no_vmport,
|
bool no_vmport,
|
||||||
uint32 hpet_irqs)
|
uint32 hpet_irqs)
|
||||||
@@ -1489,8 +1496,9 @@ void pc_basic_device_init(ISABus *isa_bus, qemu_irq *gsi,
|
|||||||
|
|
||||||
for(i = 0; i < MAX_FD; i++) {
|
for(i = 0; i < MAX_FD; i++) {
|
||||||
fd[i] = drive_get(IF_FLOPPY, 0, i);
|
fd[i] = drive_get(IF_FLOPPY, 0, i);
|
||||||
|
create_fdctrl |= !!fd[i];
|
||||||
}
|
}
|
||||||
*floppy = fdctrl_init_isa(isa_bus, fd);
|
*floppy = create_fdctrl ? fdctrl_init_isa(isa_bus, fd) : NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
void pc_nic_init(ISABus *isa_bus, PCIBus *pci_bus)
|
void pc_nic_init(ISABus *isa_bus, PCIBus *pci_bus)
|
||||||
@@ -1543,51 +1551,6 @@ void ioapic_init_gsi(GSIState *gsi_state, const char *parent_name)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void pc_generic_machine_class_init(ObjectClass *oc, void *data)
|
|
||||||
{
|
|
||||||
MachineClass *mc = MACHINE_CLASS(oc);
|
|
||||||
QEMUMachine *qm = data;
|
|
||||||
|
|
||||||
mc->family = qm->family;
|
|
||||||
mc->name = qm->name;
|
|
||||||
mc->alias = qm->alias;
|
|
||||||
mc->desc = qm->desc;
|
|
||||||
mc->init = qm->init;
|
|
||||||
mc->reset = qm->reset;
|
|
||||||
mc->hot_add_cpu = qm->hot_add_cpu;
|
|
||||||
mc->kvm_type = qm->kvm_type;
|
|
||||||
mc->block_default_type = qm->block_default_type;
|
|
||||||
mc->units_per_default_bus = qm->units_per_default_bus;
|
|
||||||
mc->max_cpus = qm->max_cpus;
|
|
||||||
mc->no_serial = qm->no_serial;
|
|
||||||
mc->no_parallel = qm->no_parallel;
|
|
||||||
mc->use_virtcon = qm->use_virtcon;
|
|
||||||
mc->use_sclp = qm->use_sclp;
|
|
||||||
mc->no_floppy = qm->no_floppy;
|
|
||||||
mc->no_cdrom = qm->no_cdrom;
|
|
||||||
mc->no_sdcard = qm->no_sdcard;
|
|
||||||
mc->is_default = qm->is_default;
|
|
||||||
mc->default_machine_opts = qm->default_machine_opts;
|
|
||||||
mc->default_boot_order = qm->default_boot_order;
|
|
||||||
mc->default_display = qm->default_display;
|
|
||||||
mc->compat_props = qm->compat_props;
|
|
||||||
mc->hw_version = qm->hw_version;
|
|
||||||
}
|
|
||||||
|
|
||||||
void qemu_register_pc_machine(QEMUMachine *m)
|
|
||||||
{
|
|
||||||
char *name = g_strconcat(m->name, TYPE_MACHINE_SUFFIX, NULL);
|
|
||||||
TypeInfo ti = {
|
|
||||||
.name = name,
|
|
||||||
.parent = TYPE_PC_MACHINE,
|
|
||||||
.class_init = pc_generic_machine_class_init,
|
|
||||||
.class_data = (void *)m,
|
|
||||||
};
|
|
||||||
|
|
||||||
type_register(&ti);
|
|
||||||
g_free(name);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void pc_dimm_plug(HotplugHandler *hotplug_dev,
|
static void pc_dimm_plug(HotplugHandler *hotplug_dev,
|
||||||
DeviceState *dev, Error **errp)
|
DeviceState *dev, Error **errp)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -59,6 +59,7 @@ static const int ide_iobase[MAX_IDE_BUS] = { 0x1f0, 0x170 };
|
|||||||
static const int ide_iobase2[MAX_IDE_BUS] = { 0x3f6, 0x376 };
|
static const int ide_iobase2[MAX_IDE_BUS] = { 0x3f6, 0x376 };
|
||||||
static const int ide_irq[MAX_IDE_BUS] = { 14, 15 };
|
static const int ide_irq[MAX_IDE_BUS] = { 14, 15 };
|
||||||
|
|
||||||
|
static bool pci_enabled = true;
|
||||||
static bool has_acpi_build = true;
|
static bool has_acpi_build = true;
|
||||||
static bool rsdp_in_ram = true;
|
static bool rsdp_in_ram = true;
|
||||||
static int legacy_acpi_table_size;
|
static int legacy_acpi_table_size;
|
||||||
@@ -71,11 +72,10 @@ static bool smbios_uuid_encoded = true;
|
|||||||
*/
|
*/
|
||||||
static bool gigabyte_align = true;
|
static bool gigabyte_align = true;
|
||||||
static bool has_reserved_memory = true;
|
static bool has_reserved_memory = true;
|
||||||
|
static bool kvmclock_enabled = true;
|
||||||
|
|
||||||
/* PC hardware initialisation */
|
/* PC hardware initialisation */
|
||||||
static void pc_init1(MachineState *machine,
|
static void pc_init1(MachineState *machine)
|
||||||
int pci_enabled,
|
|
||||||
int kvmclock_enabled)
|
|
||||||
{
|
{
|
||||||
PCMachineState *pc_machine = PC_MACHINE(machine);
|
PCMachineState *pc_machine = PC_MACHINE(machine);
|
||||||
MemoryRegion *system_memory = get_system_memory();
|
MemoryRegion *system_memory = get_system_memory();
|
||||||
@@ -86,10 +86,9 @@ static void pc_init1(MachineState *machine,
|
|||||||
ISABus *isa_bus;
|
ISABus *isa_bus;
|
||||||
PCII440FXState *i440fx_state;
|
PCII440FXState *i440fx_state;
|
||||||
int piix3_devfn = -1;
|
int piix3_devfn = -1;
|
||||||
qemu_irq *cpu_irq;
|
|
||||||
qemu_irq *gsi;
|
qemu_irq *gsi;
|
||||||
qemu_irq *i8259;
|
qemu_irq *i8259;
|
||||||
qemu_irq *smi_irq;
|
qemu_irq smi_irq;
|
||||||
GSIState *gsi_state;
|
GSIState *gsi_state;
|
||||||
DriveInfo *hd[MAX_IDE_BUS * MAX_IDE_DEVS];
|
DriveInfo *hd[MAX_IDE_BUS * MAX_IDE_DEVS];
|
||||||
BusState *idebus[MAX_IDE_BUS];
|
BusState *idebus[MAX_IDE_BUS];
|
||||||
@@ -99,7 +98,6 @@ static void pc_init1(MachineState *machine,
|
|||||||
MemoryRegion *pci_memory;
|
MemoryRegion *pci_memory;
|
||||||
MemoryRegion *rom_memory;
|
MemoryRegion *rom_memory;
|
||||||
DeviceState *icc_bridge;
|
DeviceState *icc_bridge;
|
||||||
FWCfgState *fw_cfg = NULL;
|
|
||||||
PcGuestInfo *guest_info;
|
PcGuestInfo *guest_info;
|
||||||
ram_addr_t lowmem;
|
ram_addr_t lowmem;
|
||||||
|
|
||||||
@@ -180,16 +178,16 @@ static void pc_init1(MachineState *machine,
|
|||||||
|
|
||||||
/* allocate ram and load rom/bios */
|
/* allocate ram and load rom/bios */
|
||||||
if (!xen_enabled()) {
|
if (!xen_enabled()) {
|
||||||
fw_cfg = pc_memory_init(machine, system_memory,
|
pc_memory_init(machine, system_memory,
|
||||||
below_4g_mem_size, above_4g_mem_size,
|
below_4g_mem_size, above_4g_mem_size,
|
||||||
rom_memory, &ram_memory, guest_info);
|
rom_memory, &ram_memory, guest_info);
|
||||||
} else if (machine->kernel_filename != NULL) {
|
} else if (machine->kernel_filename != NULL) {
|
||||||
/* For xen HVM direct kernel boot, load linux here */
|
/* For xen HVM direct kernel boot, load linux here */
|
||||||
fw_cfg = xen_load_linux(machine->kernel_filename,
|
xen_load_linux(machine->kernel_filename,
|
||||||
machine->kernel_cmdline,
|
machine->kernel_cmdline,
|
||||||
machine->initrd_filename,
|
machine->initrd_filename,
|
||||||
below_4g_mem_size,
|
below_4g_mem_size,
|
||||||
guest_info);
|
guest_info);
|
||||||
}
|
}
|
||||||
|
|
||||||
gsi_state = g_malloc0(sizeof(*gsi_state));
|
gsi_state = g_malloc0(sizeof(*gsi_state));
|
||||||
@@ -220,13 +218,13 @@ static void pc_init1(MachineState *machine,
|
|||||||
} else if (xen_enabled()) {
|
} else if (xen_enabled()) {
|
||||||
i8259 = xen_interrupt_controller_init();
|
i8259 = xen_interrupt_controller_init();
|
||||||
} else {
|
} else {
|
||||||
cpu_irq = pc_allocate_cpu_irq();
|
i8259 = i8259_init(isa_bus, pc_allocate_cpu_irq());
|
||||||
i8259 = i8259_init(isa_bus, cpu_irq[0]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for (i = 0; i < ISA_NUM_IRQS; i++) {
|
for (i = 0; i < ISA_NUM_IRQS; i++) {
|
||||||
gsi_state->i8259_irq[i] = i8259[i];
|
gsi_state->i8259_irq[i] = i8259[i];
|
||||||
}
|
}
|
||||||
|
g_free(i8259);
|
||||||
if (pci_enabled) {
|
if (pci_enabled) {
|
||||||
ioapic_init_gsi(gsi_state, "i440fx");
|
ioapic_init_gsi(gsi_state, "i440fx");
|
||||||
}
|
}
|
||||||
@@ -242,7 +240,7 @@ static void pc_init1(MachineState *machine,
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* init basic PC hardware */
|
/* init basic PC hardware */
|
||||||
pc_basic_device_init(isa_bus, gsi, &rtc_state, &floppy,
|
pc_basic_device_init(isa_bus, gsi, &rtc_state, true, &floppy,
|
||||||
(pc_machine->vmport != ON_OFF_AUTO_ON), 0x4);
|
(pc_machine->vmport != ON_OFF_AUTO_ON), 0x4);
|
||||||
|
|
||||||
pc_nic_init(isa_bus, pci_bus);
|
pc_nic_init(isa_bus, pci_bus);
|
||||||
@@ -284,11 +282,11 @@ static void pc_init1(MachineState *machine,
|
|||||||
DeviceState *piix4_pm;
|
DeviceState *piix4_pm;
|
||||||
I2CBus *smbus;
|
I2CBus *smbus;
|
||||||
|
|
||||||
smi_irq = qemu_allocate_irqs(pc_acpi_smi_interrupt, first_cpu, 1);
|
smi_irq = qemu_allocate_irq(pc_acpi_smi_interrupt, first_cpu, 0);
|
||||||
/* TODO: Populate SPD eeprom data. */
|
/* TODO: Populate SPD eeprom data. */
|
||||||
smbus = piix4_pm_init(pci_bus, piix3_devfn + 3, 0xb100,
|
smbus = piix4_pm_init(pci_bus, piix3_devfn + 3, 0xb100,
|
||||||
gsi[9], *smi_irq,
|
gsi[9], smi_irq,
|
||||||
kvm_enabled(), fw_cfg, &piix4_pm);
|
kvm_enabled(), &piix4_pm);
|
||||||
smbus_eeprom_init(smbus, 8, NULL, 0);
|
smbus_eeprom_init(smbus, 8, NULL, 0);
|
||||||
|
|
||||||
object_property_add_link(OBJECT(machine), PC_MACHINE_ACPI_DEVICE_PROP,
|
object_property_add_link(OBJECT(machine), PC_MACHINE_ACPI_DEVICE_PROP,
|
||||||
@@ -305,11 +303,6 @@ static void pc_init1(MachineState *machine,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void pc_init_pci(MachineState *machine)
|
|
||||||
{
|
|
||||||
pc_init1(machine, 1, 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void pc_compat_2_3(MachineState *machine)
|
static void pc_compat_2_3(MachineState *machine)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
@@ -418,76 +411,16 @@ static void pc_compat_1_2(MachineState *machine)
|
|||||||
x86_cpu_compat_kvm_no_autoenable(FEAT_KVM, 1 << KVM_FEATURE_PV_EOI);
|
x86_cpu_compat_kvm_no_autoenable(FEAT_KVM, 1 << KVM_FEATURE_PV_EOI);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void pc_init_pci_2_3(MachineState *machine)
|
/* PC compat function for pc-0.10 to pc-0.13 */
|
||||||
{
|
static void pc_compat_0_13(MachineState *machine)
|
||||||
pc_compat_2_3(machine);
|
|
||||||
pc_init_pci(machine);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void pc_init_pci_2_2(MachineState *machine)
|
|
||||||
{
|
|
||||||
pc_compat_2_2(machine);
|
|
||||||
pc_init_pci(machine);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void pc_init_pci_2_1(MachineState *machine)
|
|
||||||
{
|
|
||||||
pc_compat_2_1(machine);
|
|
||||||
pc_init_pci(machine);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void pc_init_pci_2_0(MachineState *machine)
|
|
||||||
{
|
|
||||||
pc_compat_2_0(machine);
|
|
||||||
pc_init_pci(machine);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void pc_init_pci_1_7(MachineState *machine)
|
|
||||||
{
|
|
||||||
pc_compat_1_7(machine);
|
|
||||||
pc_init_pci(machine);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void pc_init_pci_1_6(MachineState *machine)
|
|
||||||
{
|
|
||||||
pc_compat_1_6(machine);
|
|
||||||
pc_init_pci(machine);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void pc_init_pci_1_5(MachineState *machine)
|
|
||||||
{
|
|
||||||
pc_compat_1_5(machine);
|
|
||||||
pc_init_pci(machine);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void pc_init_pci_1_4(MachineState *machine)
|
|
||||||
{
|
|
||||||
pc_compat_1_4(machine);
|
|
||||||
pc_init_pci(machine);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void pc_init_pci_1_3(MachineState *machine)
|
|
||||||
{
|
|
||||||
pc_compat_1_3(machine);
|
|
||||||
pc_init_pci(machine);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* PC machine init function for pc-0.14 to pc-1.2 */
|
|
||||||
static void pc_init_pci_1_2(MachineState *machine)
|
|
||||||
{
|
{
|
||||||
pc_compat_1_2(machine);
|
pc_compat_1_2(machine);
|
||||||
pc_init_pci(machine);
|
kvmclock_enabled = false;
|
||||||
}
|
|
||||||
|
|
||||||
/* PC init function for pc-0.10 to pc-0.13 */
|
|
||||||
static void pc_init_pci_no_kvmclock(MachineState *machine)
|
|
||||||
{
|
|
||||||
pc_compat_1_2(machine);
|
|
||||||
pc_init1(machine, 1, 0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void pc_init_isa(MachineState *machine)
|
static void pc_init_isa(MachineState *machine)
|
||||||
{
|
{
|
||||||
|
pci_enabled = false;
|
||||||
has_acpi_build = false;
|
has_acpi_build = false;
|
||||||
smbios_defaults = false;
|
smbios_defaults = false;
|
||||||
gigabyte_align = false;
|
gigabyte_align = false;
|
||||||
@@ -500,7 +433,7 @@ static void pc_init_isa(MachineState *machine)
|
|||||||
}
|
}
|
||||||
x86_cpu_compat_kvm_no_autoenable(FEAT_KVM, 1 << KVM_FEATURE_PV_EOI);
|
x86_cpu_compat_kvm_no_autoenable(FEAT_KVM, 1 << KVM_FEATURE_PV_EOI);
|
||||||
enable_compat_apic_id_mode();
|
enable_compat_apic_id_mode();
|
||||||
pc_init1(machine, 0, 1);
|
pc_init1(machine);
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef CONFIG_XEN
|
#ifdef CONFIG_XEN
|
||||||
@@ -508,7 +441,7 @@ static void pc_xen_hvm_init(MachineState *machine)
|
|||||||
{
|
{
|
||||||
PCIBus *bus;
|
PCIBus *bus;
|
||||||
|
|
||||||
pc_init_pci(machine);
|
pc_init1(machine);
|
||||||
|
|
||||||
bus = pci_find_primary_bus();
|
bus = pci_find_primary_bus();
|
||||||
if (bus != NULL) {
|
if (bus != NULL) {
|
||||||
@@ -517,118 +450,126 @@ static void pc_xen_hvm_init(MachineState *machine)
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define PC_I440FX_MACHINE_OPTIONS \
|
#define DEFINE_I440FX_MACHINE(suffix, name, compatfn, optionfn) \
|
||||||
PC_DEFAULT_MACHINE_OPTIONS, \
|
static void pc_init_##suffix(MachineState *machine) \
|
||||||
.family = "pc_piix", \
|
{ \
|
||||||
.desc = "Standard PC (i440FX + PIIX, 1996)", \
|
void (*compat)(MachineState *m) = (compatfn); \
|
||||||
.hot_add_cpu = pc_hot_add_cpu
|
if (compat) { \
|
||||||
|
compat(machine); \
|
||||||
|
} \
|
||||||
|
pc_init1(machine); \
|
||||||
|
} \
|
||||||
|
DEFINE_PC_MACHINE(suffix, name, pc_init_##suffix, optionfn)
|
||||||
|
|
||||||
#define PC_I440FX_2_4_MACHINE_OPTIONS \
|
static void pc_i440fx_machine_options(MachineClass *m)
|
||||||
PC_I440FX_MACHINE_OPTIONS, \
|
{
|
||||||
.default_machine_opts = "firmware=bios-256k.bin", \
|
pc_default_machine_options(m);
|
||||||
.default_display = "std"
|
m->family = "pc_piix";
|
||||||
|
m->desc = "Standard PC (i440FX + PIIX, 1996)";
|
||||||
|
m->hot_add_cpu = pc_hot_add_cpu;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void pc_i440fx_2_4_machine_options(MachineClass *m)
|
||||||
|
{
|
||||||
|
pc_i440fx_machine_options(m);
|
||||||
|
m->default_machine_opts = "firmware=bios-256k.bin";
|
||||||
|
m->default_display = "std";
|
||||||
|
m->alias = "pc";
|
||||||
|
m->is_default = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
DEFINE_I440FX_MACHINE(v2_4, "pc-i440fx-2.4", NULL,
|
||||||
|
pc_i440fx_2_4_machine_options)
|
||||||
|
|
||||||
|
|
||||||
static QEMUMachine pc_i440fx_machine_v2_4 = {
|
static void pc_i440fx_2_3_machine_options(MachineClass *m)
|
||||||
PC_I440FX_2_4_MACHINE_OPTIONS,
|
{
|
||||||
.name = "pc-i440fx-2.4",
|
pc_i440fx_machine_options(m);
|
||||||
.alias = "pc",
|
m->alias = NULL;
|
||||||
.init = pc_init_pci,
|
m->is_default = 0;
|
||||||
.is_default = 1,
|
SET_MACHINE_COMPAT(m, PC_COMPAT_2_3);
|
||||||
};
|
}
|
||||||
|
|
||||||
#define PC_I440FX_2_3_MACHINE_OPTIONS PC_I440FX_2_4_MACHINE_OPTIONS
|
DEFINE_I440FX_MACHINE(v2_3, "pc-i440fx-2.3", pc_compat_2_3,
|
||||||
|
pc_i440fx_2_3_machine_options);
|
||||||
|
|
||||||
static QEMUMachine pc_i440fx_machine_v2_3 = {
|
|
||||||
PC_I440FX_2_3_MACHINE_OPTIONS,
|
|
||||||
.name = "pc-i440fx-2.3",
|
|
||||||
.init = pc_init_pci_2_3,
|
|
||||||
};
|
|
||||||
|
|
||||||
#define PC_I440FX_2_2_MACHINE_OPTIONS PC_I440FX_2_3_MACHINE_OPTIONS
|
static void pc_i440fx_2_2_machine_options(MachineClass *m)
|
||||||
|
{
|
||||||
|
pc_i440fx_2_3_machine_options(m);
|
||||||
|
SET_MACHINE_COMPAT(m, PC_COMPAT_2_2);
|
||||||
|
}
|
||||||
|
|
||||||
static QEMUMachine pc_i440fx_machine_v2_2 = {
|
DEFINE_I440FX_MACHINE(v2_2, "pc-i440fx-2.2", pc_compat_2_2,
|
||||||
PC_I440FX_2_2_MACHINE_OPTIONS,
|
pc_i440fx_2_2_machine_options);
|
||||||
.name = "pc-i440fx-2.2",
|
|
||||||
.init = pc_init_pci_2_2,
|
|
||||||
};
|
|
||||||
|
|
||||||
#define PC_I440FX_2_1_MACHINE_OPTIONS \
|
|
||||||
PC_I440FX_MACHINE_OPTIONS, \
|
|
||||||
.default_machine_opts = "firmware=bios-256k.bin"
|
|
||||||
|
|
||||||
static QEMUMachine pc_i440fx_machine_v2_1 = {
|
static void pc_i440fx_2_1_machine_options(MachineClass *m)
|
||||||
PC_I440FX_2_1_MACHINE_OPTIONS,
|
{
|
||||||
.name = "pc-i440fx-2.1",
|
pc_i440fx_2_2_machine_options(m);
|
||||||
.init = pc_init_pci_2_1,
|
m->default_display = NULL;
|
||||||
.compat_props = (GlobalProperty[]) {
|
SET_MACHINE_COMPAT(m, PC_COMPAT_2_1);
|
||||||
HW_COMPAT_2_1,
|
}
|
||||||
{ /* end of list */ }
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
#define PC_I440FX_2_0_MACHINE_OPTIONS PC_I440FX_2_1_MACHINE_OPTIONS
|
DEFINE_I440FX_MACHINE(v2_1, "pc-i440fx-2.1", pc_compat_2_1,
|
||||||
|
pc_i440fx_2_1_machine_options);
|
||||||
|
|
||||||
static QEMUMachine pc_i440fx_machine_v2_0 = {
|
|
||||||
PC_I440FX_2_0_MACHINE_OPTIONS,
|
|
||||||
.name = "pc-i440fx-2.0",
|
|
||||||
.init = pc_init_pci_2_0,
|
|
||||||
.compat_props = (GlobalProperty[]) {
|
|
||||||
PC_COMPAT_2_0,
|
|
||||||
{ /* end of list */ }
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
#define PC_I440FX_1_7_MACHINE_OPTIONS PC_I440FX_MACHINE_OPTIONS
|
|
||||||
|
|
||||||
static QEMUMachine pc_i440fx_machine_v1_7 = {
|
static void pc_i440fx_2_0_machine_options(MachineClass *m)
|
||||||
PC_I440FX_1_7_MACHINE_OPTIONS,
|
{
|
||||||
.name = "pc-i440fx-1.7",
|
pc_i440fx_2_1_machine_options(m);
|
||||||
.init = pc_init_pci_1_7,
|
SET_MACHINE_COMPAT(m, PC_COMPAT_2_0);
|
||||||
.compat_props = (GlobalProperty[]) {
|
}
|
||||||
PC_COMPAT_1_7,
|
|
||||||
{ /* end of list */ }
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
#define PC_I440FX_1_6_MACHINE_OPTIONS PC_I440FX_MACHINE_OPTIONS
|
DEFINE_I440FX_MACHINE(v2_0, "pc-i440fx-2.0", pc_compat_2_0,
|
||||||
|
pc_i440fx_2_0_machine_options);
|
||||||
|
|
||||||
static QEMUMachine pc_i440fx_machine_v1_6 = {
|
|
||||||
PC_I440FX_1_6_MACHINE_OPTIONS,
|
|
||||||
.name = "pc-i440fx-1.6",
|
|
||||||
.init = pc_init_pci_1_6,
|
|
||||||
.compat_props = (GlobalProperty[]) {
|
|
||||||
PC_COMPAT_1_6,
|
|
||||||
{ /* end of list */ }
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
static QEMUMachine pc_i440fx_machine_v1_5 = {
|
static void pc_i440fx_1_7_machine_options(MachineClass *m)
|
||||||
PC_I440FX_1_6_MACHINE_OPTIONS,
|
{
|
||||||
.name = "pc-i440fx-1.5",
|
pc_i440fx_2_0_machine_options(m);
|
||||||
.init = pc_init_pci_1_5,
|
m->default_machine_opts = NULL;
|
||||||
.compat_props = (GlobalProperty[]) {
|
SET_MACHINE_COMPAT(m, PC_COMPAT_1_7);
|
||||||
PC_COMPAT_1_5,
|
}
|
||||||
{ /* end of list */ }
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
#define PC_I440FX_1_4_MACHINE_OPTIONS \
|
DEFINE_I440FX_MACHINE(v1_7, "pc-i440fx-1.7", pc_compat_1_7,
|
||||||
PC_I440FX_1_6_MACHINE_OPTIONS, \
|
pc_i440fx_1_7_machine_options);
|
||||||
.hot_add_cpu = NULL
|
|
||||||
|
|
||||||
|
static void pc_i440fx_1_6_machine_options(MachineClass *m)
|
||||||
|
{
|
||||||
|
pc_i440fx_1_7_machine_options(m);
|
||||||
|
SET_MACHINE_COMPAT(m, PC_COMPAT_1_6);
|
||||||
|
}
|
||||||
|
|
||||||
|
DEFINE_I440FX_MACHINE(v1_6, "pc-i440fx-1.6", pc_compat_1_6,
|
||||||
|
pc_i440fx_1_6_machine_options);
|
||||||
|
|
||||||
|
|
||||||
|
static void pc_i440fx_1_5_machine_options(MachineClass *m)
|
||||||
|
{
|
||||||
|
pc_i440fx_1_6_machine_options(m);
|
||||||
|
SET_MACHINE_COMPAT(m, PC_COMPAT_1_5);
|
||||||
|
}
|
||||||
|
|
||||||
|
DEFINE_I440FX_MACHINE(v1_5, "pc-i440fx-1.5", pc_compat_1_5,
|
||||||
|
pc_i440fx_1_5_machine_options);
|
||||||
|
|
||||||
|
|
||||||
|
static void pc_i440fx_1_4_machine_options(MachineClass *m)
|
||||||
|
{
|
||||||
|
pc_i440fx_1_5_machine_options(m);
|
||||||
|
m->hot_add_cpu = NULL;
|
||||||
|
SET_MACHINE_COMPAT(m, PC_COMPAT_1_4);
|
||||||
|
}
|
||||||
|
|
||||||
|
DEFINE_I440FX_MACHINE(v1_4, "pc-i440fx-1.4", pc_compat_1_4,
|
||||||
|
pc_i440fx_1_4_machine_options);
|
||||||
|
|
||||||
static QEMUMachine pc_i440fx_machine_v1_4 = {
|
|
||||||
PC_I440FX_1_4_MACHINE_OPTIONS,
|
|
||||||
.name = "pc-i440fx-1.4",
|
|
||||||
.init = pc_init_pci_1_4,
|
|
||||||
.compat_props = (GlobalProperty[]) {
|
|
||||||
PC_COMPAT_1_4,
|
|
||||||
{ /* end of list */ }
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
#define PC_COMPAT_1_3 \
|
#define PC_COMPAT_1_3 \
|
||||||
PC_COMPAT_1_4, \
|
PC_COMPAT_1_4 \
|
||||||
{\
|
{\
|
||||||
.driver = "usb-tablet",\
|
.driver = "usb-tablet",\
|
||||||
.property = "usb_version",\
|
.property = "usb_version",\
|
||||||
@@ -645,20 +586,21 @@ static QEMUMachine pc_i440fx_machine_v1_4 = {
|
|||||||
.driver = "e1000",\
|
.driver = "e1000",\
|
||||||
.property = "autonegotiation",\
|
.property = "autonegotiation",\
|
||||||
.value = "off",\
|
.value = "off",\
|
||||||
}
|
},
|
||||||
|
|
||||||
|
|
||||||
|
static void pc_i440fx_1_3_machine_options(MachineClass *m)
|
||||||
|
{
|
||||||
|
pc_i440fx_1_4_machine_options(m);
|
||||||
|
SET_MACHINE_COMPAT(m, PC_COMPAT_1_3);
|
||||||
|
}
|
||||||
|
|
||||||
|
DEFINE_I440FX_MACHINE(v1_3, "pc-1.3", pc_compat_1_3,
|
||||||
|
pc_i440fx_1_3_machine_options);
|
||||||
|
|
||||||
static QEMUMachine pc_machine_v1_3 = {
|
|
||||||
PC_I440FX_1_4_MACHINE_OPTIONS,
|
|
||||||
.name = "pc-1.3",
|
|
||||||
.init = pc_init_pci_1_3,
|
|
||||||
.compat_props = (GlobalProperty[]) {
|
|
||||||
PC_COMPAT_1_3,
|
|
||||||
{ /* end of list */ }
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
#define PC_COMPAT_1_2 \
|
#define PC_COMPAT_1_2 \
|
||||||
PC_COMPAT_1_3,\
|
PC_COMPAT_1_3 \
|
||||||
{\
|
{\
|
||||||
.driver = "nec-usb-xhci",\
|
.driver = "nec-usb-xhci",\
|
||||||
.property = "msi",\
|
.property = "msi",\
|
||||||
@@ -683,23 +625,20 @@ static QEMUMachine pc_machine_v1_3 = {
|
|||||||
.driver = "VGA",\
|
.driver = "VGA",\
|
||||||
.property = "mmio",\
|
.property = "mmio",\
|
||||||
.value = "off",\
|
.value = "off",\
|
||||||
}
|
},
|
||||||
|
|
||||||
#define PC_I440FX_1_2_MACHINE_OPTIONS \
|
static void pc_i440fx_1_2_machine_options(MachineClass *m)
|
||||||
PC_I440FX_1_4_MACHINE_OPTIONS, \
|
{
|
||||||
.init = pc_init_pci_1_2
|
pc_i440fx_1_3_machine_options(m);
|
||||||
|
SET_MACHINE_COMPAT(m, PC_COMPAT_1_2);
|
||||||
|
}
|
||||||
|
|
||||||
|
DEFINE_I440FX_MACHINE(v1_2, "pc-1.2", pc_compat_1_2,
|
||||||
|
pc_i440fx_1_2_machine_options);
|
||||||
|
|
||||||
static QEMUMachine pc_machine_v1_2 = {
|
|
||||||
PC_I440FX_1_2_MACHINE_OPTIONS,
|
|
||||||
.name = "pc-1.2",
|
|
||||||
.compat_props = (GlobalProperty[]) {
|
|
||||||
PC_COMPAT_1_2,
|
|
||||||
{ /* end of list */ }
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
#define PC_COMPAT_1_1 \
|
#define PC_COMPAT_1_1 \
|
||||||
PC_COMPAT_1_2,\
|
PC_COMPAT_1_2 \
|
||||||
{\
|
{\
|
||||||
.driver = "virtio-scsi-pci",\
|
.driver = "virtio-scsi-pci",\
|
||||||
.property = "hotplug",\
|
.property = "hotplug",\
|
||||||
@@ -728,19 +667,20 @@ static QEMUMachine pc_machine_v1_2 = {
|
|||||||
.driver = "virtio-blk-pci",\
|
.driver = "virtio-blk-pci",\
|
||||||
.property = "config-wce",\
|
.property = "config-wce",\
|
||||||
.value = "off",\
|
.value = "off",\
|
||||||
}
|
},
|
||||||
|
|
||||||
|
static void pc_i440fx_1_1_machine_options(MachineClass *m)
|
||||||
|
{
|
||||||
|
pc_i440fx_1_2_machine_options(m);
|
||||||
|
SET_MACHINE_COMPAT(m, PC_COMPAT_1_1);
|
||||||
|
}
|
||||||
|
|
||||||
|
DEFINE_I440FX_MACHINE(v1_1, "pc-1.1", pc_compat_1_2,
|
||||||
|
pc_i440fx_1_1_machine_options);
|
||||||
|
|
||||||
static QEMUMachine pc_machine_v1_1 = {
|
|
||||||
PC_I440FX_1_2_MACHINE_OPTIONS,
|
|
||||||
.name = "pc-1.1",
|
|
||||||
.compat_props = (GlobalProperty[]) {
|
|
||||||
PC_COMPAT_1_1,
|
|
||||||
{ /* end of list */ }
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
#define PC_COMPAT_1_0 \
|
#define PC_COMPAT_1_0 \
|
||||||
PC_COMPAT_1_1,\
|
PC_COMPAT_1_1 \
|
||||||
{\
|
{\
|
||||||
.driver = TYPE_ISA_FDC,\
|
.driver = TYPE_ISA_FDC,\
|
||||||
.property = "check_media_rate",\
|
.property = "check_media_rate",\
|
||||||
@@ -757,33 +697,35 @@ static QEMUMachine pc_machine_v1_1 = {
|
|||||||
.driver = TYPE_USB_DEVICE,\
|
.driver = TYPE_USB_DEVICE,\
|
||||||
.property = "full-path",\
|
.property = "full-path",\
|
||||||
.value = "no",\
|
.value = "no",\
|
||||||
}
|
},
|
||||||
|
|
||||||
|
static void pc_i440fx_1_0_machine_options(MachineClass *m)
|
||||||
|
{
|
||||||
|
pc_i440fx_1_1_machine_options(m);
|
||||||
|
m->hw_version = "1.0";
|
||||||
|
SET_MACHINE_COMPAT(m, PC_COMPAT_1_0);
|
||||||
|
}
|
||||||
|
|
||||||
|
DEFINE_I440FX_MACHINE(v1_0, "pc-1.0", pc_compat_1_2,
|
||||||
|
pc_i440fx_1_0_machine_options);
|
||||||
|
|
||||||
static QEMUMachine pc_machine_v1_0 = {
|
|
||||||
PC_I440FX_1_2_MACHINE_OPTIONS,
|
|
||||||
.name = "pc-1.0",
|
|
||||||
.compat_props = (GlobalProperty[]) {
|
|
||||||
PC_COMPAT_1_0,
|
|
||||||
{ /* end of list */ }
|
|
||||||
},
|
|
||||||
.hw_version = "1.0",
|
|
||||||
};
|
|
||||||
|
|
||||||
#define PC_COMPAT_0_15 \
|
#define PC_COMPAT_0_15 \
|
||||||
PC_COMPAT_1_0
|
PC_COMPAT_1_0
|
||||||
|
|
||||||
static QEMUMachine pc_machine_v0_15 = {
|
static void pc_i440fx_0_15_machine_options(MachineClass *m)
|
||||||
PC_I440FX_1_2_MACHINE_OPTIONS,
|
{
|
||||||
.name = "pc-0.15",
|
pc_i440fx_1_0_machine_options(m);
|
||||||
.compat_props = (GlobalProperty[]) {
|
m->hw_version = "0.15";
|
||||||
PC_COMPAT_0_15,
|
SET_MACHINE_COMPAT(m, PC_COMPAT_0_15);
|
||||||
{ /* end of list */ }
|
}
|
||||||
},
|
|
||||||
.hw_version = "0.15",
|
DEFINE_I440FX_MACHINE(v0_15, "pc-0.15", pc_compat_1_2,
|
||||||
};
|
pc_i440fx_0_15_machine_options);
|
||||||
|
|
||||||
|
|
||||||
#define PC_COMPAT_0_14 \
|
#define PC_COMPAT_0_14 \
|
||||||
PC_COMPAT_0_15,\
|
PC_COMPAT_0_15 \
|
||||||
{\
|
{\
|
||||||
.driver = "virtio-blk-pci",\
|
.driver = "virtio-blk-pci",\
|
||||||
.property = "event_idx",\
|
.property = "event_idx",\
|
||||||
@@ -800,29 +742,29 @@ static QEMUMachine pc_machine_v0_15 = {
|
|||||||
.driver = "virtio-balloon-pci",\
|
.driver = "virtio-balloon-pci",\
|
||||||
.property = "event_idx",\
|
.property = "event_idx",\
|
||||||
.value = "off",\
|
.value = "off",\
|
||||||
}
|
},{\
|
||||||
|
.driver = "qxl",\
|
||||||
static QEMUMachine pc_machine_v0_14 = {
|
.property = "revision",\
|
||||||
PC_I440FX_1_2_MACHINE_OPTIONS,
|
.value = stringify(2),\
|
||||||
.name = "pc-0.14",
|
},{\
|
||||||
.compat_props = (GlobalProperty[]) {
|
.driver = "qxl-vga",\
|
||||||
PC_COMPAT_0_14,
|
.property = "revision",\
|
||||||
{
|
.value = stringify(2),\
|
||||||
.driver = "qxl",
|
|
||||||
.property = "revision",
|
|
||||||
.value = stringify(2),
|
|
||||||
},{
|
|
||||||
.driver = "qxl-vga",
|
|
||||||
.property = "revision",
|
|
||||||
.value = stringify(2),
|
|
||||||
},
|
},
|
||||||
{ /* end of list */ }
|
|
||||||
},
|
static void pc_i440fx_0_14_machine_options(MachineClass *m)
|
||||||
.hw_version = "0.14",
|
{
|
||||||
};
|
pc_i440fx_0_15_machine_options(m);
|
||||||
|
m->hw_version = "0.14";
|
||||||
|
SET_MACHINE_COMPAT(m, PC_COMPAT_0_14);
|
||||||
|
}
|
||||||
|
|
||||||
|
DEFINE_I440FX_MACHINE(v0_14, "pc-0.14", pc_compat_1_2,
|
||||||
|
pc_i440fx_0_14_machine_options);
|
||||||
|
|
||||||
|
|
||||||
#define PC_COMPAT_0_13 \
|
#define PC_COMPAT_0_13 \
|
||||||
PC_COMPAT_0_14,\
|
PC_COMPAT_0_14 \
|
||||||
{\
|
{\
|
||||||
.driver = TYPE_PCI_DEVICE,\
|
.driver = TYPE_PCI_DEVICE,\
|
||||||
.property = "command_serr_enable",\
|
.property = "command_serr_enable",\
|
||||||
@@ -831,37 +773,33 @@ static QEMUMachine pc_machine_v0_14 = {
|
|||||||
.driver = "AC97",\
|
.driver = "AC97",\
|
||||||
.property = "use_broken_id",\
|
.property = "use_broken_id",\
|
||||||
.value = stringify(1),\
|
.value = stringify(1),\
|
||||||
}
|
},{\
|
||||||
|
.driver = "virtio-9p-pci",\
|
||||||
#define PC_I440FX_0_13_MACHINE_OPTIONS \
|
.property = "vectors",\
|
||||||
PC_I440FX_1_2_MACHINE_OPTIONS, \
|
.value = stringify(0),\
|
||||||
.init = pc_init_pci_no_kvmclock
|
},{\
|
||||||
|
.driver = "VGA",\
|
||||||
static QEMUMachine pc_machine_v0_13 = {
|
.property = "rombar",\
|
||||||
PC_I440FX_0_13_MACHINE_OPTIONS,
|
.value = stringify(0),\
|
||||||
.name = "pc-0.13",
|
},{\
|
||||||
.compat_props = (GlobalProperty[]) {
|
.driver = "vmware-svga",\
|
||||||
PC_COMPAT_0_13,
|
.property = "rombar",\
|
||||||
{
|
.value = stringify(0),\
|
||||||
.driver = "virtio-9p-pci",
|
|
||||||
.property = "vectors",
|
|
||||||
.value = stringify(0),
|
|
||||||
},{
|
|
||||||
.driver = "VGA",
|
|
||||||
.property = "rombar",
|
|
||||||
.value = stringify(0),
|
|
||||||
},{
|
|
||||||
.driver = "vmware-svga",
|
|
||||||
.property = "rombar",
|
|
||||||
.value = stringify(0),
|
|
||||||
},
|
},
|
||||||
{ /* end of list */ }
|
|
||||||
},
|
static void pc_i440fx_0_13_machine_options(MachineClass *m)
|
||||||
.hw_version = "0.13",
|
{
|
||||||
};
|
pc_i440fx_0_14_machine_options(m);
|
||||||
|
m->hw_version = "0.13";
|
||||||
|
SET_MACHINE_COMPAT(m, PC_COMPAT_0_13);
|
||||||
|
}
|
||||||
|
|
||||||
|
DEFINE_I440FX_MACHINE(v0_13, "pc-0.13", pc_compat_0_13,
|
||||||
|
pc_i440fx_0_13_machine_options);
|
||||||
|
|
||||||
|
|
||||||
#define PC_COMPAT_0_12 \
|
#define PC_COMPAT_0_12 \
|
||||||
PC_COMPAT_0_13,\
|
PC_COMPAT_0_13 \
|
||||||
{\
|
{\
|
||||||
.driver = "virtio-serial-pci",\
|
.driver = "virtio-serial-pci",\
|
||||||
.property = "max_ports",\
|
.property = "max_ports",\
|
||||||
@@ -882,29 +820,21 @@ static QEMUMachine pc_machine_v0_13 = {
|
|||||||
.driver = "usb-kbd",\
|
.driver = "usb-kbd",\
|
||||||
.property = "serial",\
|
.property = "serial",\
|
||||||
.value = "1",\
|
.value = "1",\
|
||||||
}
|
|
||||||
|
|
||||||
static QEMUMachine pc_machine_v0_12 = {
|
|
||||||
PC_I440FX_0_13_MACHINE_OPTIONS,
|
|
||||||
.name = "pc-0.12",
|
|
||||||
.compat_props = (GlobalProperty[]) {
|
|
||||||
PC_COMPAT_0_12,
|
|
||||||
{
|
|
||||||
.driver = "VGA",
|
|
||||||
.property = "rombar",
|
|
||||||
.value = stringify(0),
|
|
||||||
},{
|
|
||||||
.driver = "vmware-svga",
|
|
||||||
.property = "rombar",
|
|
||||||
.value = stringify(0),
|
|
||||||
},
|
},
|
||||||
{ /* end of list */ }
|
|
||||||
},
|
static void pc_i440fx_0_12_machine_options(MachineClass *m)
|
||||||
.hw_version = "0.12",
|
{
|
||||||
};
|
pc_i440fx_0_13_machine_options(m);
|
||||||
|
m->hw_version = "0.12";
|
||||||
|
SET_MACHINE_COMPAT(m, PC_COMPAT_0_12);
|
||||||
|
}
|
||||||
|
|
||||||
|
DEFINE_I440FX_MACHINE(v0_12, "pc-0.12", pc_compat_0_13,
|
||||||
|
pc_i440fx_0_12_machine_options);
|
||||||
|
|
||||||
|
|
||||||
#define PC_COMPAT_0_11 \
|
#define PC_COMPAT_0_11 \
|
||||||
PC_COMPAT_0_12,\
|
PC_COMPAT_0_12 \
|
||||||
{\
|
{\
|
||||||
.driver = "virtio-blk-pci",\
|
.driver = "virtio-blk-pci",\
|
||||||
.property = "vectors",\
|
.property = "vectors",\
|
||||||
@@ -913,106 +843,83 @@ static QEMUMachine pc_machine_v0_12 = {
|
|||||||
.driver = TYPE_PCI_DEVICE,\
|
.driver = TYPE_PCI_DEVICE,\
|
||||||
.property = "rombar",\
|
.property = "rombar",\
|
||||||
.value = stringify(0),\
|
.value = stringify(0),\
|
||||||
}
|
},{\
|
||||||
|
.driver = "ide-drive",\
|
||||||
static QEMUMachine pc_machine_v0_11 = {
|
.property = "ver",\
|
||||||
PC_I440FX_0_13_MACHINE_OPTIONS,
|
.value = "0.11",\
|
||||||
.name = "pc-0.11",
|
},{\
|
||||||
.compat_props = (GlobalProperty[]) {
|
.driver = "scsi-disk",\
|
||||||
PC_COMPAT_0_11,
|
.property = "ver",\
|
||||||
{
|
.value = "0.11",\
|
||||||
.driver = "ide-drive",
|
|
||||||
.property = "ver",
|
|
||||||
.value = "0.11",
|
|
||||||
},{
|
|
||||||
.driver = "scsi-disk",
|
|
||||||
.property = "ver",
|
|
||||||
.value = "0.11",
|
|
||||||
},
|
},
|
||||||
{ /* end of list */ }
|
|
||||||
},
|
|
||||||
.hw_version = "0.11",
|
|
||||||
};
|
|
||||||
|
|
||||||
static QEMUMachine pc_machine_v0_10 = {
|
static void pc_i440fx_0_11_machine_options(MachineClass *m)
|
||||||
PC_I440FX_0_13_MACHINE_OPTIONS,
|
|
||||||
.name = "pc-0.10",
|
|
||||||
.compat_props = (GlobalProperty[]) {
|
|
||||||
PC_COMPAT_0_11,
|
|
||||||
{
|
|
||||||
.driver = "virtio-blk-pci",
|
|
||||||
.property = "class",
|
|
||||||
.value = stringify(PCI_CLASS_STORAGE_OTHER),
|
|
||||||
},{
|
|
||||||
.driver = "virtio-serial-pci",
|
|
||||||
.property = "class",
|
|
||||||
.value = stringify(PCI_CLASS_DISPLAY_OTHER),
|
|
||||||
},{
|
|
||||||
.driver = "virtio-net-pci",
|
|
||||||
.property = "vectors",
|
|
||||||
.value = stringify(0),
|
|
||||||
},{
|
|
||||||
.driver = "ide-drive",
|
|
||||||
.property = "ver",
|
|
||||||
.value = "0.10",
|
|
||||||
},{
|
|
||||||
.driver = "scsi-disk",
|
|
||||||
.property = "ver",
|
|
||||||
.value = "0.10",
|
|
||||||
},
|
|
||||||
{ /* end of list */ }
|
|
||||||
},
|
|
||||||
.hw_version = "0.10",
|
|
||||||
};
|
|
||||||
|
|
||||||
static QEMUMachine isapc_machine = {
|
|
||||||
PC_COMMON_MACHINE_OPTIONS,
|
|
||||||
.name = "isapc",
|
|
||||||
.desc = "ISA-only PC",
|
|
||||||
.init = pc_init_isa,
|
|
||||||
.max_cpus = 1,
|
|
||||||
.compat_props = (GlobalProperty[]) {
|
|
||||||
{ /* end of list */ }
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
#ifdef CONFIG_XEN
|
|
||||||
static QEMUMachine xenfv_machine = {
|
|
||||||
PC_COMMON_MACHINE_OPTIONS,
|
|
||||||
.name = "xenfv",
|
|
||||||
.desc = "Xen Fully-virtualized PC",
|
|
||||||
.init = pc_xen_hvm_init,
|
|
||||||
.max_cpus = HVM_MAX_VCPUS,
|
|
||||||
.default_machine_opts = "accel=xen",
|
|
||||||
.hot_add_cpu = pc_hot_add_cpu,
|
|
||||||
};
|
|
||||||
#endif
|
|
||||||
|
|
||||||
static void pc_machine_init(void)
|
|
||||||
{
|
{
|
||||||
qemu_register_pc_machine(&pc_i440fx_machine_v2_4);
|
pc_i440fx_0_12_machine_options(m);
|
||||||
qemu_register_pc_machine(&pc_i440fx_machine_v2_3);
|
m->hw_version = "0.11";
|
||||||
qemu_register_pc_machine(&pc_i440fx_machine_v2_2);
|
SET_MACHINE_COMPAT(m, PC_COMPAT_0_11);
|
||||||
qemu_register_pc_machine(&pc_i440fx_machine_v2_1);
|
|
||||||
qemu_register_pc_machine(&pc_i440fx_machine_v2_0);
|
|
||||||
qemu_register_pc_machine(&pc_i440fx_machine_v1_7);
|
|
||||||
qemu_register_pc_machine(&pc_i440fx_machine_v1_6);
|
|
||||||
qemu_register_pc_machine(&pc_i440fx_machine_v1_5);
|
|
||||||
qemu_register_pc_machine(&pc_i440fx_machine_v1_4);
|
|
||||||
qemu_register_pc_machine(&pc_machine_v1_3);
|
|
||||||
qemu_register_pc_machine(&pc_machine_v1_2);
|
|
||||||
qemu_register_pc_machine(&pc_machine_v1_1);
|
|
||||||
qemu_register_pc_machine(&pc_machine_v1_0);
|
|
||||||
qemu_register_pc_machine(&pc_machine_v0_15);
|
|
||||||
qemu_register_pc_machine(&pc_machine_v0_14);
|
|
||||||
qemu_register_pc_machine(&pc_machine_v0_13);
|
|
||||||
qemu_register_pc_machine(&pc_machine_v0_12);
|
|
||||||
qemu_register_pc_machine(&pc_machine_v0_11);
|
|
||||||
qemu_register_pc_machine(&pc_machine_v0_10);
|
|
||||||
qemu_register_pc_machine(&isapc_machine);
|
|
||||||
#ifdef CONFIG_XEN
|
|
||||||
qemu_register_pc_machine(&xenfv_machine);
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
machine_init(pc_machine_init);
|
DEFINE_I440FX_MACHINE(v0_11, "pc-0.11", pc_compat_0_13,
|
||||||
|
pc_i440fx_0_11_machine_options);
|
||||||
|
|
||||||
|
|
||||||
|
#define PC_COMPAT_0_10 \
|
||||||
|
PC_COMPAT_0_11 \
|
||||||
|
{\
|
||||||
|
.driver = "virtio-blk-pci",\
|
||||||
|
.property = "class",\
|
||||||
|
.value = stringify(PCI_CLASS_STORAGE_OTHER),\
|
||||||
|
},{\
|
||||||
|
.driver = "virtio-serial-pci",\
|
||||||
|
.property = "class",\
|
||||||
|
.value = stringify(PCI_CLASS_DISPLAY_OTHER),\
|
||||||
|
},{\
|
||||||
|
.driver = "virtio-net-pci",\
|
||||||
|
.property = "vectors",\
|
||||||
|
.value = stringify(0),\
|
||||||
|
},{\
|
||||||
|
.driver = "ide-drive",\
|
||||||
|
.property = "ver",\
|
||||||
|
.value = "0.10",\
|
||||||
|
},{\
|
||||||
|
.driver = "scsi-disk",\
|
||||||
|
.property = "ver",\
|
||||||
|
.value = "0.10",\
|
||||||
|
},
|
||||||
|
|
||||||
|
static void pc_i440fx_0_10_machine_options(MachineClass *m)
|
||||||
|
{
|
||||||
|
pc_i440fx_0_11_machine_options(m);
|
||||||
|
m->hw_version = "0.10";
|
||||||
|
SET_MACHINE_COMPAT(m, PC_COMPAT_0_10);
|
||||||
|
}
|
||||||
|
|
||||||
|
DEFINE_I440FX_MACHINE(v0_10, "pc-0.10", pc_compat_0_13,
|
||||||
|
pc_i440fx_0_10_machine_options);
|
||||||
|
|
||||||
|
|
||||||
|
static void isapc_machine_options(MachineClass *m)
|
||||||
|
{
|
||||||
|
pc_common_machine_options(m);
|
||||||
|
m->desc = "ISA-only PC";
|
||||||
|
m->max_cpus = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
DEFINE_PC_MACHINE(isapc, "isapc", pc_init_isa,
|
||||||
|
isapc_machine_options);
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef CONFIG_XEN
|
||||||
|
static void xenfv_machine_options(MachineClass *m)
|
||||||
|
{
|
||||||
|
pc_common_machine_options(m);
|
||||||
|
m->desc = "Xen Fully-virtualized PC";
|
||||||
|
m->max_cpus = HVM_MAX_VCPUS;
|
||||||
|
m->default_machine_opts = "accel=xen";
|
||||||
|
m->hot_add_cpu = pc_hot_add_cpu;
|
||||||
|
}
|
||||||
|
|
||||||
|
DEFINE_PC_MACHINE(xenfv, "xenfv", pc_xen_hvm_init,
|
||||||
|
xenfv_machine_options);
|
||||||
|
#endif
|
||||||
|
|||||||
237
hw/i386/pc_q35.c
237
hw/i386/pc_q35.c
@@ -79,7 +79,6 @@ static void pc_q35_init(MachineState *machine)
|
|||||||
GSIState *gsi_state;
|
GSIState *gsi_state;
|
||||||
ISABus *isa_bus;
|
ISABus *isa_bus;
|
||||||
int pci_enabled = 1;
|
int pci_enabled = 1;
|
||||||
qemu_irq *cpu_irq;
|
|
||||||
qemu_irq *gsi;
|
qemu_irq *gsi;
|
||||||
qemu_irq *i8259;
|
qemu_irq *i8259;
|
||||||
int i;
|
int i;
|
||||||
@@ -89,6 +88,7 @@ static void pc_q35_init(MachineState *machine)
|
|||||||
PcGuestInfo *guest_info;
|
PcGuestInfo *guest_info;
|
||||||
ram_addr_t lowmem;
|
ram_addr_t lowmem;
|
||||||
DriveInfo *hd[MAX_SATA_PORTS];
|
DriveInfo *hd[MAX_SATA_PORTS];
|
||||||
|
MachineClass *mc = MACHINE_GET_CLASS(machine);
|
||||||
|
|
||||||
/* Check whether RAM fits below 4G (leaving 1/2 GByte for IO memory
|
/* Check whether RAM fits below 4G (leaving 1/2 GByte for IO memory
|
||||||
* and 256 Mbytes for PCI Express Enhanced Configuration Access Mapping
|
* and 256 Mbytes for PCI Express Enhanced Configuration Access Mapping
|
||||||
@@ -163,7 +163,6 @@ static void pc_q35_init(MachineState *machine)
|
|||||||
guest_info->legacy_acpi_table_size = 0;
|
guest_info->legacy_acpi_table_size = 0;
|
||||||
|
|
||||||
if (smbios_defaults) {
|
if (smbios_defaults) {
|
||||||
MachineClass *mc = MACHINE_GET_CLASS(machine);
|
|
||||||
/* These values are guest ABI, do not change */
|
/* These values are guest ABI, do not change */
|
||||||
smbios_set_defaults("QEMU", "Standard PC (Q35 + ICH9, 2009)",
|
smbios_set_defaults("QEMU", "Standard PC (Q35 + ICH9, 2009)",
|
||||||
mc->name, smbios_legacy_mode, smbios_uuid_encoded);
|
mc->name, smbios_legacy_mode, smbios_uuid_encoded);
|
||||||
@@ -230,8 +229,7 @@ static void pc_q35_init(MachineState *machine)
|
|||||||
} else if (xen_enabled()) {
|
} else if (xen_enabled()) {
|
||||||
i8259 = xen_interrupt_controller_init();
|
i8259 = xen_interrupt_controller_init();
|
||||||
} else {
|
} else {
|
||||||
cpu_irq = pc_allocate_cpu_irq();
|
i8259 = i8259_init(isa_bus, pc_allocate_cpu_irq());
|
||||||
i8259 = i8259_init(isa_bus, cpu_irq[0]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for (i = 0; i < ISA_NUM_IRQS; i++) {
|
for (i = 0; i < ISA_NUM_IRQS; i++) {
|
||||||
@@ -250,7 +248,7 @@ static void pc_q35_init(MachineState *machine)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* init basic PC hardware */
|
/* init basic PC hardware */
|
||||||
pc_basic_device_init(isa_bus, gsi, &rtc_state, &floppy,
|
pc_basic_device_init(isa_bus, gsi, &rtc_state, !mc->no_floppy, &floppy,
|
||||||
(pc_machine->vmport != ON_OFF_AUTO_ON), 0xff0104);
|
(pc_machine->vmport != ON_OFF_AUTO_ON), 0xff0104);
|
||||||
|
|
||||||
/* connect pm stuff to lpc */
|
/* connect pm stuff to lpc */
|
||||||
@@ -366,174 +364,119 @@ static void pc_compat_1_4(MachineState *machine)
|
|||||||
x86_cpu_compat_set_features("Westmere", FEAT_1_ECX, 0, CPUID_EXT_PCLMULQDQ);
|
x86_cpu_compat_set_features("Westmere", FEAT_1_ECX, 0, CPUID_EXT_PCLMULQDQ);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void pc_q35_init_2_3(MachineState *machine)
|
#define DEFINE_Q35_MACHINE(suffix, name, compatfn, optionfn) \
|
||||||
|
static void pc_init_##suffix(MachineState *machine) \
|
||||||
|
{ \
|
||||||
|
void (*compat)(MachineState *m) = (compatfn); \
|
||||||
|
if (compat) { \
|
||||||
|
compat(machine); \
|
||||||
|
} \
|
||||||
|
pc_q35_init(machine); \
|
||||||
|
} \
|
||||||
|
DEFINE_PC_MACHINE(suffix, name, pc_init_##suffix, optionfn)
|
||||||
|
|
||||||
|
|
||||||
|
static void pc_q35_machine_options(MachineClass *m)
|
||||||
{
|
{
|
||||||
pc_compat_2_3(machine);
|
pc_default_machine_options(m);
|
||||||
pc_q35_init(machine);
|
m->family = "pc_q35";
|
||||||
|
m->desc = "Standard PC (Q35 + ICH9, 2009)";
|
||||||
|
m->hot_add_cpu = pc_hot_add_cpu;
|
||||||
|
m->units_per_default_bus = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void pc_q35_init_2_2(MachineState *machine)
|
static void pc_q35_2_4_machine_options(MachineClass *m)
|
||||||
{
|
{
|
||||||
pc_compat_2_2(machine);
|
pc_q35_machine_options(m);
|
||||||
pc_q35_init(machine);
|
m->default_machine_opts = "firmware=bios-256k.bin";
|
||||||
|
m->default_display = "std";
|
||||||
|
m->no_floppy = 1;
|
||||||
|
m->alias = "q35";
|
||||||
}
|
}
|
||||||
|
|
||||||
static void pc_q35_init_2_1(MachineState *machine)
|
DEFINE_Q35_MACHINE(v2_4, "pc-q35-2.4", NULL,
|
||||||
|
pc_q35_2_4_machine_options);
|
||||||
|
|
||||||
|
|
||||||
|
static void pc_q35_2_3_machine_options(MachineClass *m)
|
||||||
{
|
{
|
||||||
pc_compat_2_1(machine);
|
pc_q35_2_4_machine_options(m);
|
||||||
pc_q35_init(machine);
|
m->alias = NULL;
|
||||||
|
SET_MACHINE_COMPAT(m, PC_COMPAT_2_3);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void pc_q35_init_2_0(MachineState *machine)
|
DEFINE_Q35_MACHINE(v2_3, "pc-q35-2.3", pc_compat_2_3,
|
||||||
|
pc_q35_2_3_machine_options);
|
||||||
|
|
||||||
|
|
||||||
|
static void pc_q35_2_2_machine_options(MachineClass *m)
|
||||||
{
|
{
|
||||||
pc_compat_2_0(machine);
|
pc_q35_2_3_machine_options(m);
|
||||||
pc_q35_init(machine);
|
SET_MACHINE_COMPAT(m, PC_COMPAT_2_2);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void pc_q35_init_1_7(MachineState *machine)
|
DEFINE_Q35_MACHINE(v2_2, "pc-q35-2.2", pc_compat_2_2,
|
||||||
|
pc_q35_2_2_machine_options);
|
||||||
|
|
||||||
|
|
||||||
|
static void pc_q35_2_1_machine_options(MachineClass *m)
|
||||||
{
|
{
|
||||||
pc_compat_1_7(machine);
|
pc_q35_2_2_machine_options(m);
|
||||||
pc_q35_init(machine);
|
m->default_display = NULL;
|
||||||
|
SET_MACHINE_COMPAT(m, PC_COMPAT_2_1);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void pc_q35_init_1_6(MachineState *machine)
|
DEFINE_Q35_MACHINE(v2_1, "pc-q35-2.1", pc_compat_2_1,
|
||||||
|
pc_q35_2_1_machine_options);
|
||||||
|
|
||||||
|
|
||||||
|
static void pc_q35_2_0_machine_options(MachineClass *m)
|
||||||
{
|
{
|
||||||
pc_compat_1_6(machine);
|
pc_q35_2_1_machine_options(m);
|
||||||
pc_q35_init(machine);
|
SET_MACHINE_COMPAT(m, PC_COMPAT_2_0);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void pc_q35_init_1_5(MachineState *machine)
|
DEFINE_Q35_MACHINE(v2_0, "pc-q35-2.0", pc_compat_2_0,
|
||||||
|
pc_q35_2_0_machine_options);
|
||||||
|
|
||||||
|
|
||||||
|
static void pc_q35_1_7_machine_options(MachineClass *m)
|
||||||
{
|
{
|
||||||
pc_compat_1_5(machine);
|
pc_q35_2_0_machine_options(m);
|
||||||
pc_q35_init(machine);
|
m->default_machine_opts = NULL;
|
||||||
|
SET_MACHINE_COMPAT(m, PC_COMPAT_1_7);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void pc_q35_init_1_4(MachineState *machine)
|
DEFINE_Q35_MACHINE(v1_7, "pc-q35-1.7", pc_compat_1_7,
|
||||||
|
pc_q35_1_7_machine_options);
|
||||||
|
|
||||||
|
|
||||||
|
static void pc_q35_1_6_machine_options(MachineClass *m)
|
||||||
{
|
{
|
||||||
pc_compat_1_4(machine);
|
pc_q35_machine_options(m);
|
||||||
pc_q35_init(machine);
|
SET_MACHINE_COMPAT(m, PC_COMPAT_1_6);
|
||||||
}
|
}
|
||||||
|
|
||||||
#define PC_Q35_MACHINE_OPTIONS \
|
DEFINE_Q35_MACHINE(v1_6, "pc-q35-1.6", pc_compat_1_6,
|
||||||
PC_DEFAULT_MACHINE_OPTIONS, \
|
pc_q35_1_6_machine_options);
|
||||||
.family = "pc_q35", \
|
|
||||||
.desc = "Standard PC (Q35 + ICH9, 2009)", \
|
|
||||||
.hot_add_cpu = pc_hot_add_cpu, \
|
|
||||||
.units_per_default_bus = 1
|
|
||||||
|
|
||||||
#define PC_Q35_2_4_MACHINE_OPTIONS \
|
|
||||||
PC_Q35_MACHINE_OPTIONS, \
|
|
||||||
.default_machine_opts = "firmware=bios-256k.bin", \
|
|
||||||
.default_display = "std"
|
|
||||||
|
|
||||||
static QEMUMachine pc_q35_machine_v2_4 = {
|
static void pc_q35_1_5_machine_options(MachineClass *m)
|
||||||
PC_Q35_2_4_MACHINE_OPTIONS,
|
|
||||||
.name = "pc-q35-2.4",
|
|
||||||
.alias = "q35",
|
|
||||||
.init = pc_q35_init,
|
|
||||||
};
|
|
||||||
|
|
||||||
#define PC_Q35_2_3_MACHINE_OPTIONS PC_Q35_2_4_MACHINE_OPTIONS
|
|
||||||
|
|
||||||
static QEMUMachine pc_q35_machine_v2_3 = {
|
|
||||||
PC_Q35_2_3_MACHINE_OPTIONS,
|
|
||||||
.name = "pc-q35-2.3",
|
|
||||||
.init = pc_q35_init_2_3,
|
|
||||||
};
|
|
||||||
|
|
||||||
#define PC_Q35_2_2_MACHINE_OPTIONS PC_Q35_2_3_MACHINE_OPTIONS
|
|
||||||
|
|
||||||
static QEMUMachine pc_q35_machine_v2_2 = {
|
|
||||||
PC_Q35_2_2_MACHINE_OPTIONS,
|
|
||||||
.name = "pc-q35-2.2",
|
|
||||||
.init = pc_q35_init_2_2,
|
|
||||||
};
|
|
||||||
|
|
||||||
#define PC_Q35_2_1_MACHINE_OPTIONS \
|
|
||||||
PC_Q35_MACHINE_OPTIONS, \
|
|
||||||
.default_machine_opts = "firmware=bios-256k.bin"
|
|
||||||
|
|
||||||
static QEMUMachine pc_q35_machine_v2_1 = {
|
|
||||||
PC_Q35_2_1_MACHINE_OPTIONS,
|
|
||||||
.name = "pc-q35-2.1",
|
|
||||||
.init = pc_q35_init_2_1,
|
|
||||||
.compat_props = (GlobalProperty[]) {
|
|
||||||
HW_COMPAT_2_1,
|
|
||||||
{ /* end of list */ }
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
#define PC_Q35_2_0_MACHINE_OPTIONS PC_Q35_2_1_MACHINE_OPTIONS
|
|
||||||
|
|
||||||
static QEMUMachine pc_q35_machine_v2_0 = {
|
|
||||||
PC_Q35_2_0_MACHINE_OPTIONS,
|
|
||||||
.name = "pc-q35-2.0",
|
|
||||||
.init = pc_q35_init_2_0,
|
|
||||||
.compat_props = (GlobalProperty[]) {
|
|
||||||
PC_COMPAT_2_0,
|
|
||||||
{ /* end of list */ }
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
#define PC_Q35_1_7_MACHINE_OPTIONS PC_Q35_MACHINE_OPTIONS
|
|
||||||
|
|
||||||
static QEMUMachine pc_q35_machine_v1_7 = {
|
|
||||||
PC_Q35_1_7_MACHINE_OPTIONS,
|
|
||||||
.name = "pc-q35-1.7",
|
|
||||||
.init = pc_q35_init_1_7,
|
|
||||||
.compat_props = (GlobalProperty[]) {
|
|
||||||
PC_COMPAT_1_7,
|
|
||||||
{ /* end of list */ }
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
#define PC_Q35_1_6_MACHINE_OPTIONS PC_Q35_MACHINE_OPTIONS
|
|
||||||
|
|
||||||
static QEMUMachine pc_q35_machine_v1_6 = {
|
|
||||||
PC_Q35_1_6_MACHINE_OPTIONS,
|
|
||||||
.name = "pc-q35-1.6",
|
|
||||||
.init = pc_q35_init_1_6,
|
|
||||||
.compat_props = (GlobalProperty[]) {
|
|
||||||
PC_COMPAT_1_6,
|
|
||||||
{ /* end of list */ }
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
static QEMUMachine pc_q35_machine_v1_5 = {
|
|
||||||
PC_Q35_1_6_MACHINE_OPTIONS,
|
|
||||||
.name = "pc-q35-1.5",
|
|
||||||
.init = pc_q35_init_1_5,
|
|
||||||
.compat_props = (GlobalProperty[]) {
|
|
||||||
PC_COMPAT_1_5,
|
|
||||||
{ /* end of list */ }
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
#define PC_Q35_1_4_MACHINE_OPTIONS \
|
|
||||||
PC_Q35_1_6_MACHINE_OPTIONS, \
|
|
||||||
.hot_add_cpu = NULL
|
|
||||||
|
|
||||||
static QEMUMachine pc_q35_machine_v1_4 = {
|
|
||||||
PC_Q35_1_4_MACHINE_OPTIONS,
|
|
||||||
.name = "pc-q35-1.4",
|
|
||||||
.init = pc_q35_init_1_4,
|
|
||||||
.compat_props = (GlobalProperty[]) {
|
|
||||||
PC_COMPAT_1_4,
|
|
||||||
{ /* end of list */ }
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
static void pc_q35_machine_init(void)
|
|
||||||
{
|
{
|
||||||
qemu_register_pc_machine(&pc_q35_machine_v2_4);
|
pc_q35_1_6_machine_options(m);
|
||||||
qemu_register_pc_machine(&pc_q35_machine_v2_3);
|
SET_MACHINE_COMPAT(m, PC_COMPAT_1_5);
|
||||||
qemu_register_pc_machine(&pc_q35_machine_v2_2);
|
|
||||||
qemu_register_pc_machine(&pc_q35_machine_v2_1);
|
|
||||||
qemu_register_pc_machine(&pc_q35_machine_v2_0);
|
|
||||||
qemu_register_pc_machine(&pc_q35_machine_v1_7);
|
|
||||||
qemu_register_pc_machine(&pc_q35_machine_v1_6);
|
|
||||||
qemu_register_pc_machine(&pc_q35_machine_v1_5);
|
|
||||||
qemu_register_pc_machine(&pc_q35_machine_v1_4);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
machine_init(pc_q35_machine_init);
|
DEFINE_Q35_MACHINE(v1_5, "pc-q35-1.5", pc_compat_1_5,
|
||||||
|
pc_q35_1_5_machine_options);
|
||||||
|
|
||||||
|
|
||||||
|
static void pc_q35_1_4_machine_options(MachineClass *m)
|
||||||
|
{
|
||||||
|
pc_q35_1_5_machine_options(m);
|
||||||
|
m->hot_add_cpu = NULL;
|
||||||
|
SET_MACHINE_COMPAT(m, PC_COMPAT_1_4);
|
||||||
|
}
|
||||||
|
|
||||||
|
DEFINE_Q35_MACHINE(v1_4, "pc-q35-1.4", pc_compat_1_4,
|
||||||
|
pc_q35_1_4_machine_options);
|
||||||
|
|||||||
36
hw/i386/ssdt-tpm-common.dsl
Normal file
36
hw/i386/ssdt-tpm-common.dsl
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
/*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
|
||||||
|
* You should have received a copy of the GNU General Public License along
|
||||||
|
* with this program; if not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Common parts for TPM 1.2 and TPM 2 (with slight differences for PPI)
|
||||||
|
* to be #included
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
External(\_SB.PCI0.ISA, DeviceObj)
|
||||||
|
Scope(\_SB.PCI0.ISA) {
|
||||||
|
/* TPM with emulated TPM TIS interface */
|
||||||
|
Device (TPM) {
|
||||||
|
Name (_HID, EisaID ("PNP0C31"))
|
||||||
|
Name (_CRS, ResourceTemplate ()
|
||||||
|
{
|
||||||
|
Memory32Fixed (ReadWrite, TPM_TIS_ADDR_BASE, TPM_TIS_ADDR_SIZE)
|
||||||
|
IRQNoFlags () {TPM_TIS_IRQ}
|
||||||
|
})
|
||||||
|
Method (_STA, 0, NotSerialized) {
|
||||||
|
Return (0x0F)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -25,19 +25,5 @@ DefinitionBlock (
|
|||||||
0x1 // OEM Revision
|
0x1 // OEM Revision
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
Scope(\_SB) {
|
#include "ssdt-tpm-common.dsl"
|
||||||
/* TPM with emulated TPM TIS interface */
|
|
||||||
Device (TPM) {
|
|
||||||
Name (_HID, EisaID ("PNP0C31"))
|
|
||||||
Name (_CRS, ResourceTemplate ()
|
|
||||||
{
|
|
||||||
Memory32Fixed (ReadWrite, TPM_TIS_ADDR_BASE, TPM_TIS_ADDR_SIZE)
|
|
||||||
// older Linux tpm_tis drivers do not work with IRQ
|
|
||||||
//IRQNoFlags () {TPM_TIS_IRQ}
|
|
||||||
})
|
|
||||||
Method (_STA, 0, NotSerialized) {
|
|
||||||
Return (0x0F)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,12 +3,12 @@ static unsigned char ssdt_tpm_aml[] = {
|
|||||||
0x53,
|
0x53,
|
||||||
0x44,
|
0x44,
|
||||||
0x54,
|
0x54,
|
||||||
0x5d,
|
0x6b,
|
||||||
0x0,
|
0x0,
|
||||||
0x0,
|
0x0,
|
||||||
0x0,
|
0x0,
|
||||||
0x1,
|
0x1,
|
||||||
0x1c,
|
0x37,
|
||||||
0x42,
|
0x42,
|
||||||
0x58,
|
0x58,
|
||||||
0x50,
|
0x50,
|
||||||
@@ -36,15 +36,26 @@ static unsigned char ssdt_tpm_aml[] = {
|
|||||||
0x14,
|
0x14,
|
||||||
0x20,
|
0x20,
|
||||||
0x10,
|
0x10,
|
||||||
0x38,
|
0x46,
|
||||||
|
0x4,
|
||||||
0x5c,
|
0x5c,
|
||||||
|
0x2f,
|
||||||
|
0x3,
|
||||||
0x5f,
|
0x5f,
|
||||||
0x53,
|
0x53,
|
||||||
0x42,
|
0x42,
|
||||||
0x5f,
|
0x5f,
|
||||||
|
0x50,
|
||||||
|
0x43,
|
||||||
|
0x49,
|
||||||
|
0x30,
|
||||||
|
0x49,
|
||||||
|
0x53,
|
||||||
|
0x41,
|
||||||
|
0x5f,
|
||||||
0x5b,
|
0x5b,
|
||||||
0x82,
|
0x82,
|
||||||
0x30,
|
0x33,
|
||||||
0x54,
|
0x54,
|
||||||
0x50,
|
0x50,
|
||||||
0x4d,
|
0x4d,
|
||||||
@@ -65,9 +76,9 @@ static unsigned char ssdt_tpm_aml[] = {
|
|||||||
0x52,
|
0x52,
|
||||||
0x53,
|
0x53,
|
||||||
0x11,
|
0x11,
|
||||||
0x11,
|
0x14,
|
||||||
0xa,
|
0xa,
|
||||||
0xe,
|
0x11,
|
||||||
0x86,
|
0x86,
|
||||||
0x9,
|
0x9,
|
||||||
0x0,
|
0x0,
|
||||||
@@ -80,6 +91,9 @@ static unsigned char ssdt_tpm_aml[] = {
|
|||||||
0x50,
|
0x50,
|
||||||
0x0,
|
0x0,
|
||||||
0x0,
|
0x0,
|
||||||
|
0x22,
|
||||||
|
0x20,
|
||||||
|
0x0,
|
||||||
0x79,
|
0x79,
|
||||||
0x0,
|
0x0,
|
||||||
0x14,
|
0x14,
|
||||||
|
|||||||
29
hw/i386/ssdt-tpm2.dsl
Normal file
29
hw/i386/ssdt-tpm2.dsl
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
/*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
|
||||||
|
* You should have received a copy of the GNU General Public License along
|
||||||
|
* with this program; if not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
#include "hw/acpi/tpm.h"
|
||||||
|
|
||||||
|
ACPI_EXTRACT_ALL_CODE ssdt_tpm2_aml
|
||||||
|
|
||||||
|
DefinitionBlock (
|
||||||
|
"ssdt-tpm2.aml", // Output Filename
|
||||||
|
"SSDT", // Signature
|
||||||
|
0x01, // SSDT Compliance Revision
|
||||||
|
"BXPC", // OEMID
|
||||||
|
"BXSSDT", // TABLE ID
|
||||||
|
0x1 // OEM Revision
|
||||||
|
)
|
||||||
|
{
|
||||||
|
#include "ssdt-tpm-common.dsl"
|
||||||
|
}
|
||||||
109
hw/i386/ssdt-tpm2.hex.generated
Normal file
109
hw/i386/ssdt-tpm2.hex.generated
Normal file
@@ -0,0 +1,109 @@
|
|||||||
|
static unsigned char ssdt_tpm2_aml[] = {
|
||||||
|
0x53,
|
||||||
|
0x53,
|
||||||
|
0x44,
|
||||||
|
0x54,
|
||||||
|
0x6b,
|
||||||
|
0x0,
|
||||||
|
0x0,
|
||||||
|
0x0,
|
||||||
|
0x1,
|
||||||
|
0x37,
|
||||||
|
0x42,
|
||||||
|
0x58,
|
||||||
|
0x50,
|
||||||
|
0x43,
|
||||||
|
0x0,
|
||||||
|
0x0,
|
||||||
|
0x42,
|
||||||
|
0x58,
|
||||||
|
0x53,
|
||||||
|
0x53,
|
||||||
|
0x44,
|
||||||
|
0x54,
|
||||||
|
0x0,
|
||||||
|
0x0,
|
||||||
|
0x1,
|
||||||
|
0x0,
|
||||||
|
0x0,
|
||||||
|
0x0,
|
||||||
|
0x49,
|
||||||
|
0x4e,
|
||||||
|
0x54,
|
||||||
|
0x4c,
|
||||||
|
0x7,
|
||||||
|
0x11,
|
||||||
|
0x14,
|
||||||
|
0x20,
|
||||||
|
0x10,
|
||||||
|
0x46,
|
||||||
|
0x4,
|
||||||
|
0x5c,
|
||||||
|
0x2f,
|
||||||
|
0x3,
|
||||||
|
0x5f,
|
||||||
|
0x53,
|
||||||
|
0x42,
|
||||||
|
0x5f,
|
||||||
|
0x50,
|
||||||
|
0x43,
|
||||||
|
0x49,
|
||||||
|
0x30,
|
||||||
|
0x49,
|
||||||
|
0x53,
|
||||||
|
0x41,
|
||||||
|
0x5f,
|
||||||
|
0x5b,
|
||||||
|
0x82,
|
||||||
|
0x33,
|
||||||
|
0x54,
|
||||||
|
0x50,
|
||||||
|
0x4d,
|
||||||
|
0x5f,
|
||||||
|
0x8,
|
||||||
|
0x5f,
|
||||||
|
0x48,
|
||||||
|
0x49,
|
||||||
|
0x44,
|
||||||
|
0xc,
|
||||||
|
0x41,
|
||||||
|
0xd0,
|
||||||
|
0xc,
|
||||||
|
0x31,
|
||||||
|
0x8,
|
||||||
|
0x5f,
|
||||||
|
0x43,
|
||||||
|
0x52,
|
||||||
|
0x53,
|
||||||
|
0x11,
|
||||||
|
0x14,
|
||||||
|
0xa,
|
||||||
|
0x11,
|
||||||
|
0x86,
|
||||||
|
0x9,
|
||||||
|
0x0,
|
||||||
|
0x1,
|
||||||
|
0x0,
|
||||||
|
0x0,
|
||||||
|
0xd4,
|
||||||
|
0xfe,
|
||||||
|
0x0,
|
||||||
|
0x50,
|
||||||
|
0x0,
|
||||||
|
0x0,
|
||||||
|
0x22,
|
||||||
|
0x20,
|
||||||
|
0x0,
|
||||||
|
0x79,
|
||||||
|
0x0,
|
||||||
|
0x14,
|
||||||
|
0x9,
|
||||||
|
0x5f,
|
||||||
|
0x53,
|
||||||
|
0x54,
|
||||||
|
0x41,
|
||||||
|
0x0,
|
||||||
|
0xa4,
|
||||||
|
0xa,
|
||||||
|
0xf
|
||||||
|
};
|
||||||
281
hw/ide/macio.c
281
hw/ide/macio.c
@@ -51,8 +51,15 @@ static const int debug_macio = 0;
|
|||||||
|
|
||||||
#define MACIO_PAGE_SIZE 4096
|
#define MACIO_PAGE_SIZE 4096
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Unaligned DMA read/write access functions required for OS X/Darwin which
|
||||||
|
* don't perform DMA transactions on sector boundaries. These functions are
|
||||||
|
* modelled on bdrv_co_do_preadv()/bdrv_co_do_pwritev() and so should be
|
||||||
|
* easy to remove if the unaligned block APIs are ever exposed.
|
||||||
|
*/
|
||||||
|
|
||||||
static void pmac_dma_read(BlockBackend *blk,
|
static void pmac_dma_read(BlockBackend *blk,
|
||||||
int64_t sector_num, int nb_sectors,
|
int64_t offset, unsigned int bytes,
|
||||||
void (*cb)(void *opaque, int ret), void *opaque)
|
void (*cb)(void *opaque, int ret), void *opaque)
|
||||||
{
|
{
|
||||||
DBDMA_io *io = opaque;
|
DBDMA_io *io = opaque;
|
||||||
@@ -60,76 +67,48 @@ static void pmac_dma_read(BlockBackend *blk,
|
|||||||
IDEState *s = idebus_active_if(&m->bus);
|
IDEState *s = idebus_active_if(&m->bus);
|
||||||
dma_addr_t dma_addr, dma_len;
|
dma_addr_t dma_addr, dma_len;
|
||||||
void *mem;
|
void *mem;
|
||||||
int nsector, remainder;
|
int64_t sector_num;
|
||||||
|
int nsector;
|
||||||
|
uint64_t align = BDRV_SECTOR_SIZE;
|
||||||
|
size_t head_bytes, tail_bytes;
|
||||||
|
|
||||||
qemu_iovec_destroy(&io->iov);
|
qemu_iovec_destroy(&io->iov);
|
||||||
qemu_iovec_init(&io->iov, io->len / MACIO_PAGE_SIZE + 1);
|
qemu_iovec_init(&io->iov, io->len / MACIO_PAGE_SIZE + 1);
|
||||||
|
|
||||||
if (io->remainder_len > 0) {
|
sector_num = (offset >> 9);
|
||||||
/* Return remainder of request */
|
nsector = (io->len >> 9);
|
||||||
int transfer = MIN(io->remainder_len, io->len);
|
|
||||||
|
|
||||||
MACIO_DPRINTF("--- DMA read pop - bounce addr: %p addr: %"
|
MACIO_DPRINTF("--- DMA read transfer (0x%" HWADDR_PRIx ",0x%x): "
|
||||||
HWADDR_PRIx " remainder_len: %x\n",
|
"sector_num: %" PRId64 ", nsector: %d\n", io->addr, io->len,
|
||||||
&io->remainder + (0x200 - transfer), io->addr,
|
sector_num, nsector);
|
||||||
io->remainder_len);
|
|
||||||
|
|
||||||
cpu_physical_memory_write(io->addr,
|
|
||||||
&io->remainder + (0x200 - transfer),
|
|
||||||
transfer);
|
|
||||||
|
|
||||||
io->remainder_len -= transfer;
|
|
||||||
io->len -= transfer;
|
|
||||||
io->addr += transfer;
|
|
||||||
|
|
||||||
s->io_buffer_index += transfer;
|
|
||||||
s->io_buffer_size -= transfer;
|
|
||||||
|
|
||||||
if (io->remainder_len != 0) {
|
|
||||||
/* Still waiting for remainder */
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (io->len == 0) {
|
|
||||||
MACIO_DPRINTF("--- finished all read processing; go and finish\n");
|
|
||||||
cb(opaque, 0);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (s->drive_kind == IDE_CD) {
|
|
||||||
sector_num = (int64_t)(s->lba << 2) + (s->io_buffer_index >> 9);
|
|
||||||
} else {
|
|
||||||
sector_num = ide_get_sector(s) + (s->io_buffer_index >> 9);
|
|
||||||
}
|
|
||||||
|
|
||||||
nsector = ((io->len + 0x1ff) >> 9);
|
|
||||||
remainder = (nsector << 9) - io->len;
|
|
||||||
|
|
||||||
MACIO_DPRINTF("--- DMA read transfer - addr: %" HWADDR_PRIx " len: %x\n",
|
|
||||||
io->addr, io->len);
|
|
||||||
|
|
||||||
dma_addr = io->addr;
|
dma_addr = io->addr;
|
||||||
dma_len = io->len;
|
dma_len = io->len;
|
||||||
mem = dma_memory_map(&address_space_memory, dma_addr, &dma_len,
|
mem = dma_memory_map(&address_space_memory, dma_addr, &dma_len,
|
||||||
DMA_DIRECTION_FROM_DEVICE);
|
DMA_DIRECTION_FROM_DEVICE);
|
||||||
|
|
||||||
if (!remainder) {
|
if (offset & (align - 1)) {
|
||||||
MACIO_DPRINTF("--- DMA read aligned - addr: %" HWADDR_PRIx
|
head_bytes = offset & (align - 1);
|
||||||
" len: %x\n", io->addr, io->len);
|
|
||||||
qemu_iovec_add(&io->iov, mem, io->len);
|
|
||||||
} else {
|
|
||||||
MACIO_DPRINTF("--- DMA read unaligned - addr: %" HWADDR_PRIx
|
|
||||||
" len: %x\n", io->addr, io->len);
|
|
||||||
qemu_iovec_add(&io->iov, mem, io->len);
|
|
||||||
|
|
||||||
MACIO_DPRINTF("--- DMA read push - bounce addr: %p "
|
MACIO_DPRINTF("--- DMA unaligned head: sector %" PRId64 ", "
|
||||||
"remainder_len: %x\n",
|
"discarding %zu bytes\n", sector_num, head_bytes);
|
||||||
&io->remainder + 0x200 - remainder, remainder);
|
|
||||||
qemu_iovec_add(&io->iov, &io->remainder + 0x200 - remainder,
|
|
||||||
remainder);
|
|
||||||
|
|
||||||
io->remainder_len = remainder;
|
qemu_iovec_add(&io->iov, &io->head_remainder, head_bytes);
|
||||||
|
|
||||||
|
bytes += offset & (align - 1);
|
||||||
|
offset = offset & ~(align - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
qemu_iovec_add(&io->iov, mem, io->len);
|
||||||
|
|
||||||
|
if ((offset + bytes) & (align - 1)) {
|
||||||
|
tail_bytes = (offset + bytes) & (align - 1);
|
||||||
|
|
||||||
|
MACIO_DPRINTF("--- DMA unaligned tail: sector %" PRId64 ", "
|
||||||
|
"discarding bytes %zu\n", sector_num, tail_bytes);
|
||||||
|
|
||||||
|
qemu_iovec_add(&io->iov, &io->tail_remainder, align - tail_bytes);
|
||||||
|
bytes = ROUND_UP(bytes, align);
|
||||||
}
|
}
|
||||||
|
|
||||||
s->io_buffer_size -= io->len;
|
s->io_buffer_size -= io->len;
|
||||||
@@ -137,15 +116,15 @@ static void pmac_dma_read(BlockBackend *blk,
|
|||||||
|
|
||||||
io->len = 0;
|
io->len = 0;
|
||||||
|
|
||||||
MACIO_DPRINTF("--- Block read transfer - sector_num: %"PRIx64" "
|
MACIO_DPRINTF("--- Block read transfer - sector_num: %" PRIx64 " "
|
||||||
"nsector: %x\n",
|
"nsector: %x\n", (offset >> 9), (bytes >> 9));
|
||||||
sector_num, nsector);
|
|
||||||
|
|
||||||
m->aiocb = blk_aio_readv(blk, sector_num, &io->iov, nsector, cb, io);
|
m->aiocb = blk_aio_readv(blk, (offset >> 9), &io->iov, (bytes >> 9),
|
||||||
|
cb, io);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void pmac_dma_write(BlockBackend *blk,
|
static void pmac_dma_write(BlockBackend *blk,
|
||||||
int64_t sector_num, int nb_sectors,
|
int64_t offset, int bytes,
|
||||||
void (*cb)(void *opaque, int ret), void *opaque)
|
void (*cb)(void *opaque, int ret), void *opaque)
|
||||||
{
|
{
|
||||||
DBDMA_io *io = opaque;
|
DBDMA_io *io = opaque;
|
||||||
@@ -153,53 +132,20 @@ static void pmac_dma_write(BlockBackend *blk,
|
|||||||
IDEState *s = idebus_active_if(&m->bus);
|
IDEState *s = idebus_active_if(&m->bus);
|
||||||
dma_addr_t dma_addr, dma_len;
|
dma_addr_t dma_addr, dma_len;
|
||||||
void *mem;
|
void *mem;
|
||||||
int nsector, remainder;
|
int64_t sector_num;
|
||||||
int extra = 0;
|
int nsector;
|
||||||
|
uint64_t align = BDRV_SECTOR_SIZE;
|
||||||
|
size_t head_bytes, tail_bytes;
|
||||||
|
bool unaligned_head = false, unaligned_tail = false;
|
||||||
|
|
||||||
qemu_iovec_destroy(&io->iov);
|
qemu_iovec_destroy(&io->iov);
|
||||||
qemu_iovec_init(&io->iov, io->len / MACIO_PAGE_SIZE + 1);
|
qemu_iovec_init(&io->iov, io->len / MACIO_PAGE_SIZE + 1);
|
||||||
|
|
||||||
if (io->remainder_len > 0) {
|
sector_num = (offset >> 9);
|
||||||
/* Return remainder of request */
|
|
||||||
int transfer = MIN(io->remainder_len, io->len);
|
|
||||||
|
|
||||||
MACIO_DPRINTF("--- processing write remainder %x\n", transfer);
|
|
||||||
cpu_physical_memory_read(io->addr,
|
|
||||||
&io->remainder + (0x200 - transfer),
|
|
||||||
transfer);
|
|
||||||
|
|
||||||
io->remainder_len -= transfer;
|
|
||||||
io->len -= transfer;
|
|
||||||
io->addr += transfer;
|
|
||||||
|
|
||||||
s->io_buffer_index += transfer;
|
|
||||||
s->io_buffer_size -= transfer;
|
|
||||||
|
|
||||||
if (io->remainder_len != 0) {
|
|
||||||
/* Still waiting for remainder */
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
MACIO_DPRINTF("--> prepending bounce buffer with size 0x200\n");
|
|
||||||
|
|
||||||
/* Sector transfer complete - prepend to request */
|
|
||||||
qemu_iovec_add(&io->iov, &io->remainder, 0x200);
|
|
||||||
extra = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (s->drive_kind == IDE_CD) {
|
|
||||||
sector_num = (int64_t)(s->lba << 2) + (s->io_buffer_index >> 9);
|
|
||||||
} else {
|
|
||||||
sector_num = ide_get_sector(s) + (s->io_buffer_index >> 9);
|
|
||||||
}
|
|
||||||
|
|
||||||
nsector = (io->len >> 9);
|
nsector = (io->len >> 9);
|
||||||
remainder = io->len - (nsector << 9);
|
|
||||||
|
|
||||||
MACIO_DPRINTF("--- DMA write transfer - addr: %" HWADDR_PRIx " len: %x\n",
|
MACIO_DPRINTF("--- DMA write transfer (0x%" HWADDR_PRIx ",0x%x): "
|
||||||
io->addr, io->len);
|
"sector_num: %" PRId64 ", nsector: %d\n", io->addr, io->len,
|
||||||
MACIO_DPRINTF("xxx remainder: %x\n", remainder);
|
|
||||||
MACIO_DPRINTF("xxx sector_num: %"PRIx64" nsector: %x\n",
|
|
||||||
sector_num, nsector);
|
sector_num, nsector);
|
||||||
|
|
||||||
dma_addr = io->addr;
|
dma_addr = io->addr;
|
||||||
@@ -207,36 +153,59 @@ static void pmac_dma_write(BlockBackend *blk,
|
|||||||
mem = dma_memory_map(&address_space_memory, dma_addr, &dma_len,
|
mem = dma_memory_map(&address_space_memory, dma_addr, &dma_len,
|
||||||
DMA_DIRECTION_TO_DEVICE);
|
DMA_DIRECTION_TO_DEVICE);
|
||||||
|
|
||||||
if (!remainder) {
|
if (offset & (align - 1)) {
|
||||||
MACIO_DPRINTF("--- DMA write aligned - addr: %" HWADDR_PRIx
|
head_bytes = offset & (align - 1);
|
||||||
" len: %x\n", io->addr, io->len);
|
sector_num = ((offset & ~(align - 1)) >> 9);
|
||||||
|
|
||||||
|
MACIO_DPRINTF("--- DMA unaligned head: pre-reading head sector %"
|
||||||
|
PRId64 "\n", sector_num);
|
||||||
|
|
||||||
|
blk_pread(s->blk, (sector_num << 9), &io->head_remainder, align);
|
||||||
|
|
||||||
|
qemu_iovec_add(&io->iov, &io->head_remainder, head_bytes);
|
||||||
qemu_iovec_add(&io->iov, mem, io->len);
|
qemu_iovec_add(&io->iov, mem, io->len);
|
||||||
} else {
|
|
||||||
/* Write up to last complete sector */
|
|
||||||
MACIO_DPRINTF("--- DMA write unaligned - addr: %" HWADDR_PRIx
|
|
||||||
" len: %x\n", io->addr, (nsector << 9));
|
|
||||||
qemu_iovec_add(&io->iov, mem, (nsector << 9));
|
|
||||||
|
|
||||||
MACIO_DPRINTF("--- DMA write read - bounce addr: %p "
|
bytes += offset & (align - 1);
|
||||||
"remainder_len: %x\n", &io->remainder, remainder);
|
offset = offset & ~(align - 1);
|
||||||
cpu_physical_memory_read(io->addr + (nsector << 9), &io->remainder,
|
|
||||||
remainder);
|
|
||||||
|
|
||||||
io->remainder_len = 0x200 - remainder;
|
unaligned_head = true;
|
||||||
|
|
||||||
MACIO_DPRINTF("xxx remainder_len: %x\n", io->remainder_len);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
s->io_buffer_size -= ((nsector + extra) << 9);
|
if ((offset + bytes) & (align - 1)) {
|
||||||
s->io_buffer_index += ((nsector + extra) << 9);
|
tail_bytes = (offset + bytes) & (align - 1);
|
||||||
|
sector_num = (((offset + bytes) & ~(align - 1)) >> 9);
|
||||||
|
|
||||||
|
MACIO_DPRINTF("--- DMA unaligned tail: pre-reading tail sector %"
|
||||||
|
PRId64 "\n", sector_num);
|
||||||
|
|
||||||
|
blk_pread(s->blk, (sector_num << 9), &io->tail_remainder, align);
|
||||||
|
|
||||||
|
if (!unaligned_head) {
|
||||||
|
qemu_iovec_add(&io->iov, mem, io->len);
|
||||||
|
}
|
||||||
|
|
||||||
|
qemu_iovec_add(&io->iov, &io->tail_remainder + tail_bytes,
|
||||||
|
align - tail_bytes);
|
||||||
|
|
||||||
|
bytes = ROUND_UP(bytes, align);
|
||||||
|
|
||||||
|
unaligned_tail = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!unaligned_head && !unaligned_tail) {
|
||||||
|
qemu_iovec_add(&io->iov, mem, io->len);
|
||||||
|
}
|
||||||
|
|
||||||
|
s->io_buffer_size -= io->len;
|
||||||
|
s->io_buffer_index += io->len;
|
||||||
|
|
||||||
io->len = 0;
|
io->len = 0;
|
||||||
|
|
||||||
MACIO_DPRINTF("--- Block write transfer - sector_num: %"PRIx64" "
|
MACIO_DPRINTF("--- Block write transfer - sector_num: %" PRIx64 " "
|
||||||
"nsector: %x\n", sector_num, nsector + extra);
|
"nsector: %x\n", (offset >> 9), (bytes >> 9));
|
||||||
|
|
||||||
m->aiocb = blk_aio_writev(blk, sector_num, &io->iov, nsector + extra, cb,
|
m->aiocb = blk_aio_writev(blk, (offset >> 9), &io->iov, (bytes >> 9),
|
||||||
io);
|
cb, io);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void pmac_ide_atapi_transfer_cb(void *opaque, int ret)
|
static void pmac_ide_atapi_transfer_cb(void *opaque, int ret)
|
||||||
@@ -244,19 +213,12 @@ static void pmac_ide_atapi_transfer_cb(void *opaque, int ret)
|
|||||||
DBDMA_io *io = opaque;
|
DBDMA_io *io = opaque;
|
||||||
MACIOIDEState *m = io->opaque;
|
MACIOIDEState *m = io->opaque;
|
||||||
IDEState *s = idebus_active_if(&m->bus);
|
IDEState *s = idebus_active_if(&m->bus);
|
||||||
int64_t sector_num;
|
int64_t offset;
|
||||||
int nsector, remainder;
|
|
||||||
|
|
||||||
MACIO_DPRINTF("\ns is %p\n", s);
|
MACIO_DPRINTF("pmac_ide_atapi_transfer_cb\n");
|
||||||
MACIO_DPRINTF("io_buffer_index: %x\n", s->io_buffer_index);
|
|
||||||
MACIO_DPRINTF("io_buffer_size: %x packet_transfer_size: %x\n",
|
|
||||||
s->io_buffer_size, s->packet_transfer_size);
|
|
||||||
MACIO_DPRINTF("lba: %x\n", s->lba);
|
|
||||||
MACIO_DPRINTF("io_addr: %" HWADDR_PRIx " io_len: %x\n", io->addr,
|
|
||||||
io->len);
|
|
||||||
|
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
MACIO_DPRINTF("THERE WAS AN ERROR! %d\n", ret);
|
MACIO_DPRINTF("DMA error: %d\n", ret);
|
||||||
ide_atapi_io_error(s, ret);
|
ide_atapi_io_error(s, ret);
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
@@ -270,6 +232,7 @@ static void pmac_ide_atapi_transfer_cb(void *opaque, int ret)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (s->io_buffer_size <= 0) {
|
if (s->io_buffer_size <= 0) {
|
||||||
|
MACIO_DPRINTF("End of IDE transfer\n");
|
||||||
ide_atapi_cmd_ok(s);
|
ide_atapi_cmd_ok(s);
|
||||||
m->dma_active = false;
|
m->dma_active = false;
|
||||||
goto done;
|
goto done;
|
||||||
@@ -289,19 +252,13 @@ static void pmac_ide_atapi_transfer_cb(void *opaque, int ret)
|
|||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Calculate number of sectors */
|
/* Calculate current offset */
|
||||||
sector_num = (int64_t)(s->lba << 2) + (s->io_buffer_index >> 9);
|
offset = (int64_t)(s->lba << 11) + s->io_buffer_index;
|
||||||
nsector = (io->len + 0x1ff) >> 9;
|
|
||||||
remainder = io->len & 0x1ff;
|
|
||||||
|
|
||||||
MACIO_DPRINTF("nsector: %d remainder: %x\n", nsector, remainder);
|
pmac_dma_read(s->blk, offset, io->len, pmac_ide_atapi_transfer_cb, io);
|
||||||
MACIO_DPRINTF("sector: %"PRIx64" %zx\n", sector_num, io->iov.size / 512);
|
|
||||||
|
|
||||||
pmac_dma_read(s->blk, sector_num, nsector, pmac_ide_atapi_transfer_cb, io);
|
|
||||||
return;
|
return;
|
||||||
|
|
||||||
done:
|
done:
|
||||||
MACIO_DPRINTF("done DMA\n\n");
|
|
||||||
block_acct_done(blk_get_stats(s->blk), &s->acct);
|
block_acct_done(blk_get_stats(s->blk), &s->acct);
|
||||||
io->dma_end(opaque);
|
io->dma_end(opaque);
|
||||||
|
|
||||||
@@ -313,16 +270,14 @@ static void pmac_ide_transfer_cb(void *opaque, int ret)
|
|||||||
DBDMA_io *io = opaque;
|
DBDMA_io *io = opaque;
|
||||||
MACIOIDEState *m = io->opaque;
|
MACIOIDEState *m = io->opaque;
|
||||||
IDEState *s = idebus_active_if(&m->bus);
|
IDEState *s = idebus_active_if(&m->bus);
|
||||||
int64_t sector_num;
|
int64_t offset;
|
||||||
int nsector, remainder;
|
|
||||||
|
|
||||||
MACIO_DPRINTF("pmac_ide_transfer_cb\n");
|
MACIO_DPRINTF("pmac_ide_transfer_cb\n");
|
||||||
|
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
MACIO_DPRINTF("DMA error\n");
|
MACIO_DPRINTF("DMA error: %d\n", ret);
|
||||||
m->aiocb = NULL;
|
m->aiocb = NULL;
|
||||||
ide_dma_error(s);
|
ide_dma_error(s);
|
||||||
io->remainder_len = 0;
|
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -335,7 +290,7 @@ static void pmac_ide_transfer_cb(void *opaque, int ret)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (s->io_buffer_size <= 0) {
|
if (s->io_buffer_size <= 0) {
|
||||||
MACIO_DPRINTF("end of transfer\n");
|
MACIO_DPRINTF("End of IDE transfer\n");
|
||||||
s->status = READY_STAT | SEEK_STAT;
|
s->status = READY_STAT | SEEK_STAT;
|
||||||
ide_set_irq(s->bus);
|
ide_set_irq(s->bus);
|
||||||
m->dma_active = false;
|
m->dma_active = false;
|
||||||
@@ -348,24 +303,16 @@ static void pmac_ide_transfer_cb(void *opaque, int ret)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Calculate number of sectors */
|
/* Calculate number of sectors */
|
||||||
sector_num = ide_get_sector(s) + (s->io_buffer_index >> 9);
|
offset = (ide_get_sector(s) << 9) + s->io_buffer_index;
|
||||||
nsector = (io->len + 0x1ff) >> 9;
|
|
||||||
remainder = io->len & 0x1ff;
|
|
||||||
|
|
||||||
s->nsector -= nsector;
|
|
||||||
|
|
||||||
MACIO_DPRINTF("nsector: %d remainder: %x\n", nsector, remainder);
|
|
||||||
MACIO_DPRINTF("sector: %"PRIx64" %x\n", sector_num, nsector);
|
|
||||||
|
|
||||||
switch (s->dma_cmd) {
|
switch (s->dma_cmd) {
|
||||||
case IDE_DMA_READ:
|
case IDE_DMA_READ:
|
||||||
pmac_dma_read(s->blk, sector_num, nsector, pmac_ide_transfer_cb, io);
|
pmac_dma_read(s->blk, offset, io->len, pmac_ide_transfer_cb, io);
|
||||||
break;
|
break;
|
||||||
case IDE_DMA_WRITE:
|
case IDE_DMA_WRITE:
|
||||||
pmac_dma_write(s->blk, sector_num, nsector, pmac_ide_transfer_cb, io);
|
pmac_dma_write(s->blk, offset, io->len, pmac_ide_transfer_cb, io);
|
||||||
break;
|
break;
|
||||||
case IDE_DMA_TRIM:
|
case IDE_DMA_TRIM:
|
||||||
MACIO_DPRINTF("TRIM command issued!");
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -561,15 +508,12 @@ static void ide_dbdma_start(IDEDMA *dma, IDEState *s,
|
|||||||
BlockCompletionFunc *cb)
|
BlockCompletionFunc *cb)
|
||||||
{
|
{
|
||||||
MACIOIDEState *m = container_of(dma, MACIOIDEState, dma);
|
MACIOIDEState *m = container_of(dma, MACIOIDEState, dma);
|
||||||
DBDMAState *dbdma = m->dbdma;
|
|
||||||
DBDMA_io *io;
|
|
||||||
int i;
|
|
||||||
|
|
||||||
s->io_buffer_index = 0;
|
s->io_buffer_index = 0;
|
||||||
if (s->drive_kind == IDE_CD) {
|
if (s->drive_kind == IDE_CD) {
|
||||||
s->io_buffer_size = s->packet_transfer_size;
|
s->io_buffer_size = s->packet_transfer_size;
|
||||||
} else {
|
} else {
|
||||||
s->io_buffer_size = s->nsector * 0x200;
|
s->io_buffer_size = s->nsector * BDRV_SECTOR_SIZE;
|
||||||
}
|
}
|
||||||
|
|
||||||
MACIO_DPRINTF("\n\n------------ IDE transfer\n");
|
MACIO_DPRINTF("\n\n------------ IDE transfer\n");
|
||||||
@@ -578,15 +522,6 @@ static void ide_dbdma_start(IDEDMA *dma, IDEState *s,
|
|||||||
MACIO_DPRINTF("lba: %x size: %x\n", s->lba, s->io_buffer_size);
|
MACIO_DPRINTF("lba: %x size: %x\n", s->lba, s->io_buffer_size);
|
||||||
MACIO_DPRINTF("-------------------------\n");
|
MACIO_DPRINTF("-------------------------\n");
|
||||||
|
|
||||||
for (i = 0; i < DBDMA_CHANNELS; i++) {
|
|
||||||
io = &dbdma->channels[i].io;
|
|
||||||
|
|
||||||
if (io->opaque == m) {
|
|
||||||
io->remainder_len = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
MACIO_DPRINTF("\n");
|
|
||||||
m->dma_active = true;
|
m->dma_active = true;
|
||||||
DBDMA_kick(m->dbdma);
|
DBDMA_kick(m->dbdma);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -452,8 +452,6 @@ static const struct IDEDMAOps bmdma_ops = {
|
|||||||
|
|
||||||
void bmdma_init(IDEBus *bus, BMDMAState *bm, PCIIDEState *d)
|
void bmdma_init(IDEBus *bus, BMDMAState *bm, PCIIDEState *d)
|
||||||
{
|
{
|
||||||
qemu_irq *irq;
|
|
||||||
|
|
||||||
if (bus->dma == &bm->dma) {
|
if (bus->dma == &bm->dma) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -461,8 +459,7 @@ void bmdma_init(IDEBus *bus, BMDMAState *bm, PCIIDEState *d)
|
|||||||
bm->dma.ops = &bmdma_ops;
|
bm->dma.ops = &bmdma_ops;
|
||||||
bus->dma = &bm->dma;
|
bus->dma = &bm->dma;
|
||||||
bm->irq = bus->irq;
|
bm->irq = bus->irq;
|
||||||
irq = qemu_allocate_irqs(bmdma_irq, bm, 1);
|
bus->irq = qemu_allocate_irq(bmdma_irq, bm, 0);
|
||||||
bus->irq = *irq;
|
|
||||||
bm->pci_dev = d;
|
bm->pci_dev = d;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -166,7 +166,7 @@ static void virtio_input_set_config(VirtIODevice *vdev,
|
|||||||
virtio_notify_config(vdev);
|
virtio_notify_config(vdev);
|
||||||
}
|
}
|
||||||
|
|
||||||
static uint32_t virtio_input_get_features(VirtIODevice *vdev, uint32_t f)
|
static uint64_t virtio_input_get_features(VirtIODevice *vdev, uint64_t f)
|
||||||
{
|
{
|
||||||
return f;
|
return f;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ common-obj-$(CONFIG_SLAVIO) += slavio_intctl.o
|
|||||||
common-obj-$(CONFIG_IOAPIC) += ioapic_common.o
|
common-obj-$(CONFIG_IOAPIC) += ioapic_common.o
|
||||||
common-obj-$(CONFIG_ARM_GIC) += arm_gic_common.o
|
common-obj-$(CONFIG_ARM_GIC) += arm_gic_common.o
|
||||||
common-obj-$(CONFIG_ARM_GIC) += arm_gic.o
|
common-obj-$(CONFIG_ARM_GIC) += arm_gic.o
|
||||||
|
common-obj-$(CONFIG_ARM_GIC) += arm_gicv2m.o
|
||||||
common-obj-$(CONFIG_OPENPIC) += openpic.o
|
common-obj-$(CONFIG_OPENPIC) += openpic.o
|
||||||
|
|
||||||
obj-$(CONFIG_APIC) += apic.o apic_common.o
|
obj-$(CONFIG_APIC) += apic.o apic_common.o
|
||||||
|
|||||||
@@ -370,13 +370,14 @@ static int apic_irq_pending(APICCommonState *s)
|
|||||||
static void apic_update_irq(APICCommonState *s)
|
static void apic_update_irq(APICCommonState *s)
|
||||||
{
|
{
|
||||||
CPUState *cpu;
|
CPUState *cpu;
|
||||||
|
DeviceState *dev = (DeviceState *)s;
|
||||||
|
|
||||||
cpu = CPU(s->cpu);
|
cpu = CPU(s->cpu);
|
||||||
if (!qemu_cpu_is_self(cpu)) {
|
if (!qemu_cpu_is_self(cpu)) {
|
||||||
cpu_interrupt(cpu, CPU_INTERRUPT_POLL);
|
cpu_interrupt(cpu, CPU_INTERRUPT_POLL);
|
||||||
} else if (apic_irq_pending(s) > 0) {
|
} else if (apic_irq_pending(s) > 0) {
|
||||||
cpu_interrupt(cpu, CPU_INTERRUPT_HARD);
|
cpu_interrupt(cpu, CPU_INTERRUPT_HARD);
|
||||||
} else if (!apic_accept_pic_intr(&s->busdev.qdev) || !pic_get_output(isa_pic)) {
|
} else if (!apic_accept_pic_intr(dev) || !pic_get_output(isa_pic)) {
|
||||||
cpu_reset_interrupt(cpu, CPU_INTERRUPT_HARD);
|
cpu_reset_interrupt(cpu, CPU_INTERRUPT_HARD);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -549,10 +550,12 @@ static void apic_deliver(DeviceState *dev, uint8_t dest, uint8_t dest_mode,
|
|||||||
|
|
||||||
static bool apic_check_pic(APICCommonState *s)
|
static bool apic_check_pic(APICCommonState *s)
|
||||||
{
|
{
|
||||||
if (!apic_accept_pic_intr(&s->busdev.qdev) || !pic_get_output(isa_pic)) {
|
DeviceState *dev = (DeviceState *)s;
|
||||||
|
|
||||||
|
if (!apic_accept_pic_intr(dev) || !pic_get_output(isa_pic)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
apic_deliver_pic_intr(&s->busdev.qdev, 1);
|
apic_deliver_pic_intr(dev, 1);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
192
hw/intc/arm_gicv2m.c
Normal file
192
hw/intc/arm_gicv2m.c
Normal file
@@ -0,0 +1,192 @@
|
|||||||
|
/*
|
||||||
|
* GICv2m extension for MSI/MSI-x support with a GICv2-based system
|
||||||
|
*
|
||||||
|
* Copyright (C) 2015 Linaro, All rights reserved.
|
||||||
|
*
|
||||||
|
* Author: Christoffer Dall <christoffer.dall@linaro.org>
|
||||||
|
*
|
||||||
|
* This library is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 2 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This library is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
|
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* This file implements an emulated GICv2m widget as described in the ARM
|
||||||
|
* Server Base System Architecture (SBSA) specification Version 2.2
|
||||||
|
* (ARM-DEN-0029 v2.2) pages 35-39 without any optional implementation defined
|
||||||
|
* identification registers and with a single non-secure MSI register frame.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "hw/sysbus.h"
|
||||||
|
#include "hw/pci/msi.h"
|
||||||
|
|
||||||
|
#define TYPE_ARM_GICV2M "arm-gicv2m"
|
||||||
|
#define ARM_GICV2M(obj) OBJECT_CHECK(ARMGICv2mState, (obj), TYPE_ARM_GICV2M)
|
||||||
|
|
||||||
|
#define GICV2M_NUM_SPI_MAX 128
|
||||||
|
|
||||||
|
#define V2M_MSI_TYPER 0x008
|
||||||
|
#define V2M_MSI_SETSPI_NS 0x040
|
||||||
|
#define V2M_MSI_IIDR 0xFCC
|
||||||
|
#define V2M_IIDR0 0xFD0
|
||||||
|
#define V2M_IIDR11 0xFFC
|
||||||
|
|
||||||
|
#define PRODUCT_ID_QEMU 0x51 /* ASCII code Q */
|
||||||
|
|
||||||
|
typedef struct ARMGICv2mState {
|
||||||
|
SysBusDevice parent_obj;
|
||||||
|
|
||||||
|
MemoryRegion iomem;
|
||||||
|
qemu_irq spi[GICV2M_NUM_SPI_MAX];
|
||||||
|
|
||||||
|
uint32_t base_spi;
|
||||||
|
uint32_t num_spi;
|
||||||
|
} ARMGICv2mState;
|
||||||
|
|
||||||
|
static void gicv2m_set_irq(void *opaque, int irq)
|
||||||
|
{
|
||||||
|
ARMGICv2mState *s = (ARMGICv2mState *)opaque;
|
||||||
|
|
||||||
|
qemu_irq_pulse(s->spi[irq]);
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint64_t gicv2m_read(void *opaque, hwaddr offset,
|
||||||
|
unsigned size)
|
||||||
|
{
|
||||||
|
ARMGICv2mState *s = (ARMGICv2mState *)opaque;
|
||||||
|
uint32_t val;
|
||||||
|
|
||||||
|
if (size != 4) {
|
||||||
|
qemu_log_mask(LOG_GUEST_ERROR, "gicv2m_read: bad size %u\n", size);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (offset) {
|
||||||
|
case V2M_MSI_TYPER:
|
||||||
|
val = (s->base_spi + 32) << 16;
|
||||||
|
val |= s->num_spi;
|
||||||
|
return val;
|
||||||
|
case V2M_MSI_IIDR:
|
||||||
|
/* We don't have any valid implementor so we leave that field as zero
|
||||||
|
* and we return 0 in the arch revision as per the spec.
|
||||||
|
*/
|
||||||
|
return (PRODUCT_ID_QEMU << 20);
|
||||||
|
case V2M_IIDR0 ... V2M_IIDR11:
|
||||||
|
/* We do not implement any optional identification registers and the
|
||||||
|
* mandatory MSI_PIDR2 register reads as 0x0, so we capture all
|
||||||
|
* implementation defined registers here.
|
||||||
|
*/
|
||||||
|
return 0;
|
||||||
|
default:
|
||||||
|
qemu_log_mask(LOG_GUEST_ERROR,
|
||||||
|
"gicv2m_read: Bad offset %x\n", (int)offset);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void gicv2m_write(void *opaque, hwaddr offset,
|
||||||
|
uint64_t value, unsigned size)
|
||||||
|
{
|
||||||
|
ARMGICv2mState *s = (ARMGICv2mState *)opaque;
|
||||||
|
|
||||||
|
if (size != 2 && size != 4) {
|
||||||
|
qemu_log_mask(LOG_GUEST_ERROR, "gicv2m_write: bad size %u\n", size);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (offset) {
|
||||||
|
case V2M_MSI_SETSPI_NS: {
|
||||||
|
int spi;
|
||||||
|
|
||||||
|
spi = (value & 0x3ff) - (s->base_spi + 32);
|
||||||
|
if (spi >= 0 && spi < s->num_spi) {
|
||||||
|
gicv2m_set_irq(s, spi);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
qemu_log_mask(LOG_GUEST_ERROR,
|
||||||
|
"gicv2m_write: Bad offset %x\n", (int)offset);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static const MemoryRegionOps gicv2m_ops = {
|
||||||
|
.read = gicv2m_read,
|
||||||
|
.write = gicv2m_write,
|
||||||
|
.endianness = DEVICE_LITTLE_ENDIAN,
|
||||||
|
};
|
||||||
|
|
||||||
|
static void gicv2m_realize(DeviceState *dev, Error **errp)
|
||||||
|
{
|
||||||
|
ARMGICv2mState *s = ARM_GICV2M(dev);
|
||||||
|
int i;
|
||||||
|
|
||||||
|
if (s->num_spi > GICV2M_NUM_SPI_MAX) {
|
||||||
|
error_setg(errp,
|
||||||
|
"requested %u SPIs exceeds GICv2m frame maximum %d",
|
||||||
|
s->num_spi, GICV2M_NUM_SPI_MAX);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (s->base_spi + 32 > 1020 - s->num_spi) {
|
||||||
|
error_setg(errp,
|
||||||
|
"requested base SPI %u+%u exceeds max. number 1020",
|
||||||
|
s->base_spi + 32, s->num_spi);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < s->num_spi; i++) {
|
||||||
|
sysbus_init_irq(SYS_BUS_DEVICE(dev), &s->spi[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
msi_supported = true;
|
||||||
|
kvm_gsi_direct_mapping = true;
|
||||||
|
kvm_msi_via_irqfd_allowed = kvm_irqfds_enabled();
|
||||||
|
}
|
||||||
|
|
||||||
|
static void gicv2m_init(Object *obj)
|
||||||
|
{
|
||||||
|
SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
|
||||||
|
ARMGICv2mState *s = ARM_GICV2M(obj);
|
||||||
|
|
||||||
|
memory_region_init_io(&s->iomem, OBJECT(s), &gicv2m_ops, s,
|
||||||
|
"gicv2m", 0x1000);
|
||||||
|
sysbus_init_mmio(sbd, &s->iomem);
|
||||||
|
}
|
||||||
|
|
||||||
|
static Property gicv2m_properties[] = {
|
||||||
|
DEFINE_PROP_UINT32("base-spi", ARMGICv2mState, base_spi, 0),
|
||||||
|
DEFINE_PROP_UINT32("num-spi", ARMGICv2mState, num_spi, 64),
|
||||||
|
DEFINE_PROP_END_OF_LIST(),
|
||||||
|
};
|
||||||
|
|
||||||
|
static void gicv2m_class_init(ObjectClass *klass, void *data)
|
||||||
|
{
|
||||||
|
DeviceClass *dc = DEVICE_CLASS(klass);
|
||||||
|
|
||||||
|
dc->props = gicv2m_properties;
|
||||||
|
dc->realize = gicv2m_realize;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const TypeInfo gicv2m_info = {
|
||||||
|
.name = TYPE_ARM_GICV2M,
|
||||||
|
.parent = TYPE_SYS_BUS_DEVICE,
|
||||||
|
.instance_size = sizeof(ARMGICv2mState),
|
||||||
|
.instance_init = gicv2m_init,
|
||||||
|
.class_init = gicv2m_class_init,
|
||||||
|
};
|
||||||
|
|
||||||
|
static void gicv2m_register_types(void)
|
||||||
|
{
|
||||||
|
type_register_static(&gicv2m_info);
|
||||||
|
}
|
||||||
|
|
||||||
|
type_init(gicv2m_register_types)
|
||||||
@@ -213,9 +213,6 @@ void exynos4210_init_board_irqs(Exynos4210Irq *s)
|
|||||||
uint32_t grp, bit, irq_id, n;
|
uint32_t grp, bit, irq_id, n;
|
||||||
|
|
||||||
for (n = 0; n < EXYNOS4210_MAX_EXT_COMBINER_IN_IRQ; n++) {
|
for (n = 0; n < EXYNOS4210_MAX_EXT_COMBINER_IN_IRQ; n++) {
|
||||||
s->board_irqs[n] = qemu_irq_split(s->int_combiner_irq[n],
|
|
||||||
s->ext_combiner_irq[n]);
|
|
||||||
|
|
||||||
irq_id = 0;
|
irq_id = 0;
|
||||||
if (n == EXYNOS4210_COMBINER_GET_IRQ_NUM(1, 4) ||
|
if (n == EXYNOS4210_COMBINER_GET_IRQ_NUM(1, 4) ||
|
||||||
n == EXYNOS4210_COMBINER_GET_IRQ_NUM(12, 4)) {
|
n == EXYNOS4210_COMBINER_GET_IRQ_NUM(12, 4)) {
|
||||||
@@ -230,8 +227,10 @@ void exynos4210_init_board_irqs(Exynos4210Irq *s)
|
|||||||
if (irq_id) {
|
if (irq_id) {
|
||||||
s->board_irqs[n] = qemu_irq_split(s->int_combiner_irq[n],
|
s->board_irqs[n] = qemu_irq_split(s->int_combiner_irq[n],
|
||||||
s->ext_gic_irq[irq_id-32]);
|
s->ext_gic_irq[irq_id-32]);
|
||||||
|
} else {
|
||||||
|
s->board_irqs[n] = qemu_irq_split(s->int_combiner_irq[n],
|
||||||
|
s->ext_combiner_irq[n]);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
for (; n < EXYNOS4210_MAX_INT_COMBINER_IN_IRQ; n++) {
|
for (; n < EXYNOS4210_MAX_INT_COMBINER_IN_IRQ; n++) {
|
||||||
/* these IDs are passed to Internal Combiner and External GIC */
|
/* these IDs are passed to Internal Combiner and External GIC */
|
||||||
|
|||||||
@@ -65,7 +65,6 @@ static void i82378_realize(PCIDevice *pci, Error **errp)
|
|||||||
uint8_t *pci_conf;
|
uint8_t *pci_conf;
|
||||||
ISABus *isabus;
|
ISABus *isabus;
|
||||||
ISADevice *isa;
|
ISADevice *isa;
|
||||||
qemu_irq *out0_irq;
|
|
||||||
|
|
||||||
pci_conf = pci->config;
|
pci_conf = pci->config;
|
||||||
pci_set_word(pci_conf + PCI_COMMAND,
|
pci_set_word(pci_conf + PCI_COMMAND,
|
||||||
@@ -88,11 +87,9 @@ static void i82378_realize(PCIDevice *pci, Error **errp)
|
|||||||
All devices accept byte access only, except timer
|
All devices accept byte access only, except timer
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* Workaround the fact that i8259 is not qdev'ified... */
|
|
||||||
out0_irq = qemu_allocate_irqs(i82378_request_out0_irq, s, 1);
|
|
||||||
|
|
||||||
/* 2 82C59 (irq) */
|
/* 2 82C59 (irq) */
|
||||||
s->i8259 = i8259_init(isabus, *out0_irq);
|
s->i8259 = i8259_init(isabus,
|
||||||
|
qemu_allocate_irq(i82378_request_out0_irq, s, 0));
|
||||||
isa_bus_irqs(isabus, s->i8259);
|
isa_bus_irqs(isabus, s->i8259);
|
||||||
|
|
||||||
/* 1 82C54 (pit) */
|
/* 1 82C54 (pit) */
|
||||||
|
|||||||
@@ -21,6 +21,7 @@
|
|||||||
#include "hw/sysbus.h"
|
#include "hw/sysbus.h"
|
||||||
#include "sysemu/sysemu.h"
|
#include "sysemu/sysemu.h"
|
||||||
#include "hw/isa/isa.h"
|
#include "hw/isa/isa.h"
|
||||||
|
#include "hw/i386/pc.h"
|
||||||
|
|
||||||
static ISABus *isabus;
|
static ISABus *isabus;
|
||||||
|
|
||||||
@@ -267,3 +268,28 @@ MemoryRegion *isa_address_space_io(ISADevice *dev)
|
|||||||
}
|
}
|
||||||
|
|
||||||
type_init(isabus_register_types)
|
type_init(isabus_register_types)
|
||||||
|
|
||||||
|
static void parallel_init(ISABus *bus, int index, CharDriverState *chr)
|
||||||
|
{
|
||||||
|
DeviceState *dev;
|
||||||
|
ISADevice *isadev;
|
||||||
|
|
||||||
|
isadev = isa_create(bus, "isa-parallel");
|
||||||
|
dev = DEVICE(isadev);
|
||||||
|
qdev_prop_set_uint32(dev, "index", index);
|
||||||
|
qdev_prop_set_chr(dev, "chardev", chr);
|
||||||
|
qdev_init_nofail(dev);
|
||||||
|
}
|
||||||
|
|
||||||
|
void parallel_hds_isa_init(ISABus *bus, int n)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
assert(n <= MAX_PARALLEL_PORTS);
|
||||||
|
|
||||||
|
for (i = 0; i < n; i++) {
|
||||||
|
if (parallel_hds[i]) {
|
||||||
|
parallel_init(bus, i, parallel_hds[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -360,11 +360,8 @@ static void ich9_set_sci(void *opaque, int irq_num, int level)
|
|||||||
void ich9_lpc_pm_init(PCIDevice *lpc_pci)
|
void ich9_lpc_pm_init(PCIDevice *lpc_pci)
|
||||||
{
|
{
|
||||||
ICH9LPCState *lpc = ICH9_LPC_DEVICE(lpc_pci);
|
ICH9LPCState *lpc = ICH9_LPC_DEVICE(lpc_pci);
|
||||||
qemu_irq *sci_irq;
|
|
||||||
|
|
||||||
sci_irq = qemu_allocate_irqs(ich9_set_sci, lpc, 1);
|
|
||||||
ich9_pm_init(lpc_pci, &lpc->pm, sci_irq[0]);
|
|
||||||
|
|
||||||
|
ich9_pm_init(lpc_pci, &lpc->pm, qemu_allocate_irq(ich9_set_sci, lpc, 0));
|
||||||
ich9_lpc_reset(&lpc->d.qdev);
|
ich9_lpc_reset(&lpc->d.qdev);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -410,12 +407,28 @@ static void ich9_lpc_rcba_update(ICH9LPCState *lpc, uint32_t rbca_old)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* config:GEN_PMCON* */
|
||||||
|
static void
|
||||||
|
ich9_lpc_pmcon_update(ICH9LPCState *lpc)
|
||||||
|
{
|
||||||
|
uint16_t gen_pmcon_1 = pci_get_word(lpc->d.config + ICH9_LPC_GEN_PMCON_1);
|
||||||
|
uint16_t wmask;
|
||||||
|
|
||||||
|
if (gen_pmcon_1 & ICH9_LPC_GEN_PMCON_1_SMI_LOCK) {
|
||||||
|
wmask = pci_get_word(lpc->d.wmask + ICH9_LPC_GEN_PMCON_1);
|
||||||
|
wmask &= ~ICH9_LPC_GEN_PMCON_1_SMI_LOCK;
|
||||||
|
pci_set_word(lpc->d.wmask + ICH9_LPC_GEN_PMCON_1, wmask);
|
||||||
|
lpc->pm.smi_en_wmask &= ~1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static int ich9_lpc_post_load(void *opaque, int version_id)
|
static int ich9_lpc_post_load(void *opaque, int version_id)
|
||||||
{
|
{
|
||||||
ICH9LPCState *lpc = opaque;
|
ICH9LPCState *lpc = opaque;
|
||||||
|
|
||||||
ich9_lpc_pmbase_update(lpc);
|
ich9_lpc_pmbase_update(lpc);
|
||||||
ich9_lpc_rcba_update(lpc, 0 /* disabled ICH9_LPC_RBCA_EN */);
|
ich9_lpc_rcba_update(lpc, 0 /* disabled ICH9_LPC_RBCA_EN */);
|
||||||
|
ich9_lpc_pmcon_update(lpc);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -438,6 +451,9 @@ static void ich9_lpc_config_write(PCIDevice *d,
|
|||||||
if (ranges_overlap(addr, len, ICH9_LPC_PIRQE_ROUT, 4)) {
|
if (ranges_overlap(addr, len, ICH9_LPC_PIRQE_ROUT, 4)) {
|
||||||
pci_bus_fire_intx_routing_notifier(lpc->d.bus);
|
pci_bus_fire_intx_routing_notifier(lpc->d.bus);
|
||||||
}
|
}
|
||||||
|
if (ranges_overlap(addr, len, ICH9_LPC_GEN_PMCON_1, 8)) {
|
||||||
|
ich9_lpc_pmcon_update(lpc);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void ich9_lpc_reset(DeviceState *qdev)
|
static void ich9_lpc_reset(DeviceState *qdev)
|
||||||
@@ -494,7 +510,7 @@ static void ich9_lpc_machine_ready(Notifier *n, void *opaque)
|
|||||||
/* lpt */
|
/* lpt */
|
||||||
pci_conf[0x82] |= 0x04;
|
pci_conf[0x82] |= 0x04;
|
||||||
}
|
}
|
||||||
if (memory_region_present(io_as, 0x3f0)) {
|
if (memory_region_present(io_as, 0x3f2)) {
|
||||||
/* floppy */
|
/* floppy */
|
||||||
pci_conf[0x82] |= 0x08;
|
pci_conf[0x82] |= 0x08;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -356,7 +356,7 @@ static void vt82c686b_pm_realize(PCIDevice *dev, Error **errp)
|
|||||||
|
|
||||||
acpi_pm_tmr_init(&s->ar, pm_tmr_timer, &s->io);
|
acpi_pm_tmr_init(&s->ar, pm_tmr_timer, &s->io);
|
||||||
acpi_pm1_evt_init(&s->ar, pm_tmr_timer, &s->io);
|
acpi_pm1_evt_init(&s->ar, pm_tmr_timer, &s->io);
|
||||||
acpi_pm1_cnt_init(&s->ar, &s->io, 2);
|
acpi_pm1_cnt_init(&s->ar, &s->io, false, false, 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
I2CBus *vt82c686b_pm_init(PCIBus *bus, int devfn, uint32_t smb_io_base,
|
I2CBus *vt82c686b_pm_init(PCIBus *bus, int devfn, uint32_t smb_io_base,
|
||||||
|
|||||||
@@ -78,7 +78,7 @@ static void lm32_evr_init(MachineState *machine)
|
|||||||
DriveInfo *dinfo;
|
DriveInfo *dinfo;
|
||||||
MemoryRegion *address_space_mem = get_system_memory();
|
MemoryRegion *address_space_mem = get_system_memory();
|
||||||
MemoryRegion *phys_ram = g_new(MemoryRegion, 1);
|
MemoryRegion *phys_ram = g_new(MemoryRegion, 1);
|
||||||
qemu_irq *cpu_irq, irq[32];
|
qemu_irq irq[32];
|
||||||
ResetInfo *reset_info;
|
ResetInfo *reset_info;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
@@ -123,8 +123,7 @@ static void lm32_evr_init(MachineState *machine)
|
|||||||
1, 2, 0x01, 0x7e, 0x43, 0x00, 0x555, 0x2aa, 1);
|
1, 2, 0x01, 0x7e, 0x43, 0x00, 0x555, 0x2aa, 1);
|
||||||
|
|
||||||
/* create irq lines */
|
/* create irq lines */
|
||||||
cpu_irq = qemu_allocate_irqs(cpu_irq_handler, cpu, 1);
|
env->pic_state = lm32_pic_init(qemu_allocate_irq(cpu_irq_handler, cpu, 0));
|
||||||
env->pic_state = lm32_pic_init(*cpu_irq);
|
|
||||||
for (i = 0; i < 32; i++) {
|
for (i = 0; i < 32; i++) {
|
||||||
irq[i] = qdev_get_gpio_in(env->pic_state, i);
|
irq[i] = qdev_get_gpio_in(env->pic_state, i);
|
||||||
}
|
}
|
||||||
@@ -173,7 +172,7 @@ static void lm32_uclinux_init(MachineState *machine)
|
|||||||
DriveInfo *dinfo;
|
DriveInfo *dinfo;
|
||||||
MemoryRegion *address_space_mem = get_system_memory();
|
MemoryRegion *address_space_mem = get_system_memory();
|
||||||
MemoryRegion *phys_ram = g_new(MemoryRegion, 1);
|
MemoryRegion *phys_ram = g_new(MemoryRegion, 1);
|
||||||
qemu_irq *cpu_irq, irq[32];
|
qemu_irq irq[32];
|
||||||
HWSetup *hw;
|
HWSetup *hw;
|
||||||
ResetInfo *reset_info;
|
ResetInfo *reset_info;
|
||||||
int i;
|
int i;
|
||||||
@@ -225,8 +224,7 @@ static void lm32_uclinux_init(MachineState *machine)
|
|||||||
1, 2, 0x01, 0x7e, 0x43, 0x00, 0x555, 0x2aa, 1);
|
1, 2, 0x01, 0x7e, 0x43, 0x00, 0x555, 0x2aa, 1);
|
||||||
|
|
||||||
/* create irq lines */
|
/* create irq lines */
|
||||||
cpu_irq = qemu_allocate_irqs(cpu_irq_handler, env, 1);
|
env->pic_state = lm32_pic_init(qemu_allocate_irq(cpu_irq_handler, env, 0));
|
||||||
env->pic_state = lm32_pic_init(*cpu_irq);
|
|
||||||
for (i = 0; i < 32; i++) {
|
for (i = 0; i < 32; i++) {
|
||||||
irq[i] = qdev_get_gpio_in(env->pic_state, i);
|
irq[i] = qdev_get_gpio_in(env->pic_state, i);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -86,7 +86,7 @@ milkymist_init(MachineState *machine)
|
|||||||
DriveInfo *dinfo;
|
DriveInfo *dinfo;
|
||||||
MemoryRegion *address_space_mem = get_system_memory();
|
MemoryRegion *address_space_mem = get_system_memory();
|
||||||
MemoryRegion *phys_sdram = g_new(MemoryRegion, 1);
|
MemoryRegion *phys_sdram = g_new(MemoryRegion, 1);
|
||||||
qemu_irq irq[32], *cpu_irq;
|
qemu_irq irq[32];
|
||||||
int i;
|
int i;
|
||||||
char *bios_filename;
|
char *bios_filename;
|
||||||
ResetInfo *reset_info;
|
ResetInfo *reset_info;
|
||||||
@@ -130,8 +130,7 @@ milkymist_init(MachineState *machine)
|
|||||||
2, 0x00, 0x89, 0x00, 0x1d, 1);
|
2, 0x00, 0x89, 0x00, 0x1d, 1);
|
||||||
|
|
||||||
/* create irq lines */
|
/* create irq lines */
|
||||||
cpu_irq = qemu_allocate_irqs(cpu_irq_handler, cpu, 1);
|
env->pic_state = lm32_pic_init(qemu_allocate_irq(cpu_irq_handler, cpu, 0));
|
||||||
env->pic_state = lm32_pic_init(*cpu_irq);
|
|
||||||
for (i = 0; i < 32; i++) {
|
for (i = 0; i < 32; i++) {
|
||||||
irq[i] = qdev_get_gpio_in(env->pic_state, i);
|
irq[i] = qdev_get_gpio_in(env->pic_state, i);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -211,7 +211,6 @@ uint64_t pc_dimm_get_free_addr(uint64_t address_space_start,
|
|||||||
uint64_t address_space_end = address_space_start + address_space_size;
|
uint64_t address_space_end = address_space_start + address_space_size;
|
||||||
|
|
||||||
g_assert(QEMU_ALIGN_UP(address_space_start, align) == address_space_start);
|
g_assert(QEMU_ALIGN_UP(address_space_start, align) == address_space_start);
|
||||||
g_assert(QEMU_ALIGN_UP(address_space_size, align) == address_space_size);
|
|
||||||
|
|
||||||
if (!address_space_size) {
|
if (!address_space_size) {
|
||||||
error_setg(errp, "memory hotplug is not enabled, "
|
error_setg(errp, "memory hotplug is not enabled, "
|
||||||
|
|||||||
@@ -1161,7 +1161,7 @@ void mips_malta_init(MachineState *machine)
|
|||||||
pci_piix4_ide_init(pci_bus, hd, piix4_devfn + 1);
|
pci_piix4_ide_init(pci_bus, hd, piix4_devfn + 1);
|
||||||
pci_create_simple(pci_bus, piix4_devfn + 2, "piix4-usb-uhci");
|
pci_create_simple(pci_bus, piix4_devfn + 2, "piix4-usb-uhci");
|
||||||
smbus = piix4_pm_init(pci_bus, piix4_devfn + 3, 0x1100,
|
smbus = piix4_pm_init(pci_bus, piix4_devfn + 3, 0x1100,
|
||||||
isa_get_irq(NULL, 9), NULL, 0, NULL, NULL);
|
isa_get_irq(NULL, 9), NULL, 0, NULL);
|
||||||
smbus_eeprom_init(smbus, 8, smbus_eeprom_buf, smbus_eeprom_size);
|
smbus_eeprom_init(smbus, 8, smbus_eeprom_buf, smbus_eeprom_size);
|
||||||
g_free(smbus_eeprom_buf);
|
g_free(smbus_eeprom_buf);
|
||||||
pit = pit_init(isa_bus, 0x40, 0, NULL);
|
pit = pit_init(isa_bus, 0x40, 0, NULL);
|
||||||
|
|||||||
@@ -126,17 +126,18 @@ static void macio_bar_setup(MacIOState *macio_state)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static int macio_common_initfn(PCIDevice *d)
|
static void macio_common_realize(PCIDevice *d, Error **errp)
|
||||||
{
|
{
|
||||||
MacIOState *s = MACIO(d);
|
MacIOState *s = MACIO(d);
|
||||||
SysBusDevice *sysbus_dev;
|
SysBusDevice *sysbus_dev;
|
||||||
int ret;
|
Error *err = NULL;
|
||||||
|
|
||||||
d->config[0x3d] = 0x01; // interrupt on pin 1
|
d->config[0x3d] = 0x01; // interrupt on pin 1
|
||||||
|
|
||||||
ret = qdev_init(DEVICE(&s->cuda));
|
object_property_set_bool(OBJECT(&s->cuda), true, "realized", &err);
|
||||||
if (ret < 0) {
|
if (err) {
|
||||||
return ret;
|
error_propagate(errp, err);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
sysbus_dev = SYS_BUS_DEVICE(&s->cuda);
|
sysbus_dev = SYS_BUS_DEVICE(&s->cuda);
|
||||||
memory_region_add_subregion(&s->bar, 0x16000,
|
memory_region_add_subregion(&s->bar, 0x16000,
|
||||||
@@ -144,12 +145,11 @@ static int macio_common_initfn(PCIDevice *d)
|
|||||||
|
|
||||||
macio_bar_setup(s);
|
macio_bar_setup(s);
|
||||||
pci_register_bar(d, 0, PCI_BASE_ADDRESS_SPACE_MEMORY, &s->bar);
|
pci_register_bar(d, 0, PCI_BASE_ADDRESS_SPACE_MEMORY, &s->bar);
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int macio_initfn_ide(MacIOState *s, MACIOIDEState *ide, qemu_irq irq0,
|
static void macio_realize_ide(MacIOState *s, MACIOIDEState *ide,
|
||||||
qemu_irq irq1, int dmaid)
|
qemu_irq irq0, qemu_irq irq1, int dmaid,
|
||||||
|
Error **errp)
|
||||||
{
|
{
|
||||||
SysBusDevice *sysbus_dev;
|
SysBusDevice *sysbus_dev;
|
||||||
|
|
||||||
@@ -157,27 +157,31 @@ static int macio_initfn_ide(MacIOState *s, MACIOIDEState *ide, qemu_irq irq0,
|
|||||||
sysbus_connect_irq(sysbus_dev, 0, irq0);
|
sysbus_connect_irq(sysbus_dev, 0, irq0);
|
||||||
sysbus_connect_irq(sysbus_dev, 1, irq1);
|
sysbus_connect_irq(sysbus_dev, 1, irq1);
|
||||||
macio_ide_register_dma(ide, s->dbdma, dmaid);
|
macio_ide_register_dma(ide, s->dbdma, dmaid);
|
||||||
return qdev_init(DEVICE(ide));
|
object_property_set_bool(OBJECT(ide), true, "realized", errp);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int macio_oldworld_initfn(PCIDevice *d)
|
static void macio_oldworld_realize(PCIDevice *d, Error **errp)
|
||||||
{
|
{
|
||||||
MacIOState *s = MACIO(d);
|
MacIOState *s = MACIO(d);
|
||||||
OldWorldMacIOState *os = OLDWORLD_MACIO(d);
|
OldWorldMacIOState *os = OLDWORLD_MACIO(d);
|
||||||
|
Error *err = NULL;
|
||||||
SysBusDevice *sysbus_dev;
|
SysBusDevice *sysbus_dev;
|
||||||
int i;
|
int i;
|
||||||
int cur_irq = 0;
|
int cur_irq = 0;
|
||||||
int ret = macio_common_initfn(d);
|
|
||||||
if (ret < 0) {
|
macio_common_realize(d, &err);
|
||||||
return ret;
|
if (err) {
|
||||||
|
error_propagate(errp, err);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
sysbus_dev = SYS_BUS_DEVICE(&s->cuda);
|
sysbus_dev = SYS_BUS_DEVICE(&s->cuda);
|
||||||
sysbus_connect_irq(sysbus_dev, 0, os->irqs[cur_irq++]);
|
sysbus_connect_irq(sysbus_dev, 0, os->irqs[cur_irq++]);
|
||||||
|
|
||||||
ret = qdev_init(DEVICE(&os->nvram));
|
object_property_set_bool(OBJECT(&os->nvram), true, "realized", &err);
|
||||||
if (ret < 0) {
|
if (err) {
|
||||||
return ret;
|
error_propagate(errp, err);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
sysbus_dev = SYS_BUS_DEVICE(&os->nvram);
|
sysbus_dev = SYS_BUS_DEVICE(&os->nvram);
|
||||||
memory_region_add_subregion(&s->bar, 0x60000,
|
memory_region_add_subregion(&s->bar, 0x60000,
|
||||||
@@ -194,13 +198,12 @@ static int macio_oldworld_initfn(PCIDevice *d)
|
|||||||
qemu_irq irq0 = os->irqs[cur_irq++];
|
qemu_irq irq0 = os->irqs[cur_irq++];
|
||||||
qemu_irq irq1 = os->irqs[cur_irq++];
|
qemu_irq irq1 = os->irqs[cur_irq++];
|
||||||
|
|
||||||
ret = macio_initfn_ide(s, &os->ide[i], irq0, irq1, 0x16 + (i * 4));
|
macio_realize_ide(s, &os->ide[i], irq0, irq1, 0x16 + (i * 4), &err);
|
||||||
if (ret < 0) {
|
if (err) {
|
||||||
return ret;
|
error_propagate(errp, err);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void macio_init_ide(MacIOState *s, MACIOIDEState *ide, size_t ide_size,
|
static void macio_init_ide(MacIOState *s, MACIOIDEState *ide, size_t ide_size,
|
||||||
@@ -268,17 +271,20 @@ static const MemoryRegionOps timer_ops = {
|
|||||||
.endianness = DEVICE_LITTLE_ENDIAN,
|
.endianness = DEVICE_LITTLE_ENDIAN,
|
||||||
};
|
};
|
||||||
|
|
||||||
static int macio_newworld_initfn(PCIDevice *d)
|
static void macio_newworld_realize(PCIDevice *d, Error **errp)
|
||||||
{
|
{
|
||||||
MacIOState *s = MACIO(d);
|
MacIOState *s = MACIO(d);
|
||||||
NewWorldMacIOState *ns = NEWWORLD_MACIO(d);
|
NewWorldMacIOState *ns = NEWWORLD_MACIO(d);
|
||||||
|
Error *err = NULL;
|
||||||
SysBusDevice *sysbus_dev;
|
SysBusDevice *sysbus_dev;
|
||||||
MemoryRegion *timer_memory = NULL;
|
MemoryRegion *timer_memory = NULL;
|
||||||
int i;
|
int i;
|
||||||
int cur_irq = 0;
|
int cur_irq = 0;
|
||||||
int ret = macio_common_initfn(d);
|
|
||||||
if (ret < 0) {
|
macio_common_realize(d, &err);
|
||||||
return ret;
|
if (err) {
|
||||||
|
error_propagate(errp, err);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
sysbus_dev = SYS_BUS_DEVICE(&s->cuda);
|
sysbus_dev = SYS_BUS_DEVICE(&s->cuda);
|
||||||
@@ -294,9 +300,10 @@ static int macio_newworld_initfn(PCIDevice *d)
|
|||||||
qemu_irq irq0 = ns->irqs[cur_irq++];
|
qemu_irq irq0 = ns->irqs[cur_irq++];
|
||||||
qemu_irq irq1 = ns->irqs[cur_irq++];
|
qemu_irq irq1 = ns->irqs[cur_irq++];
|
||||||
|
|
||||||
ret = macio_initfn_ide(s, &ns->ide[i], irq0, irq1, 0x16 + (i * 4));
|
macio_realize_ide(s, &ns->ide[i], irq0, irq1, 0x16 + (i * 4), &err);
|
||||||
if (ret < 0) {
|
if (err) {
|
||||||
return ret;
|
error_propagate(errp, err);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -305,8 +312,6 @@ static int macio_newworld_initfn(PCIDevice *d)
|
|||||||
memory_region_init_io(timer_memory, OBJECT(s), &timer_ops, NULL, "timer",
|
memory_region_init_io(timer_memory, OBJECT(s), &timer_ops, NULL, "timer",
|
||||||
0x1000);
|
0x1000);
|
||||||
memory_region_add_subregion(&s->bar, 0x15000, timer_memory);
|
memory_region_add_subregion(&s->bar, 0x15000, timer_memory);
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void macio_newworld_init(Object *obj)
|
static void macio_newworld_init(Object *obj)
|
||||||
@@ -352,7 +357,7 @@ static void macio_oldworld_class_init(ObjectClass *oc, void *data)
|
|||||||
PCIDeviceClass *pdc = PCI_DEVICE_CLASS(oc);
|
PCIDeviceClass *pdc = PCI_DEVICE_CLASS(oc);
|
||||||
DeviceClass *dc = DEVICE_CLASS(oc);
|
DeviceClass *dc = DEVICE_CLASS(oc);
|
||||||
|
|
||||||
pdc->init = macio_oldworld_initfn;
|
pdc->realize = macio_oldworld_realize;
|
||||||
pdc->device_id = PCI_DEVICE_ID_APPLE_343S1201;
|
pdc->device_id = PCI_DEVICE_ID_APPLE_343S1201;
|
||||||
dc->vmsd = &vmstate_macio_oldworld;
|
dc->vmsd = &vmstate_macio_oldworld;
|
||||||
}
|
}
|
||||||
@@ -372,7 +377,7 @@ static void macio_newworld_class_init(ObjectClass *oc, void *data)
|
|||||||
PCIDeviceClass *pdc = PCI_DEVICE_CLASS(oc);
|
PCIDeviceClass *pdc = PCI_DEVICE_CLASS(oc);
|
||||||
DeviceClass *dc = DEVICE_CLASS(oc);
|
DeviceClass *dc = DEVICE_CLASS(oc);
|
||||||
|
|
||||||
pdc->init = macio_newworld_initfn;
|
pdc->realize = macio_newworld_realize;
|
||||||
pdc->device_id = PCI_DEVICE_ID_APPLE_UNI_N_KEYL;
|
pdc->device_id = PCI_DEVICE_ID_APPLE_UNI_N_KEYL;
|
||||||
dc->vmsd = &vmstate_macio_newworld;
|
dc->vmsd = &vmstate_macio_newworld;
|
||||||
}
|
}
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user