mirror of
https://github.com/izzy2lost/xemu.git
synced 2026-07-06 00:20:22 -07:00
Merge remote-tracking branch 'remotes/mst/tags/for_upstream' into staging
virtio,acpi,pci: features, fixes, cleanups, tests Max slots negotiation for vhost-user. Free page reporting for balloon. Partial TPM2 ACPI support for ARM. Support for NVDIMMs having their own proximity domains. New vhost-user-vsock device. Fixes, cleanups in ACPI, PCI, virtio. New tests for TPM ACPI. Signed-off-by: Michael S. Tsirkin <mst@redhat.com> # gpg: Signature made Fri 12 Jun 2020 15:18:04 BST # gpg: using RSA key 5D09FD0871C8F85B94CA8A0D281F0DB8D28D5469 # gpg: issuer "mst@redhat.com" # gpg: Good signature from "Michael S. Tsirkin <mst@kernel.org>" [full] # gpg: aka "Michael S. Tsirkin <mst@redhat.com>" [full] # Primary key fingerprint: 0270 606B 6F3C DF3D 0B17 0970 C350 3912 AFBE 8E67 # Subkey fingerprint: 5D09 FD08 71C8 F85B 94CA 8A0D 281F 0DB8 D28D 5469 * remotes/mst/tags/for_upstream: (58 commits) virtio-pci: fix queue_enable write pci: Display PCI IRQ pin in "info pci" Fix parameter type in vhost migration log path acpi: ged: rename event memory region acpi: fadt: add hw-reduced sleep register support acpi: madt: skip pci override on pci-less systems. acpi: create acpi-common.c and move madt code acpi: make build_madt() more generic. virtio: add vhost-user-vsock-pci device virtio: add vhost-user-vsock base device vhost-vsock: add vhost-vsock-common abstraction hw/pci: Fix crash when running QEMU with "-nic model=rocker" libvhost-user: advertise vring features Lift max ram slots limit in libvhost-user Support individual region unmap in libvhost-user Support adding individual regions in libvhost-user Support ram slot configuration in libvhost-user Refactor out libvhost-user fault generation logic Lift max memory slots limit imposed by vhost-user Transmit vhost-user memory regions individually ... Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
+2
-1
@@ -1531,7 +1531,7 @@ F: hw/acpi/*
|
||||
F: hw/smbios/*
|
||||
F: hw/i386/acpi-build.[hc]
|
||||
F: hw/arm/virt-acpi-build.c
|
||||
F: tests/qtest/bios-tables-test.c
|
||||
F: tests/qtest/bios-tables-test*
|
||||
F: tests/qtest/acpi-utils.[hc]
|
||||
F: tests/data/acpi/
|
||||
|
||||
@@ -2328,6 +2328,7 @@ S: Maintained
|
||||
F: qtest.c
|
||||
F: accel/qtest.c
|
||||
F: tests/qtest/
|
||||
X: tests/qtest/bios-tables-test-allowed-diff.h
|
||||
|
||||
Device Fuzzing
|
||||
M: Alexander Bulekov <alxndr@bu.edu>
|
||||
|
||||
@@ -175,15 +175,16 @@ static int tcp_chr_write(Chardev *chr, const uint8_t *buf, int len)
|
||||
|
||||
if (ret < 0 && errno != EAGAIN) {
|
||||
if (tcp_chr_read_poll(chr) <= 0) {
|
||||
/* Perform disconnect and return error. */
|
||||
tcp_chr_disconnect_locked(chr);
|
||||
return len;
|
||||
} /* else let the read handler finish it properly */
|
||||
}
|
||||
|
||||
return ret;
|
||||
} else {
|
||||
/* XXX: indicate an error ? */
|
||||
return len;
|
||||
/* Indicate an error. */
|
||||
errno = EIO;
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -7196,6 +7196,9 @@ if test "$vhost_crypto" = "yes" ; then
|
||||
fi
|
||||
if test "$vhost_vsock" = "yes" ; then
|
||||
echo "CONFIG_VHOST_VSOCK=y" >> $config_host_mak
|
||||
if test "$vhost_user" = "yes" ; then
|
||||
echo "CONFIG_VHOST_USER_VSOCK=y" >> $config_host_mak
|
||||
fi
|
||||
fi
|
||||
if test "$vhost_kernel" = "yes" ; then
|
||||
echo "CONFIG_VHOST_KERNEL=y" >> $config_host_mak
|
||||
|
||||
@@ -137,6 +137,9 @@ vu_request_to_string(unsigned int req)
|
||||
REQ(VHOST_USER_SET_INFLIGHT_FD),
|
||||
REQ(VHOST_USER_GPU_SET_SOCKET),
|
||||
REQ(VHOST_USER_VRING_KICK),
|
||||
REQ(VHOST_USER_GET_MAX_MEM_SLOTS),
|
||||
REQ(VHOST_USER_ADD_MEM_REG),
|
||||
REQ(VHOST_USER_REM_MEM_REG),
|
||||
REQ(VHOST_USER_MAX),
|
||||
};
|
||||
#undef REQ
|
||||
@@ -266,7 +269,7 @@ have_userfault(void)
|
||||
static bool
|
||||
vu_message_read(VuDev *dev, int conn_fd, VhostUserMsg *vmsg)
|
||||
{
|
||||
char control[CMSG_SPACE(VHOST_MEMORY_MAX_NREGIONS * sizeof(int))] = { };
|
||||
char control[CMSG_SPACE(VHOST_MEMORY_BASELINE_NREGIONS * sizeof(int))] = {};
|
||||
struct iovec iov = {
|
||||
.iov_base = (char *)vmsg,
|
||||
.iov_len = VHOST_USER_HDR_SIZE,
|
||||
@@ -337,7 +340,7 @@ vu_message_write(VuDev *dev, int conn_fd, VhostUserMsg *vmsg)
|
||||
{
|
||||
int rc;
|
||||
uint8_t *p = (uint8_t *)vmsg;
|
||||
char control[CMSG_SPACE(VHOST_MEMORY_MAX_NREGIONS * sizeof(int))] = { };
|
||||
char control[CMSG_SPACE(VHOST_MEMORY_BASELINE_NREGIONS * sizeof(int))] = {};
|
||||
struct iovec iov = {
|
||||
.iov_base = (char *)vmsg,
|
||||
.iov_len = VHOST_USER_HDR_SIZE,
|
||||
@@ -350,7 +353,7 @@ vu_message_write(VuDev *dev, int conn_fd, VhostUserMsg *vmsg)
|
||||
struct cmsghdr *cmsg;
|
||||
|
||||
memset(control, 0, sizeof(control));
|
||||
assert(vmsg->fd_num <= VHOST_MEMORY_MAX_NREGIONS);
|
||||
assert(vmsg->fd_num <= VHOST_MEMORY_BASELINE_NREGIONS);
|
||||
if (vmsg->fd_num > 0) {
|
||||
size_t fdsize = vmsg->fd_num * sizeof(int);
|
||||
msg.msg_controllen = CMSG_SPACE(fdsize);
|
||||
@@ -495,6 +498,16 @@ static bool
|
||||
vu_get_features_exec(VuDev *dev, VhostUserMsg *vmsg)
|
||||
{
|
||||
vmsg->payload.u64 =
|
||||
/*
|
||||
* The following VIRTIO feature bits are supported by our virtqueue
|
||||
* implementation:
|
||||
*/
|
||||
1ULL << VIRTIO_F_NOTIFY_ON_EMPTY |
|
||||
1ULL << VIRTIO_RING_F_INDIRECT_DESC |
|
||||
1ULL << VIRTIO_RING_F_EVENT_IDX |
|
||||
1ULL << VIRTIO_F_VERSION_1 |
|
||||
|
||||
/* vhost-user feature bits */
|
||||
1ULL << VHOST_F_LOG_ALL |
|
||||
1ULL << VHOST_USER_F_PROTOCOL_FEATURES;
|
||||
|
||||
@@ -583,6 +596,244 @@ map_ring(VuDev *dev, VuVirtq *vq)
|
||||
return !(vq->vring.desc && vq->vring.used && vq->vring.avail);
|
||||
}
|
||||
|
||||
static bool
|
||||
generate_faults(VuDev *dev) {
|
||||
int i;
|
||||
for (i = 0; i < dev->nregions; i++) {
|
||||
VuDevRegion *dev_region = &dev->regions[i];
|
||||
int ret;
|
||||
#ifdef UFFDIO_REGISTER
|
||||
/*
|
||||
* We should already have an open ufd. Mark each memory
|
||||
* range as ufd.
|
||||
* Discard any mapping we have here; note I can't use MADV_REMOVE
|
||||
* or fallocate to make the hole since I don't want to lose
|
||||
* data that's already arrived in the shared process.
|
||||
* TODO: How to do hugepage
|
||||
*/
|
||||
ret = madvise((void *)(uintptr_t)dev_region->mmap_addr,
|
||||
dev_region->size + dev_region->mmap_offset,
|
||||
MADV_DONTNEED);
|
||||
if (ret) {
|
||||
fprintf(stderr,
|
||||
"%s: Failed to madvise(DONTNEED) region %d: %s\n",
|
||||
__func__, i, strerror(errno));
|
||||
}
|
||||
/*
|
||||
* Turn off transparent hugepages so we dont get lose wakeups
|
||||
* in neighbouring pages.
|
||||
* TODO: Turn this backon later.
|
||||
*/
|
||||
ret = madvise((void *)(uintptr_t)dev_region->mmap_addr,
|
||||
dev_region->size + dev_region->mmap_offset,
|
||||
MADV_NOHUGEPAGE);
|
||||
if (ret) {
|
||||
/*
|
||||
* Note: This can happen legally on kernels that are configured
|
||||
* without madvise'able hugepages
|
||||
*/
|
||||
fprintf(stderr,
|
||||
"%s: Failed to madvise(NOHUGEPAGE) region %d: %s\n",
|
||||
__func__, i, strerror(errno));
|
||||
}
|
||||
struct uffdio_register reg_struct;
|
||||
reg_struct.range.start = (uintptr_t)dev_region->mmap_addr;
|
||||
reg_struct.range.len = dev_region->size + dev_region->mmap_offset;
|
||||
reg_struct.mode = UFFDIO_REGISTER_MODE_MISSING;
|
||||
|
||||
if (ioctl(dev->postcopy_ufd, UFFDIO_REGISTER, ®_struct)) {
|
||||
vu_panic(dev, "%s: Failed to userfault region %d "
|
||||
"@%p + size:%zx offset: %zx: (ufd=%d)%s\n",
|
||||
__func__, i,
|
||||
dev_region->mmap_addr,
|
||||
dev_region->size, dev_region->mmap_offset,
|
||||
dev->postcopy_ufd, strerror(errno));
|
||||
return false;
|
||||
}
|
||||
if (!(reg_struct.ioctls & ((__u64)1 << _UFFDIO_COPY))) {
|
||||
vu_panic(dev, "%s Region (%d) doesn't support COPY",
|
||||
__func__, i);
|
||||
return false;
|
||||
}
|
||||
DPRINT("%s: region %d: Registered userfault for %"
|
||||
PRIx64 " + %" PRIx64 "\n", __func__, i,
|
||||
(uint64_t)reg_struct.range.start,
|
||||
(uint64_t)reg_struct.range.len);
|
||||
/* Now it's registered we can let the client at it */
|
||||
if (mprotect((void *)(uintptr_t)dev_region->mmap_addr,
|
||||
dev_region->size + dev_region->mmap_offset,
|
||||
PROT_READ | PROT_WRITE)) {
|
||||
vu_panic(dev, "failed to mprotect region %d for postcopy (%s)",
|
||||
i, strerror(errno));
|
||||
return false;
|
||||
}
|
||||
/* TODO: Stash 'zero' support flags somewhere */
|
||||
#endif
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool
|
||||
vu_add_mem_reg(VuDev *dev, VhostUserMsg *vmsg) {
|
||||
int i;
|
||||
bool track_ramblocks = dev->postcopy_listening;
|
||||
VhostUserMemoryRegion m = vmsg->payload.memreg.region, *msg_region = &m;
|
||||
VuDevRegion *dev_region = &dev->regions[dev->nregions];
|
||||
void *mmap_addr;
|
||||
|
||||
/*
|
||||
* If we are in postcopy mode and we receive a u64 payload with a 0 value
|
||||
* we know all the postcopy client bases have been recieved, and we
|
||||
* should start generating faults.
|
||||
*/
|
||||
if (track_ramblocks &&
|
||||
vmsg->size == sizeof(vmsg->payload.u64) &&
|
||||
vmsg->payload.u64 == 0) {
|
||||
(void)generate_faults(dev);
|
||||
return false;
|
||||
}
|
||||
|
||||
DPRINT("Adding region: %d\n", dev->nregions);
|
||||
DPRINT(" guest_phys_addr: 0x%016"PRIx64"\n",
|
||||
msg_region->guest_phys_addr);
|
||||
DPRINT(" memory_size: 0x%016"PRIx64"\n",
|
||||
msg_region->memory_size);
|
||||
DPRINT(" userspace_addr 0x%016"PRIx64"\n",
|
||||
msg_region->userspace_addr);
|
||||
DPRINT(" mmap_offset 0x%016"PRIx64"\n",
|
||||
msg_region->mmap_offset);
|
||||
|
||||
dev_region->gpa = msg_region->guest_phys_addr;
|
||||
dev_region->size = msg_region->memory_size;
|
||||
dev_region->qva = msg_region->userspace_addr;
|
||||
dev_region->mmap_offset = msg_region->mmap_offset;
|
||||
|
||||
/*
|
||||
* We don't use offset argument of mmap() since the
|
||||
* mapped address has to be page aligned, and we use huge
|
||||
* pages.
|
||||
*/
|
||||
if (track_ramblocks) {
|
||||
/*
|
||||
* In postcopy we're using PROT_NONE here to catch anyone
|
||||
* accessing it before we userfault.
|
||||
*/
|
||||
mmap_addr = mmap(0, dev_region->size + dev_region->mmap_offset,
|
||||
PROT_NONE, MAP_SHARED,
|
||||
vmsg->fds[0], 0);
|
||||
} else {
|
||||
mmap_addr = mmap(0, dev_region->size + dev_region->mmap_offset,
|
||||
PROT_READ | PROT_WRITE, MAP_SHARED, vmsg->fds[0],
|
||||
0);
|
||||
}
|
||||
|
||||
if (mmap_addr == MAP_FAILED) {
|
||||
vu_panic(dev, "region mmap error: %s", strerror(errno));
|
||||
} else {
|
||||
dev_region->mmap_addr = (uint64_t)(uintptr_t)mmap_addr;
|
||||
DPRINT(" mmap_addr: 0x%016"PRIx64"\n",
|
||||
dev_region->mmap_addr);
|
||||
}
|
||||
|
||||
close(vmsg->fds[0]);
|
||||
|
||||
if (track_ramblocks) {
|
||||
/*
|
||||
* Return the address to QEMU so that it can translate the ufd
|
||||
* fault addresses back.
|
||||
*/
|
||||
msg_region->userspace_addr = (uintptr_t)(mmap_addr +
|
||||
dev_region->mmap_offset);
|
||||
|
||||
/* Send the message back to qemu with the addresses filled in. */
|
||||
vmsg->fd_num = 0;
|
||||
if (!vu_send_reply(dev, dev->sock, vmsg)) {
|
||||
vu_panic(dev, "failed to respond to add-mem-region for postcopy");
|
||||
return false;
|
||||
}
|
||||
|
||||
DPRINT("Successfully added new region in postcopy\n");
|
||||
dev->nregions++;
|
||||
return false;
|
||||
|
||||
} else {
|
||||
for (i = 0; i < dev->max_queues; i++) {
|
||||
if (dev->vq[i].vring.desc) {
|
||||
if (map_ring(dev, &dev->vq[i])) {
|
||||
vu_panic(dev, "remapping queue %d for new memory region",
|
||||
i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
DPRINT("Successfully added new region\n");
|
||||
dev->nregions++;
|
||||
vmsg_set_reply_u64(vmsg, 0);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
static inline bool reg_equal(VuDevRegion *vudev_reg,
|
||||
VhostUserMemoryRegion *msg_reg)
|
||||
{
|
||||
if (vudev_reg->gpa == msg_reg->guest_phys_addr &&
|
||||
vudev_reg->qva == msg_reg->userspace_addr &&
|
||||
vudev_reg->size == msg_reg->memory_size) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool
|
||||
vu_rem_mem_reg(VuDev *dev, VhostUserMsg *vmsg) {
|
||||
int i, j;
|
||||
bool found = false;
|
||||
VuDevRegion shadow_regions[VHOST_USER_MAX_RAM_SLOTS] = {};
|
||||
VhostUserMemoryRegion m = vmsg->payload.memreg.region, *msg_region = &m;
|
||||
|
||||
DPRINT("Removing region:\n");
|
||||
DPRINT(" guest_phys_addr: 0x%016"PRIx64"\n",
|
||||
msg_region->guest_phys_addr);
|
||||
DPRINT(" memory_size: 0x%016"PRIx64"\n",
|
||||
msg_region->memory_size);
|
||||
DPRINT(" userspace_addr 0x%016"PRIx64"\n",
|
||||
msg_region->userspace_addr);
|
||||
DPRINT(" mmap_offset 0x%016"PRIx64"\n",
|
||||
msg_region->mmap_offset);
|
||||
|
||||
for (i = 0, j = 0; i < dev->nregions; i++) {
|
||||
if (!reg_equal(&dev->regions[i], msg_region)) {
|
||||
shadow_regions[j].gpa = dev->regions[i].gpa;
|
||||
shadow_regions[j].size = dev->regions[i].size;
|
||||
shadow_regions[j].qva = dev->regions[i].qva;
|
||||
shadow_regions[j].mmap_offset = dev->regions[i].mmap_offset;
|
||||
j++;
|
||||
} else {
|
||||
found = true;
|
||||
VuDevRegion *r = &dev->regions[i];
|
||||
void *m = (void *) (uintptr_t) r->mmap_addr;
|
||||
|
||||
if (m) {
|
||||
munmap(m, r->size + r->mmap_offset);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (found) {
|
||||
memcpy(dev->regions, shadow_regions,
|
||||
sizeof(VuDevRegion) * VHOST_USER_MAX_RAM_SLOTS);
|
||||
DPRINT("Successfully removed a region\n");
|
||||
dev->nregions--;
|
||||
vmsg_set_reply_u64(vmsg, 0);
|
||||
} else {
|
||||
vu_panic(dev, "Specified region not found\n");
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool
|
||||
vu_set_mem_table_exec_postcopy(VuDev *dev, VhostUserMsg *vmsg)
|
||||
{
|
||||
@@ -655,74 +906,7 @@ vu_set_mem_table_exec_postcopy(VuDev *dev, VhostUserMsg *vmsg)
|
||||
}
|
||||
|
||||
/* OK, now we can go and register the memory and generate faults */
|
||||
for (i = 0; i < dev->nregions; i++) {
|
||||
VuDevRegion *dev_region = &dev->regions[i];
|
||||
int ret;
|
||||
#ifdef UFFDIO_REGISTER
|
||||
/* We should already have an open ufd. Mark each memory
|
||||
* range as ufd.
|
||||
* Discard any mapping we have here; note I can't use MADV_REMOVE
|
||||
* or fallocate to make the hole since I don't want to lose
|
||||
* data that's already arrived in the shared process.
|
||||
* TODO: How to do hugepage
|
||||
*/
|
||||
ret = madvise((void *)(uintptr_t)dev_region->mmap_addr,
|
||||
dev_region->size + dev_region->mmap_offset,
|
||||
MADV_DONTNEED);
|
||||
if (ret) {
|
||||
fprintf(stderr,
|
||||
"%s: Failed to madvise(DONTNEED) region %d: %s\n",
|
||||
__func__, i, strerror(errno));
|
||||
}
|
||||
/* Turn off transparent hugepages so we dont get lose wakeups
|
||||
* in neighbouring pages.
|
||||
* TODO: Turn this backon later.
|
||||
*/
|
||||
ret = madvise((void *)(uintptr_t)dev_region->mmap_addr,
|
||||
dev_region->size + dev_region->mmap_offset,
|
||||
MADV_NOHUGEPAGE);
|
||||
if (ret) {
|
||||
/* Note: This can happen legally on kernels that are configured
|
||||
* without madvise'able hugepages
|
||||
*/
|
||||
fprintf(stderr,
|
||||
"%s: Failed to madvise(NOHUGEPAGE) region %d: %s\n",
|
||||
__func__, i, strerror(errno));
|
||||
}
|
||||
struct uffdio_register reg_struct;
|
||||
reg_struct.range.start = (uintptr_t)dev_region->mmap_addr;
|
||||
reg_struct.range.len = dev_region->size + dev_region->mmap_offset;
|
||||
reg_struct.mode = UFFDIO_REGISTER_MODE_MISSING;
|
||||
|
||||
if (ioctl(dev->postcopy_ufd, UFFDIO_REGISTER, ®_struct)) {
|
||||
vu_panic(dev, "%s: Failed to userfault region %d "
|
||||
"@%p + size:%zx offset: %zx: (ufd=%d)%s\n",
|
||||
__func__, i,
|
||||
dev_region->mmap_addr,
|
||||
dev_region->size, dev_region->mmap_offset,
|
||||
dev->postcopy_ufd, strerror(errno));
|
||||
return false;
|
||||
}
|
||||
if (!(reg_struct.ioctls & ((__u64)1 << _UFFDIO_COPY))) {
|
||||
vu_panic(dev, "%s Region (%d) doesn't support COPY",
|
||||
__func__, i);
|
||||
return false;
|
||||
}
|
||||
DPRINT("%s: region %d: Registered userfault for %"
|
||||
PRIx64 " + %" PRIx64 "\n", __func__, i,
|
||||
(uint64_t)reg_struct.range.start,
|
||||
(uint64_t)reg_struct.range.len);
|
||||
/* Now it's registered we can let the client at it */
|
||||
if (mprotect((void *)(uintptr_t)dev_region->mmap_addr,
|
||||
dev_region->size + dev_region->mmap_offset,
|
||||
PROT_READ | PROT_WRITE)) {
|
||||
vu_panic(dev, "failed to mprotect region %d for postcopy (%s)",
|
||||
i, strerror(errno));
|
||||
return false;
|
||||
}
|
||||
/* TODO: Stash 'zero' support flags somewhere */
|
||||
#endif
|
||||
}
|
||||
(void)generate_faults(dev);
|
||||
|
||||
return false;
|
||||
}
|
||||
@@ -1220,7 +1404,8 @@ vu_get_protocol_features_exec(VuDev *dev, VhostUserMsg *vmsg)
|
||||
1ULL << VHOST_USER_PROTOCOL_F_SLAVE_REQ |
|
||||
1ULL << VHOST_USER_PROTOCOL_F_HOST_NOTIFIER |
|
||||
1ULL << VHOST_USER_PROTOCOL_F_SLAVE_SEND_FD |
|
||||
1ULL << VHOST_USER_PROTOCOL_F_REPLY_ACK;
|
||||
1ULL << VHOST_USER_PROTOCOL_F_REPLY_ACK |
|
||||
1ULL << VHOST_USER_PROTOCOL_F_CONFIGURE_MEM_SLOTS;
|
||||
|
||||
if (have_userfault()) {
|
||||
features |= 1ULL << VHOST_USER_PROTOCOL_F_PAGEFAULT;
|
||||
@@ -1554,6 +1739,22 @@ vu_handle_vring_kick(VuDev *dev, VhostUserMsg *vmsg)
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool vu_handle_get_max_memslots(VuDev *dev, VhostUserMsg *vmsg)
|
||||
{
|
||||
vmsg->flags = VHOST_USER_REPLY_MASK | VHOST_USER_VERSION;
|
||||
vmsg->size = sizeof(vmsg->payload.u64);
|
||||
vmsg->payload.u64 = VHOST_USER_MAX_RAM_SLOTS;
|
||||
vmsg->fd_num = 0;
|
||||
|
||||
if (!vu_message_write(dev, dev->sock, vmsg)) {
|
||||
vu_panic(dev, "Failed to send max ram slots: %s\n", strerror(errno));
|
||||
}
|
||||
|
||||
DPRINT("u64: 0x%016"PRIx64"\n", (uint64_t) VHOST_USER_MAX_RAM_SLOTS);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool
|
||||
vu_process_message(VuDev *dev, VhostUserMsg *vmsg)
|
||||
{
|
||||
@@ -1638,6 +1839,12 @@ vu_process_message(VuDev *dev, VhostUserMsg *vmsg)
|
||||
return vu_set_inflight_fd(dev, vmsg);
|
||||
case VHOST_USER_VRING_KICK:
|
||||
return vu_handle_vring_kick(dev, vmsg);
|
||||
case VHOST_USER_GET_MAX_MEM_SLOTS:
|
||||
return vu_handle_get_max_memslots(dev, vmsg);
|
||||
case VHOST_USER_ADD_MEM_REG:
|
||||
return vu_add_mem_reg(dev, vmsg);
|
||||
case VHOST_USER_REM_MEM_REG:
|
||||
return vu_rem_mem_reg(dev, vmsg);
|
||||
default:
|
||||
vmsg_close_fds(vmsg);
|
||||
vu_panic(dev, "Unhandled request: %d", vmsg->request);
|
||||
|
||||
@@ -28,7 +28,13 @@
|
||||
|
||||
#define VIRTQUEUE_MAX_SIZE 1024
|
||||
|
||||
#define VHOST_MEMORY_MAX_NREGIONS 8
|
||||
#define VHOST_MEMORY_BASELINE_NREGIONS 8
|
||||
|
||||
/*
|
||||
* Set a reasonable maximum number of ram slots, which will be supported by
|
||||
* any architecture.
|
||||
*/
|
||||
#define VHOST_USER_MAX_RAM_SLOTS 32
|
||||
|
||||
typedef enum VhostSetConfigType {
|
||||
VHOST_SET_CONFIG_TYPE_MASTER = 0,
|
||||
@@ -55,6 +61,7 @@ enum VhostUserProtocolFeature {
|
||||
VHOST_USER_PROTOCOL_F_HOST_NOTIFIER = 11,
|
||||
VHOST_USER_PROTOCOL_F_INFLIGHT_SHMFD = 12,
|
||||
VHOST_USER_PROTOCOL_F_INBAND_NOTIFICATIONS = 14,
|
||||
VHOST_USER_PROTOCOL_F_CONFIGURE_MEM_SLOTS = 15,
|
||||
|
||||
VHOST_USER_PROTOCOL_F_MAX
|
||||
};
|
||||
@@ -97,6 +104,9 @@ typedef enum VhostUserRequest {
|
||||
VHOST_USER_SET_INFLIGHT_FD = 32,
|
||||
VHOST_USER_GPU_SET_SOCKET = 33,
|
||||
VHOST_USER_VRING_KICK = 35,
|
||||
VHOST_USER_GET_MAX_MEM_SLOTS = 36,
|
||||
VHOST_USER_ADD_MEM_REG = 37,
|
||||
VHOST_USER_REM_MEM_REG = 38,
|
||||
VHOST_USER_MAX
|
||||
} VhostUserRequest;
|
||||
|
||||
@@ -120,9 +130,14 @@ typedef struct VhostUserMemoryRegion {
|
||||
typedef struct VhostUserMemory {
|
||||
uint32_t nregions;
|
||||
uint32_t padding;
|
||||
VhostUserMemoryRegion regions[VHOST_MEMORY_MAX_NREGIONS];
|
||||
VhostUserMemoryRegion regions[VHOST_MEMORY_BASELINE_NREGIONS];
|
||||
} VhostUserMemory;
|
||||
|
||||
typedef struct VhostUserMemRegMsg {
|
||||
uint32_t padding;
|
||||
VhostUserMemoryRegion region;
|
||||
} VhostUserMemRegMsg;
|
||||
|
||||
typedef struct VhostUserLog {
|
||||
uint64_t mmap_size;
|
||||
uint64_t mmap_offset;
|
||||
@@ -175,13 +190,14 @@ typedef struct VhostUserMsg {
|
||||
struct vhost_vring_state state;
|
||||
struct vhost_vring_addr addr;
|
||||
VhostUserMemory memory;
|
||||
VhostUserMemRegMsg memreg;
|
||||
VhostUserLog log;
|
||||
VhostUserConfig config;
|
||||
VhostUserVringArea area;
|
||||
VhostUserInflight inflight;
|
||||
} payload;
|
||||
|
||||
int fds[VHOST_MEMORY_MAX_NREGIONS];
|
||||
int fds[VHOST_MEMORY_BASELINE_NREGIONS];
|
||||
int fd_num;
|
||||
uint8_t *data;
|
||||
} VU_PACKED VhostUserMsg;
|
||||
@@ -359,7 +375,7 @@ typedef struct VuDevInflightInfo {
|
||||
struct VuDev {
|
||||
int sock;
|
||||
uint32_t nregions;
|
||||
VuDevRegion regions[VHOST_MEMORY_MAX_NREGIONS];
|
||||
VuDevRegion regions[VHOST_USER_MAX_RAM_SLOTS];
|
||||
VuVirtq *vq;
|
||||
VuDevInflightInfo inflight_info;
|
||||
int log_call_fd;
|
||||
|
||||
@@ -382,9 +382,7 @@ vub_get_features(VuDev *dev)
|
||||
1ull << VIRTIO_BLK_F_DISCARD |
|
||||
1ull << VIRTIO_BLK_F_WRITE_ZEROES |
|
||||
#endif
|
||||
1ull << VIRTIO_BLK_F_CONFIG_WCE |
|
||||
1ull << VIRTIO_F_VERSION_1 |
|
||||
1ull << VHOST_USER_F_PROTOCOL_FEATURES;
|
||||
1ull << VIRTIO_BLK_F_CONFIG_WCE;
|
||||
|
||||
if (vdev_blk->enable_ro) {
|
||||
features |= 1ull << VIRTIO_BLK_F_RO;
|
||||
|
||||
@@ -815,6 +815,7 @@ Protocol features
|
||||
#define VHOST_USER_PROTOCOL_F_INFLIGHT_SHMFD 12
|
||||
#define VHOST_USER_PROTOCOL_F_RESET_DEVICE 13
|
||||
#define VHOST_USER_PROTOCOL_F_INBAND_NOTIFICATIONS 14
|
||||
#define VHOST_USER_PROTOCOL_F_CONFIGURE_MEM_SLOTS 15
|
||||
|
||||
Master message types
|
||||
--------------------
|
||||
@@ -1263,6 +1264,49 @@ Master message types
|
||||
|
||||
The state.num field is currently reserved and must be set to 0.
|
||||
|
||||
``VHOST_USER_GET_MAX_MEM_SLOTS``
|
||||
:id: 36
|
||||
:equivalent ioctl: N/A
|
||||
:slave payload: u64
|
||||
|
||||
When the ``VHOST_USER_PROTOCOL_F_CONFIGURE_MEM_SLOTS`` protocol
|
||||
feature has been successfully negotiated, this message is submitted
|
||||
by master to the slave. The slave should return the message with a
|
||||
u64 payload containing the maximum number of memory slots for
|
||||
QEMU to expose to the guest. The value returned by the backend
|
||||
will be capped at the maximum number of ram slots which can be
|
||||
supported by the target platform.
|
||||
|
||||
``VHOST_USER_ADD_MEM_REG``
|
||||
:id: 37
|
||||
:equivalent ioctl: N/A
|
||||
:slave payload: memory region
|
||||
|
||||
When the ``VHOST_USER_PROTOCOL_F_CONFIGURE_MEM_SLOTS`` protocol
|
||||
feature has been successfully negotiated, this message is submitted
|
||||
by the master to the slave. The message payload contains a memory
|
||||
region descriptor struct, describing a region of guest memory which
|
||||
the slave device must map in. When the
|
||||
``VHOST_USER_PROTOCOL_F_CONFIGURE_MEM_SLOTS`` protocol feature has
|
||||
been successfully negotiated, along with the
|
||||
``VHOST_USER_REM_MEM_REG`` message, this message is used to set and
|
||||
update the memory tables of the slave device.
|
||||
|
||||
``VHOST_USER_REM_MEM_REG``
|
||||
:id: 38
|
||||
:equivalent ioctl: N/A
|
||||
:slave payload: memory region
|
||||
|
||||
When the ``VHOST_USER_PROTOCOL_F_CONFIGURE_MEM_SLOTS`` protocol
|
||||
feature has been successfully negotiated, this message is submitted
|
||||
by the master to the slave. The message payload contains a memory
|
||||
region descriptor struct, describing a region of guest memory which
|
||||
the slave device must unmap. When the
|
||||
``VHOST_USER_PROTOCOL_F_CONFIGURE_MEM_SLOTS`` protocol feature has
|
||||
been successfully negotiated, along with the
|
||||
``VHOST_USER_ADD_MEM_REG`` message, this message is used to set and
|
||||
update the memory tables of the slave device.
|
||||
|
||||
Slave message types
|
||||
-------------------
|
||||
|
||||
|
||||
+47
-2
@@ -26,6 +26,7 @@
|
||||
#include "qemu/bitops.h"
|
||||
#include "sysemu/numa.h"
|
||||
#include "hw/boards.h"
|
||||
#include "hw/acpi/tpm.h"
|
||||
|
||||
static GArray *build_alloc_array(void)
|
||||
{
|
||||
@@ -1865,9 +1866,9 @@ void build_fadt(GArray *tbl, BIOSLinker *linker, const AcpiFadtData *f,
|
||||
}
|
||||
|
||||
/* SLEEP_CONTROL_REG */
|
||||
build_append_gas(tbl, AML_AS_SYSTEM_MEMORY, 0 , 0, 0, 0);
|
||||
build_append_gas_from_struct(tbl, &f->sleep_ctl);
|
||||
/* SLEEP_STATUS_REG */
|
||||
build_append_gas(tbl, AML_AS_SYSTEM_MEMORY, 0 , 0, 0, 0);
|
||||
build_append_gas_from_struct(tbl, &f->sleep_sts);
|
||||
|
||||
/* TODO: extra fields need to be added to support revisions above rev5 */
|
||||
assert(f->rev == 5);
|
||||
@@ -1877,6 +1878,50 @@ build_hdr:
|
||||
"FACP", tbl->len - fadt_start, f->rev, oem_id, oem_table_id);
|
||||
}
|
||||
|
||||
void build_tpm2(GArray *table_data, BIOSLinker *linker, GArray *tcpalog)
|
||||
{
|
||||
Acpi20TPM2 *tpm2_ptr = acpi_data_push(table_data, sizeof(AcpiTableHeader));
|
||||
unsigned log_addr_size = sizeof(tpm2_ptr->log_area_start_address);
|
||||
unsigned log_addr_offset =
|
||||
(char *)&tpm2_ptr->log_area_start_address - table_data->data;
|
||||
uint8_t start_method_params[12] = {};
|
||||
TPMIf *tpmif = tpm_find();
|
||||
|
||||
/* platform class */
|
||||
build_append_int_noprefix(table_data, TPM2_ACPI_CLASS_CLIENT, 2);
|
||||
/* reserved */
|
||||
build_append_int_noprefix(table_data, 0, 2);
|
||||
if (TPM_IS_TIS_ISA(tpmif) || TPM_IS_TIS_SYSBUS(tpmif)) {
|
||||
/* address of control area */
|
||||
build_append_int_noprefix(table_data, 0, 8);
|
||||
/* start method */
|
||||
build_append_int_noprefix(table_data, TPM2_START_METHOD_MMIO, 4);
|
||||
} else if (TPM_IS_CRB(tpmif)) {
|
||||
build_append_int_noprefix(table_data, TPM_CRB_ADDR_CTRL, 8);
|
||||
build_append_int_noprefix(table_data, TPM2_START_METHOD_CRB, 4);
|
||||
} else {
|
||||
g_warn_if_reached();
|
||||
}
|
||||
|
||||
/* platform specific parameters */
|
||||
g_array_append_vals(table_data, &start_method_params, 12);
|
||||
|
||||
/* log area minimum length */
|
||||
build_append_int_noprefix(table_data, TPM_LOG_AREA_MINIMUM_SIZE, 4);
|
||||
|
||||
acpi_data_push(tcpalog, TPM_LOG_AREA_MINIMUM_SIZE);
|
||||
bios_linker_loader_alloc(linker, ACPI_BUILD_TPMLOG_FILE, tcpalog, 1,
|
||||
false);
|
||||
|
||||
/* log area start address to be filled by Guest linker */
|
||||
build_append_int_noprefix(table_data, 0, 8);
|
||||
bios_linker_loader_add_pointer(linker, ACPI_BUILD_TABLE_FILE,
|
||||
log_addr_offset, log_addr_size,
|
||||
ACPI_BUILD_TPMLOG_FILE, 0);
|
||||
build_header(linker, table_data,
|
||||
(void *)tpm2_ptr, "TPM2", sizeof(*tpm2_ptr), 4, NULL, NULL);
|
||||
}
|
||||
|
||||
/* ACPI 5.0: 6.4.3.8.2 Serial Bus Connection Descriptors */
|
||||
static Aml *aml_serial_bus_device(uint8_t serial_bus_type, uint8_t flags,
|
||||
uint16_t type_flags,
|
||||
|
||||
@@ -142,7 +142,7 @@ void build_ged_aml(Aml *table, const char *name, HotplugHandler *hotplug_dev,
|
||||
}
|
||||
|
||||
/* Memory read by the GED _EVT AML dynamic method */
|
||||
static uint64_t ged_read(void *opaque, hwaddr addr, unsigned size)
|
||||
static uint64_t ged_evt_read(void *opaque, hwaddr addr, unsigned size)
|
||||
{
|
||||
uint64_t val = 0;
|
||||
GEDState *ged_st = opaque;
|
||||
@@ -161,14 +161,14 @@ static uint64_t ged_read(void *opaque, hwaddr addr, unsigned size)
|
||||
}
|
||||
|
||||
/* Nothing is expected to be written to the GED memory region */
|
||||
static void ged_write(void *opaque, hwaddr addr, uint64_t data,
|
||||
unsigned int size)
|
||||
static void ged_evt_write(void *opaque, hwaddr addr, uint64_t data,
|
||||
unsigned int size)
|
||||
{
|
||||
}
|
||||
|
||||
static const MemoryRegionOps ged_ops = {
|
||||
.read = ged_read,
|
||||
.write = ged_write,
|
||||
static const MemoryRegionOps ged_evt_ops = {
|
||||
.read = ged_evt_read,
|
||||
.write = ged_evt_write,
|
||||
.endianness = DEVICE_LITTLE_ENDIAN,
|
||||
.valid = {
|
||||
.min_access_size = 4,
|
||||
@@ -287,9 +287,9 @@ static void acpi_ged_initfn(Object *obj)
|
||||
SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
|
||||
GEDState *ged_st = &s->ged_state;
|
||||
|
||||
memory_region_init_io(&ged_st->io, obj, &ged_ops, ged_st,
|
||||
memory_region_init_io(&ged_st->evt, obj, &ged_evt_ops, ged_st,
|
||||
TYPE_ACPI_GED, ACPI_GED_EVT_SEL_LEN);
|
||||
sysbus_init_mmio(sbd, &ged_st->io);
|
||||
sysbus_init_mmio(sbd, &ged_st->evt);
|
||||
|
||||
sysbus_init_irq(sbd, &s->irq);
|
||||
|
||||
|
||||
@@ -28,6 +28,7 @@
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "qemu/uuid.h"
|
||||
#include "qapi/error.h"
|
||||
#include "hw/acpi/acpi.h"
|
||||
#include "hw/acpi/aml-build.h"
|
||||
#include "hw/acpi/bios-linker-loader.h"
|
||||
@@ -1334,6 +1335,28 @@ static void nvdimm_build_ssdt(GArray *table_offsets, GArray *table_data,
|
||||
free_aml_allocator();
|
||||
}
|
||||
|
||||
void nvdimm_build_srat(GArray *table_data)
|
||||
{
|
||||
GSList *device_list = nvdimm_get_device_list();
|
||||
|
||||
for (; device_list; device_list = device_list->next) {
|
||||
AcpiSratMemoryAffinity *numamem = NULL;
|
||||
DeviceState *dev = device_list->data;
|
||||
Object *obj = OBJECT(dev);
|
||||
uint64_t addr, size;
|
||||
int node;
|
||||
|
||||
node = object_property_get_int(obj, PC_DIMM_NODE_PROP, &error_abort);
|
||||
addr = object_property_get_uint(obj, PC_DIMM_ADDR_PROP, &error_abort);
|
||||
size = object_property_get_uint(obj, PC_DIMM_SIZE_PROP, &error_abort);
|
||||
|
||||
numamem = acpi_data_push(table_data, sizeof *numamem);
|
||||
build_srat_memory(numamem, addr, size, node,
|
||||
MEM_AFFINITY_ENABLED | MEM_AFFINITY_NON_VOLATILE);
|
||||
}
|
||||
g_slist_free(device_list);
|
||||
}
|
||||
|
||||
void nvdimm_build_acpi(GArray *table_offsets, GArray *table_data,
|
||||
BIOSLinker *linker, NVDIMMState *state,
|
||||
uint32_t ram_slots)
|
||||
|
||||
@@ -41,12 +41,14 @@
|
||||
#include "hw/acpi/pci.h"
|
||||
#include "hw/acpi/memory_hotplug.h"
|
||||
#include "hw/acpi/generic_event_device.h"
|
||||
#include "hw/acpi/tpm.h"
|
||||
#include "hw/pci/pcie_host.h"
|
||||
#include "hw/pci/pci.h"
|
||||
#include "hw/arm/virt.h"
|
||||
#include "hw/mem/nvdimm.h"
|
||||
#include "sysemu/numa.h"
|
||||
#include "sysemu/reset.h"
|
||||
#include "sysemu/tpm.h"
|
||||
#include "kvm_arm.h"
|
||||
#include "migration/vmstate.h"
|
||||
#include "hw/acpi/ghes.h"
|
||||
@@ -539,6 +541,10 @@ build_srat(GArray *table_data, BIOSLinker *linker, VirtMachineState *vms)
|
||||
}
|
||||
}
|
||||
|
||||
if (ms->nvdimms_state->is_enabled) {
|
||||
nvdimm_build_srat(table_data);
|
||||
}
|
||||
|
||||
if (ms->device_memory) {
|
||||
numamem = acpi_data_push(table_data, sizeof *numamem);
|
||||
build_srat_memory(numamem, ms->device_memory->base,
|
||||
@@ -844,6 +850,11 @@ void virt_acpi_build(VirtMachineState *vms, AcpiBuildTables *tables)
|
||||
build_iort(tables_blob, tables->linker, vms);
|
||||
}
|
||||
|
||||
if (tpm_get_version(tpm_find()) == TPM_VERSION_2_0) {
|
||||
acpi_add_table(table_offsets, tables_blob);
|
||||
build_tpm2(tables_blob, tables->linker, tables->tcpalog);
|
||||
}
|
||||
|
||||
/* XSDT is pointed to by RSDP */
|
||||
xsdt = tables_blob->len;
|
||||
build_xsdt(tables_blob, tables->linker, table_offsets, NULL, NULL);
|
||||
|
||||
@@ -349,6 +349,19 @@ static void vhost_user_blk_disconnect(DeviceState *dev)
|
||||
vhost_dev_cleanup(&s->dev);
|
||||
}
|
||||
|
||||
static void vhost_user_blk_event(void *opaque, QEMUChrEvent event);
|
||||
|
||||
static void vhost_user_blk_chr_closed_bh(void *opaque)
|
||||
{
|
||||
DeviceState *dev = opaque;
|
||||
VirtIODevice *vdev = VIRTIO_DEVICE(dev);
|
||||
VHostUserBlk *s = VHOST_USER_BLK(vdev);
|
||||
|
||||
vhost_user_blk_disconnect(dev);
|
||||
qemu_chr_fe_set_handlers(&s->chardev, NULL, NULL, vhost_user_blk_event,
|
||||
NULL, opaque, NULL, true);
|
||||
}
|
||||
|
||||
static void vhost_user_blk_event(void *opaque, QEMUChrEvent event)
|
||||
{
|
||||
DeviceState *dev = opaque;
|
||||
@@ -363,7 +376,30 @@ static void vhost_user_blk_event(void *opaque, QEMUChrEvent event)
|
||||
}
|
||||
break;
|
||||
case CHR_EVENT_CLOSED:
|
||||
vhost_user_blk_disconnect(dev);
|
||||
/*
|
||||
* A close event may happen during a read/write, but vhost
|
||||
* code assumes the vhost_dev remains setup, so delay the
|
||||
* stop & clear. There are two possible paths to hit this
|
||||
* disconnect event:
|
||||
* 1. When VM is in the RUN_STATE_PRELAUNCH state. The
|
||||
* vhost_user_blk_device_realize() is a caller.
|
||||
* 2. In tha main loop phase after VM start.
|
||||
*
|
||||
* For p2 the disconnect event will be delayed. We can't
|
||||
* do the same for p1, because we are not running the loop
|
||||
* at this moment. So just skip this step and perform
|
||||
* disconnect in the caller function.
|
||||
*
|
||||
* TODO: maybe it is a good idea to make the same fix
|
||||
* for other vhost-user devices.
|
||||
*/
|
||||
if (runstate_is_running()) {
|
||||
AioContext *ctx = qemu_get_current_aio_context();
|
||||
|
||||
qemu_chr_fe_set_handlers(&s->chardev, NULL, NULL, NULL, NULL,
|
||||
NULL, NULL, false);
|
||||
aio_bh_schedule_oneshot(ctx, vhost_user_blk_chr_closed_bh, opaque);
|
||||
}
|
||||
break;
|
||||
case CHR_EVENT_BREAK:
|
||||
case CHR_EVENT_MUX_IN:
|
||||
|
||||
@@ -28,6 +28,7 @@
|
||||
#include "qemu/module.h"
|
||||
#include "chardev/char-parallel.h"
|
||||
#include "chardev/char-fe.h"
|
||||
#include "hw/acpi/aml-build.h"
|
||||
#include "hw/irq.h"
|
||||
#include "hw/isa/isa.h"
|
||||
#include "hw/qdev-properties.h"
|
||||
@@ -568,6 +569,25 @@ static void parallel_isa_realizefn(DeviceState *dev, Error **errp)
|
||||
s, "parallel");
|
||||
}
|
||||
|
||||
static void parallel_isa_build_aml(ISADevice *isadev, Aml *scope)
|
||||
{
|
||||
ISAParallelState *isa = ISA_PARALLEL(isadev);
|
||||
Aml *dev;
|
||||
Aml *crs;
|
||||
|
||||
crs = aml_resource_template();
|
||||
aml_append(crs, aml_io(AML_DECODE16, isa->iobase, isa->iobase, 0x08, 0x08));
|
||||
aml_append(crs, aml_irq_no_flags(isa->isairq));
|
||||
|
||||
dev = aml_device("LPT%d", isa->index + 1);
|
||||
aml_append(dev, aml_name_decl("_HID", aml_eisaid("PNP0400")));
|
||||
aml_append(dev, aml_name_decl("_UID", aml_int(isa->index + 1)));
|
||||
aml_append(dev, aml_name_decl("_STA", aml_int(0xf)));
|
||||
aml_append(dev, aml_name_decl("_CRS", crs));
|
||||
|
||||
aml_append(scope, dev);
|
||||
}
|
||||
|
||||
/* Memory mapped interface */
|
||||
static uint64_t parallel_mm_readfn(void *opaque, hwaddr addr, unsigned size)
|
||||
{
|
||||
@@ -624,9 +644,11 @@ static Property parallel_isa_properties[] = {
|
||||
static void parallel_isa_class_initfn(ObjectClass *klass, void *data)
|
||||
{
|
||||
DeviceClass *dc = DEVICE_CLASS(klass);
|
||||
ISADeviceClass *isa = ISA_DEVICE_CLASS(klass);
|
||||
|
||||
dc->realize = parallel_isa_realizefn;
|
||||
dc->vmsd = &vmstate_parallel_isa;
|
||||
isa->build_aml = parallel_isa_build_aml;
|
||||
device_class_set_props(dc, parallel_isa_properties);
|
||||
set_bit(DEVICE_CATEGORY_INPUT, dc->categories);
|
||||
}
|
||||
|
||||
@@ -27,6 +27,7 @@
|
||||
#include "qapi/error.h"
|
||||
#include "qemu/module.h"
|
||||
#include "sysemu/sysemu.h"
|
||||
#include "hw/acpi/aml-build.h"
|
||||
#include "hw/char/serial.h"
|
||||
#include "hw/isa/isa.h"
|
||||
#include "hw/qdev-properties.h"
|
||||
@@ -81,6 +82,25 @@ static void serial_isa_realizefn(DeviceState *dev, Error **errp)
|
||||
isa_register_ioport(isadev, &s->io, isa->iobase);
|
||||
}
|
||||
|
||||
static void serial_isa_build_aml(ISADevice *isadev, Aml *scope)
|
||||
{
|
||||
ISASerialState *isa = ISA_SERIAL(isadev);
|
||||
Aml *dev;
|
||||
Aml *crs;
|
||||
|
||||
crs = aml_resource_template();
|
||||
aml_append(crs, aml_io(AML_DECODE16, isa->iobase, isa->iobase, 0x00, 0x08));
|
||||
aml_append(crs, aml_irq_no_flags(isa->isairq));
|
||||
|
||||
dev = aml_device("COM%d", isa->index + 1);
|
||||
aml_append(dev, aml_name_decl("_HID", aml_eisaid("PNP0501")));
|
||||
aml_append(dev, aml_name_decl("_UID", aml_int(isa->index + 1)));
|
||||
aml_append(dev, aml_name_decl("_STA", aml_int(0xf)));
|
||||
aml_append(dev, aml_name_decl("_CRS", crs));
|
||||
|
||||
aml_append(scope, dev);
|
||||
}
|
||||
|
||||
static const VMStateDescription vmstate_isa_serial = {
|
||||
.name = "serial",
|
||||
.version_id = 3,
|
||||
@@ -103,9 +123,11 @@ static Property serial_isa_properties[] = {
|
||||
static void serial_isa_class_initfn(ObjectClass *klass, void *data)
|
||||
{
|
||||
DeviceClass *dc = DEVICE_CLASS(klass);
|
||||
ISADeviceClass *isa = ISA_DEVICE_CLASS(klass);
|
||||
|
||||
dc->realize = serial_isa_realizefn;
|
||||
dc->vmsd = &vmstate_isa_serial;
|
||||
isa->build_aml = serial_isa_build_aml;
|
||||
device_class_set_props(dc, serial_isa_properties);
|
||||
set_bit(DEVICE_CATEGORY_INPUT, dc->categories);
|
||||
}
|
||||
|
||||
+3
-1
@@ -28,7 +28,9 @@
|
||||
#include "hw/mem/nvdimm.h"
|
||||
#include "migration/vmstate.h"
|
||||
|
||||
GlobalProperty hw_compat_5_0[] = {};
|
||||
GlobalProperty hw_compat_5_0[] = {
|
||||
{ "virtio-balloon-device", "page-poison", "false" },
|
||||
};
|
||||
const size_t hw_compat_5_0_len = G_N_ELEMENTS(hw_compat_5_0);
|
||||
|
||||
GlobalProperty hw_compat_4_2[] = {
|
||||
|
||||
@@ -16,4 +16,5 @@ obj-$(CONFIG_VMMOUSE) += vmmouse.o
|
||||
obj-$(CONFIG_PC) += port92.o
|
||||
|
||||
obj-y += kvmvapic.o
|
||||
obj-$(CONFIG_ACPI) += acpi-common.o
|
||||
obj-$(CONFIG_PC) += acpi-build.o
|
||||
|
||||
+12
-258
@@ -24,6 +24,7 @@
|
||||
#include "qapi/error.h"
|
||||
#include "qapi/qmp/qnum.h"
|
||||
#include "acpi-build.h"
|
||||
#include "acpi-common.h"
|
||||
#include "qemu/bitmap.h"
|
||||
#include "qemu/error-report.h"
|
||||
#include "hw/pci/pci.h"
|
||||
@@ -89,9 +90,6 @@
|
||||
#define ACPI_BUILD_DPRINTF(fmt, ...)
|
||||
#endif
|
||||
|
||||
/* Default IOAPIC ID */
|
||||
#define ACPI_BUILD_IOAPIC_ID 0x0
|
||||
|
||||
typedef struct AcpiPmInfo {
|
||||
bool s3_disabled;
|
||||
bool s4_disabled;
|
||||
@@ -327,125 +325,6 @@ build_facs(GArray *table_data)
|
||||
facs->length = cpu_to_le32(sizeof(*facs));
|
||||
}
|
||||
|
||||
void pc_madt_cpu_entry(AcpiDeviceIf *adev, int uid,
|
||||
const CPUArchIdList *apic_ids, GArray *entry)
|
||||
{
|
||||
uint32_t apic_id = apic_ids->cpus[uid].arch_id;
|
||||
|
||||
/* ACPI spec says that LAPIC entry for non present
|
||||
* CPU may be omitted from MADT or it must be marked
|
||||
* as disabled. However omitting non present CPU from
|
||||
* MADT breaks hotplug on linux. So possible CPUs
|
||||
* should be put in MADT but kept disabled.
|
||||
*/
|
||||
if (apic_id < 255) {
|
||||
AcpiMadtProcessorApic *apic = acpi_data_push(entry, sizeof *apic);
|
||||
|
||||
apic->type = ACPI_APIC_PROCESSOR;
|
||||
apic->length = sizeof(*apic);
|
||||
apic->processor_id = uid;
|
||||
apic->local_apic_id = apic_id;
|
||||
if (apic_ids->cpus[uid].cpu != NULL) {
|
||||
apic->flags = cpu_to_le32(1);
|
||||
} else {
|
||||
apic->flags = cpu_to_le32(0);
|
||||
}
|
||||
} else {
|
||||
AcpiMadtProcessorX2Apic *apic = acpi_data_push(entry, sizeof *apic);
|
||||
|
||||
apic->type = ACPI_APIC_LOCAL_X2APIC;
|
||||
apic->length = sizeof(*apic);
|
||||
apic->uid = cpu_to_le32(uid);
|
||||
apic->x2apic_id = cpu_to_le32(apic_id);
|
||||
if (apic_ids->cpus[uid].cpu != NULL) {
|
||||
apic->flags = cpu_to_le32(1);
|
||||
} else {
|
||||
apic->flags = cpu_to_le32(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
build_madt(GArray *table_data, BIOSLinker *linker, PCMachineState *pcms)
|
||||
{
|
||||
MachineClass *mc = MACHINE_GET_CLASS(pcms);
|
||||
X86MachineState *x86ms = X86_MACHINE(pcms);
|
||||
const CPUArchIdList *apic_ids = mc->possible_cpu_arch_ids(MACHINE(pcms));
|
||||
int madt_start = table_data->len;
|
||||
AcpiDeviceIfClass *adevc = ACPI_DEVICE_IF_GET_CLASS(pcms->acpi_dev);
|
||||
AcpiDeviceIf *adev = ACPI_DEVICE_IF(pcms->acpi_dev);
|
||||
bool x2apic_mode = false;
|
||||
|
||||
AcpiMultipleApicTable *madt;
|
||||
AcpiMadtIoApic *io_apic;
|
||||
AcpiMadtIntsrcovr *intsrcovr;
|
||||
int i;
|
||||
|
||||
madt = acpi_data_push(table_data, sizeof *madt);
|
||||
madt->local_apic_address = cpu_to_le32(APIC_DEFAULT_ADDRESS);
|
||||
madt->flags = cpu_to_le32(1);
|
||||
|
||||
for (i = 0; i < apic_ids->len; i++) {
|
||||
adevc->madt_cpu(adev, i, apic_ids, table_data);
|
||||
if (apic_ids->cpus[i].arch_id > 254) {
|
||||
x2apic_mode = true;
|
||||
}
|
||||
}
|
||||
|
||||
io_apic = acpi_data_push(table_data, sizeof *io_apic);
|
||||
io_apic->type = ACPI_APIC_IO;
|
||||
io_apic->length = sizeof(*io_apic);
|
||||
io_apic->io_apic_id = ACPI_BUILD_IOAPIC_ID;
|
||||
io_apic->address = cpu_to_le32(IO_APIC_DEFAULT_ADDRESS);
|
||||
io_apic->interrupt = cpu_to_le32(0);
|
||||
|
||||
if (x86ms->apic_xrupt_override) {
|
||||
intsrcovr = acpi_data_push(table_data, sizeof *intsrcovr);
|
||||
intsrcovr->type = ACPI_APIC_XRUPT_OVERRIDE;
|
||||
intsrcovr->length = sizeof(*intsrcovr);
|
||||
intsrcovr->source = 0;
|
||||
intsrcovr->gsi = cpu_to_le32(2);
|
||||
intsrcovr->flags = cpu_to_le16(0); /* conforms to bus specifications */
|
||||
}
|
||||
for (i = 1; i < 16; i++) {
|
||||
#define ACPI_BUILD_PCI_IRQS ((1<<5) | (1<<9) | (1<<10) | (1<<11))
|
||||
if (!(ACPI_BUILD_PCI_IRQS & (1 << i))) {
|
||||
/* No need for a INT source override structure. */
|
||||
continue;
|
||||
}
|
||||
intsrcovr = acpi_data_push(table_data, sizeof *intsrcovr);
|
||||
intsrcovr->type = ACPI_APIC_XRUPT_OVERRIDE;
|
||||
intsrcovr->length = sizeof(*intsrcovr);
|
||||
intsrcovr->source = i;
|
||||
intsrcovr->gsi = cpu_to_le32(i);
|
||||
intsrcovr->flags = cpu_to_le16(0xd); /* active high, level triggered */
|
||||
}
|
||||
|
||||
if (x2apic_mode) {
|
||||
AcpiMadtLocalX2ApicNmi *local_nmi;
|
||||
|
||||
local_nmi = acpi_data_push(table_data, sizeof *local_nmi);
|
||||
local_nmi->type = ACPI_APIC_LOCAL_X2APIC_NMI;
|
||||
local_nmi->length = sizeof(*local_nmi);
|
||||
local_nmi->uid = 0xFFFFFFFF; /* all processors */
|
||||
local_nmi->flags = cpu_to_le16(0);
|
||||
local_nmi->lint = 1; /* ACPI_LINT1 */
|
||||
} else {
|
||||
AcpiMadtLocalNmi *local_nmi;
|
||||
|
||||
local_nmi = acpi_data_push(table_data, sizeof *local_nmi);
|
||||
local_nmi->type = ACPI_APIC_LOCAL_NMI;
|
||||
local_nmi->length = sizeof(*local_nmi);
|
||||
local_nmi->processor_id = 0xff; /* all processors */
|
||||
local_nmi->flags = cpu_to_le16(0);
|
||||
local_nmi->lint = 1; /* ACPI_LINT1 */
|
||||
}
|
||||
|
||||
build_header(linker, table_data,
|
||||
(void *)(table_data->data + madt_start), "APIC",
|
||||
table_data->len - madt_start, 1, NULL, NULL);
|
||||
}
|
||||
|
||||
static void build_append_pcihp_notify_entry(Aml *method, int slot)
|
||||
{
|
||||
Aml *if_ctx;
|
||||
@@ -1137,22 +1016,6 @@ static Aml *build_fdc_device_aml(ISADevice *fdc)
|
||||
return dev;
|
||||
}
|
||||
|
||||
static Aml *build_rtc_device_aml(void)
|
||||
{
|
||||
Aml *dev;
|
||||
Aml *crs;
|
||||
|
||||
dev = aml_device("RTC");
|
||||
aml_append(dev, aml_name_decl("_HID", aml_eisaid("PNP0B00")));
|
||||
crs = aml_resource_template();
|
||||
aml_append(crs, aml_io(AML_DECODE16, 0x0070, 0x0070, 0x10, 0x02));
|
||||
aml_append(crs, aml_irq_no_flags(8));
|
||||
aml_append(crs, aml_io(AML_DECODE16, 0x0072, 0x0072, 0x02, 0x06));
|
||||
aml_append(dev, aml_name_decl("_CRS", crs));
|
||||
|
||||
return dev;
|
||||
}
|
||||
|
||||
static Aml *build_kbd_device_aml(void)
|
||||
{
|
||||
Aml *dev;
|
||||
@@ -1189,87 +1052,6 @@ static Aml *build_mouse_device_aml(void)
|
||||
return dev;
|
||||
}
|
||||
|
||||
static Aml *build_lpt_device_aml(void)
|
||||
{
|
||||
Aml *dev;
|
||||
Aml *crs;
|
||||
Aml *method;
|
||||
Aml *if_ctx;
|
||||
Aml *else_ctx;
|
||||
Aml *zero = aml_int(0);
|
||||
Aml *is_present = aml_local(0);
|
||||
|
||||
dev = aml_device("LPT");
|
||||
aml_append(dev, aml_name_decl("_HID", aml_eisaid("PNP0400")));
|
||||
|
||||
method = aml_method("_STA", 0, AML_NOTSERIALIZED);
|
||||
aml_append(method, aml_store(aml_name("LPEN"), is_present));
|
||||
if_ctx = aml_if(aml_equal(is_present, zero));
|
||||
{
|
||||
aml_append(if_ctx, aml_return(aml_int(0x00)));
|
||||
}
|
||||
aml_append(method, if_ctx);
|
||||
else_ctx = aml_else();
|
||||
{
|
||||
aml_append(else_ctx, aml_return(aml_int(0x0f)));
|
||||
}
|
||||
aml_append(method, else_ctx);
|
||||
aml_append(dev, method);
|
||||
|
||||
crs = aml_resource_template();
|
||||
aml_append(crs, aml_io(AML_DECODE16, 0x0378, 0x0378, 0x08, 0x08));
|
||||
aml_append(crs, aml_irq_no_flags(7));
|
||||
aml_append(dev, aml_name_decl("_CRS", crs));
|
||||
|
||||
return dev;
|
||||
}
|
||||
|
||||
static Aml *build_com_device_aml(uint8_t uid)
|
||||
{
|
||||
Aml *dev;
|
||||
Aml *crs;
|
||||
Aml *method;
|
||||
Aml *if_ctx;
|
||||
Aml *else_ctx;
|
||||
Aml *zero = aml_int(0);
|
||||
Aml *is_present = aml_local(0);
|
||||
const char *enabled_field = "CAEN";
|
||||
uint8_t irq = 4;
|
||||
uint16_t io_port = 0x03F8;
|
||||
|
||||
assert(uid == 1 || uid == 2);
|
||||
if (uid == 2) {
|
||||
enabled_field = "CBEN";
|
||||
irq = 3;
|
||||
io_port = 0x02F8;
|
||||
}
|
||||
|
||||
dev = aml_device("COM%d", uid);
|
||||
aml_append(dev, aml_name_decl("_HID", aml_eisaid("PNP0501")));
|
||||
aml_append(dev, aml_name_decl("_UID", aml_int(uid)));
|
||||
|
||||
method = aml_method("_STA", 0, AML_NOTSERIALIZED);
|
||||
aml_append(method, aml_store(aml_name("%s", enabled_field), is_present));
|
||||
if_ctx = aml_if(aml_equal(is_present, zero));
|
||||
{
|
||||
aml_append(if_ctx, aml_return(aml_int(0x00)));
|
||||
}
|
||||
aml_append(method, if_ctx);
|
||||
else_ctx = aml_else();
|
||||
{
|
||||
aml_append(else_ctx, aml_return(aml_int(0x0f)));
|
||||
}
|
||||
aml_append(method, else_ctx);
|
||||
aml_append(dev, method);
|
||||
|
||||
crs = aml_resource_template();
|
||||
aml_append(crs, aml_io(AML_DECODE16, io_port, io_port, 0x00, 0x08));
|
||||
aml_append(crs, aml_irq_no_flags(irq));
|
||||
aml_append(dev, aml_name_decl("_CRS", crs));
|
||||
|
||||
return dev;
|
||||
}
|
||||
|
||||
static void build_isa_devices_aml(Aml *table)
|
||||
{
|
||||
ISADevice *fdc = pc_find_fdc0();
|
||||
@@ -1278,15 +1060,11 @@ static void build_isa_devices_aml(Aml *table)
|
||||
Aml *scope = aml_scope("_SB.PCI0.ISA");
|
||||
Object *obj = object_resolve_path_type("", TYPE_ISA_BUS, &ambiguous);
|
||||
|
||||
aml_append(scope, build_rtc_device_aml());
|
||||
aml_append(scope, build_kbd_device_aml());
|
||||
aml_append(scope, build_mouse_device_aml());
|
||||
if (fdc) {
|
||||
aml_append(scope, build_fdc_device_aml(fdc));
|
||||
}
|
||||
aml_append(scope, build_lpt_device_aml());
|
||||
aml_append(scope, build_com_device_aml(1));
|
||||
aml_append(scope, build_com_device_aml(2));
|
||||
|
||||
if (ambiguous) {
|
||||
error_report("Multiple ISA busses, unable to define IPMI ACPI data");
|
||||
@@ -2295,36 +2073,6 @@ build_tpm_tcpa(GArray *table_data, BIOSLinker *linker, GArray *tcpalog)
|
||||
(void *)tcpa, "TCPA", sizeof(*tcpa), 2, NULL, NULL);
|
||||
}
|
||||
|
||||
static void
|
||||
build_tpm2(GArray *table_data, BIOSLinker *linker, GArray *tcpalog)
|
||||
{
|
||||
Acpi20TPM2 *tpm2_ptr = acpi_data_push(table_data, sizeof *tpm2_ptr);
|
||||
unsigned log_addr_size = sizeof(tpm2_ptr->log_area_start_address);
|
||||
unsigned log_addr_offset =
|
||||
(char *)&tpm2_ptr->log_area_start_address - table_data->data;
|
||||
|
||||
tpm2_ptr->platform_class = cpu_to_le16(TPM2_ACPI_CLASS_CLIENT);
|
||||
if (TPM_IS_TIS_ISA(tpm_find())) {
|
||||
tpm2_ptr->control_area_address = cpu_to_le64(0);
|
||||
tpm2_ptr->start_method = cpu_to_le32(TPM2_START_METHOD_MMIO);
|
||||
} else if (TPM_IS_CRB(tpm_find())) {
|
||||
tpm2_ptr->control_area_address = cpu_to_le64(TPM_CRB_ADDR_CTRL);
|
||||
tpm2_ptr->start_method = cpu_to_le32(TPM2_START_METHOD_CRB);
|
||||
} else {
|
||||
g_warn_if_reached();
|
||||
}
|
||||
|
||||
tpm2_ptr->log_area_minimum_length =
|
||||
cpu_to_le32(TPM_LOG_AREA_MINIMUM_SIZE);
|
||||
|
||||
/* log area start address to be filled by Guest linker */
|
||||
bios_linker_loader_add_pointer(linker, ACPI_BUILD_TABLE_FILE,
|
||||
log_addr_offset, log_addr_size,
|
||||
ACPI_BUILD_TPMLOG_FILE, 0);
|
||||
build_header(linker, table_data,
|
||||
(void *)tpm2_ptr, "TPM2", sizeof(*tpm2_ptr), 4, NULL, NULL);
|
||||
}
|
||||
|
||||
#define HOLE_640K_START (640 * KiB)
|
||||
#define HOLE_640K_END (1 * MiB)
|
||||
|
||||
@@ -2428,6 +2176,11 @@ build_srat(GArray *table_data, BIOSLinker *linker, MachineState *machine)
|
||||
MEM_AFFINITY_ENABLED);
|
||||
}
|
||||
}
|
||||
|
||||
if (machine->nvdimms_state->is_enabled) {
|
||||
nvdimm_build_srat(table_data);
|
||||
}
|
||||
|
||||
slots = (table_data->len - numa_start) / sizeof *numamem;
|
||||
for (; slots < pcms->numa_nodes + 2; slots++) {
|
||||
numamem = acpi_data_push(table_data, sizeof *numamem);
|
||||
@@ -2834,7 +2587,8 @@ void acpi_build(AcpiBuildTables *tables, MachineState *machine)
|
||||
aml_len += tables_blob->len - fadt;
|
||||
|
||||
acpi_add_table(table_offsets, tables_blob);
|
||||
build_madt(tables_blob, tables->linker, pcms);
|
||||
acpi_build_madt(tables_blob, tables->linker, x86ms,
|
||||
ACPI_DEVICE_IF(pcms->acpi_dev), true);
|
||||
|
||||
vmgenid_dev = find_vmgenid_dev();
|
||||
if (vmgenid_dev) {
|
||||
@@ -2848,10 +2602,10 @@ void acpi_build(AcpiBuildTables *tables, MachineState *machine)
|
||||
build_hpet(tables_blob, tables->linker);
|
||||
}
|
||||
if (misc.tpm_version != TPM_VERSION_UNSPEC) {
|
||||
acpi_add_table(table_offsets, tables_blob);
|
||||
build_tpm_tcpa(tables_blob, tables->linker, tables->tcpalog);
|
||||
|
||||
if (misc.tpm_version == TPM_VERSION_2_0) {
|
||||
if (misc.tpm_version == TPM_VERSION_1_2) {
|
||||
acpi_add_table(table_offsets, tables_blob);
|
||||
build_tpm_tcpa(tables_blob, tables->linker, tables->tcpalog);
|
||||
} else { /* TPM_VERSION_2_0 */
|
||||
acpi_add_table(table_offsets, tables_blob);
|
||||
build_tpm2(tables_blob, tables->linker, tables->tcpalog);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,156 @@
|
||||
/* Support for generating ACPI tables and passing them to Guests
|
||||
*
|
||||
* 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>
|
||||
*
|
||||
* 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/osdep.h"
|
||||
#include "qapi/error.h"
|
||||
|
||||
#include "exec/memory.h"
|
||||
#include "hw/acpi/acpi.h"
|
||||
#include "hw/acpi/aml-build.h"
|
||||
#include "hw/acpi/utils.h"
|
||||
#include "hw/i386/pc.h"
|
||||
#include "target/i386/cpu.h"
|
||||
|
||||
#include "acpi-build.h"
|
||||
#include "acpi-common.h"
|
||||
|
||||
void pc_madt_cpu_entry(AcpiDeviceIf *adev, int uid,
|
||||
const CPUArchIdList *apic_ids, GArray *entry)
|
||||
{
|
||||
uint32_t apic_id = apic_ids->cpus[uid].arch_id;
|
||||
|
||||
/* ACPI spec says that LAPIC entry for non present
|
||||
* CPU may be omitted from MADT or it must be marked
|
||||
* as disabled. However omitting non present CPU from
|
||||
* MADT breaks hotplug on linux. So possible CPUs
|
||||
* should be put in MADT but kept disabled.
|
||||
*/
|
||||
if (apic_id < 255) {
|
||||
AcpiMadtProcessorApic *apic = acpi_data_push(entry, sizeof *apic);
|
||||
|
||||
apic->type = ACPI_APIC_PROCESSOR;
|
||||
apic->length = sizeof(*apic);
|
||||
apic->processor_id = uid;
|
||||
apic->local_apic_id = apic_id;
|
||||
if (apic_ids->cpus[uid].cpu != NULL) {
|
||||
apic->flags = cpu_to_le32(1);
|
||||
} else {
|
||||
apic->flags = cpu_to_le32(0);
|
||||
}
|
||||
} else {
|
||||
AcpiMadtProcessorX2Apic *apic = acpi_data_push(entry, sizeof *apic);
|
||||
|
||||
apic->type = ACPI_APIC_LOCAL_X2APIC;
|
||||
apic->length = sizeof(*apic);
|
||||
apic->uid = cpu_to_le32(uid);
|
||||
apic->x2apic_id = cpu_to_le32(apic_id);
|
||||
if (apic_ids->cpus[uid].cpu != NULL) {
|
||||
apic->flags = cpu_to_le32(1);
|
||||
} else {
|
||||
apic->flags = cpu_to_le32(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void acpi_build_madt(GArray *table_data, BIOSLinker *linker,
|
||||
X86MachineState *x86ms, AcpiDeviceIf *adev,
|
||||
bool has_pci)
|
||||
{
|
||||
MachineClass *mc = MACHINE_GET_CLASS(x86ms);
|
||||
const CPUArchIdList *apic_ids = mc->possible_cpu_arch_ids(MACHINE(x86ms));
|
||||
int madt_start = table_data->len;
|
||||
AcpiDeviceIfClass *adevc = ACPI_DEVICE_IF_GET_CLASS(adev);
|
||||
bool x2apic_mode = false;
|
||||
|
||||
AcpiMultipleApicTable *madt;
|
||||
AcpiMadtIoApic *io_apic;
|
||||
AcpiMadtIntsrcovr *intsrcovr;
|
||||
int i;
|
||||
|
||||
madt = acpi_data_push(table_data, sizeof *madt);
|
||||
madt->local_apic_address = cpu_to_le32(APIC_DEFAULT_ADDRESS);
|
||||
madt->flags = cpu_to_le32(1);
|
||||
|
||||
for (i = 0; i < apic_ids->len; i++) {
|
||||
adevc->madt_cpu(adev, i, apic_ids, table_data);
|
||||
if (apic_ids->cpus[i].arch_id > 254) {
|
||||
x2apic_mode = true;
|
||||
}
|
||||
}
|
||||
|
||||
io_apic = acpi_data_push(table_data, sizeof *io_apic);
|
||||
io_apic->type = ACPI_APIC_IO;
|
||||
io_apic->length = sizeof(*io_apic);
|
||||
io_apic->io_apic_id = ACPI_BUILD_IOAPIC_ID;
|
||||
io_apic->address = cpu_to_le32(IO_APIC_DEFAULT_ADDRESS);
|
||||
io_apic->interrupt = cpu_to_le32(0);
|
||||
|
||||
if (x86ms->apic_xrupt_override) {
|
||||
intsrcovr = acpi_data_push(table_data, sizeof *intsrcovr);
|
||||
intsrcovr->type = ACPI_APIC_XRUPT_OVERRIDE;
|
||||
intsrcovr->length = sizeof(*intsrcovr);
|
||||
intsrcovr->source = 0;
|
||||
intsrcovr->gsi = cpu_to_le32(2);
|
||||
intsrcovr->flags = cpu_to_le16(0); /* conforms to bus specifications */
|
||||
}
|
||||
|
||||
if (has_pci) {
|
||||
for (i = 1; i < 16; i++) {
|
||||
#define ACPI_BUILD_PCI_IRQS ((1<<5) | (1<<9) | (1<<10) | (1<<11))
|
||||
if (!(ACPI_BUILD_PCI_IRQS & (1 << i))) {
|
||||
/* No need for a INT source override structure. */
|
||||
continue;
|
||||
}
|
||||
intsrcovr = acpi_data_push(table_data, sizeof *intsrcovr);
|
||||
intsrcovr->type = ACPI_APIC_XRUPT_OVERRIDE;
|
||||
intsrcovr->length = sizeof(*intsrcovr);
|
||||
intsrcovr->source = i;
|
||||
intsrcovr->gsi = cpu_to_le32(i);
|
||||
intsrcovr->flags = cpu_to_le16(0xd); /* active high, level triggered */
|
||||
}
|
||||
}
|
||||
|
||||
if (x2apic_mode) {
|
||||
AcpiMadtLocalX2ApicNmi *local_nmi;
|
||||
|
||||
local_nmi = acpi_data_push(table_data, sizeof *local_nmi);
|
||||
local_nmi->type = ACPI_APIC_LOCAL_X2APIC_NMI;
|
||||
local_nmi->length = sizeof(*local_nmi);
|
||||
local_nmi->uid = 0xFFFFFFFF; /* all processors */
|
||||
local_nmi->flags = cpu_to_le16(0);
|
||||
local_nmi->lint = 1; /* ACPI_LINT1 */
|
||||
} else {
|
||||
AcpiMadtLocalNmi *local_nmi;
|
||||
|
||||
local_nmi = acpi_data_push(table_data, sizeof *local_nmi);
|
||||
local_nmi->type = ACPI_APIC_LOCAL_NMI;
|
||||
local_nmi->length = sizeof(*local_nmi);
|
||||
local_nmi->processor_id = 0xff; /* all processors */
|
||||
local_nmi->flags = cpu_to_le16(0);
|
||||
local_nmi->lint = 1; /* ACPI_LINT1 */
|
||||
}
|
||||
|
||||
build_header(linker, table_data,
|
||||
(void *)(table_data->data + madt_start), "APIC",
|
||||
table_data->len - madt_start, 1, NULL, NULL);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
#ifndef HW_I386_ACPI_COMMON_H
|
||||
#define HW_I386_ACPI_COMMON_H
|
||||
#include "include/hw/acpi/acpi_dev_interface.h"
|
||||
|
||||
#include "include/hw/acpi/bios-linker-loader.h"
|
||||
#include "include/hw/i386/x86.h"
|
||||
|
||||
/* Default IOAPIC ID */
|
||||
#define ACPI_BUILD_IOAPIC_ID 0x0
|
||||
|
||||
void acpi_build_madt(GArray *table_data, BIOSLinker *linker,
|
||||
X86MachineState *x86ms, AcpiDeviceIf *adev,
|
||||
bool has_pci);
|
||||
|
||||
#endif
|
||||
@@ -23,6 +23,7 @@
|
||||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "qemu/units.h"
|
||||
#include "qemu/range.h"
|
||||
#include "hw/i386/pc.h"
|
||||
#include "hw/pci/pci.h"
|
||||
@@ -301,7 +302,7 @@ PCIBus *i440fx_init(const char *host_type, const char *pci_type,
|
||||
memory_region_set_enabled(&f->smram_region, true);
|
||||
|
||||
/* smram, as seen by SMM CPUs */
|
||||
memory_region_init(&f->smram, OBJECT(d), "smram", 1ull << 32);
|
||||
memory_region_init(&f->smram, OBJECT(d), "smram", 4 * GiB);
|
||||
memory_region_set_enabled(&f->smram, true);
|
||||
memory_region_init_alias(&f->low_smram, OBJECT(d), "smram-low",
|
||||
f->ram_memory, 0xa0000, 0x20000);
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user