Merge remote-tracking branch 'remotes/mst/tags/for_upstream' into staging

pc and misc cleanups and fixes, virtio optimizations

Included here:
Refactoring and bugfix patches in PC/ACPI.
New commands for ipmi.
Virtio optimizations.

Signed-off-by: Michael S. Tsirkin <mst@redhat.com>

# gpg: Signature made Sat 06 Feb 2016 18:44:26 GMT using RSA key ID D28D5469
# gpg: Good signature from "Michael S. Tsirkin <mst@kernel.org>"
# gpg:                 aka "Michael S. Tsirkin <mst@redhat.com>"

* remotes/mst/tags/for_upstream: (45 commits)
  net: set endianness on all backend devices
  fix MSI injection on Xen
  intel_iommu: large page support
  dimm: Correct type of MemoryHotplugState->base
  pc: set the OEM fields in the RSDT and the FADT from the SLIC
  acpi: add function to extract oem_id and oem_table_id from the user's SLIC
  acpi: expose oem_id and oem_table_id in build_rsdt()
  acpi: take oem_id in build_header(), optionally
  pc: Eliminate PcGuestInfo struct
  pc: Move APIC and NUMA data from PcGuestInfo to PCMachineState
  pc: Move PcGuestInfo.fw_cfg to PCMachineState
  pc: Remove PcGuestInfo.isapc_ram_fw field
  pc: Remove RAM size fields from PcGuestInfo
  pc: Remove compat fields from PcGuestInfo
  acpi: Don't save PcGuestInfo on AcpiBuildState
  acpi: Remove guest_info parameters from functions
  pc: Simplify xen_load_linux() signature
  pc: Simplify pc_memory_init() signature
  pc: Eliminate struct PcGuestInfoState
  pc: Move PcGuestInfo declaration to top of file
  ...

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
Peter Maydell
2016-02-08 11:25:31 +00:00
59 changed files with 1476 additions and 1122 deletions
+1 -1
View File
@@ -1587,7 +1587,7 @@ static int v9fs_xattr_read(V9fsState *s, V9fsPDU *pdu, V9fsFidState *fidp,
int read_count;
int64_t xattr_len;
V9fsVirtioState *v = container_of(s, V9fsVirtioState, state);
VirtQueueElement *elem = &v->elems[pdu->idx];
VirtQueueElement *elem = v->elems[pdu->idx];
xattr_len = fidp->fs.xattr.len;
read_count = xattr_len - off;
+10 -7
View File
@@ -26,10 +26,12 @@ void virtio_9p_push_and_notify(V9fsPDU *pdu)
{
V9fsState *s = pdu->s;
V9fsVirtioState *v = container_of(s, V9fsVirtioState, state);
VirtQueueElement *elem = &v->elems[pdu->idx];
VirtQueueElement *elem = v->elems[pdu->idx];
/* push onto queue and notify */
virtqueue_push(v->vq, elem, pdu->size);
g_free(elem);
v->elems[pdu->idx] = NULL;
/* FIXME: we should batch these completions */
virtio_notify(VIRTIO_DEVICE(v), v->vq);
@@ -48,10 +50,10 @@ static void handle_9p_output(VirtIODevice *vdev, VirtQueue *vq)
uint8_t id;
uint16_t tag_le;
} QEMU_PACKED out;
VirtQueueElement *elem = &v->elems[pdu->idx];
VirtQueueElement *elem;
len = virtqueue_pop(vq, elem);
if (!len) {
elem = virtqueue_pop(vq, sizeof(VirtQueueElement));
if (!elem) {
pdu_free(pdu);
break;
}
@@ -59,6 +61,7 @@ static void handle_9p_output(VirtIODevice *vdev, VirtQueue *vq)
BUG_ON(elem->out_num == 0 || elem->in_num == 0);
QEMU_BUILD_BUG_ON(sizeof out != 7);
v->elems[pdu->idx] = elem;
len = iov_to_buf(elem->out_sg, elem->out_num, 0,
&out, sizeof out);
BUG_ON(len != sizeof out);
@@ -141,7 +144,7 @@ ssize_t virtio_pdu_vmarshal(V9fsPDU *pdu, size_t offset,
{
V9fsState *s = pdu->s;
V9fsVirtioState *v = container_of(s, V9fsVirtioState, state);
VirtQueueElement *elem = &v->elems[pdu->idx];
VirtQueueElement *elem = v->elems[pdu->idx];
return v9fs_iov_vmarshal(elem->in_sg, elem->in_num, offset, 1, fmt, ap);
}
@@ -151,7 +154,7 @@ ssize_t virtio_pdu_vunmarshal(V9fsPDU *pdu, size_t offset,
{
V9fsState *s = pdu->s;
V9fsVirtioState *v = container_of(s, V9fsVirtioState, state);
VirtQueueElement *elem = &v->elems[pdu->idx];
VirtQueueElement *elem = v->elems[pdu->idx];
return v9fs_iov_vunmarshal(elem->out_sg, elem->out_num, offset, 1, fmt, ap);
}
@@ -161,7 +164,7 @@ void virtio_init_iov_from_pdu(V9fsPDU *pdu, struct iovec **piov,
{
V9fsState *s = pdu->s;
V9fsVirtioState *v = container_of(s, V9fsVirtioState, state);
VirtQueueElement *elem = &v->elems[pdu->idx];
VirtQueueElement *elem = v->elems[pdu->idx];
if (is_write) {
*piov = elem->out_sg;
+1 -1
View File
@@ -11,7 +11,7 @@ typedef struct V9fsVirtioState
VirtQueue *vq;
size_t config_size;
V9fsPDU pdus[MAX_REQ];
VirtQueueElement elems[MAX_REQ];
VirtQueueElement *elems[MAX_REQ];
V9fsState state;
} V9fsVirtioState;
+10 -4
View File
@@ -1426,12 +1426,17 @@ Aml *aml_alias(const char *source_object, const char *alias_object)
void
build_header(GArray *linker, GArray *table_data,
AcpiTableHeader *h, const char *sig, int len, uint8_t rev,
const char *oem_table_id)
const char *oem_id, const char *oem_table_id)
{
memcpy(&h->signature, sig, 4);
h->length = cpu_to_le32(len);
h->revision = rev;
memcpy(h->oem_id, ACPI_BUILD_APPNAME6, 6);
if (oem_id) {
strncpy((char *)h->oem_id, oem_id, sizeof h->oem_id);
} else {
memcpy(h->oem_id, ACPI_BUILD_APPNAME6, 6);
}
if (oem_table_id) {
strncpy((char *)h->oem_table_id, oem_table_id, sizeof(h->oem_table_id));
@@ -1487,7 +1492,8 @@ void acpi_build_tables_cleanup(AcpiBuildTables *tables, bool mfre)
/* Build rsdt table */
void
build_rsdt(GArray *table_data, GArray *linker, GArray *table_offsets)
build_rsdt(GArray *table_data, GArray *linker, GArray *table_offsets,
const char *oem_id, const char *oem_table_id)
{
AcpiRsdtDescriptorRev1 *rsdt;
size_t rsdt_len;
@@ -1506,5 +1512,5 @@ build_rsdt(GArray *table_data, GArray *linker, GArray *table_offsets)
sizeof(uint32_t));
}
build_header(linker, table_data,
(void *)rsdt, "RSDT", rsdt_len, 1, NULL);
(void *)rsdt, "RSDT", rsdt_len, 1, oem_id, oem_table_id);
}
+16
View File
@@ -350,6 +350,22 @@ uint8_t *acpi_table_next(uint8_t *current)
}
}
int acpi_get_slic_oem(AcpiSlicOem *oem)
{
uint8_t *u;
for (u = acpi_table_first(); u; u = acpi_table_next(u)) {
struct acpi_table_header *hdr = (void *)(u - sizeof(hdr->_length));
if (memcmp(hdr->sig, "SLIC", 4) == 0) {
oem->id = hdr->oem_id;
oem->table_id = hdr->oem_table_id;
return 0;
}
}
return -1;
}
static void acpi_notify_wakeup(Notifier *notifier, void *data)
{
ACPIREGS *ar = container_of(notifier, ACPIREGS, wakeup);
+2 -2
View File
@@ -366,7 +366,7 @@ static void nvdimm_build_nfit(GSList *device_list, GArray *table_offsets,
build_header(linker, table_data,
(void *)(table_data->data + header), "NFIT",
sizeof(NvdimmNfitHeader) + structures->len, 1, NULL);
sizeof(NvdimmNfitHeader) + structures->len, 1, NULL, NULL);
g_array_free(structures, true);
}
@@ -471,7 +471,7 @@ static void nvdimm_build_ssdt(GSList *device_list, GArray *table_offsets,
g_array_append_vals(table_data, ssdt->buf->data, ssdt->buf->len);
build_header(linker, table_data,
(void *)(table_data->data + table_data->len - ssdt->buf->len),
"SSDT", ssdt->buf->len, 1, "NVDIMM");
"SSDT", ssdt->buf->len, 1, NULL, "NVDIMM");
free_aml_allocator();
}
+7 -7
View File
@@ -394,7 +394,7 @@ build_spcr(GArray *table_data, GArray *linker, VirtGuestInfo *guest_info)
spcr->pci_vendor_id = 0xffff; /* PCI Vendor ID: not a PCI device */
build_header(linker, table_data, (void *)spcr, "SPCR", sizeof(*spcr), 2,
NULL);
NULL, NULL);
}
static void
@@ -413,7 +413,7 @@ build_mcfg(GArray *table_data, GArray *linker, VirtGuestInfo *guest_info)
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, 1, NULL);
build_header(linker, table_data, (void *)mcfg, "MCFG", len, 1, NULL, NULL);
}
/* GTDT */
@@ -439,7 +439,7 @@ build_gtdt(GArray *table_data, GArray *linker)
build_header(linker, table_data,
(void *)(table_data->data + gtdt_start), "GTDT",
table_data->len - gtdt_start, 2, NULL);
table_data->len - gtdt_start, 2, NULL, NULL);
}
/* MADT */
@@ -498,7 +498,7 @@ build_madt(GArray *table_data, GArray *linker, VirtGuestInfo *guest_info)
build_header(linker, table_data,
(void *)(table_data->data + madt_start), "APIC",
table_data->len - madt_start, 3, NULL);
table_data->len - madt_start, 3, NULL, NULL);
}
/* FADT */
@@ -523,7 +523,7 @@ build_fadt(GArray *table_data, GArray *linker, unsigned dsdt)
sizeof fadt->dsdt);
build_header(linker, table_data,
(void *)fadt, "FACP", sizeof(*fadt), 5, NULL);
(void *)fadt, "FACP", sizeof(*fadt), 5, NULL, NULL);
}
/* DSDT */
@@ -562,7 +562,7 @@ build_dsdt(GArray *table_data, GArray *linker, VirtGuestInfo *guest_info)
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, 2, NULL);
"DSDT", dsdt->buf->len, 2, NULL, NULL);
free_aml_allocator();
}
@@ -623,7 +623,7 @@ void virt_acpi_build(VirtGuestInfo *guest_info, AcpiBuildTables *tables)
/* RSDT is pointed to by RSDP */
rsdt = tables_blob->len;
build_rsdt(tables_blob, tables->linker, table_offsets);
build_rsdt(tables_blob, tables->linker, table_offsets, NULL, NULL);
/* RSDP is in FSEG memory, so allocate it separately */
build_rsdp(tables->rsdp, tables->linker, rsdt);
+5 -6
View File
@@ -100,20 +100,19 @@ static void handle_notify(EventNotifier *e)
blk_io_plug(s->conf->conf.blk);
for (;;) {
MultiReqBuffer mrb = {};
int ret;
/* Disable guest->host notifies to avoid unnecessary vmexits */
vring_disable_notification(s->vdev, &s->vring);
for (;;) {
VirtIOBlockReq *req = virtio_blk_alloc_request(vblk);
VirtIOBlockReq *req = vring_pop(s->vdev, &s->vring,
sizeof(VirtIOBlockReq));
ret = vring_pop(s->vdev, &s->vring, &req->elem);
if (ret < 0) {
virtio_blk_free_request(req);
if (req == NULL) {
break; /* no more requests */
}
virtio_blk_init_request(vblk, req);
trace_virtio_blk_data_plane_process_request(s, req->elem.out_num,
req->elem.in_num,
req->elem.index);
@@ -125,7 +124,7 @@ static void handle_notify(EventNotifier *e)
virtio_blk_submit_multireq(s->conf->conf.blk, &mrb);
}
if (likely(ret == -EAGAIN)) { /* vring emptied */
if (likely(!vring_more_avail(s->vdev, &s->vring))) { /* vring emptied */
/* Re-enable guest->host notifies and stop processing the vring.
* But if the guest has snuck in more descriptors, keep processing.
*/
+8 -15
View File
@@ -29,15 +29,13 @@
#include "hw/virtio/virtio-bus.h"
#include "hw/virtio/virtio-access.h"
VirtIOBlockReq *virtio_blk_alloc_request(VirtIOBlock *s)
void virtio_blk_init_request(VirtIOBlock *s, VirtIOBlockReq *req)
{
VirtIOBlockReq *req = g_new(VirtIOBlockReq, 1);
req->dev = s;
req->qiov.size = 0;
req->in_len = 0;
req->next = NULL;
req->mr_next = NULL;
return req;
}
void virtio_blk_free_request(VirtIOBlockReq *req)
@@ -193,13 +191,11 @@ out:
static VirtIOBlockReq *virtio_blk_get_request(VirtIOBlock *s)
{
VirtIOBlockReq *req = virtio_blk_alloc_request(s);
VirtIOBlockReq *req = virtqueue_pop(s->vq, sizeof(VirtIOBlockReq));
if (!virtqueue_pop(s->vq, &req->elem)) {
virtio_blk_free_request(req);
return NULL;
if (req) {
virtio_blk_init_request(s, req);
}
return req;
}
@@ -812,8 +808,7 @@ static void virtio_blk_save_device(VirtIODevice *vdev, QEMUFile *f)
while (req) {
qemu_put_sbyte(f, 1);
qemu_put_buffer(f, (unsigned char *)&req->elem,
sizeof(VirtQueueElement));
qemu_put_virtqueue_element(f, &req->elem);
req = req->next;
}
qemu_put_sbyte(f, 0);
@@ -836,13 +831,11 @@ static int virtio_blk_load_device(VirtIODevice *vdev, QEMUFile *f,
VirtIOBlock *s = VIRTIO_BLK(vdev);
while (qemu_get_sbyte(f)) {
VirtIOBlockReq *req = virtio_blk_alloc_request(s);
qemu_get_buffer(f, (unsigned char *)&req->elem,
sizeof(VirtQueueElement));
VirtIOBlockReq *req;
req = qemu_get_virtqueue_element(f, sizeof(VirtIOBlockReq));
virtio_blk_init_request(s, req);
req->next = s->rq;
s->rq = req;
virtqueue_map(&req->elem);
}
return 0;
+47 -31
View File
@@ -83,7 +83,7 @@ static bool use_multiport(VirtIOSerial *vser)
static size_t write_to_port(VirtIOSerialPort *port,
const uint8_t *buf, size_t size)
{
VirtQueueElement elem;
VirtQueueElement *elem;
VirtQueue *vq;
size_t offset;
@@ -96,15 +96,17 @@ static size_t write_to_port(VirtIOSerialPort *port,
while (offset < size) {
size_t len;
if (!virtqueue_pop(vq, &elem)) {
elem = virtqueue_pop(vq, sizeof(VirtQueueElement));
if (!elem) {
break;
}
len = iov_from_buf(elem.in_sg, elem.in_num, 0,
len = iov_from_buf(elem->in_sg, elem->in_num, 0,
buf + offset, size - offset);
offset += len;
virtqueue_push(vq, &elem, len);
virtqueue_push(vq, elem, len);
g_free(elem);
}
virtio_notify(VIRTIO_DEVICE(port->vser), vq);
@@ -113,13 +115,18 @@ static size_t write_to_port(VirtIOSerialPort *port,
static void discard_vq_data(VirtQueue *vq, VirtIODevice *vdev)
{
VirtQueueElement elem;
VirtQueueElement *elem;
if (!virtio_queue_ready(vq)) {
return;
}
while (virtqueue_pop(vq, &elem)) {
virtqueue_push(vq, &elem, 0);
for (;;) {
elem = virtqueue_pop(vq, sizeof(VirtQueueElement));
if (!elem) {
break;
}
virtqueue_push(vq, elem, 0);
g_free(elem);
}
virtio_notify(vdev, vq);
}
@@ -138,21 +145,22 @@ static void do_flush_queued_data(VirtIOSerialPort *port, VirtQueue *vq,
unsigned int i;
/* Pop an elem only if we haven't left off a previous one mid-way */
if (!port->elem.out_num) {
if (!virtqueue_pop(vq, &port->elem)) {
if (!port->elem) {
port->elem = virtqueue_pop(vq, sizeof(VirtQueueElement));
if (!port->elem) {
break;
}
port->iov_idx = 0;
port->iov_offset = 0;
}
for (i = port->iov_idx; i < port->elem.out_num; i++) {
for (i = port->iov_idx; i < port->elem->out_num; i++) {
size_t buf_size;
ssize_t ret;
buf_size = port->elem.out_sg[i].iov_len - port->iov_offset;
buf_size = port->elem->out_sg[i].iov_len - port->iov_offset;
ret = vsc->have_data(port,
port->elem.out_sg[i].iov_base
port->elem->out_sg[i].iov_base
+ port->iov_offset,
buf_size);
if (port->throttled) {
@@ -167,8 +175,9 @@ static void do_flush_queued_data(VirtIOSerialPort *port, VirtQueue *vq,
if (port->throttled) {
break;
}
virtqueue_push(vq, &port->elem, 0);
port->elem.out_num = 0;
virtqueue_push(vq, port->elem, 0);
g_free(port->elem);
port->elem = NULL;
}
virtio_notify(vdev, vq);
}
@@ -185,22 +194,26 @@ static void flush_queued_data(VirtIOSerialPort *port)
static size_t send_control_msg(VirtIOSerial *vser, void *buf, size_t len)
{
VirtQueueElement elem;
VirtQueueElement *elem;
VirtQueue *vq;
vq = vser->c_ivq;
if (!virtio_queue_ready(vq)) {
return 0;
}
if (!virtqueue_pop(vq, &elem)) {
elem = virtqueue_pop(vq, sizeof(VirtQueueElement));
if (!elem) {
return 0;
}
/* TODO: detect a buffer that's too short, set NEEDS_RESET */
iov_from_buf(elem.in_sg, elem.in_num, 0, buf, len);
iov_from_buf(elem->in_sg, elem->in_num, 0, buf, len);
virtqueue_push(vq, &elem, len);
virtqueue_push(vq, elem, len);
virtio_notify(VIRTIO_DEVICE(vser), vq);
g_free(elem);
return len;
}
@@ -414,7 +427,7 @@ static void control_in(VirtIODevice *vdev, VirtQueue *vq)
static void control_out(VirtIODevice *vdev, VirtQueue *vq)
{
VirtQueueElement elem;
VirtQueueElement *elem;
VirtIOSerial *vser;
uint8_t *buf;
size_t len;
@@ -423,10 +436,15 @@ static void control_out(VirtIODevice *vdev, VirtQueue *vq)
len = 0;
buf = NULL;
while (virtqueue_pop(vq, &elem)) {
for (;;) {
size_t cur_len;
cur_len = iov_size(elem.out_sg, elem.out_num);
elem = virtqueue_pop(vq, sizeof(VirtQueueElement));
if (!elem) {
break;
}
cur_len = iov_size(elem->out_sg, elem->out_num);
/*
* Allocate a new buf only if we didn't have one previously or
* if the size of the buf differs
@@ -437,10 +455,11 @@ static void control_out(VirtIODevice *vdev, VirtQueue *vq)
buf = g_malloc(cur_len);
len = cur_len;
}
iov_to_buf(elem.out_sg, elem.out_num, 0, buf, cur_len);
iov_to_buf(elem->out_sg, elem->out_num, 0, buf, cur_len);
handle_control_message(vser, buf, cur_len);
virtqueue_push(vq, &elem, 0);
virtqueue_push(vq, elem, 0);
g_free(elem);
}
g_free(buf);
virtio_notify(vdev, vq);
@@ -620,16 +639,14 @@ static void virtio_serial_save_device(VirtIODevice *vdev, QEMUFile *f)
qemu_put_byte(f, port->host_connected);
elem_popped = 0;
if (port->elem.out_num) {
if (port->elem) {
elem_popped = 1;
}
qemu_put_be32s(f, &elem_popped);
if (elem_popped) {
qemu_put_be32s(f, &port->iov_idx);
qemu_put_be64s(f, &port->iov_offset);
qemu_put_buffer(f, (unsigned char *)&port->elem,
sizeof(port->elem));
qemu_put_virtqueue_element(f, port->elem);
}
}
}
@@ -704,9 +721,8 @@ static int fetch_active_ports_list(QEMUFile *f, int version_id,
qemu_get_be32s(f, &port->iov_idx);
qemu_get_be64s(f, &port->iov_offset);
qemu_get_buffer(f, (unsigned char *)&port->elem,
sizeof(port->elem));
virtqueue_map(&port->elem);
port->elem =
qemu_get_virtqueue_element(f, sizeof(VirtQueueElement));
/*
* Port was throttled on source machine. Let's
@@ -928,7 +944,7 @@ static void virtser_port_device_realize(DeviceState *dev, Error **errp)
return;
}
port->elem.out_num = 0;
port->elem = NULL;
}
static void virtser_port_device_plug(HotplugHandler *hotplug_dev,
+13 -8
View File
@@ -804,16 +804,15 @@ static void virtio_gpu_handle_ctrl(VirtIODevice *vdev, VirtQueue *vq)
}
#endif
cmd = g_new(struct virtio_gpu_ctrl_command, 1);
while (virtqueue_pop(vq, &cmd->elem)) {
cmd = virtqueue_pop(vq, sizeof(struct virtio_gpu_ctrl_command));
while (cmd) {
cmd->vq = vq;
cmd->error = 0;
cmd->finished = false;
cmd->waiting = false;
QTAILQ_INSERT_TAIL(&g->cmdq, cmd, next);
cmd = g_new(struct virtio_gpu_ctrl_command, 1);
cmd = virtqueue_pop(vq, sizeof(struct virtio_gpu_ctrl_command));
}
g_free(cmd);
virtio_gpu_process_cmdq(g);
@@ -833,15 +832,20 @@ static void virtio_gpu_ctrl_bh(void *opaque)
static void virtio_gpu_handle_cursor(VirtIODevice *vdev, VirtQueue *vq)
{
VirtIOGPU *g = VIRTIO_GPU(vdev);
VirtQueueElement elem;
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,
for (;;) {
elem = virtqueue_pop(vq, sizeof(VirtQueueElement));
if (!elem) {
break;
}
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,
@@ -850,8 +854,9 @@ static void virtio_gpu_handle_cursor(VirtIODevice *vdev, VirtQueue *vq)
} else {
update_cursor(g, &cursor_info);
}
virtqueue_push(vq, &elem, 0);
virtqueue_push(vq, elem, 0);
virtio_notify(vdev, vq);
g_free(elem);
}
}
+509 -527
View File
File diff suppressed because it is too large Load Diff
+1 -1
View File
@@ -4,6 +4,6 @@
#include "qemu/typedefs.h"
void acpi_setup(PcGuestInfo *);
void acpi_setup(void);
#endif
+53 -21
View File
@@ -153,14 +153,27 @@ static gboolean vtd_hash_remove_by_domain(gpointer key, gpointer value,
return entry->domain_id == domain_id;
}
/* The shift of an addr for a certain level of paging structure */
static inline uint32_t vtd_slpt_level_shift(uint32_t level)
{
return VTD_PAGE_SHIFT_4K + (level - 1) * VTD_SL_LEVEL_BITS;
}
static inline uint64_t vtd_slpt_level_page_mask(uint32_t level)
{
return ~((1ULL << vtd_slpt_level_shift(level)) - 1);
}
static gboolean vtd_hash_remove_by_page(gpointer key, gpointer value,
gpointer user_data)
{
VTDIOTLBEntry *entry = (VTDIOTLBEntry *)value;
VTDIOTLBPageInvInfo *info = (VTDIOTLBPageInvInfo *)user_data;
uint64_t gfn = info->gfn & info->mask;
uint64_t gfn = (info->addr >> VTD_PAGE_SHIFT_4K) & info->mask;
uint64_t gfn_tlb = (info->addr & entry->mask) >> VTD_PAGE_SHIFT_4K;
return (entry->domain_id == info->domain_id) &&
((entry->gfn & info->mask) == gfn);
(((entry->gfn & info->mask) == gfn) ||
(entry->gfn == gfn_tlb));
}
/* Reset all the gen of VTDAddressSpace to zero and set the gen of
@@ -194,24 +207,46 @@ static void vtd_reset_iotlb(IntelIOMMUState *s)
g_hash_table_remove_all(s->iotlb);
}
static uint64_t vtd_get_iotlb_key(uint64_t gfn, uint8_t source_id,
uint32_t level)
{
return gfn | ((uint64_t)(source_id) << VTD_IOTLB_SID_SHIFT) |
((uint64_t)(level) << VTD_IOTLB_LVL_SHIFT);
}
static uint64_t vtd_get_iotlb_gfn(hwaddr addr, uint32_t level)
{
return (addr & vtd_slpt_level_page_mask(level)) >> VTD_PAGE_SHIFT_4K;
}
static VTDIOTLBEntry *vtd_lookup_iotlb(IntelIOMMUState *s, uint16_t source_id,
hwaddr addr)
{
VTDIOTLBEntry *entry;
uint64_t key;
int level;
key = (addr >> VTD_PAGE_SHIFT_4K) |
((uint64_t)(source_id) << VTD_IOTLB_SID_SHIFT);
return g_hash_table_lookup(s->iotlb, &key);
for (level = VTD_SL_PT_LEVEL; level < VTD_SL_PML4_LEVEL; level++) {
key = vtd_get_iotlb_key(vtd_get_iotlb_gfn(addr, level),
source_id, level);
entry = g_hash_table_lookup(s->iotlb, &key);
if (entry) {
goto out;
}
}
out:
return entry;
}
static void vtd_update_iotlb(IntelIOMMUState *s, uint16_t source_id,
uint16_t domain_id, hwaddr addr, uint64_t slpte,
bool read_flags, bool write_flags)
bool read_flags, bool write_flags,
uint32_t level)
{
VTDIOTLBEntry *entry = g_malloc(sizeof(*entry));
uint64_t *key = g_malloc(sizeof(*key));
uint64_t gfn = addr >> VTD_PAGE_SHIFT_4K;
uint64_t gfn = vtd_get_iotlb_gfn(addr, level);
VTD_DPRINTF(CACHE, "update iotlb sid 0x%"PRIx16 " gpa 0x%"PRIx64
" slpte 0x%"PRIx64 " did 0x%"PRIx16, source_id, addr, slpte,
@@ -226,7 +261,8 @@ static void vtd_update_iotlb(IntelIOMMUState *s, uint16_t source_id,
entry->slpte = slpte;
entry->read_flags = read_flags;
entry->write_flags = write_flags;
*key = gfn | ((uint64_t)(source_id) << VTD_IOTLB_SID_SHIFT);
entry->mask = vtd_slpt_level_page_mask(level);
*key = vtd_get_iotlb_key(gfn, source_id, level);
g_hash_table_replace(s->iotlb, key, entry);
}
@@ -501,12 +537,6 @@ static inline dma_addr_t vtd_get_slpt_base_from_context(VTDContextEntry *ce)
return ce->lo & VTD_CONTEXT_ENTRY_SLPTPTR;
}
/* The shift of an addr for a certain level of paging structure */
static inline uint32_t vtd_slpt_level_shift(uint32_t level)
{
return VTD_PAGE_SHIFT_4K + (level - 1) * VTD_SL_LEVEL_BITS;
}
static inline uint64_t vtd_get_slpte_addr(uint64_t slpte)
{
return slpte & VTD_SL_PT_BASE_ADDR_MASK;
@@ -762,7 +792,7 @@ static void vtd_do_iommu_translate(VTDAddressSpace *vtd_as, PCIBus *bus,
VTDContextEntry ce;
uint8_t bus_num = pci_bus_num(bus);
VTDContextCacheEntry *cc_entry = &vtd_as->context_cache_entry;
uint64_t slpte;
uint64_t slpte, page_mask;
uint32_t level;
uint16_t source_id = vtd_make_source_id(bus_num, devfn);
int ret_fr;
@@ -802,6 +832,7 @@ static void vtd_do_iommu_translate(VTDAddressSpace *vtd_as, PCIBus *bus,
slpte = iotlb_entry->slpte;
reads = iotlb_entry->read_flags;
writes = iotlb_entry->write_flags;
page_mask = iotlb_entry->mask;
goto out;
}
/* Try to fetch context-entry from cache first */
@@ -848,12 +879,13 @@ static void vtd_do_iommu_translate(VTDAddressSpace *vtd_as, PCIBus *bus,
return;
}
page_mask = vtd_slpt_level_page_mask(level);
vtd_update_iotlb(s, source_id, VTD_CONTEXT_ENTRY_DID(ce.hi), addr, slpte,
reads, writes);
reads, writes, level);
out:
entry->iova = addr & VTD_PAGE_MASK_4K;
entry->translated_addr = vtd_get_slpte_addr(slpte) & VTD_PAGE_MASK_4K;
entry->addr_mask = ~VTD_PAGE_MASK_4K;
entry->iova = addr & page_mask;
entry->translated_addr = vtd_get_slpte_addr(slpte) & page_mask;
entry->addr_mask = ~page_mask;
entry->perm = (writes ? 2 : 0) + (reads ? 1 : 0);
}
@@ -991,7 +1023,7 @@ static void vtd_iotlb_page_invalidate(IntelIOMMUState *s, uint16_t domain_id,
assert(am <= VTD_MAMV);
info.domain_id = domain_id;
info.gfn = addr >> VTD_PAGE_SHIFT_4K;
info.addr = addr;
info.mask = ~((1 << am) - 1);
g_hash_table_foreach_remove(s->iotlb, vtd_hash_remove_by_page, &info);
}
@@ -1917,7 +1949,7 @@ static void vtd_init(IntelIOMMUState *s)
s->iq_last_desc_type = VTD_INV_DESC_NONE;
s->next_frcd_reg = 0;
s->cap = VTD_CAP_FRO | VTD_CAP_NFR | VTD_CAP_ND | VTD_CAP_MGAW |
VTD_CAP_SAGAW | VTD_CAP_MAMV | VTD_CAP_PSI;
VTD_CAP_SAGAW | VTD_CAP_MAMV | VTD_CAP_PSI | VTD_CAP_SLLPS;
s->ecap = VTD_ECAP_QI | VTD_ECAP_IRO;
vtd_reset_context_cache(s);
+4 -2
View File
@@ -113,6 +113,7 @@
/* The shift of source_id in the key of IOTLB hash table */
#define VTD_IOTLB_SID_SHIFT 36
#define VTD_IOTLB_LVL_SHIFT 44
#define VTD_IOTLB_MAX_SIZE 1024 /* Max size of the hash table */
/* IOTLB_REG */
@@ -185,9 +186,10 @@
#define VTD_CAP_ND (((VTD_DOMAIN_ID_SHIFT - 4) / 2) & 7ULL)
#define VTD_MGAW 39 /* Maximum Guest Address Width */
#define VTD_CAP_MGAW (((VTD_MGAW - 1) & 0x3fULL) << 16)
#define VTD_MAMV 9ULL
#define VTD_MAMV 18ULL
#define VTD_CAP_MAMV (VTD_MAMV << 48)
#define VTD_CAP_PSI (1ULL << 39)
#define VTD_CAP_SLLPS ((1ULL << 34) | (1ULL << 35))
/* Supported Adjusted Guest Address Widths */
#define VTD_CAP_SAGAW_SHIFT 8
@@ -320,7 +322,7 @@ typedef struct VTDInvDesc VTDInvDesc;
/* Information about page-selective IOTLB invalidate */
struct VTDIOTLBPageInvInfo {
uint16_t domain_id;
uint64_t gfn;
uint64_t addr;
uint8_t mask;
};
typedef struct VTDIOTLBPageInvInfo VTDIOTLBPageInvInfo;
+31 -46
View File
@@ -1156,18 +1156,12 @@ typedef struct PcRomPciInfo {
uint64_t w64_max;
} PcRomPciInfo;
typedef struct PcGuestInfoState {
PcGuestInfo info;
Notifier machine_done;
} PcGuestInfoState;
static
void pc_guest_info_machine_done(Notifier *notifier, void *data)
void pc_machine_done(Notifier *notifier, void *data)
{
PcGuestInfoState *guest_info_state = container_of(notifier,
PcGuestInfoState,
machine_done);
PCIBus *bus = PC_MACHINE(qdev_get_machine())->bus;
PCMachineState *pcms = container_of(notifier,
PCMachineState, machine_done);
PCIBus *bus = pcms->bus;
if (bus) {
int extra_hosts = 0;
@@ -1178,51 +1172,46 @@ void pc_guest_info_machine_done(Notifier *notifier, void *data)
extra_hosts++;
}
}
if (extra_hosts && guest_info_state->info.fw_cfg) {
if (extra_hosts && pcms->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,
fw_cfg_add_file(pcms->fw_cfg,
"etc/extra-pci-roots", val, sizeof(*val));
}
}
acpi_setup(&guest_info_state->info);
acpi_setup();
}
PcGuestInfo *pc_guest_info_init(PCMachineState *pcms)
void pc_guest_info_init(PCMachineState *pcms)
{
PcGuestInfoState *guest_info_state = g_malloc0(sizeof *guest_info_state);
PcGuestInfo *guest_info = &guest_info_state->info;
int i, j;
guest_info->ram_size_below_4g = pcms->below_4g_mem_size;
guest_info->ram_size = pcms->below_4g_mem_size + pcms->above_4g_mem_size;
guest_info->apic_id_limit = pc_apic_id_limit(max_cpus);
guest_info->apic_xrupt_override = kvm_allows_irq0_override();
guest_info->numa_nodes = nb_numa_nodes;
guest_info->node_mem = g_malloc0(guest_info->numa_nodes *
sizeof *guest_info->node_mem);
pcms->apic_id_limit = pc_apic_id_limit(max_cpus);
pcms->apic_xrupt_override = kvm_allows_irq0_override();
pcms->numa_nodes = nb_numa_nodes;
pcms->node_mem = g_malloc0(pcms->numa_nodes *
sizeof *pcms->node_mem);
for (i = 0; i < nb_numa_nodes; i++) {
guest_info->node_mem[i] = numa_info[i].node_mem;
pcms->node_mem[i] = numa_info[i].node_mem;
}
guest_info->node_cpu = g_malloc0(guest_info->apic_id_limit *
sizeof *guest_info->node_cpu);
pcms->node_cpu = g_malloc0(pcms->apic_id_limit *
sizeof *pcms->node_cpu);
for (i = 0; i < max_cpus; i++) {
unsigned int apic_id = x86_cpu_apic_id_from_index(i);
assert(apic_id < guest_info->apic_id_limit);
assert(apic_id < pcms->apic_id_limit);
for (j = 0; j < nb_numa_nodes; j++) {
if (test_bit(i, numa_info[j].node_cpu)) {
guest_info->node_cpu[apic_id] = j;
pcms->node_cpu[apic_id] = j;
break;
}
}
}
guest_info_state->machine_done.notify = pc_guest_info_machine_done;
qemu_add_machine_init_done_notifier(&guest_info_state->machine_done);
return guest_info;
pcms->machine_done.notify = pc_machine_done;
qemu_add_machine_init_done_notifier(&pcms->machine_done);
}
/* setup pci memory address space mapping into system address space */
@@ -1262,8 +1251,7 @@ void pc_acpi_init(const char *default_dsdt)
}
}
FWCfgState *xen_load_linux(PCMachineState *pcms,
PcGuestInfo *guest_info)
void xen_load_linux(PCMachineState *pcms)
{
int i;
FWCfgState *fw_cfg;
@@ -1279,15 +1267,13 @@ FWCfgState *xen_load_linux(PCMachineState *pcms,
!strcmp(option_rom[i].name, "multiboot.bin"));
rom_add_option(option_rom[i].name, option_rom[i].bootindex);
}
guest_info->fw_cfg = fw_cfg;
return fw_cfg;
pcms->fw_cfg = fw_cfg;
}
FWCfgState *pc_memory_init(PCMachineState *pcms,
MemoryRegion *system_memory,
MemoryRegion *rom_memory,
MemoryRegion **ram_memory,
PcGuestInfo *guest_info)
void pc_memory_init(PCMachineState *pcms,
MemoryRegion *system_memory,
MemoryRegion *rom_memory,
MemoryRegion **ram_memory)
{
int linux_boot, i;
MemoryRegion *ram, *option_rom_mr;
@@ -1324,7 +1310,7 @@ FWCfgState *pc_memory_init(PCMachineState *pcms,
e820_add_entry(0x100000000ULL, pcms->above_4g_mem_size, E820_RAM);
}
if (!guest_info->has_reserved_memory &&
if (!pcmc->has_reserved_memory &&
(machine->ram_slots ||
(machine->maxram_size > machine->ram_size))) {
MachineClass *mc = MACHINE_GET_CLASS(machine);
@@ -1335,7 +1321,7 @@ FWCfgState *pc_memory_init(PCMachineState *pcms,
}
/* initialize hotplug memory address space */
if (guest_info->has_reserved_memory &&
if (pcmc->has_reserved_memory &&
(machine->ram_size < machine->maxram_size)) {
ram_addr_t hotplug_mem_size =
machine->maxram_size - machine->ram_size;
@@ -1375,7 +1361,7 @@ FWCfgState *pc_memory_init(PCMachineState *pcms,
}
/* Initialize PC system firmware */
pc_system_firmware_init(rom_memory, guest_info->isapc_ram_fw);
pc_system_firmware_init(rom_memory, !pcmc->pci_enabled);
option_rom_mr = g_malloc(sizeof(*option_rom_mr));
memory_region_init_ram(option_rom_mr, NULL, "pc.rom", PC_ROM_SIZE,
@@ -1390,7 +1376,7 @@ FWCfgState *pc_memory_init(PCMachineState *pcms,
rom_set_fw(fw_cfg);
if (guest_info->has_reserved_memory && pcms->hotplug_memory.base) {
if (pcmc->has_reserved_memory && pcms->hotplug_memory.base) {
uint64_t *val = g_malloc(sizeof(*val));
PCMachineClass *pcmc = PC_MACHINE_GET_CLASS(pcms);
uint64_t res_mem_end = pcms->hotplug_memory.base;
@@ -1409,8 +1395,7 @@ FWCfgState *pc_memory_init(PCMachineState *pcms,
for (i = 0; i < nb_option_roms; i++) {
rom_add_option(option_rom[i].name, option_rom[i].bootindex);
}
guest_info->fw_cfg = fw_cfg;
return fw_cfg;
pcms->fw_cfg = fw_cfg;
}
qemu_irq pc_allocate_cpu_irq(void)
+3 -11
View File
@@ -85,7 +85,6 @@ static void pc_init1(MachineState *machine,
MemoryRegion *ram_memory;
MemoryRegion *pci_memory;
MemoryRegion *rom_memory;
PcGuestInfo *guest_info;
ram_addr_t lowmem;
/* Check whether RAM fits below 4G (leaving 1/2 GByte for IO memory).
@@ -141,14 +140,7 @@ static void pc_init1(MachineState *machine,
rom_memory = system_memory;
}
guest_info = pc_guest_info_init(pcms);
guest_info->has_acpi_build = pcmc->has_acpi_build;
guest_info->legacy_acpi_table_size = pcmc->legacy_acpi_table_size;
guest_info->isapc_ram_fw = !pcmc->pci_enabled;
guest_info->has_reserved_memory = pcmc->has_reserved_memory;
guest_info->rsdp_in_ram = pcmc->rsdp_in_ram;
pc_guest_info_init(pcms);
if (pcmc->smbios_defaults) {
MachineClass *mc = MACHINE_GET_CLASS(machine);
@@ -162,10 +154,10 @@ static void pc_init1(MachineState *machine,
/* allocate ram and load rom/bios */
if (!xen_enabled()) {
pc_memory_init(pcms, system_memory,
rom_memory, &ram_memory, guest_info);
rom_memory, &ram_memory);
} else if (machine->kernel_filename != NULL) {
/* For xen HVM direct kernel boot, load linux here */
xen_load_linux(pcms, guest_info);
xen_load_linux(pcms);
}
gsi_state = g_malloc0(sizeof(*gsi_state));
+2 -12
View File
@@ -71,7 +71,6 @@ static void pc_q35_init(MachineState *machine)
int i;
ICH9LPCState *ich9_lpc;
PCIDevice *ahci;
PcGuestInfo *guest_info;
ram_addr_t lowmem;
DriveInfo *hd[MAX_SATA_PORTS];
MachineClass *mc = MACHINE_GET_CLASS(machine);
@@ -134,16 +133,7 @@ static void pc_q35_init(MachineState *machine)
rom_memory = get_system_memory();
}
guest_info = pc_guest_info_init(pcms);
guest_info->isapc_ram_fw = false;
guest_info->has_acpi_build = pcmc->has_acpi_build;
guest_info->has_reserved_memory = pcmc->has_reserved_memory;
guest_info->rsdp_in_ram = pcmc->rsdp_in_ram;
/* Migration was not supported in 2.0 for Q35, so do not bother
* with this hack (see hw/i386/acpi-build.c).
*/
guest_info->legacy_acpi_table_size = 0;
pc_guest_info_init(pcms);
if (pcmc->smbios_defaults) {
/* These values are guest ABI, do not change */
@@ -156,7 +146,7 @@ static void pc_q35_init(MachineState *machine)
/* allocate ram and load rom/bios */
if (!xen_enabled()) {
pc_memory_init(pcms, get_system_memory(),
rom_memory, &ram_memory, guest_info);
rom_memory, &ram_memory);
}
/* irq lines */
+16 -8
View File
@@ -17,7 +17,7 @@
void virtio_input_send(VirtIOInput *vinput, virtio_input_event *event)
{
VirtQueueElement elem;
VirtQueueElement *elem;
unsigned have, need;
int i, len;
@@ -50,14 +50,16 @@ void virtio_input_send(VirtIOInput *vinput, virtio_input_event *event)
/* ... and finally pass them to the guest */
for (i = 0; i < vinput->qindex; i++) {
if (!virtqueue_pop(vinput->evt, &elem)) {
elem = virtqueue_pop(vinput->evt, sizeof(VirtQueueElement));
if (!elem) {
/* should not happen, we've checked for space beforehand */
fprintf(stderr, "%s: Huh? No vq elem available ...\n", __func__);
return;
}
len = iov_from_buf(elem.in_sg, elem.in_num,
len = iov_from_buf(elem->in_sg, elem->in_num,
0, vinput->queue+i, sizeof(virtio_input_event));
virtqueue_push(vinput->evt, &elem, len);
virtqueue_push(vinput->evt, elem, len);
g_free(elem);
}
virtio_notify(VIRTIO_DEVICE(vinput), vinput->evt);
vinput->qindex = 0;
@@ -73,17 +75,23 @@ static void virtio_input_handle_sts(VirtIODevice *vdev, VirtQueue *vq)
VirtIOInputClass *vic = VIRTIO_INPUT_GET_CLASS(vdev);
VirtIOInput *vinput = VIRTIO_INPUT(vdev);
virtio_input_event event;
VirtQueueElement elem;
VirtQueueElement *elem;
int len;
while (virtqueue_pop(vinput->sts, &elem)) {
for (;;) {
elem = virtqueue_pop(vinput->sts, sizeof(VirtQueueElement));
if (!elem) {
break;
}
memset(&event, 0, sizeof(event));
len = iov_to_buf(elem.out_sg, elem.out_num,
len = iov_to_buf(elem->out_sg, elem->out_num,
0, &event, sizeof(event));
if (vic->handle_status) {
vic->handle_status(vinput, &event);
}
virtqueue_push(vinput->sts, &elem, len);
virtqueue_push(vinput->sts, elem, len);
g_free(elem);
}
virtio_notify(vdev, vinput->sts);
}
+205 -146
View File
File diff suppressed because it is too large Load Diff

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