Merge remote-tracking branch 'agraf/s390-for-upstream' into staging
authorAnthony Liguori <aliguori@us.ibm.com>
Wed, 15 Aug 2012 19:59:48 +0000 (14:59 -0500)
committerAnthony Liguori <aliguori@us.ibm.com>
Wed, 15 Aug 2012 19:59:48 +0000 (14:59 -0500)
* agraf/s390-for-upstream:
  s390: provide interface for service interrupt/introduce interrupt.c
  s390: Fix error handling and condition code of service call

76 files changed:
Makefile
arch_init.h
block.c
block/iscsi.c
block/raw-posix.c
block/raw-win32.c
block/vdi.c
block/vmdk.c
block/vpc.c
block/vvfat.c
compiler.h
cputlb.c
cutils.c
docs/bootindex.txt
hw/alpha_pci.c
hw/apic_common.c
hw/cirrus_vga.c
hw/framebuffer.c
hw/ivshmem.c
hw/kvm/i8254.c
hw/mips_malta.c
hw/openpic.c
hw/pc.c
hw/pc.h
hw/ppc/Makefile.objs
hw/ppc/e500.c [new file with mode: 0644]
hw/ppc/e500.h [new file with mode: 0644]
hw/ppc/e500plat.c [new file with mode: 0644]
hw/ppc/mpc8544ds.c [new file with mode: 0644]
hw/ppc_newworld.c
hw/ppc_oldworld.c
hw/ppc_prep.c
hw/ppce500_mpc8544ds.c [deleted file]
hw/qdev-monitor.c
hw/spapr.c
hw/spapr.h
hw/spapr_iommu.c
hw/spapr_llan.c
hw/spapr_pci.c
hw/spapr_pci.h
hw/spapr_vio.c
hw/spapr_vio.h
hw/spapr_vty.c
hw/sun4u.c
hw/usb/hcd-ehci.c
hw/versatilepb.c
hw/vga-pci.c
hw/vga-pci.h [new file with mode: 0644]
hw/xics.c
hw/xics.h
iov.c
monitor.c
monitor.h
osdep.c
pc-bios/README
pc-bios/slof.bin
qapi-schema.json
qemu-char.c
qemu-common.h
qemu-tool.c
qemu-user.c
qmp-commands.hx
qmp.c
roms/SLOF
savevm.c
scripts/simpletrace.py
scripts/tracetool/backend/simple.py
scripts/update-linux-headers.sh
target-i386/cpu.c
target-ppc/kvm.c
target-ppc/translate_init.c
tests/Makefile
tests/qemu-iotests/030
trace-events
trace/simple.c
trace/simple.h

index d736ea53111186bca1d59835fcd412018c0374a2..1cd5bc80d50ceeac4808a72d183877e895bf9ddc 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -148,9 +148,6 @@ install-libcacard: libcacard.la
        $(call quiet-command,$(MAKE) $(SUBDIR_MAKEFLAGS) -C libcacard V="$(V)" TARGET_DIR="$*/" install-libcacard,)
 endif
 
-vscclient$(EXESUF): $(libcacard-y) $(oslib-obj-y) $(trace-obj-y) qemu-timer-common.o libcacard/vscclient.o
-       $(call quiet-command,$(CC) $(LDFLAGS) -o $@ $^ $(libcacard_libs) $(LIBS),"  LINK  $@")
-
 ######################################################################
 
 qemu-img.o: qemu-img-cmds.h
@@ -166,6 +163,9 @@ qemu-io$(EXESUF): qemu-io.o cmd.o $(tools-obj-y) $(block-obj-y)
 
 qemu-bridge-helper$(EXESUF): qemu-bridge-helper.o
 
+vscclient$(EXESUF): $(libcacard-y) $(oslib-obj-y) $(trace-obj-y) $(tools-obj-y) qemu-timer-common.o libcacard/vscclient.o
+       $(call quiet-command,$(CC) $(LDFLAGS) -o $@ $^ $(libcacard_libs) $(LIBS),"  LINK  $@")
+
 fsdev/virtfs-proxy-helper$(EXESUF): fsdev/virtfs-proxy-helper.o fsdev/virtio-9p-marshal.o oslib-posix.o $(trace-obj-y)
 fsdev/virtfs-proxy-helper$(EXESUF): LIBS += -lcap
 
@@ -214,13 +214,10 @@ clean:
 # avoid old build problems by removing potentially incorrect old files
        rm -f config.mak op-i386.h opc-i386.h gen-op-i386.h op-arm.h opc-arm.h gen-op-arm.h
        rm -f qemu-options.def
-       rm -f *.o *.d *.a *.lo $(TOOLS) $(HELPERS-y) qemu-ga TAGS cscope.* *.pod *~ */*~
+       find . -name '*.[od]' -exec rm -f {} +
+       rm -f *.a *.lo $(TOOLS) $(HELPERS-y) qemu-ga TAGS cscope.* *.pod *~ */*~
        rm -Rf .libs
-       rm -f slirp/*.o slirp/*.d audio/*.o audio/*.d block/*.o block/*.d net/*.o net/*.d fsdev/*.o fsdev/*.d ui/*.o ui/*.d qapi/*.o qapi/*.d qga/*.o qga/*.d
-       rm -f qom/*.o qom/*.d libuser/qom/*.o libuser/qom/*.d
-       rm -f hw/usb/*.o hw/usb/*.d hw/*.o hw/*.d
        rm -f qemu-img-cmds.h
-       rm -f trace/*.o trace/*.d
        rm -f trace-dtrace.dtrace trace-dtrace.dtrace-timestamp
        @# May not be present in GENERATED_HEADERS
        rm -f trace-dtrace.h trace-dtrace.h-timestamp
index 547f93cd1d43fe4f810fdeaf16456c4fd2445d03..d9c572aee860358fcdbddb89d7686821c38893e8 100644 (file)
@@ -1,6 +1,8 @@
 #ifndef QEMU_ARCH_INIT_H
 #define QEMU_ARCH_INIT_H
 
+#include "qmp-commands.h"
+
 enum {
     QEMU_ARCH_ALL = -1,
     QEMU_ARCH_ALPHA = 1,
@@ -32,4 +34,6 @@ int tcg_available(void);
 int kvm_available(void);
 int xen_available(void);
 
+CpuDefinitionInfoList GCC_WEAK_DECL *arch_query_cpu_definitions(Error **errp);
+
 #endif
diff --git a/block.c b/block.c
index 016858bf8c58accd6b8c938f3953d5c34481f2cc..470bdcc1f67ecf1fc5283d4c7546187d253d9088 100644 (file)
--- a/block.c
+++ b/block.c
@@ -3534,7 +3534,7 @@ int coroutine_fn bdrv_co_flush(BlockDriverState *bs)
 
     /* But don't actually force it to the disk with cache=unsafe */
     if (bs->open_flags & BDRV_O_NO_FLUSH) {
-        return 0;
+        goto flush_parent;
     }
 
     if (bs->drv->bdrv_co_flush_to_disk) {
@@ -3573,6 +3573,7 @@ int coroutine_fn bdrv_co_flush(BlockDriverState *bs)
     /* Now flush the underlying protocol.  It will also have BDRV_O_NO_FLUSH
      * in the case of cache=unsafe, so there are no useless flushes.
      */
+flush_parent:
     return bdrv_co_flush(bs->file);
 }
 
index 219f92782380786c693f9c7889a2b3b752461389..bb9cf82459c0c573d45f2b46b8942896c5c120b8 100644 (file)
@@ -76,6 +76,10 @@ static void
 iscsi_abort_task_cb(struct iscsi_context *iscsi, int status, void *command_data,
                     void *private_data)
 {
+    IscsiAIOCB *acb = (IscsiAIOCB *)private_data;
+
+    scsi_free_scsi_task(acb->task);
+    acb->task = NULL;
 }
 
 static void
@@ -84,15 +88,15 @@ iscsi_aio_cancel(BlockDriverAIOCB *blockacb)
     IscsiAIOCB *acb = (IscsiAIOCB *)blockacb;
     IscsiLun *iscsilun = acb->iscsilun;
 
-    acb->common.cb(acb->common.opaque, -ECANCELED);
     acb->canceled = 1;
 
-    /* send a task mgmt call to the target to cancel the task on the target */
-    iscsi_task_mgmt_abort_task_async(iscsilun->iscsi, acb->task,
-                                     iscsi_abort_task_cb, NULL);
+    acb->common.cb(acb->common.opaque, -ECANCELED);
 
-    /* then also cancel the task locally in libiscsi */
-    iscsi_scsi_task_cancel(iscsilun->iscsi, acb->task);
+    /* send a task mgmt call to the target to cancel the task on the target
+     * this also cancels the task in libiscsi
+     */
+    iscsi_task_mgmt_abort_task_async(iscsilun->iscsi, acb->task,
+                                     iscsi_abort_task_cb, &acb);
 }
 
 static AIOPool iscsi_aio_pool = {
@@ -179,11 +183,18 @@ iscsi_readv_writev_bh_cb(void *p)
 
     qemu_bh_delete(acb->bh);
 
-    if (acb->canceled == 0) {
+    if (!acb->canceled) {
         acb->common.cb(acb->common.opaque, acb->status);
     }
 
     qemu_aio_release(acb);
+
+    if (acb->canceled) {
+        return;
+    }
+
+    scsi_free_scsi_task(acb->task);
+    acb->task = NULL;
 }
 
 
@@ -197,10 +208,8 @@ iscsi_aio_write16_cb(struct iscsi_context *iscsi, int status,
 
     g_free(acb->buf);
 
-    if (acb->canceled != 0) {
+    if (acb->canceled) {
         qemu_aio_release(acb);
-        scsi_free_scsi_task(acb->task);
-        acb->task = NULL;
         return;
     }
 
@@ -212,8 +221,6 @@ iscsi_aio_write16_cb(struct iscsi_context *iscsi, int status,
     }
 
     iscsi_schedule_bh(iscsi_readv_writev_bh_cb, acb);
-    scsi_free_scsi_task(acb->task);
-    acb->task = NULL;
 }
 
 static int64_t sector_qemu2lun(int64_t sector, IscsiLun *iscsilun)
@@ -298,10 +305,8 @@ iscsi_aio_read16_cb(struct iscsi_context *iscsi, int status,
 
     trace_iscsi_aio_read16_cb(iscsi, status, acb, acb->canceled);
 
-    if (acb->canceled != 0) {
+    if (acb->canceled) {
         qemu_aio_release(acb);
-        scsi_free_scsi_task(acb->task);
-        acb->task = NULL;
         return;
     }
 
@@ -313,8 +318,6 @@ iscsi_aio_read16_cb(struct iscsi_context *iscsi, int status,
     }
 
     iscsi_schedule_bh(iscsi_readv_writev_bh_cb, acb);
-    scsi_free_scsi_task(acb->task);
-    acb->task = NULL;
 }
 
 static BlockDriverAIOCB *
@@ -414,10 +417,8 @@ iscsi_synccache10_cb(struct iscsi_context *iscsi, int status,
 {
     IscsiAIOCB *acb = opaque;
 
-    if (acb->canceled != 0) {
+    if (acb->canceled) {
         qemu_aio_release(acb);
-        scsi_free_scsi_task(acb->task);
-        acb->task = NULL;
         return;
     }
 
@@ -429,8 +430,6 @@ iscsi_synccache10_cb(struct iscsi_context *iscsi, int status,
     }
 
     iscsi_schedule_bh(iscsi_readv_writev_bh_cb, acb);
-    scsi_free_scsi_task(acb->task);
-    acb->task = NULL;
 }
 
 static BlockDriverAIOCB *
@@ -468,10 +467,8 @@ iscsi_unmap_cb(struct iscsi_context *iscsi, int status,
 {
     IscsiAIOCB *acb = opaque;
 
-    if (acb->canceled != 0) {
+    if (acb->canceled) {
         qemu_aio_release(acb);
-        scsi_free_scsi_task(acb->task);
-        acb->task = NULL;
         return;
     }
 
@@ -483,8 +480,6 @@ iscsi_unmap_cb(struct iscsi_context *iscsi, int status,
     }
 
     iscsi_schedule_bh(iscsi_readv_writev_bh_cb, acb);
-    scsi_free_scsi_task(acb->task);
-    acb->task = NULL;
 }
 
 static BlockDriverAIOCB *
@@ -528,10 +523,8 @@ iscsi_aio_ioctl_cb(struct iscsi_context *iscsi, int status,
 {
     IscsiAIOCB *acb = opaque;
 
-    if (acb->canceled != 0) {
+    if (acb->canceled) {
         qemu_aio_release(acb);
-        scsi_free_scsi_task(acb->task);
-        acb->task = NULL;
         return;
     }
 
@@ -560,8 +553,6 @@ iscsi_aio_ioctl_cb(struct iscsi_context *iscsi, int status,
     }
 
     iscsi_schedule_bh(iscsi_readv_writev_bh_cb, acb);
-    scsi_free_scsi_task(acb->task);
-    acb->task = NULL;
 }
 
 static BlockDriverAIOCB *iscsi_aio_ioctl(BlockDriverState *bs,
index 0dce089be537d8ed3e8d7f30f57dc7412554add6..6be20b192573f3ff2ded72d5a55d3330471cd96e 100644 (file)
@@ -271,7 +271,7 @@ static int raw_open_common(BlockDriverState *bs, const char *filename,
 out_free_buf:
     qemu_vfree(s->aligned_buf);
 out_close:
-    close(fd);
+    qemu_close(fd);
     return -errno;
 }
 
@@ -376,7 +376,7 @@ static void raw_close(BlockDriverState *bs)
 {
     BDRVRawState *s = bs->opaque;
     if (s->fd >= 0) {
-        close(s->fd);
+        qemu_close(s->fd);
         s->fd = -1;
         if (s->aligned_buf != NULL)
             qemu_vfree(s->aligned_buf);
@@ -572,15 +572,15 @@ static int raw_create(const char *filename, QEMUOptionParameter *options)
         options++;
     }
 
-    fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY,
-              0644);
+    fd = qemu_open(filename, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY,
+                   0644);
     if (fd < 0) {
         result = -errno;
     } else {
         if (ftruncate(fd, total_size * BDRV_SECTOR_SIZE) != 0) {
             result = -errno;
         }
-        if (close(fd) != 0) {
+        if (qemu_close(fd) != 0) {
             result = -errno;
         }
     }
@@ -846,11 +846,11 @@ static int hdev_open(BlockDriverState *bs, const char *filename, int flags)
         if ( bsdPath[ 0 ] != '\0' ) {
             strcat(bsdPath,"s0");
             /* some CDs don't have a partition 0 */
-            fd = open(bsdPath, O_RDONLY | O_BINARY | O_LARGEFILE);
+            fd = qemu_open(bsdPath, O_RDONLY | O_BINARY | O_LARGEFILE);
             if (fd < 0) {
                 bsdPath[strlen(bsdPath)-1] = '1';
             } else {
-                close(fd);
+                qemu_close(fd);
             }
             filename = bsdPath;
         }
@@ -889,7 +889,7 @@ static int fd_open(BlockDriverState *bs)
     last_media_present = (s->fd >= 0);
     if (s->fd >= 0 &&
         (get_clock() - s->fd_open_time) >= FD_OPEN_TIMEOUT) {
-        close(s->fd);
+        qemu_close(s->fd);
         s->fd = -1;
 #ifdef DEBUG_FLOPPY
         printf("Floppy closed\n");
@@ -903,7 +903,7 @@ static int fd_open(BlockDriverState *bs)
 #endif
             return -EIO;
         }
-        s->fd = open(bs->filename, s->open_flags & ~O_NONBLOCK);
+        s->fd = qemu_open(bs->filename, s->open_flags & ~O_NONBLOCK);
         if (s->fd < 0) {
             s->fd_error_time = get_clock();
             s->fd_got_error = 1;
@@ -977,7 +977,7 @@ static int hdev_create(const char *filename, QEMUOptionParameter *options)
         options++;
     }
 
-    fd = open(filename, O_WRONLY | O_BINARY);
+    fd = qemu_open(filename, O_WRONLY | O_BINARY);
     if (fd < 0)
         return -errno;
 
@@ -988,7 +988,7 @@ static int hdev_create(const char *filename, QEMUOptionParameter *options)
     else if (lseek(fd, 0, SEEK_END) < total_size * BDRV_SECTOR_SIZE)
         ret = -ENOSPC;
 
-    close(fd);
+    qemu_close(fd);
     return ret;
 }
 
@@ -1038,7 +1038,7 @@ static int floppy_open(BlockDriverState *bs, const char *filename, int flags)
         return ret;
 
     /* close fd so that we can reopen it as needed */
-    close(s->fd);
+    qemu_close(s->fd);
     s->fd = -1;
     s->fd_media_changed = 1;
 
@@ -1052,10 +1052,12 @@ static int floppy_probe_device(const char *filename)
     struct floppy_struct fdparam;
     struct stat st;
 
-    if (strstart(filename, "/dev/fd", NULL))
+    if (strstart(filename, "/dev/fd", NULL) &&
+        !strstart(filename, "/dev/fdset/", NULL)) {
         prio = 50;
+    }
 
-    fd = open(filename, O_RDONLY | O_NONBLOCK);
+    fd = qemu_open(filename, O_RDONLY | O_NONBLOCK);
     if (fd < 0) {
         goto out;
     }
@@ -1070,7 +1072,7 @@ static int floppy_probe_device(const char *filename)
         prio = 100;
 
 outc:
-    close(fd);
+    qemu_close(fd);
 out:
     return prio;
 }
@@ -1105,14 +1107,14 @@ static void floppy_eject(BlockDriverState *bs, bool eject_flag)
     int fd;
 
     if (s->fd >= 0) {
-        close(s->fd);
+        qemu_close(s->fd);
         s->fd = -1;
     }
-    fd = open(bs->filename, s->open_flags | O_NONBLOCK);
+    fd = qemu_open(bs->filename, s->open_flags | O_NONBLOCK);
     if (fd >= 0) {
         if (ioctl(fd, FDEJECT, 0) < 0)
             perror("FDEJECT");
-        close(fd);
+        qemu_close(fd);
     }
 }
 
@@ -1158,7 +1160,7 @@ static int cdrom_probe_device(const char *filename)
     int prio = 0;
     struct stat st;
 
-    fd = open(filename, O_RDONLY | O_NONBLOCK);
+    fd = qemu_open(filename, O_RDONLY | O_NONBLOCK);
     if (fd < 0) {
         goto out;
     }
@@ -1173,7 +1175,7 @@ static int cdrom_probe_device(const char *filename)
         prio = 100;
 
 outc:
-    close(fd);
+    qemu_close(fd);
 out:
     return prio;
 }
@@ -1281,8 +1283,8 @@ static int cdrom_reopen(BlockDriverState *bs)
      * FreeBSD seems to not notice sometimes...
      */
     if (s->fd >= 0)
-        close(s->fd);
-    fd = open(bs->filename, s->open_flags, 0644);
+        qemu_close(s->fd);
+    fd = qemu_open(bs->filename, s->open_flags, 0644);
     if (fd < 0) {
         s->fd = -1;
         return -EIO;
index e4b0b75b706b7c0d4edd282d3483b641d73296d5..c56bf83375e15cf57f7c74a8b1a293fe24482602 100644 (file)
@@ -255,13 +255,13 @@ static int raw_create(const char *filename, QEMUOptionParameter *options)
         options++;
     }
 
-    fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY,
-              0644);
+    fd = qemu_open(filename, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY,
+                   0644);
     if (fd < 0)
         return -EIO;
     set_sparse(fd);
     ftruncate(fd, total_size * 512);
-    close(fd);
+    qemu_close(fd);
     return 0;
 }
 
index 57325d65c4a87e8331f2cfac1d4c776c415e7790..c4f1529db9b04f73fa20f6a0e2db6801e4691a1b 100644 (file)
@@ -653,8 +653,9 @@ static int vdi_create(const char *filename, QEMUOptionParameter *options)
         options++;
     }
 
-    fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY | O_LARGEFILE,
-              0644);
+    fd = qemu_open(filename,
+                   O_WRONLY | O_CREAT | O_TRUNC | O_BINARY | O_LARGEFILE,
+                   0644);
     if (fd < 0) {
         return -errno;
     }
index 18e9b4caf6dc6562817aade2b46666aac6f2ca42..daee4268bea5f1a38d4903ed29e8ba21e0c214cb 100644 (file)
@@ -1161,10 +1161,9 @@ static int vmdk_create_extent(const char *filename, int64_t filesize,
     VMDK4Header header;
     uint32_t tmp, magic, grains, gd_size, gt_size, gt_count;
 
-    fd = open(
-        filename,
-        O_WRONLY | O_CREAT | O_TRUNC | O_BINARY | O_LARGEFILE,
-        0644);
+    fd = qemu_open(filename,
+                   O_WRONLY | O_CREAT | O_TRUNC | O_BINARY | O_LARGEFILE,
+                   0644);
     if (fd < 0) {
         return -errno;
     }
@@ -1259,7 +1258,7 @@ static int vmdk_create_extent(const char *filename, int64_t filesize,
 
     ret = 0;
  exit:
-    close(fd);
+    qemu_close(fd);
     return ret;
 }
 
@@ -1484,15 +1483,13 @@ static int vmdk_create(const char *filename, QEMUOptionParameter *options)
             (flags & BLOCK_FLAG_COMPAT6 ? 6 : 4),
             total_size / (int64_t)(63 * 16 * 512));
     if (split || flat) {
-        fd = open(
-                filename,
-                O_WRONLY | O_CREAT | O_TRUNC | O_BINARY | O_LARGEFILE,
-                0644);
+        fd = qemu_open(filename,
+                       O_WRONLY | O_CREAT | O_TRUNC | O_BINARY | O_LARGEFILE,
+                       0644);
     } else {
-        fd = open(
-                filename,
-                O_WRONLY | O_BINARY | O_LARGEFILE,
-                0644);
+        fd = qemu_open(filename,
+                       O_WRONLY | O_BINARY | O_LARGEFILE,
+                       0644);
     }
     if (fd < 0) {
         return -errno;
@@ -1509,7 +1506,7 @@ static int vmdk_create(const char *filename, QEMUOptionParameter *options)
     }
     ret = 0;
 exit:
-    close(fd);
+    qemu_close(fd);
     return ret;
 }
 
index 5cd13d17a11efd31a6753c30daee514a776e25fe..c0b82c4f574f10d6ee77bcd9515729f37c3c6cfd 100644 (file)
@@ -678,7 +678,7 @@ static int vpc_create(const char *filename, QEMUOptionParameter *options)
     }
 
     /* Create the file */
-    fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, 0644);
+    fd = qemu_open(filename, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, 0644);
     if (fd < 0) {
         return -EIO;
     }
@@ -744,7 +744,7 @@ static int vpc_create(const char *filename, QEMUOptionParameter *options)
     }
 
  fail:
-    close(fd);
+    qemu_close(fd);
     return ret;
 }
 
index 7b1dcee144ac429bcfea72e51a7155e91a1463c7..59d3c5b8ac213513667b5b61eadb0328c138e7d0 100644 (file)
@@ -1105,7 +1105,7 @@ static inline void vvfat_close_current_file(BDRVVVFATState *s)
     if(s->current_mapping) {
        s->current_mapping = NULL;
        if (s->current_fd) {
-               close(s->current_fd);
+               qemu_close(s->current_fd);
                s->current_fd = 0;
        }
     }
@@ -1162,7 +1162,7 @@ static int open_file(BDRVVVFATState* s,mapping_t* mapping)
     if(!s->current_mapping ||
            strcmp(s->current_mapping->path,mapping->path)) {
        /* open file */
-       int fd = open(mapping->path, O_RDONLY | O_BINARY | O_LARGEFILE);
+       int fd = qemu_open(mapping->path, O_RDONLY | O_BINARY | O_LARGEFILE);
        if(fd<0)
            return -1;
        vvfat_close_current_file(s);
@@ -2221,7 +2221,7 @@ static int commit_one_file(BDRVVVFATState* s,
     for (i = s->cluster_size; i < offset; i += s->cluster_size)
        c = modified_fat_get(s, c);
 
-    fd = open(mapping->path, O_RDWR | O_CREAT | O_BINARY, 0666);
+    fd = qemu_open(mapping->path, O_RDWR | O_CREAT | O_BINARY, 0666);
     if (fd < 0) {
        fprintf(stderr, "Could not open %s... (%s, %d)\n", mapping->path,
                strerror(errno), errno);
@@ -2230,7 +2230,7 @@ static int commit_one_file(BDRVVVFATState* s,
     }
     if (offset > 0) {
         if (lseek(fd, offset, SEEK_SET) != offset) {
-            close(fd);
+            qemu_close(fd);
             g_free(cluster);
             return -3;
         }
@@ -2251,13 +2251,13 @@ static int commit_one_file(BDRVVVFATState* s,
            (uint8_t*)cluster, (rest_size + 0x1ff) / 0x200);
 
         if (ret < 0) {
-            close(fd);
+            qemu_close(fd);
             g_free(cluster);
             return ret;
         }
 
         if (write(fd, cluster, rest_size) < 0) {
-            close(fd);
+            qemu_close(fd);
             g_free(cluster);
             return -2;
         }
@@ -2268,11 +2268,11 @@ static int commit_one_file(BDRVVVFATState* s,
 
     if (ftruncate(fd, size)) {
         perror("ftruncate()");
-        close(fd);
+        qemu_close(fd);
         g_free(cluster);
         return -4;
     }
-    close(fd);
+    qemu_close(fd);
     g_free(cluster);
 
     return commit_mappings(s, first_cluster, dir_index);
index f76921e5b059f16857e3cc136089358c275681be..07ba1f81139c6ad1203ea22345a79a20b392ed7b 100644 (file)
 #  define GCC_ATTR __attribute__((__unused__, format(gnu_printf, 1, 2)))
 #  define GCC_FMT_ATTR(n, m) __attribute__((format(gnu_printf, n, m)))
 # endif
+#if defined(_WIN32)
+#define GCC_WEAK __attribute__((weak))
+#define GCC_WEAK_DECL GCC_WEAK
+#else
 #define GCC_WEAK __attribute__((weak))
+#define GCC_WEAK_DECL
+#endif
 #else
 #define GCC_ATTR /**/
 #define GCC_FMT_ATTR(n, m)
index 0d1e2527fb0b761431cd62fda55b5d4ad3b6412b..d3e7b257ae3752f67a9207497c918fc048477e3f 100644 (file)
--- a/cputlb.c
+++ b/cputlb.c
@@ -312,7 +312,9 @@ void tlb_set_page(CPUArchState *env, target_ulong vaddr,
 
 /* NOTE: this function can trigger an exception */
 /* NOTE2: the returned address is not exactly the physical address: it
-   is the offset relative to phys_ram_base */
+ * is actually a ram_addr_t (in system mode; the user mode emulation
+ * version of this function returns a guest virtual address).
+ */
 tb_page_addr_t get_page_addr_code(CPUArchState *env1, target_ulong addr)
 {
     int mmu_idx, page_index, pd;
index ee4614d3786a604a1a287d8e9f6ad462023d43c8..8ef648f4b928e794d54956088fed40969288f6fb 100644 (file)
--- a/cutils.c
+++ b/cutils.c
@@ -383,6 +383,11 @@ int qemu_parse_fd(const char *param)
     return fd;
 }
 
+int qemu_parse_fdset(const char *param)
+{
+    return qemu_parse_fd(param);
+}
+
 /* round down to the nearest power of 2*/
 int64_t pow2floor(int64_t value)
 {
index 16083b387e4cba117a427cf030a3bbdc041dca59..803ebfc8314ecc587239b7e19b73d2123839a71c 100644 (file)
@@ -1,4 +1,4 @@
-= Bootindex propery =
+= Bootindex property =
 
 Block and net devices have bootindex property. This property is used to
 determine the order in which firmware will consider devices for booting
index 673557781e60ec3f597dea030527163c8800dc4c..ea546f83f18045a4539ea283fa18f0db20807a4c 100644 (file)
@@ -11,6 +11,7 @@
 #include "qemu-log.h"
 #include "sysemu.h"
 #include "vmware_vga.h"
+#include "vga-pci.h"
 
 
 /* PCI IO reads/writes, to byte-word addressable memory.  */
index 58e63b00da5821130bea2dd0ca7ca2cce71ffd99..371f95d909f4ee1edf514e3121a07bb239273cb6 100644 (file)
@@ -299,7 +299,9 @@ static int apic_init_common(SysBusDevice *dev)
 
     sysbus_init_mmio(dev, &s->io_memory);
 
-    if (!vapic && s->vapic_control & VAPIC_ENABLE_MASK) {
+    /* Note: We need at least 1M to map the VAPIC option ROM */
+    if (!vapic && s->vapic_control & VAPIC_ENABLE_MASK &&
+        ram_size >= 1024 * 1024) {
         vapic = sysbus_create_simple("kvmvapic", -1, NULL);
     }
     s->vapic = vapic;
index 623dd688d9071d3e83172f7707fd34da36c7ad18..e8dcc6b883a22350d6e9fa03b732f38617d16029 100644 (file)
@@ -27,8 +27,8 @@
  *   available at http://home.worldonline.dk/~finth/
  */
 #include "hw.h"
-#include "pc.h"
 #include "pci.h"
+#include "vga-pci.h"
 #include "console.h"
 #include "vga_int.h"
 #include "loader.h"
index f4747cd646629ced9ed8822e6eaa6850b6003e88..85a00a5798695fe15de37de695942d5c474c950d 100644 (file)
@@ -28,7 +28,7 @@ void framebuffer_update_display(
     MemoryRegion *address_space,
     target_phys_addr_t base,
     int cols, /* Width in pixels.  */
-    int rows, /* Leight in pixels.  */
+    int rows, /* Height in pixels.  */
     int src_width, /* Length of source line, in bytes.  */
     int dest_row_pitch, /* Bytes between adjacent horizontal output pixels.  */
     int dest_col_pitch, /* Bytes between adjacent vertical output pixels.  */
index 0c58161565e4e960787aac32b59e78c1de583dc7..b4d65a6db5b29d246f8a51aa582e4816db2bf41a 100644 (file)
@@ -677,7 +677,8 @@ static int pci_ivshmem_init(PCIDevice *dev)
     }
 
     if (s->role_val == IVSHMEM_PEER) {
-        error_set(&s->migration_blocker, QERR_DEVICE_FEATURE_BLOCKS_MIGRATION, "ivshmem", "peer mode");
+        error_set(&s->migration_blocker, QERR_DEVICE_FEATURE_BLOCKS_MIGRATION,
+                  "peer mode", "ivshmem");
         migrate_add_blocker(s->migration_blocker);
     }
 
index c5d3711a049dec00e341a1c36179fb43735c150b..53d13e3123b5f1a97f1b454d13bb09d114ebe0bc 100644 (file)
@@ -35,7 +35,8 @@
 typedef struct KVMPITState {
     PITCommonState pit;
     LostTickPolicy lost_tick_policy;
-    bool state_valid;
+    bool vm_stopped;
+    int64_t kernel_clock_offset;
 } KVMPITState;
 
 static int64_t abs64(int64_t v)
@@ -43,19 +44,11 @@ static int64_t abs64(int64_t v)
     return v < 0 ? -v : v;
 }
 
-static void kvm_pit_get(PITCommonState *pit)
+static void kvm_pit_update_clock_offset(KVMPITState *s)
 {
-    KVMPITState *s = DO_UPCAST(KVMPITState, pit, pit);
-    struct kvm_pit_state2 kpit;
-    struct kvm_pit_channel_state *kchan;
-    struct PITChannelState *sc;
     int64_t offset, clock_offset;
     struct timespec ts;
-    int i, ret;
-
-    if (s->state_valid) {
-        return;
-    }
+    int i;
 
     /*
      * Measure the delta between CLOCK_MONOTONIC, the base used for
@@ -72,6 +65,21 @@ static void kvm_pit_get(PITCommonState *pit)
             clock_offset = offset;
         }
     }
+    s->kernel_clock_offset = clock_offset;
+}
+
+static void kvm_pit_get(PITCommonState *pit)
+{
+    KVMPITState *s = DO_UPCAST(KVMPITState, pit, pit);
+    struct kvm_pit_state2 kpit;
+    struct kvm_pit_channel_state *kchan;
+    struct PITChannelState *sc;
+    int i, ret;
+
+    /* No need to re-read the state if VM is stopped. */
+    if (s->vm_stopped) {
+        return;
+    }
 
     if (kvm_has_pit_state2()) {
         ret = kvm_vm_ioctl(kvm_state, KVM_GET_PIT2, &kpit);
@@ -106,7 +114,7 @@ static void kvm_pit_get(PITCommonState *pit)
         sc->mode = kchan->mode;
         sc->bcd = kchan->bcd;
         sc->gate = kchan->gate;
-        sc->count_load_time = kchan->count_load_time + clock_offset;
+        sc->count_load_time = kchan->count_load_time + s->kernel_clock_offset;
     }
 
     sc = &pit->channels[0];
@@ -114,17 +122,23 @@ static void kvm_pit_get(PITCommonState *pit)
         pit_get_next_transition_time(sc, sc->count_load_time);
 }
 
-static void kvm_pit_put(PITCommonState *s)
+static void kvm_pit_put(PITCommonState *pit)
 {
+    KVMPITState *s = DO_UPCAST(KVMPITState, pit, pit);
     struct kvm_pit_state2 kpit;
     struct kvm_pit_channel_state *kchan;
     struct PITChannelState *sc;
     int i, ret;
 
-    kpit.flags = s->channels[0].irq_disabled ? KVM_PIT_FLAGS_HPET_LEGACY : 0;
+    /* The offset keeps changing as long as the VM is stopped. */
+    if (s->vm_stopped) {
+        kvm_pit_update_clock_offset(s);
+    }
+
+    kpit.flags = pit->channels[0].irq_disabled ? KVM_PIT_FLAGS_HPET_LEGACY : 0;
     for (i = 0; i < 3; i++) {
         kchan = &kpit.channels[i];
-        sc = &s->channels[i];
+        sc = &pit->channels[i];
         kchan->count = sc->count;
         kchan->latched_count = sc->latched_count;
         kchan->count_latched = sc->count_latched;
@@ -137,7 +151,7 @@ static void kvm_pit_put(PITCommonState *s)
         kchan->mode = sc->mode;
         kchan->bcd = sc->bcd;
         kchan->gate = sc->gate;
-        kchan->count_load_time = sc->count_load_time;
+        kchan->count_load_time = sc->count_load_time - s->kernel_clock_offset;
     }
 
     ret = kvm_vm_ioctl(kvm_state,
@@ -211,10 +225,12 @@ static void kvm_pit_vm_state_change(void *opaque, int running,
     KVMPITState *s = opaque;
 
     if (running) {
-        s->state_valid = false;
+        kvm_pit_update_clock_offset(s);
+        s->vm_stopped = false;
     } else {
+        kvm_pit_update_clock_offset(s);
         kvm_pit_get(&s->pit);
-        s->state_valid = true;
+        s->vm_stopped = true;
     }
 }
 
index 351c88ebca3153d3e3ef6a636651bb0ce76e34ef..ad23f26e597f9ff886d72c173ee5b0caefbb2871 100644 (file)
@@ -48,6 +48,7 @@
 #include "blockdev.h"
 #include "exec-memory.h"
 #include "sysbus.h"             /* SysBusDevice */
+#include "vga-pci.h"
 
 //#define DEBUG_BOARD_INIT
 
index 58ef871f684fd3face2e8f795bbf705fef4c9465..b9d856830a4ed999866edaf8335eecc7f7bfa056 100644 (file)
@@ -130,6 +130,17 @@ enum {
 #define MPIC_CPU_REG_START        0x20000
 #define MPIC_CPU_REG_SIZE         0x100 + ((MAX_CPU - 1) * 0x1000)
 
+/*
+ * Block Revision Register1 (BRR1): QEMU does not fully emulate
+ * any version on MPIC. So to start with, set the IP version to 0.
+ *
+ * NOTE: This is Freescale MPIC specific register. Keep it here till
+ * this code is refactored for different variants of OPENPIC and MPIC.
+ */
+#define FSL_BRR1_IPID (0x0040 << 16) /* 16 bit IP-block ID */
+#define FSL_BRR1_IPMJ (0x00 << 8) /* 8 bit IP major number */
+#define FSL_BRR1_IPMN 0x00 /* 8 bit IP minor number */
+
 enum mpic_ide_bits {
     IDR_EP     = 31,
     IDR_CI0     = 30,
@@ -595,6 +606,8 @@ static void openpic_gbl_write (void *opaque, target_phys_addr_t addr, uint32_t v
     if (addr & 0xF)
         return;
     switch (addr) {
+    case 0x00: /* Block Revision Register1 (BRR1) is Readonly */
+        break;
     case 0x40:
     case 0x50:
     case 0x60:
@@ -671,6 +684,7 @@ static uint32_t openpic_gbl_read (void *opaque, target_phys_addr_t addr)
     case 0x1090: /* PINT */
         retval = 0x00000000;
         break;
+    case 0x00: /* Block Revision Register1 (BRR1) */
     case 0x40:
     case 0x50:
     case 0x60:
@@ -893,6 +907,9 @@ static uint32_t openpic_cpu_read_internal(void *opaque, target_phys_addr_t addr,
     dst = &opp->dst[idx];
     addr &= 0xFF0;
     switch (addr) {
+    case 0x00: /* Block Revision Register1 (BRR1) */
+        retval = FSL_BRR1_IPID | FSL_BRR1_IPMJ | FSL_BRR1_IPMN;
+        break;
     case 0x80: /* PCTP */
         retval = dst->pctp;
         break;
diff --git a/hw/pc.c b/hw/pc.c
index e8bcfc0b4b1f758e7015be3674f6d79c8380a3c4..3ed1a3caa2e5e827b506b110b7504acef6865257 100644 (file)
--- a/hw/pc.c
+++ b/hw/pc.c
@@ -51,6 +51,7 @@
 #include "exec-memory.h"
 #include "arch_init.h"
 #include "bitmap.h"
+#include "vga-pci.h"
 
 /* output Bochs bios info messages */
 //#define DEBUG_BIOS
diff --git a/hw/pc.h b/hw/pc.h
index 31ccb6f49527ae955fc2f831b394d2fe61ed436f..e4db0715b81e8248d0f1cf76179b4f9afa4d8dd8 100644 (file)
--- a/hw/pc.h
+++ b/hw/pc.h
@@ -189,14 +189,10 @@ static inline DeviceState *isa_vga_init(ISABus *bus)
     return &dev->qdev;
 }
 
-DeviceState *pci_vga_init(PCIBus *bus);
 int isa_vga_mm_init(target_phys_addr_t vram_base,
                     target_phys_addr_t ctrl_base, int it_shift,
                     MemoryRegion *address_space);
 
-/* cirrus_vga.c */
-DeviceState *pci_cirrus_vga_init(PCIBus *bus);
-
 /* ne2000.c */
 static inline bool isa_ne2000_init(ISABus *bus, int base, int irq, NICInfo *nd)
 {
index aa4bbeb6644e3ddd9d8d5668c8a65857e10b7b2e..951e407f143e26d0b33ef0b051802001f5b4cbb4 100644 (file)
@@ -15,7 +15,7 @@ obj-$(CONFIG_PSERIES) += spapr_pci.o pci-hotplug.o spapr_iommu.o
 obj-y += ppc4xx_devs.o ppc4xx_pci.o ppc405_uc.o ppc405_boards.o
 obj-y += ppc440_bamboo.o
 # PowerPC E500 boards
-obj-$(CONFIG_FDT) += ppce500_mpc8544ds.o mpc8544_guts.o ppce500_spin.o
+obj-$(CONFIG_FDT) += mpc8544_guts.o ppce500_spin.o
 # PowerPC 440 Xilinx ML507 reference board.
 obj-y += virtex_ml507.o
 # PowerPC OpenPIC
@@ -26,3 +26,5 @@ obj-$(CONFIG_FDT) += ../device_tree.o
 obj-y += xilinx_ethlite.o
 
 obj-y := $(addprefix ../,$(obj-y))
+
+obj-$(CONFIG_FDT) += e500.o mpc8544ds.o e500plat.o
diff --git a/hw/ppc/e500.c b/hw/ppc/e500.c
new file mode 100644 (file)
index 0000000..6f0de6d
--- /dev/null
@@ -0,0 +1,589 @@
+/*
+ * QEMU PowerPC e500-based platforms
+ *
+ * Copyright (C) 2009 Freescale Semiconductor, Inc. All rights reserved.
+ *
+ * Author: Yu Liu,     <yu.liu@freescale.com>
+ *
+ * This file is derived from hw/ppc440_bamboo.c,
+ * the copyright for that material belongs to the original owners.
+ *
+ * This 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.
+ */
+
+#include "config.h"
+#include "qemu-common.h"
+#include "e500.h"
+#include "net.h"
+#include "hw/hw.h"
+#include "hw/pc.h"
+#include "hw/pci.h"
+#include "hw/boards.h"
+#include "sysemu.h"
+#include "kvm.h"
+#include "kvm_ppc.h"
+#include "device_tree.h"
+#include "hw/openpic.h"
+#include "hw/ppc.h"
+#include "hw/loader.h"
+#include "elf.h"
+#include "hw/sysbus.h"
+#include "exec-memory.h"
+#include "host-utils.h"
+
+#define BINARY_DEVICE_TREE_FILE    "mpc8544ds.dtb"
+#define UIMAGE_LOAD_BASE           0
+#define DTC_LOAD_PAD               0x500000
+#define DTC_PAD_MASK               0xFFFFF
+#define INITRD_LOAD_PAD            0x2000000
+#define INITRD_PAD_MASK            0xFFFFFF
+
+#define RAM_SIZES_ALIGN            (64UL << 20)
+
+/* TODO: parameterize */
+#define MPC8544_CCSRBAR_BASE       0xE0000000ULL
+#define MPC8544_CCSRBAR_SIZE       0x00100000ULL
+#define MPC8544_MPIC_REGS_BASE     (MPC8544_CCSRBAR_BASE + 0x40000ULL)
+#define MPC8544_SERIAL0_REGS_BASE  (MPC8544_CCSRBAR_BASE + 0x4500ULL)
+#define MPC8544_SERIAL1_REGS_BASE  (MPC8544_CCSRBAR_BASE + 0x4600ULL)
+#define MPC8544_PCI_REGS_BASE      (MPC8544_CCSRBAR_BASE + 0x8000ULL)
+#define MPC8544_PCI_REGS_SIZE      0x1000ULL
+#define MPC8544_PCI_IO             0xE1000000ULL
+#define MPC8544_PCI_IOLEN          0x10000ULL
+#define MPC8544_UTIL_BASE          (MPC8544_CCSRBAR_BASE + 0xe0000ULL)
+#define MPC8544_SPIN_BASE          0xEF000000ULL
+
+struct boot_info
+{
+    uint32_t dt_base;
+    uint32_t dt_size;
+    uint32_t entry;
+};
+
+static void pci_map_create(void *fdt, uint32_t *pci_map, uint32_t mpic)
+{
+    int i;
+    const uint32_t tmp[] = {
+                             /* IDSEL 0x11 J17 Slot 1 */
+                             0x8800, 0x0, 0x0, 0x1, mpic, 0x2, 0x1,
+                             0x8800, 0x0, 0x0, 0x2, mpic, 0x3, 0x1,
+                             0x8800, 0x0, 0x0, 0x3, mpic, 0x4, 0x1,
+                             0x8800, 0x0, 0x0, 0x4, mpic, 0x1, 0x1,
+
+                             /* IDSEL 0x12 J16 Slot 2 */
+                             0x9000, 0x0, 0x0, 0x1, mpic, 0x3, 0x1,
+                             0x9000, 0x0, 0x0, 0x2, mpic, 0x4, 0x1,
+                             0x9000, 0x0, 0x0, 0x3, mpic, 0x2, 0x1,
+                             0x9000, 0x0, 0x0, 0x4, mpic, 0x1, 0x1,
+                           };
+    for (i = 0; i < (7 * 8); i++) {
+        pci_map[i] = cpu_to_be32(tmp[i]);
+    }
+}
+
+static void dt_serial_create(void *fdt, unsigned long long offset,
+                             const char *soc, const char *mpic,
+                             const char *alias, int idx, bool defcon)
+{
+    char ser[128];
+
+    snprintf(ser, sizeof(ser), "%s/serial@%llx", soc, offset);
+    qemu_devtree_add_subnode(fdt, ser);
+    qemu_devtree_setprop_string(fdt, ser, "device_type", "serial");
+    qemu_devtree_setprop_string(fdt, ser, "compatible", "ns16550");
+    qemu_devtree_setprop_cells(fdt, ser, "reg", offset, 0x100);
+    qemu_devtree_setprop_cell(fdt, ser, "cell-index", idx);
+    qemu_devtree_setprop_cell(fdt, ser, "clock-frequency", 0);
+    qemu_devtree_setprop_cells(fdt, ser, "interrupts", 42, 2);
+    qemu_devtree_setprop_phandle(fdt, ser, "interrupt-parent", mpic);
+    qemu_devtree_setprop_string(fdt, "/aliases", alias, ser);
+
+    if (defcon) {
+        qemu_devtree_setprop_string(fdt, "/chosen", "linux,stdout-path", ser);
+    }
+}
+
+static int ppce500_load_device_tree(CPUPPCState *env,
+                                    PPCE500Params *params,
+                                    target_phys_addr_t addr,
+                                    target_phys_addr_t initrd_base,
+                                    target_phys_addr_t initrd_size)
+{
+    int ret = -1;
+    uint64_t mem_reg_property[] = { 0, cpu_to_be64(params->ram_size) };
+    int fdt_size;
+    void *fdt;
+    uint8_t hypercall[16];
+    uint32_t clock_freq = 400000000;
+    uint32_t tb_freq = 400000000;
+    int i;
+    const char *toplevel_compat = NULL; /* user override */
+    char compatible_sb[] = "fsl,mpc8544-immr\0simple-bus";
+    char soc[128];
+    char mpic[128];
+    uint32_t mpic_ph;
+    char gutil[128];
+    char pci[128];
+    uint32_t pci_map[7 * 8];
+    uint32_t pci_ranges[14] =
+        {
+            0x2000000, 0x0, 0xc0000000,
+            0x0, 0xc0000000,
+            0x0, 0x20000000,
+
+            0x1000000, 0x0, 0x0,
+            0x0, 0xe1000000,
+            0x0, 0x10000,
+        };
+    QemuOpts *machine_opts;
+    const char *dumpdtb = NULL;
+    const char *dtb_file = NULL;
+
+    machine_opts = qemu_opts_find(qemu_find_opts("machine"), 0);
+    if (machine_opts) {
+        dumpdtb = qemu_opt_get(machine_opts, "dumpdtb");
+        dtb_file = qemu_opt_get(machine_opts, "dtb");
+        toplevel_compat = qemu_opt_get(machine_opts, "dt_compatible");
+    }
+
+    if (dtb_file) {
+        char *filename;
+        filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, dtb_file);
+        if (!filename) {
+            goto out;
+        }
+
+        fdt = load_device_tree(filename, &fdt_size);
+        if (!fdt) {
+            goto out;
+        }
+        goto done;
+    }
+
+    fdt = create_device_tree(&fdt_size);
+    if (fdt == NULL) {
+        goto out;
+    }
+
+    /* Manipulate device tree in memory. */
+    qemu_devtree_setprop_cell(fdt, "/", "#address-cells", 2);
+    qemu_devtree_setprop_cell(fdt, "/", "#size-cells", 2);
+
+    qemu_devtree_add_subnode(fdt, "/memory");
+    qemu_devtree_setprop_string(fdt, "/memory", "device_type", "memory");
+    qemu_devtree_setprop(fdt, "/memory", "reg", mem_reg_property,
+                         sizeof(mem_reg_property));
+
+    qemu_devtree_add_subnode(fdt, "/chosen");
+    if (initrd_size) {
+        ret = qemu_devtree_setprop_cell(fdt, "/chosen", "linux,initrd-start",
+                                        initrd_base);
+        if (ret < 0) {
+            fprintf(stderr, "couldn't set /chosen/linux,initrd-start\n");
+        }
+
+        ret = qemu_devtree_setprop_cell(fdt, "/chosen", "linux,initrd-end",
+                                        (initrd_base + initrd_size));
+        if (ret < 0) {
+            fprintf(stderr, "couldn't set /chosen/linux,initrd-end\n");
+        }
+    }
+
+    ret = qemu_devtree_setprop_string(fdt, "/chosen", "bootargs",
+                                      params->kernel_cmdline);
+    if (ret < 0)
+        fprintf(stderr, "couldn't set /chosen/bootargs\n");
+
+    if (kvm_enabled()) {
+        /* Read out host's frequencies */
+        clock_freq = kvmppc_get_clockfreq();
+        tb_freq = kvmppc_get_tbfreq();
+
+        /* indicate KVM hypercall interface */
+        qemu_devtree_add_subnode(fdt, "/hypervisor");
+        qemu_devtree_setprop_string(fdt, "/hypervisor", "compatible",
+                                    "linux,kvm");
+        kvmppc_get_hypercall(env, hypercall, sizeof(hypercall));
+        qemu_devtree_setprop(fdt, "/hypervisor", "hcall-instructions",
+                             hypercall, sizeof(hypercall));
+    }
+
+    /* Create CPU nodes */
+    qemu_devtree_add_subnode(fdt, "/cpus");
+    qemu_devtree_setprop_cell(fdt, "/cpus", "#address-cells", 1);
+    qemu_devtree_setprop_cell(fdt, "/cpus", "#size-cells", 0);
+
+    /* We need to generate the cpu nodes in reverse order, so Linux can pick
+       the first node as boot node and be happy */
+    for (i = smp_cpus - 1; i >= 0; i--) {
+        char cpu_name[128];
+        uint64_t cpu_release_addr = MPC8544_SPIN_BASE + (i * 0x20);
+
+        for (env = first_cpu; env != NULL; env = env->next_cpu) {
+            if (env->cpu_index == i) {
+                break;
+            }
+        }
+
+        if (!env) {
+            continue;
+        }
+
+        snprintf(cpu_name, sizeof(cpu_name), "/cpus/PowerPC,8544@%x", env->cpu_index);
+        qemu_devtree_add_subnode(fdt, cpu_name);
+        qemu_devtree_setprop_cell(fdt, cpu_name, "clock-frequency", clock_freq);
+        qemu_devtree_setprop_cell(fdt, cpu_name, "timebase-frequency", tb_freq);
+        qemu_devtree_setprop_string(fdt, cpu_name, "device_type", "cpu");
+        qemu_devtree_setprop_cell(fdt, cpu_name, "reg", env->cpu_index);
+        qemu_devtree_setprop_cell(fdt, cpu_name, "d-cache-line-size",
+                                  env->dcache_line_size);
+        qemu_devtree_setprop_cell(fdt, cpu_name, "i-cache-line-size",
+                                  env->icache_line_size);
+        qemu_devtree_setprop_cell(fdt, cpu_name, "d-cache-size", 0x8000);
+        qemu_devtree_setprop_cell(fdt, cpu_name, "i-cache-size", 0x8000);
+        qemu_devtree_setprop_cell(fdt, cpu_name, "bus-frequency", 0);
+        if (env->cpu_index) {
+            qemu_devtree_setprop_string(fdt, cpu_name, "status", "disabled");
+            qemu_devtree_setprop_string(fdt, cpu_name, "enable-method", "spin-table");
+            qemu_devtree_setprop_u64(fdt, cpu_name, "cpu-release-addr",
+                                     cpu_release_addr);
+        } else {
+            qemu_devtree_setprop_string(fdt, cpu_name, "status", "okay");
+        }
+    }
+
+    qemu_devtree_add_subnode(fdt, "/aliases");
+    /* XXX These should go into their respective devices' code */
+    snprintf(soc, sizeof(soc), "/soc@%llx", MPC8544_CCSRBAR_BASE);
+    qemu_devtree_add_subnode(fdt, soc);
+    qemu_devtree_setprop_string(fdt, soc, "device_type", "soc");
+    qemu_devtree_setprop(fdt, soc, "compatible", compatible_sb,
+                         sizeof(compatible_sb));
+    qemu_devtree_setprop_cell(fdt, soc, "#address-cells", 1);
+    qemu_devtree_setprop_cell(fdt, soc, "#size-cells", 1);
+    qemu_devtree_setprop_cells(fdt, soc, "ranges", 0x0,
+                               MPC8544_CCSRBAR_BASE >> 32, MPC8544_CCSRBAR_BASE,
+                               MPC8544_CCSRBAR_SIZE);
+    /* XXX should contain a reasonable value */
+    qemu_devtree_setprop_cell(fdt, soc, "bus-frequency", 0);
+
+    snprintf(mpic, sizeof(mpic), "%s/pic@%llx", soc,
+             MPC8544_MPIC_REGS_BASE - MPC8544_CCSRBAR_BASE);
+    qemu_devtree_add_subnode(fdt, mpic);
+    qemu_devtree_setprop_string(fdt, mpic, "device_type", "open-pic");
+    qemu_devtree_setprop_string(fdt, mpic, "compatible", "chrp,open-pic");
+    qemu_devtree_setprop_cells(fdt, mpic, "reg", MPC8544_MPIC_REGS_BASE -
+                               MPC8544_CCSRBAR_BASE, 0x40000);
+    qemu_devtree_setprop_cell(fdt, mpic, "#address-cells", 0);
+    qemu_devtree_setprop_cell(fdt, mpic, "#interrupt-cells", 2);
+    mpic_ph = qemu_devtree_alloc_phandle(fdt);
+    qemu_devtree_setprop_cell(fdt, mpic, "phandle", mpic_ph);
+    qemu_devtree_setprop_cell(fdt, mpic, "linux,phandle", mpic_ph);
+    qemu_devtree_setprop(fdt, mpic, "interrupt-controller", NULL, 0);
+
+    /*
+     * We have to generate ser1 first, because Linux takes the first
+     * device it finds in the dt as serial output device. And we generate
+     * devices in reverse order to the dt.
+     */
+    dt_serial_create(fdt, MPC8544_SERIAL1_REGS_BASE - MPC8544_CCSRBAR_BASE,
+                     soc, mpic, "serial1", 1, false);
+    dt_serial_create(fdt, MPC8544_SERIAL0_REGS_BASE - MPC8544_CCSRBAR_BASE,
+                     soc, mpic, "serial0", 0, true);
+
+    snprintf(gutil, sizeof(gutil), "%s/global-utilities@%llx", soc,
+             MPC8544_UTIL_BASE - MPC8544_CCSRBAR_BASE);
+    qemu_devtree_add_subnode(fdt, gutil);
+    qemu_devtree_setprop_string(fdt, gutil, "compatible", "fsl,mpc8544-guts");
+    qemu_devtree_setprop_cells(fdt, gutil, "reg", MPC8544_UTIL_BASE -
+                               MPC8544_CCSRBAR_BASE, 0x1000);
+    qemu_devtree_setprop(fdt, gutil, "fsl,has-rstcr", NULL, 0);
+
+    snprintf(pci, sizeof(pci), "/pci@%llx", MPC8544_PCI_REGS_BASE);
+    qemu_devtree_add_subnode(fdt, pci);
+    qemu_devtree_setprop_cell(fdt, pci, "cell-index", 0);
+    qemu_devtree_setprop_string(fdt, pci, "compatible", "fsl,mpc8540-pci");
+    qemu_devtree_setprop_string(fdt, pci, "device_type", "pci");
+    qemu_devtree_setprop_cells(fdt, pci, "interrupt-map-mask", 0xf800, 0x0,
+                               0x0, 0x7);
+    pci_map_create(fdt, pci_map, qemu_devtree_get_phandle(fdt, mpic));
+    qemu_devtree_setprop(fdt, pci, "interrupt-map", pci_map, sizeof(pci_map));
+    qemu_devtree_setprop_phandle(fdt, pci, "interrupt-parent", mpic);
+    qemu_devtree_setprop_cells(fdt, pci, "interrupts", 24, 2);
+    qemu_devtree_setprop_cells(fdt, pci, "bus-range", 0, 255);
+    for (i = 0; i < 14; i++) {
+        pci_ranges[i] = cpu_to_be32(pci_ranges[i]);
+    }
+    qemu_devtree_setprop(fdt, pci, "ranges", pci_ranges, sizeof(pci_ranges));
+    qemu_devtree_setprop_cells(fdt, pci, "reg", MPC8544_PCI_REGS_BASE >> 32,
+                               MPC8544_PCI_REGS_BASE, 0, 0x1000);
+    qemu_devtree_setprop_cell(fdt, pci, "clock-frequency", 66666666);
+    qemu_devtree_setprop_cell(fdt, pci, "#interrupt-cells", 1);
+    qemu_devtree_setprop_cell(fdt, pci, "#size-cells", 2);
+    qemu_devtree_setprop_cell(fdt, pci, "#address-cells", 3);
+    qemu_devtree_setprop_string(fdt, "/aliases", "pci0", pci);
+
+    params->fixup_devtree(params, fdt);
+
+    if (toplevel_compat) {
+        qemu_devtree_setprop(fdt, "/", "compatible", toplevel_compat,
+                             strlen(toplevel_compat) + 1);
+    }
+
+done:
+    if (dumpdtb) {
+        /* Dump the dtb to a file and quit */
+        FILE *f = fopen(dumpdtb, "wb");
+        size_t len;
+        len = fwrite(fdt, fdt_size, 1, f);
+        fclose(f);
+        if (len != fdt_size) {
+            exit(1);
+        }
+        exit(0);
+    }
+
+    ret = rom_add_blob_fixed(BINARY_DEVICE_TREE_FILE, fdt, fdt_size, addr);
+    if (ret < 0) {
+        goto out;
+    }
+    g_free(fdt);
+    ret = fdt_size;
+
+out:
+
+    return ret;
+}
+
+/* Create -kernel TLB entries for BookE.  */
+static inline target_phys_addr_t booke206_page_size_to_tlb(uint64_t size)
+{
+    return 63 - clz64(size >> 10);
+}
+
+static void mmubooke_create_initial_mapping(CPUPPCState *env)
+{
+    struct boot_info *bi = env->load_info;
+    ppcmas_tlb_t *tlb = booke206_get_tlbm(env, 1, 0, 0);
+    target_phys_addr_t size, dt_end;
+    int ps;
+
+    /* Our initial TLB entry needs to cover everything from 0 to
+       the device tree top */
+    dt_end = bi->dt_base + bi->dt_size;
+    ps = booke206_page_size_to_tlb(dt_end) + 1;
+    size = (ps << MAS1_TSIZE_SHIFT);
+    tlb->mas1 = MAS1_VALID | size;
+    tlb->mas2 = 0;
+    tlb->mas7_3 = 0;
+    tlb->mas7_3 |= MAS3_UR | MAS3_UW | MAS3_UX | MAS3_SR | MAS3_SW | MAS3_SX;
+
+    env->tlb_dirty = true;
+}
+
+static void ppce500_cpu_reset_sec(void *opaque)
+{
+    PowerPCCPU *cpu = opaque;
+    CPUPPCState *env = &cpu->env;
+
+    cpu_reset(CPU(cpu));
+
+    /* Secondary CPU starts in halted state for now. Needs to change when
+       implementing non-kernel boot. */
+    env->halted = 1;
+    env->exception_index = EXCP_HLT;
+}
+
+static void ppce500_cpu_reset(void *opaque)
+{
+    PowerPCCPU *cpu = opaque;
+    CPUPPCState *env = &cpu->env;
+    struct boot_info *bi = env->load_info;
+
+    cpu_reset(CPU(cpu));
+
+    /* Set initial guest state. */
+    env->halted = 0;
+    env->gpr[1] = (16<<20) - 8;
+    env->gpr[3] = bi->dt_base;
+    env->nip = bi->entry;
+    mmubooke_create_initial_mapping(env);
+}
+
+void ppce500_init(PPCE500Params *params)
+{
+    MemoryRegion *address_space_mem = get_system_memory();
+    MemoryRegion *ram = g_new(MemoryRegion, 1);
+    PCIBus *pci_bus;
+    CPUPPCState *env = NULL;
+    uint64_t elf_entry;
+    uint64_t elf_lowaddr;
+    target_phys_addr_t entry=0;
+    target_phys_addr_t loadaddr=UIMAGE_LOAD_BASE;
+    target_long kernel_size=0;
+    target_ulong dt_base = 0;
+    target_ulong initrd_base = 0;
+    target_long initrd_size=0;
+    int i=0;
+    unsigned int pci_irq_nrs[4] = {1, 2, 3, 4};
+    qemu_irq **irqs, *mpic;
+    DeviceState *dev;
+    CPUPPCState *firstenv = NULL;
+
+    /* Setup CPUs */
+    if (params->cpu_model == NULL) {
+        params->cpu_model = "e500v2_v30";
+    }
+
+    irqs = g_malloc0(smp_cpus * sizeof(qemu_irq *));
+    irqs[0] = g_malloc0(smp_cpus * sizeof(qemu_irq) * OPENPIC_OUTPUT_NB);
+    for (i = 0; i < smp_cpus; i++) {
+        PowerPCCPU *cpu;
+        qemu_irq *input;
+
+        cpu = cpu_ppc_init(params->cpu_model);
+        if (cpu == NULL) {
+            fprintf(stderr, "Unable to initialize CPU!\n");
+            exit(1);
+        }
+        env = &cpu->env;
+
+        if (!firstenv) {
+            firstenv = env;
+        }
+
+        irqs[i] = irqs[0] + (i * OPENPIC_OUTPUT_NB);
+        input = (qemu_irq *)env->irq_inputs;
+        irqs[i][OPENPIC_OUTPUT_INT] = input[PPCE500_INPUT_INT];
+        irqs[i][OPENPIC_OUTPUT_CINT] = input[PPCE500_INPUT_CINT];
+        env->spr[SPR_BOOKE_PIR] = env->cpu_index = i;
+        env->mpic_cpu_base = MPC8544_MPIC_REGS_BASE + 0x20000;
+
+        ppc_booke_timers_init(env, 400000000, PPC_TIMER_E500);
+
+        /* Register reset handler */
+        if (!i) {
+            /* Primary CPU */
+            struct boot_info *boot_info;
+            boot_info = g_malloc0(sizeof(struct boot_info));
+            qemu_register_reset(ppce500_cpu_reset, cpu);
+            env->load_info = boot_info;
+        } else {
+            /* Secondary CPUs */
+            qemu_register_reset(ppce500_cpu_reset_sec, cpu);
+        }
+    }
+
+    env = firstenv;
+
+    /* Fixup Memory size on a alignment boundary */
+    ram_size &= ~(RAM_SIZES_ALIGN - 1);
+
+    /* Register Memory */
+    memory_region_init_ram(ram, "mpc8544ds.ram", ram_size);
+    vmstate_register_ram_global(ram);
+    memory_region_add_subregion(address_space_mem, 0, ram);
+
+    /* MPIC */
+    mpic = mpic_init(address_space_mem, MPC8544_MPIC_REGS_BASE,
+                     smp_cpus, irqs, NULL);
+
+    if (!mpic) {
+        cpu_abort(env, "MPIC failed to initialize\n");
+    }
+
+    /* Serial */
+    if (serial_hds[0]) {
+        serial_mm_init(address_space_mem, MPC8544_SERIAL0_REGS_BASE,
+                       0, mpic[12+26], 399193,
+                       serial_hds[0], DEVICE_BIG_ENDIAN);
+    }
+
+    if (serial_hds[1]) {
+        serial_mm_init(address_space_mem, MPC8544_SERIAL1_REGS_BASE,
+                       0, mpic[12+26], 399193,
+                       serial_hds[0], DEVICE_BIG_ENDIAN);
+    }
+
+    /* General Utility device */
+    sysbus_create_simple("mpc8544-guts", MPC8544_UTIL_BASE, NULL);
+
+    /* PCI */
+    dev = sysbus_create_varargs("e500-pcihost", MPC8544_PCI_REGS_BASE,
+                                mpic[pci_irq_nrs[0]], mpic[pci_irq_nrs[1]],
+                                mpic[pci_irq_nrs[2]], mpic[pci_irq_nrs[3]],
+                                NULL);
+    pci_bus = (PCIBus *)qdev_get_child_bus(dev, "pci.0");
+    if (!pci_bus)
+        printf("couldn't create PCI controller!\n");
+
+    isa_mmio_init(MPC8544_PCI_IO, MPC8544_PCI_IOLEN);
+
+    if (pci_bus) {
+        /* Register network interfaces. */
+        for (i = 0; i < nb_nics; i++) {
+            pci_nic_init_nofail(&nd_table[i], "virtio", NULL);
+        }
+    }
+
+    /* Register spinning region */
+    sysbus_create_simple("e500-spin", MPC8544_SPIN_BASE, NULL);
+
+    /* Load kernel. */
+    if (params->kernel_filename) {
+        kernel_size = load_uimage(params->kernel_filename, &entry,
+                                  &loadaddr, NULL);
+        if (kernel_size < 0) {
+            kernel_size = load_elf(params->kernel_filename, NULL, NULL,
+                                   &elf_entry, &elf_lowaddr, NULL, 1,
+                                   ELF_MACHINE, 0);
+            entry = elf_entry;
+            loadaddr = elf_lowaddr;
+        }
+        /* XXX try again as binary */
+        if (kernel_size < 0) {
+            fprintf(stderr, "qemu: could not load kernel '%s'\n",
+                    params->kernel_filename);
+            exit(1);
+        }
+    }
+
+    /* Load initrd. */
+    if (params->initrd_filename) {
+        initrd_base = (kernel_size + INITRD_LOAD_PAD) & ~INITRD_PAD_MASK;
+        initrd_size = load_image_targphys(params->initrd_filename, initrd_base,
+                                          ram_size - initrd_base);
+
+        if (initrd_size < 0) {
+            fprintf(stderr, "qemu: could not load initial ram disk '%s'\n",
+                    params->initrd_filename);
+            exit(1);
+        }
+    }
+
+    /* If we're loading a kernel directly, we must load the device tree too. */
+    if (params->kernel_filename) {
+        struct boot_info *boot_info;
+        int dt_size;
+
+        dt_base = (loadaddr + kernel_size + DTC_LOAD_PAD) & ~DTC_PAD_MASK;
+        dt_size = ppce500_load_device_tree(env, params, dt_base, initrd_base,
+                                           initrd_size);
+        if (dt_size < 0) {
+            fprintf(stderr, "couldn't load device tree\n");
+            exit(1);
+        }
+
+        boot_info = env->load_info;
+        boot_info->entry = entry;
+        boot_info->dt_base = dt_base;
+        boot_info->dt_size = dt_size;
+    }
+
+    if (kvm_enabled()) {
+        kvmppc_init();
+    }
+}
diff --git a/hw/ppc/e500.h b/hw/ppc/e500.h
new file mode 100644 (file)
index 0000000..7ae87f4
--- /dev/null
@@ -0,0 +1,21 @@
+#ifndef PPCE500_H
+#define PPCE500_H
+
+typedef struct PPCE500Params {
+    /* Standard QEMU machine init params */
+    ram_addr_t ram_size;
+    const char *boot_device;
+    const char *kernel_filename;
+    const char *kernel_cmdline;
+    const char *initrd_filename;
+    const char *cpu_model;
+
+    /* e500-specific params */
+
+    /* required -- must at least add toplevel board compatible */
+    void (*fixup_devtree)(struct PPCE500Params *params, void *fdt);
+} PPCE500Params;
+
+void ppce500_init(PPCE500Params *params);
+
+#endif
diff --git a/hw/ppc/e500plat.c b/hw/ppc/e500plat.c
new file mode 100644 (file)
index 0000000..60a5cb3
--- /dev/null
@@ -0,0 +1,60 @@
+/*
+ * Generic device-tree-driven paravirt PPC e500 platform
+ *
+ * Copyright 2012 Freescale Semiconductor, Inc.
+ *
+ * This 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.
+ */
+
+#include "config.h"
+#include "qemu-common.h"
+#include "e500.h"
+#include "../boards.h"
+#include "device_tree.h"
+
+static void e500plat_fixup_devtree(PPCE500Params *params, void *fdt)
+{
+    const char model[] = "QEMU ppce500";
+    const char compatible[] = "fsl,qemu-e500";
+
+    qemu_devtree_setprop(fdt, "/", "model", model, sizeof(model));
+    qemu_devtree_setprop(fdt, "/", "compatible", compatible,
+                         sizeof(compatible));
+}
+
+static void e500plat_init(ram_addr_t ram_size,
+                           const char *boot_device,
+                           const char *kernel_filename,
+                           const char *kernel_cmdline,
+                           const char *initrd_filename,
+                           const char *cpu_model)
+{
+    PPCE500Params params = {
+        .ram_size = ram_size,
+        .boot_device = boot_device,
+        .kernel_filename = kernel_filename,
+        .kernel_cmdline = kernel_cmdline,
+        .initrd_filename = initrd_filename,
+        .cpu_model = cpu_model,
+        .fixup_devtree = e500plat_fixup_devtree,
+    };
+
+    ppce500_init(&params);
+}
+
+static QEMUMachine e500plat_machine = {
+    .name = "ppce500",
+    .desc = "generic paravirt e500 platform",
+    .init = e500plat_init,
+    .max_cpus = 15,
+};
+
+static void e500plat_machine_init(void)
+{
+    qemu_register_machine(&e500plat_machine);
+}
+
+machine_init(e500plat_machine_init);
diff --git a/hw/ppc/mpc8544ds.c b/hw/ppc/mpc8544ds.c
new file mode 100644 (file)
index 0000000..984d21c
--- /dev/null
@@ -0,0 +1,61 @@
+/*
+ * Support for the PPC e500-based mpc8544ds board
+ *
+ * Copyright 2012 Freescale Semiconductor, Inc.
+ *
+ * This 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.
+ */
+
+#include "config.h"
+#include "qemu-common.h"
+#include "e500.h"
+#include "../boards.h"
+#include "device_tree.h"
+
+static void mpc8544ds_fixup_devtree(PPCE500Params *params, void *fdt)
+{
+    const char model[] = "MPC8544DS";
+    const char compatible[] = "MPC8544DS\0MPC85xxDS";
+
+    qemu_devtree_setprop(fdt, "/", "model", model, sizeof(model));
+    qemu_devtree_setprop(fdt, "/", "compatible", compatible,
+                         sizeof(compatible));
+}
+
+static void mpc8544ds_init(ram_addr_t ram_size,
+                           const char *boot_device,
+                           const char *kernel_filename,
+                           const char *kernel_cmdline,
+                           const char *initrd_filename,
+                           const char *cpu_model)
+{
+    PPCE500Params params = {
+        .ram_size = ram_size,
+        .boot_device = boot_device,
+        .kernel_filename = kernel_filename,
+        .kernel_cmdline = kernel_cmdline,
+        .initrd_filename = initrd_filename,
+        .cpu_model = cpu_model,
+        .fixup_devtree = mpc8544ds_fixup_devtree,
+    };
+
+    ppce500_init(&params);
+}
+
+
+static QEMUMachine ppce500_machine = {
+    .name = "mpc8544ds",
+    .desc = "mpc8544ds",
+    .init = mpc8544ds_init,
+    .max_cpus = 15,
+};
+
+static void ppce500_machine_init(void)
+{
+    qemu_register_machine(&ppce500_machine);
+}
+
+machine_init(ppce500_machine_init);
index 4e2a6e691b3a8705ce3ea015506a9c0af57d8676..e95cfe831e262da68685595e9a01edbb8b9e9c07 100644 (file)
@@ -52,7 +52,6 @@
 #include "adb.h"
 #include "mac_dbdma.h"
 #include "nvram.h"
-#include "pc.h"
 #include "pci.h"
 #include "net.h"
 #include "sysemu.h"
@@ -68,6 +67,7 @@
 #include "hw/usb.h"
 #include "blockdev.h"
 #include "exec-memory.h"
+#include "vga-pci.h"
 
 #define MAX_IDE_BUS 2
 #define CFG_ADDR 0xf0000510
index f2c6908534e8c741585215ea1fd3bf9479de736b..1dcd8a6c36d303277a7af4a0234c95dfcc7b959e 100644 (file)
@@ -29,7 +29,6 @@
 #include "adb.h"
 #include "mac_dbdma.h"
 #include "nvram.h"
-#include "pc.h"
 #include "sysemu.h"
 #include "net.h"
 #include "isa.h"
@@ -44,6 +43,7 @@
 #include "kvm_ppc.h"
 #include "blockdev.h"
 #include "exec-memory.h"
+#include "vga-pci.h"
 
 #define MAX_IDE_BUS 2
 #define CFG_ADDR 0xf0000510
index be2b26830deed1f728c01aa8f0582b63540919a8..7a876164c9b9cd82f26ad0467d3f48b04c357480 100644 (file)
@@ -39,6 +39,7 @@
 #include "blockdev.h"
 #include "arch_init.h"
 #include "exec-memory.h"
+#include "vga-pci.h"
 
 //#define HARD_DEBUG_PPC_IO
 //#define DEBUG_PPC_IO
diff --git a/hw/ppce500_mpc8544ds.c b/hw/ppce500_mpc8544ds.c
deleted file mode 100644 (file)
index 8b9fd83..0000000
+++ /dev/null
@@ -1,610 +0,0 @@
-/*
- * QEMU PowerPC MPC8544DS board emulation
- *
- * Copyright (C) 2009 Freescale Semiconductor, Inc. All rights reserved.
- *
- * Author: Yu Liu,     <yu.liu@freescale.com>
- *
- * This file is derived from hw/ppc440_bamboo.c,
- * the copyright for that material belongs to the original owners.
- *
- * This 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.
- */
-
-#include "config.h"
-#include "qemu-common.h"
-#include "net.h"
-#include "hw.h"
-#include "pc.h"
-#include "pci.h"
-#include "boards.h"
-#include "sysemu.h"
-#include "kvm.h"
-#include "kvm_ppc.h"
-#include "device_tree.h"
-#include "openpic.h"
-#include "ppc.h"
-#include "loader.h"
-#include "elf.h"
-#include "sysbus.h"
-#include "exec-memory.h"
-#include "host-utils.h"
-
-#define BINARY_DEVICE_TREE_FILE    "mpc8544ds.dtb"
-#define UIMAGE_LOAD_BASE           0
-#define DTC_LOAD_PAD               0x500000
-#define DTC_PAD_MASK               0xFFFFF
-#define INITRD_LOAD_PAD            0x2000000
-#define INITRD_PAD_MASK            0xFFFFFF
-
-#define RAM_SIZES_ALIGN            (64UL << 20)
-
-#define MPC8544_CCSRBAR_BASE       0xE0000000ULL
-#define MPC8544_CCSRBAR_SIZE       0x00100000ULL
-#define MPC8544_MPIC_REGS_BASE     (MPC8544_CCSRBAR_BASE + 0x40000ULL)
-#define MPC8544_SERIAL0_REGS_BASE  (MPC8544_CCSRBAR_BASE + 0x4500ULL)
-#define MPC8544_SERIAL1_REGS_BASE  (MPC8544_CCSRBAR_BASE + 0x4600ULL)
-#define MPC8544_PCI_REGS_BASE      (MPC8544_CCSRBAR_BASE + 0x8000ULL)
-#define MPC8544_PCI_REGS_SIZE      0x1000ULL
-#define MPC8544_PCI_IO             0xE1000000ULL
-#define MPC8544_PCI_IOLEN          0x10000ULL
-#define MPC8544_UTIL_BASE          (MPC8544_CCSRBAR_BASE + 0xe0000ULL)
-#define MPC8544_SPIN_BASE          0xEF000000ULL
-
-struct boot_info
-{
-    uint32_t dt_base;
-    uint32_t dt_size;
-    uint32_t entry;
-};
-
-static void pci_map_create(void *fdt, uint32_t *pci_map, uint32_t mpic)
-{
-    int i;
-    const uint32_t tmp[] = {
-                             /* IDSEL 0x11 J17 Slot 1 */
-                             0x8800, 0x0, 0x0, 0x1, mpic, 0x2, 0x1, 0x0, 0x0,
-                             0x8800, 0x0, 0x0, 0x2, mpic, 0x3, 0x1, 0x0, 0x0,
-                             0x8800, 0x0, 0x0, 0x3, mpic, 0x4, 0x1, 0x0, 0x0,
-                             0x8800, 0x0, 0x0, 0x4, mpic, 0x1, 0x1, 0x0, 0x0,
-
-                             /* IDSEL 0x12 J16 Slot 2 */
-                             0x9000, 0x0, 0x0, 0x1, mpic, 0x3, 0x1, 0x0, 0x0,
-                             0x9000, 0x0, 0x0, 0x2, mpic, 0x4, 0x1, 0x0, 0x0,
-                             0x9000, 0x0, 0x0, 0x3, mpic, 0x2, 0x1, 0x0, 0x0,
-                             0x9000, 0x0, 0x0, 0x4, mpic, 0x1, 0x1, 0x0, 0x0,
-                           };
-    for (i = 0; i < ARRAY_SIZE(tmp); i++) {
-        pci_map[i] = cpu_to_be32(tmp[i]);
-    }
-}
-
-static void dt_serial_create(void *fdt, unsigned long long offset,
-                             const char *soc, const char *mpic,
-                             const char *alias, int idx, bool defcon)
-{
-    char ser[128];
-
-    snprintf(ser, sizeof(ser), "%s/serial@%llx", soc, offset);
-    qemu_devtree_add_subnode(fdt, ser);
-    qemu_devtree_setprop_string(fdt, ser, "device_type", "serial");
-    qemu_devtree_setprop_string(fdt, ser, "compatible", "ns16550");
-    qemu_devtree_setprop_cells(fdt, ser, "reg", offset, 0x100);
-    qemu_devtree_setprop_cell(fdt, ser, "cell-index", idx);
-    qemu_devtree_setprop_cell(fdt, ser, "clock-frequency", 0);
-    qemu_devtree_setprop_cells(fdt, ser, "interrupts", 42, 2, 0, 0);
-    qemu_devtree_setprop_phandle(fdt, ser, "interrupt-parent", mpic);
-    qemu_devtree_setprop_string(fdt, "/aliases", alias, ser);
-
-    if (defcon) {
-        qemu_devtree_setprop_string(fdt, "/chosen", "linux,stdout-path", ser);
-    }
-}
-
-static int mpc8544_load_device_tree(CPUPPCState *env,
-                                    target_phys_addr_t addr,
-                                    target_phys_addr_t ramsize,
-                                    target_phys_addr_t initrd_base,
-                                    target_phys_addr_t initrd_size,
-                                    const char *kernel_cmdline)
-{
-    int ret = -1;
-    uint64_t mem_reg_property[] = { 0, cpu_to_be64(ramsize) };
-    int fdt_size;
-    void *fdt;
-    uint8_t hypercall[16];
-    uint32_t clock_freq = 400000000;
-    uint32_t tb_freq = 400000000;
-    int i;
-    const char *compatible = "MPC8544DS\0MPC85xxDS";
-    int compatible_len = sizeof("MPC8544DS\0MPC85xxDS");
-    char compatible_sb[] = "fsl,mpc8544-immr\0simple-bus";
-    char model[] = "MPC8544DS";
-    char soc[128];
-    char mpic[128];
-    uint32_t mpic_ph;
-    char gutil[128];
-    char pci[128];
-    uint32_t pci_map[9 * 8];
-    uint32_t pci_ranges[14] =
-        {
-            0x2000000, 0x0, 0xc0000000,
-            0x0, 0xc0000000,
-            0x0, 0x20000000,
-
-            0x1000000, 0x0, 0x0,
-            0x0, 0xe1000000,
-            0x0, 0x10000,
-        };
-    QemuOpts *machine_opts;
-    const char *dumpdtb = NULL;
-    const char *dtb_file = NULL;
-
-    machine_opts = qemu_opts_find(qemu_find_opts("machine"), 0);
-    if (machine_opts) {
-        const char *tmp;
-        dumpdtb = qemu_opt_get(machine_opts, "dumpdtb");
-        dtb_file = qemu_opt_get(machine_opts, "dtb");
-        tmp = qemu_opt_get(machine_opts, "dt_compatible");
-        if (tmp) {
-            compatible = tmp;
-            compatible_len = strlen(compatible) + 1;
-        }
-    }
-
-    if (dtb_file) {
-        char *filename;
-        filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, dtb_file);
-        if (!filename) {
-            goto out;
-        }
-
-        fdt = load_device_tree(filename, &fdt_size);
-        if (!fdt) {
-            goto out;
-        }
-        goto done;
-    }
-
-    fdt = create_device_tree(&fdt_size);
-    if (fdt == NULL) {
-        goto out;
-    }
-
-    /* Manipulate device tree in memory. */
-    qemu_devtree_setprop_string(fdt, "/", "model", model);
-    qemu_devtree_setprop(fdt, "/", "compatible", compatible, compatible_len);
-    qemu_devtree_setprop_cell(fdt, "/", "#address-cells", 2);
-    qemu_devtree_setprop_cell(fdt, "/", "#size-cells", 2);
-
-    qemu_devtree_add_subnode(fdt, "/memory");
-    qemu_devtree_setprop_string(fdt, "/memory", "device_type", "memory");
-    qemu_devtree_setprop(fdt, "/memory", "reg", mem_reg_property,
-                         sizeof(mem_reg_property));
-
-    qemu_devtree_add_subnode(fdt, "/chosen");
-    if (initrd_size) {
-        ret = qemu_devtree_setprop_cell(fdt, "/chosen", "linux,initrd-start",
-                                        initrd_base);
-        if (ret < 0) {
-            fprintf(stderr, "couldn't set /chosen/linux,initrd-start\n");
-        }
-
-        ret = qemu_devtree_setprop_cell(fdt, "/chosen", "linux,initrd-end",
-                                        (initrd_base + initrd_size));
-        if (ret < 0) {
-            fprintf(stderr, "couldn't set /chosen/linux,initrd-end\n");
-        }
-    }
-
-    ret = qemu_devtree_setprop_string(fdt, "/chosen", "bootargs",
-                                      kernel_cmdline);
-    if (ret < 0)
-        fprintf(stderr, "couldn't set /chosen/bootargs\n");
-
-    if (kvm_enabled()) {
-        /* Read out host's frequencies */
-        clock_freq = kvmppc_get_clockfreq();
-        tb_freq = kvmppc_get_tbfreq();
-
-        /* indicate KVM hypercall interface */
-        qemu_devtree_add_subnode(fdt, "/hypervisor");
-        qemu_devtree_setprop_string(fdt, "/hypervisor", "compatible",
-                                    "linux,kvm");
-        kvmppc_get_hypercall(env, hypercall, sizeof(hypercall));
-        qemu_devtree_setprop(fdt, "/hypervisor", "hcall-instructions",
-                             hypercall, sizeof(hypercall));
-    }
-
-    /* Create CPU nodes */
-    qemu_devtree_add_subnode(fdt, "/cpus");
-    qemu_devtree_setprop_cell(fdt, "/cpus", "#address-cells", 1);
-    qemu_devtree_setprop_cell(fdt, "/cpus", "#size-cells", 0);
-
-    /* We need to generate the cpu nodes in reverse order, so Linux can pick
-       the first node as boot node and be happy */
-    for (i = smp_cpus - 1; i >= 0; i--) {
-        char cpu_name[128];
-        uint64_t cpu_release_addr = MPC8544_SPIN_BASE + (i * 0x20);
-
-        for (env = first_cpu; env != NULL; env = env->next_cpu) {
-            if (env->cpu_index == i) {
-                break;
-            }
-        }
-
-        if (!env) {
-            continue;
-        }
-
-        snprintf(cpu_name, sizeof(cpu_name), "/cpus/PowerPC,8544@%x", env->cpu_index);
-        qemu_devtree_add_subnode(fdt, cpu_name);
-        qemu_devtree_setprop_cell(fdt, cpu_name, "clock-frequency", clock_freq);
-        qemu_devtree_setprop_cell(fdt, cpu_name, "timebase-frequency", tb_freq);
-        qemu_devtree_setprop_string(fdt, cpu_name, "device_type", "cpu");
-        qemu_devtree_setprop_cell(fdt, cpu_name, "reg", env->cpu_index);
-        qemu_devtree_setprop_cell(fdt, cpu_name, "d-cache-line-size",
-                                  env->dcache_line_size);
-        qemu_devtree_setprop_cell(fdt, cpu_name, "i-cache-line-size",
-                                  env->icache_line_size);
-        qemu_devtree_setprop_cell(fdt, cpu_name, "d-cache-size", 0x8000);
-        qemu_devtree_setprop_cell(fdt, cpu_name, "i-cache-size", 0x8000);
-        qemu_devtree_setprop_cell(fdt, cpu_name, "bus-frequency", 0);
-        if (env->cpu_index) {
-            qemu_devtree_setprop_string(fdt, cpu_name, "status", "disabled");
-            qemu_devtree_setprop_string(fdt, cpu_name, "enable-method", "spin-table");
-            qemu_devtree_setprop_u64(fdt, cpu_name, "cpu-release-addr",
-                                     cpu_release_addr);
-        } else {
-            qemu_devtree_setprop_string(fdt, cpu_name, "status", "okay");
-        }
-    }
-
-    qemu_devtree_add_subnode(fdt, "/aliases");
-    /* XXX These should go into their respective devices' code */
-    snprintf(soc, sizeof(soc), "/soc@%llx", MPC8544_CCSRBAR_BASE);
-    qemu_devtree_add_subnode(fdt, soc);
-    qemu_devtree_setprop_string(fdt, soc, "device_type", "soc");
-    qemu_devtree_setprop(fdt, soc, "compatible", compatible_sb,
-                         sizeof(compatible_sb));
-    qemu_devtree_setprop_cell(fdt, soc, "#address-cells", 1);
-    qemu_devtree_setprop_cell(fdt, soc, "#size-cells", 1);
-    qemu_devtree_setprop_cells(fdt, soc, "ranges", 0x0,
-                               MPC8544_CCSRBAR_BASE >> 32, MPC8544_CCSRBAR_BASE,
-                               MPC8544_CCSRBAR_SIZE);
-    /* XXX should contain a reasonable value */
-    qemu_devtree_setprop_cell(fdt, soc, "bus-frequency", 0);
-
-    snprintf(mpic, sizeof(mpic), "%s/pic@%llx", soc,
-             MPC8544_MPIC_REGS_BASE - MPC8544_CCSRBAR_BASE);
-    qemu_devtree_add_subnode(fdt, mpic);
-    qemu_devtree_setprop_string(fdt, mpic, "device_type", "open-pic");
-    qemu_devtree_setprop_string(fdt, mpic, "compatible", "fsl,mpic");
-    qemu_devtree_setprop_cells(fdt, mpic, "reg", MPC8544_MPIC_REGS_BASE -
-                               MPC8544_CCSRBAR_BASE, 0x40000);
-    qemu_devtree_setprop_cell(fdt, mpic, "#address-cells", 0);
-    qemu_devtree_setprop_cell(fdt, mpic, "#interrupt-cells", 4);
-    mpic_ph = qemu_devtree_alloc_phandle(fdt);
-    qemu_devtree_setprop_cell(fdt, mpic, "phandle", mpic_ph);
-    qemu_devtree_setprop_cell(fdt, mpic, "linux,phandle", mpic_ph);
-    qemu_devtree_setprop(fdt, mpic, "interrupt-controller", NULL, 0);
-    qemu_devtree_setprop(fdt, mpic, "big-endian", NULL, 0);
-    qemu_devtree_setprop(fdt, mpic, "single-cpu-affinity", NULL, 0);
-    qemu_devtree_setprop_cell(fdt, mpic, "last-interrupt-source", 255);
-
-    /*
-     * We have to generate ser1 first, because Linux takes the first
-     * device it finds in the dt as serial output device. And we generate
-     * devices in reverse order to the dt.
-     */
-    dt_serial_create(fdt, MPC8544_SERIAL1_REGS_BASE - MPC8544_CCSRBAR_BASE,
-                     soc, mpic, "serial1", 1, false);
-    dt_serial_create(fdt, MPC8544_SERIAL0_REGS_BASE - MPC8544_CCSRBAR_BASE,
-                     soc, mpic, "serial0", 0, true);
-
-    snprintf(gutil, sizeof(gutil), "%s/global-utilities@%llx", soc,
-             MPC8544_UTIL_BASE - MPC8544_CCSRBAR_BASE);
-    qemu_devtree_add_subnode(fdt, gutil);
-    qemu_devtree_setprop_string(fdt, gutil, "compatible", "fsl,mpc8544-guts");
-    qemu_devtree_setprop_cells(fdt, gutil, "reg", MPC8544_UTIL_BASE -
-                               MPC8544_CCSRBAR_BASE, 0x1000);
-    qemu_devtree_setprop(fdt, gutil, "fsl,has-rstcr", NULL, 0);
-
-    snprintf(pci, sizeof(pci), "/pci@%llx", MPC8544_PCI_REGS_BASE);
-    qemu_devtree_add_subnode(fdt, pci);
-    qemu_devtree_setprop_cell(fdt, pci, "cell-index", 0);
-    qemu_devtree_setprop_string(fdt, pci, "compatible", "fsl,mpc8540-pci");
-    qemu_devtree_setprop_string(fdt, pci, "device_type", "pci");
-    qemu_devtree_setprop_cells(fdt, pci, "interrupt-map-mask", 0xf800, 0x0,
-                               0x0, 0x7);
-    pci_map_create(fdt, pci_map, qemu_devtree_get_phandle(fdt, mpic));
-    qemu_devtree_setprop(fdt, pci, "interrupt-map", pci_map, sizeof(pci_map));
-    qemu_devtree_setprop_phandle(fdt, pci, "interrupt-parent", mpic);
-    qemu_devtree_setprop_cells(fdt, pci, "interrupts", 24, 2, 0, 0);
-    qemu_devtree_setprop_cells(fdt, pci, "bus-range", 0, 255);
-    for (i = 0; i < 14; i++) {
-        pci_ranges[i] = cpu_to_be32(pci_ranges[i]);
-    }
-    qemu_devtree_setprop(fdt, pci, "ranges", pci_ranges, sizeof(pci_ranges));
-    qemu_devtree_setprop_cells(fdt, pci, "reg", MPC8544_PCI_REGS_BASE >> 32,
-                               MPC8544_PCI_REGS_BASE, 0, 0x1000);
-    qemu_devtree_setprop_cell(fdt, pci, "clock-frequency", 66666666);
-    qemu_devtree_setprop_cell(fdt, pci, "#interrupt-cells", 1);
-    qemu_devtree_setprop_cell(fdt, pci, "#size-cells", 2);
-    qemu_devtree_setprop_cell(fdt, pci, "#address-cells", 3);
-    qemu_devtree_setprop_string(fdt, "/aliases", "pci0", pci);
-
-done:
-    if (dumpdtb) {
-        /* Dump the dtb to a file and quit */
-        FILE *f = fopen(dumpdtb, "wb");
-        size_t len;
-        len = fwrite(fdt, fdt_size, 1, f);
-        fclose(f);
-        if (len != fdt_size) {
-            exit(1);
-        }
-        exit(0);
-    }
-
-    ret = rom_add_blob_fixed(BINARY_DEVICE_TREE_FILE, fdt, fdt_size, addr);
-    if (ret < 0) {
-        goto out;
-    }
-    g_free(fdt);
-    ret = fdt_size;
-
-out:
-
-    return ret;
-}
-
-/* Create -kernel TLB entries for BookE.  */
-static inline target_phys_addr_t booke206_page_size_to_tlb(uint64_t size)
-{
-    return 63 - clz64(size >> 10);
-}
-
-static void mmubooke_create_initial_mapping(CPUPPCState *env)
-{
-    struct boot_info *bi = env->load_info;
-    ppcmas_tlb_t *tlb = booke206_get_tlbm(env, 1, 0, 0);
-    target_phys_addr_t size, dt_end;
-    int ps;
-
-    /* Our initial TLB entry needs to cover everything from 0 to
-       the device tree top */
-    dt_end = bi->dt_base + bi->dt_size;
-    ps = booke206_page_size_to_tlb(dt_end) + 1;
-    size = (ps << MAS1_TSIZE_SHIFT);
-    tlb->mas1 = MAS1_VALID | size;
-    tlb->mas2 = 0;
-    tlb->mas7_3 = 0;
-    tlb->mas7_3 |= MAS3_UR | MAS3_UW | MAS3_UX | MAS3_SR | MAS3_SW | MAS3_SX;
-
-    env->tlb_dirty = true;
-}
-
-static void mpc8544ds_cpu_reset_sec(void *opaque)
-{
-    PowerPCCPU *cpu = opaque;
-    CPUPPCState *env = &cpu->env;
-
-    cpu_reset(CPU(cpu));
-
-    /* Secondary CPU starts in halted state for now. Needs to change when
-       implementing non-kernel boot. */
-    env->halted = 1;
-    env->exception_index = EXCP_HLT;
-}
-
-static void mpc8544ds_cpu_reset(void *opaque)
-{
-    PowerPCCPU *cpu = opaque;
-    CPUPPCState *env = &cpu->env;
-    struct boot_info *bi = env->load_info;
-
-    cpu_reset(CPU(cpu));
-
-    /* Set initial guest state. */
-    env->halted = 0;
-    env->gpr[1] = (16<<20) - 8;
-    env->gpr[3] = bi->dt_base;
-    env->nip = bi->entry;
-    mmubooke_create_initial_mapping(env);
-}
-
-static void mpc8544ds_init(ram_addr_t ram_size,
-                         const char *boot_device,
-                         const char *kernel_filename,
-                         const char *kernel_cmdline,
-                         const char *initrd_filename,
-                         const char *cpu_model)
-{
-    MemoryRegion *address_space_mem = get_system_memory();
-    MemoryRegion *ram = g_new(MemoryRegion, 1);
-    PCIBus *pci_bus;
-    CPUPPCState *env = NULL;
-    uint64_t elf_entry;
-    uint64_t elf_lowaddr;
-    target_phys_addr_t entry=0;
-    target_phys_addr_t loadaddr=UIMAGE_LOAD_BASE;
-    target_long kernel_size=0;
-    target_ulong dt_base = 0;
-    target_ulong initrd_base = 0;
-    target_long initrd_size=0;
-    int i=0;
-    unsigned int pci_irq_nrs[4] = {1, 2, 3, 4};
-    qemu_irq **irqs, *mpic;
-    DeviceState *dev;
-    CPUPPCState *firstenv = NULL;
-
-    /* Setup CPUs */
-    if (cpu_model == NULL) {
-        cpu_model = "e500v2_v30";
-    }
-
-    irqs = g_malloc0(smp_cpus * sizeof(qemu_irq *));
-    irqs[0] = g_malloc0(smp_cpus * sizeof(qemu_irq) * OPENPIC_OUTPUT_NB);
-    for (i = 0; i < smp_cpus; i++) {
-        PowerPCCPU *cpu;
-        qemu_irq *input;
-
-        cpu = cpu_ppc_init(cpu_model);
-        if (cpu == NULL) {
-            fprintf(stderr, "Unable to initialize CPU!\n");
-            exit(1);
-        }
-        env = &cpu->env;
-
-        if (!firstenv) {
-            firstenv = env;
-        }
-
-        irqs[i] = irqs[0] + (i * OPENPIC_OUTPUT_NB);
-        input = (qemu_irq *)env->irq_inputs;
-        irqs[i][OPENPIC_OUTPUT_INT] = input[PPCE500_INPUT_INT];
-        irqs[i][OPENPIC_OUTPUT_CINT] = input[PPCE500_INPUT_CINT];
-        env->spr[SPR_BOOKE_PIR] = env->cpu_index = i;
-        env->mpic_cpu_base = MPC8544_MPIC_REGS_BASE + 0x20000;
-
-        ppc_booke_timers_init(env, 400000000, PPC_TIMER_E500);
-
-        /* Register reset handler */
-        if (!i) {
-            /* Primary CPU */
-            struct boot_info *boot_info;
-            boot_info = g_malloc0(sizeof(struct boot_info));
-            qemu_register_reset(mpc8544ds_cpu_reset, cpu);
-            env->load_info = boot_info;
-        } else {
-            /* Secondary CPUs */
-            qemu_register_reset(mpc8544ds_cpu_reset_sec, cpu);
-        }
-    }
-
-    env = firstenv;
-
-    /* Fixup Memory size on a alignment boundary */
-    ram_size &= ~(RAM_SIZES_ALIGN - 1);
-
-    /* Register Memory */
-    memory_region_init_ram(ram, "mpc8544ds.ram", ram_size);
-    vmstate_register_ram_global(ram);
-    memory_region_add_subregion(address_space_mem, 0, ram);
-
-    /* MPIC */
-    mpic = mpic_init(address_space_mem, MPC8544_MPIC_REGS_BASE,
-                     smp_cpus, irqs, NULL);
-
-    if (!mpic) {
-        cpu_abort(env, "MPIC failed to initialize\n");
-    }
-
-    /* Serial */
-    if (serial_hds[0]) {
-        serial_mm_init(address_space_mem, MPC8544_SERIAL0_REGS_BASE,
-                       0, mpic[12+26], 399193,
-                       serial_hds[0], DEVICE_BIG_ENDIAN);
-    }
-
-    if (serial_hds[1]) {
-        serial_mm_init(address_space_mem, MPC8544_SERIAL1_REGS_BASE,
-                       0, mpic[12+26], 399193,
-                       serial_hds[0], DEVICE_BIG_ENDIAN);
-    }
-
-    /* General Utility device */
-    sysbus_create_simple("mpc8544-guts", MPC8544_UTIL_BASE, NULL);
-
-    /* PCI */
-    dev = sysbus_create_varargs("e500-pcihost", MPC8544_PCI_REGS_BASE,
-                                mpic[pci_irq_nrs[0]], mpic[pci_irq_nrs[1]],
-                                mpic[pci_irq_nrs[2]], mpic[pci_irq_nrs[3]],
-                                NULL);
-    pci_bus = (PCIBus *)qdev_get_child_bus(dev, "pci.0");
-    if (!pci_bus)
-        printf("couldn't create PCI controller!\n");
-
-    isa_mmio_init(MPC8544_PCI_IO, MPC8544_PCI_IOLEN);
-
-    if (pci_bus) {
-        /* Register network interfaces. */
-        for (i = 0; i < nb_nics; i++) {
-            pci_nic_init_nofail(&nd_table[i], "virtio", NULL);
-        }
-    }
-
-    /* Register spinning region */
-    sysbus_create_simple("e500-spin", MPC8544_SPIN_BASE, NULL);
-
-    /* Load kernel. */
-    if (kernel_filename) {
-        kernel_size = load_uimage(kernel_filename, &entry, &loadaddr, NULL);
-        if (kernel_size < 0) {
-            kernel_size = load_elf(kernel_filename, NULL, NULL, &elf_entry,
-                                   &elf_lowaddr, NULL, 1, ELF_MACHINE, 0);
-            entry = elf_entry;
-            loadaddr = elf_lowaddr;
-        }
-        /* XXX try again as binary */
-        if (kernel_size < 0) {
-            fprintf(stderr, "qemu: could not load kernel '%s'\n",
-                    kernel_filename);
-            exit(1);
-        }
-    }
-
-    /* Load initrd. */
-    if (initrd_filename) {
-        initrd_base = (kernel_size + INITRD_LOAD_PAD) & ~INITRD_PAD_MASK;
-        initrd_size = load_image_targphys(initrd_filename, initrd_base,
-                                          ram_size - initrd_base);
-
-        if (initrd_size < 0) {
-            fprintf(stderr, "qemu: could not load initial ram disk '%s'\n",
-                    initrd_filename);
-            exit(1);
-        }
-    }
-
-    /* If we're loading a kernel directly, we must load the device tree too. */
-    if (kernel_filename) {
-        struct boot_info *boot_info;
-        int dt_size;
-
-        dt_base = (loadaddr + kernel_size + DTC_LOAD_PAD) & ~DTC_PAD_MASK;
-        dt_size = mpc8544_load_device_tree(env, dt_base, ram_size, initrd_base,
-                                           initrd_size, kernel_cmdline);
-        if (dt_size < 0) {
-            fprintf(stderr, "couldn't load device tree\n");
-            exit(1);
-        }
-
-        boot_info = env->load_info;
-        boot_info->entry = entry;
-        boot_info->dt_base = dt_base;
-        boot_info->dt_size = dt_size;
-    }
-
-    if (kvm_enabled()) {
-        kvmppc_init();
-    }
-}
-
-static QEMUMachine mpc8544ds_machine = {
-    .name = "mpc8544ds",
-    .desc = "mpc8544ds",
-    .init = mpc8544ds_init,
-    .max_cpus = 15,
-};
-
-static void mpc8544ds_machine_init(void)
-{
-    qemu_register_machine(&mpc8544ds_machine);
-}
-
-machine_init(mpc8544ds_machine_init);
index b22a37a00c34ad7562173db903707d4bc9c50014..018b386782b0c3a681876c88ee2b5ae9e2c8b8a6 100644 (file)
@@ -443,7 +443,7 @@ DeviceState *qdev_device_add(QemuOpts *opts)
         bus = qbus_find_recursive(sysbus_get_default(), NULL, k->bus_type);
         if (!bus) {
             qerror_report(QERR_NO_BUS_FOR_DEVICE,
-                          driver, k->bus_type);
+                          k->bus_type, driver);
             return NULL;
         }
     }
index 81c9343ca5e228b3d00c402bc75202932184193b..5178721d49c408011ef0e8e46adef88754a610c4 100644 (file)
 #include "hw/spapr_vio.h"
 #include "hw/spapr_pci.h"
 #include "hw/xics.h"
+#include "hw/msi.h"
 
 #include "kvm.h"
 #include "kvm_ppc.h"
 #include "pci.h"
+#include "vga-pci.h"
 
 #include "exec-memory.h"
 
 #define SPAPR_PCI_MEM_WIN_ADDR  (0x10000000000ULL + 0xA0000000)
 #define SPAPR_PCI_MEM_WIN_SIZE  0x20000000
 #define SPAPR_PCI_IO_WIN_ADDR   (0x10000000000ULL + 0x80000000)
+#define SPAPR_PCI_MSI_WIN_ADDR  (0x10000000000ULL + 0x90000000)
 
 #define PHANDLE_XICP            0x00001111
 
 sPAPREnvironment *spapr;
 
-qemu_irq spapr_allocate_irq(uint32_t hint, uint32_t *irq_num,
-                            enum xics_irq_type type)
+int spapr_allocate_irq(int hint, enum xics_irq_type type)
 {
-    uint32_t irq;
-    qemu_irq qirq;
+    int irq;
 
     if (hint) {
         irq = hint;
@@ -96,16 +97,40 @@ qemu_irq spapr_allocate_irq(uint32_t hint, uint32_t *irq_num,
         irq = spapr->next_irq++;
     }
 
-    qirq = xics_assign_irq(spapr->icp, irq, type);
-    if (!qirq) {
-        return NULL;
+    /* Configure irq type */
+    if (!xics_get_qirq(spapr->icp, irq)) {
+        return 0;
     }
 
-    if (irq_num) {
-        *irq_num = irq;
+    xics_set_irq_type(spapr->icp, irq, type);
+
+    return irq;
+}
+
+/* Allocate block of consequtive IRQs, returns a number of the first */
+int spapr_allocate_irq_block(int num, enum xics_irq_type type)
+{
+    int first = -1;
+    int i;
+
+    for (i = 0; i < num; ++i) {
+        int irq;
+
+        irq = spapr_allocate_irq(0, type);
+        if (!irq) {
+            return -1;
+        }
+
+        if (0 == i) {
+            first = irq;
+        }
+
+        /* If the above doesn't create a consecutive block then that's
+         * an internal bug */
+        assert(irq == (first + i));
     }
 
-    return qirq;
+    return first;
 }
 
 static int spapr_set_associativity(void *fdt, sPAPREnvironment *spapr)
@@ -257,6 +282,9 @@ static void *spapr_create_fdt_skel(const char *cpu_model,
         _FDT((fdt_property(fdt, "qemu,boot-kernel", &kprop, sizeof(kprop))));
     }
     _FDT((fdt_property_string(fdt, "qemu,boot-device", boot_device)));
+    _FDT((fdt_property_cell(fdt, "qemu,graphic-width", graphic_width)));
+    _FDT((fdt_property_cell(fdt, "qemu,graphic-height", graphic_height)));
+    _FDT((fdt_property_cell(fdt, "qemu,graphic-depth", graphic_depth)));
 
     _FDT((fdt_end_node(fdt)));
 
@@ -481,7 +509,7 @@ static void spapr_finalize_fdt(sPAPREnvironment *spapr,
     }
 
     QLIST_FOREACH(phb, &spapr->phbs, list) {
-        ret = spapr_populate_pci_devices(phb, PHANDLE_XICP, fdt);
+        ret = spapr_populate_pci_dt(phb, PHANDLE_XICP, fdt);
     }
 
     if (ret < 0) {
@@ -503,7 +531,9 @@ static void spapr_finalize_fdt(sPAPREnvironment *spapr,
         }
     }
 
-    spapr_populate_chosen_stdout(fdt, spapr->vio_bus);
+    if (!spapr->has_graphics) {
+        spapr_populate_chosen_stdout(fdt, spapr->vio_bus);
+    }
 
     _FDT((fdt_pack(fdt)));
 
@@ -532,8 +562,6 @@ static void spapr_reset(void *opaque)
 {
     sPAPREnvironment *spapr = (sPAPREnvironment *)opaque;
 
-    fprintf(stderr, "sPAPR reset\n");
-
     /* flush out the hash table */
     memset(spapr->htab, 0, spapr->htab_size);
 
@@ -556,6 +584,23 @@ static void spapr_cpu_reset(void *opaque)
     cpu_reset(CPU(cpu));
 }
 
+/* Returns whether we want to use VGA or not */
+static int spapr_vga_init(PCIBus *pci_bus)
+{
+    switch (vga_interface_type) {
+    case VGA_STD:
+        pci_vga_init(pci_bus);
+        return 1;
+    case VGA_NONE:
+        return 0;
+    default:
+        fprintf(stderr, "This vga model is not supported,"
+                "currently it only supports -vga std\n");
+        exit(0);
+        break;
+    }
+}
+
 /* pSeries LPAR / sPAPR hardware init */
 static void ppc_spapr_init(ram_addr_t ram_size,
                            const char *boot_device,
@@ -576,6 +621,8 @@ static void ppc_spapr_init(ram_addr_t ram_size,
     long pteg_shift = 17;
     char *filename;
 
+    msi_supported = true;
+
     spapr = g_malloc0(sizeof(*spapr));
     QLIST_INIT(&spapr->phbs);
 
@@ -687,10 +734,13 @@ static void ppc_spapr_init(ram_addr_t ram_size,
     }
 
     /* Set up PCI */
+    spapr_pci_rtas_init();
+
     spapr_create_phb(spapr, "pci", SPAPR_PCI_BUID,
                      SPAPR_PCI_MEM_WIN_ADDR,
                      SPAPR_PCI_MEM_WIN_SIZE,
-                     SPAPR_PCI_IO_WIN_ADDR);
+                     SPAPR_PCI_IO_WIN_ADDR,
+                     SPAPR_PCI_MSI_WIN_ADDR);
 
     for (i = 0; i < nb_nics; i++) {
         NICInfo *nd = &nd_table[i];
@@ -710,20 +760,17 @@ static void ppc_spapr_init(ram_addr_t ram_size,
         spapr_vscsi_create(spapr->vio_bus);
     }
 
+    /* Graphics */
+    if (spapr_vga_init(QLIST_FIRST(&spapr->phbs)->host_state.bus)) {
+        spapr->has_graphics = true;
+    }
+
     if (rma_size < (MIN_RMA_SLOF << 20)) {
         fprintf(stderr, "qemu: pSeries SLOF firmware requires >= "
                 "%ldM guest RMA (Real Mode Area memory)\n", MIN_RMA_SLOF);
         exit(1);
     }
 
-    fprintf(stderr, "sPAPR memory map:\n");
-    fprintf(stderr, "RTAS                 : 0x%08lx..%08lx\n",
-            (unsigned long)spapr->rtas_addr,
-            (unsigned long)(spapr->rtas_addr + spapr->rtas_size - 1));
-    fprintf(stderr, "FDT                  : 0x%08lx..%08lx\n",
-            (unsigned long)spapr->fdt_addr,
-            (unsigned long)(spapr->fdt_addr + FDT_MAX_SIZE - 1));
-
     if (kernel_filename) {
         uint64_t lowaddr = 0;
 
@@ -739,8 +786,6 @@ static void ppc_spapr_init(ram_addr_t ram_size,
                     kernel_filename);
             exit(1);
         }
-        fprintf(stderr, "Kernel               : 0x%08x..%08lx\n",
-                KERNEL_LOAD_ADDR, KERNEL_LOAD_ADDR + kernel_size - 1);
 
         /* load initrd */
         if (initrd_filename) {
@@ -755,8 +800,6 @@ static void ppc_spapr_init(ram_addr_t ram_size,
                         initrd_filename);
                 exit(1);
             }
-            fprintf(stderr, "Ramdisk              : 0x%08lx..%08lx\n",
-                    (long)initrd_base, (long)(initrd_base + initrd_size - 1));
         } else {
             initrd_base = 0;
             initrd_size = 0;
@@ -770,10 +813,6 @@ static void ppc_spapr_init(ram_addr_t ram_size,
         exit(1);
     }
     g_free(filename);
-    fprintf(stderr, "Firmware load        : 0x%08x..%08lx\n",
-            0, fw_size);
-    fprintf(stderr, "Firmware runtime     : 0x%08lx..%08lx\n",
-            load_limit, (unsigned long)spapr->fdt_addr);
 
     spapr->entry_point = 0x100;
 
index 9153f29a60f62e5cfac2f6d9a4e13209ff180b59..ac34a171e3526acacaa61a3a76d131e921e42e61 100644 (file)
@@ -23,6 +23,7 @@ typedef struct sPAPREnvironment {
     int next_irq;
     int rtc_offset;
     char *cpu_model;
+    bool has_graphics;
 } sPAPREnvironment;
 
 #define H_SUCCESS         0
@@ -288,17 +289,17 @@ void spapr_register_hypercall(target_ulong opcode, spapr_hcall_fn fn);
 target_ulong spapr_hypercall(CPUPPCState *env, target_ulong opcode,
                              target_ulong *args);
 
-qemu_irq spapr_allocate_irq(uint32_t hint, uint32_t *irq_num,
-                            enum xics_irq_type type);
+int spapr_allocate_irq(int hint, enum xics_irq_type type);
+int spapr_allocate_irq_block(int num, enum xics_irq_type type);
 
-static inline qemu_irq spapr_allocate_msi(uint32_t hint, uint32_t *irq_num)
+static inline int spapr_allocate_msi(int hint)
 {
-    return spapr_allocate_irq(hint, irq_num, XICS_MSI);
+    return spapr_allocate_irq(hint, XICS_MSI);
 }
 
-static inline qemu_irq spapr_allocate_lsi(uint32_t hint, uint32_t *irq_num)
+static inline int spapr_allocate_lsi(int hint)
 {
-    return spapr_allocate_irq(hint, irq_num, XICS_LSI);
+    return spapr_allocate_irq(hint, XICS_LSI);
 }
 
 static inline uint32_t rtas_ld(target_ulong phys, int n)
@@ -336,6 +337,8 @@ void spapr_iommu_init(void);
 DMAContext *spapr_tce_new_dma_context(uint32_t liobn, size_t window_size);
 void spapr_tce_free(DMAContext *dma);
 int spapr_dma_dt(void *fdt, int node_off, const char *propname,
-                 DMAContext *dma);
+                 uint32_t liobn, uint64_t window, uint32_t size);
+int spapr_tcet_dma_dt(void *fdt, int node_off, const char *propname,
+                      DMAContext *dma);
 
 #endif /* !defined (__HW_SPAPR_H__) */
index 388ffa4b2279308f37221b94ecc93178c813f5e2..53b731773abc1f7e6d79fa3acd16a401f48771d7 100644 (file)
@@ -216,31 +216,47 @@ void spapr_iommu_init(void)
 }
 
 int spapr_dma_dt(void *fdt, int node_off, const char *propname,
-                 DMAContext *dma)
+                 uint32_t liobn, uint64_t window, uint32_t size)
 {
-    if (dma) {
-        sPAPRTCETable *tcet = DO_UPCAST(sPAPRTCETable, dma, dma);
-        uint32_t dma_prop[] = {cpu_to_be32(tcet->liobn),
-                               0, 0,
-                               0, cpu_to_be32(tcet->window_size)};
-        int ret;
-
-        ret = fdt_setprop_cell(fdt, node_off, "ibm,#dma-address-cells", 2);
-        if (ret < 0) {
-            return ret;
-        }
+    uint32_t dma_prop[5];
+    int ret;
+
+    dma_prop[0] = cpu_to_be32(liobn);
+    dma_prop[1] = cpu_to_be32(window >> 32);
+    dma_prop[2] = cpu_to_be32(window & 0xFFFFFFFF);
+    dma_prop[3] = 0; /* window size is 32 bits */
+    dma_prop[4] = cpu_to_be32(size);
+
+    ret = fdt_setprop_cell(fdt, node_off, "ibm,#dma-address-cells", 2);
+    if (ret < 0) {
+        return ret;
+    }
 
-        ret = fdt_setprop_cell(fdt, node_off, "ibm,#dma-size-cells", 2);
-        if (ret < 0) {
-            return ret;
-        }
+    ret = fdt_setprop_cell(fdt, node_off, "ibm,#dma-size-cells", 2);
+    if (ret < 0) {
+        return ret;
+    }
 
-        ret = fdt_setprop(fdt, node_off, propname, dma_prop,
-                          sizeof(dma_prop));
-        if (ret < 0) {
-            return ret;
-        }
+    ret = fdt_setprop(fdt, node_off, propname, dma_prop, sizeof(dma_prop));
+    if (ret < 0) {
+        return ret;
     }
 
     return 0;
 }
+
+int spapr_tcet_dma_dt(void *fdt, int node_off, const char *propname,
+                      DMAContext *iommu)
+{
+    if (!iommu) {
+        return 0;
+    }
+
+    if (iommu->translate == spapr_tce_translate) {
+        sPAPRTCETable *tcet = DO_UPCAST(sPAPRTCETable, dma, iommu);
+        return spapr_dma_dt(fdt, node_off, propname,
+                tcet->liobn, 0, tcet->window_size);
+    }
+
+    return -1;
+}
index 01e54f36757082f7f39aaf93db110a4de6660a85..bd3f131d7e9a6afb9a78e6f68449c810037e6a15 100644 (file)
@@ -169,7 +169,7 @@ static ssize_t spapr_vlan_receive(NetClientState *nc, const uint8_t *buf,
     }
 
     if (sdev->signal_state & 1) {
-        qemu_irq_pulse(sdev->qirq);
+        qemu_irq_pulse(spapr_vio_qirq(sdev));
     }
 
     return size;
index b2e4f785eae8ec3f59cf29dbb5347d1f3be3d096..b92583a99124e501c137709ddebf1ae71cb8d85e 100644 (file)
  */
 #include "hw.h"
 #include "pci.h"
+#include "msi.h"
+#include "msix.h"
 #include "pci_host.h"
 #include "hw/spapr.h"
 #include "hw/spapr_pci.h"
 #include "exec-memory.h"
 #include <libfdt.h>
+#include "trace.h"
 
 #include "hw/pci_internals.h"
 
-static PCIDevice *find_dev(sPAPREnvironment *spapr,
-                           uint64_t buid, uint32_t config_addr)
+/* Copied from the kernel arch/powerpc/platforms/pseries/msi.c */
+#define RTAS_QUERY_FN           0
+#define RTAS_CHANGE_FN          1
+#define RTAS_RESET_FN           2
+#define RTAS_CHANGE_MSI_FN      3
+#define RTAS_CHANGE_MSIX_FN     4
+
+/* Interrupt types to return on RTAS_CHANGE_* */
+#define RTAS_TYPE_MSI           1
+#define RTAS_TYPE_MSIX          2
+
+static sPAPRPHBState *find_phb(sPAPREnvironment *spapr, uint64_t buid)
 {
-    int devfn = (config_addr >> 8) & 0xFF;
     sPAPRPHBState *phb;
 
     QLIST_FOREACH(phb, &spapr->phbs, list) {
-        BusChild *kid;
-
         if (phb->buid != buid) {
             continue;
         }
+        return phb;
+    }
+
+    return NULL;
+}
+
+static PCIDevice *find_dev(sPAPREnvironment *spapr, uint64_t buid,
+                           uint32_t config_addr)
+{
+    sPAPRPHBState *phb = find_phb(spapr, buid);
+    BusChild *kid;
+    int devfn = (config_addr >> 8) & 0xFF;
+
+    if (!phb) {
+        return NULL;
+    }
 
-        QTAILQ_FOREACH(kid, &phb->host_state.bus->qbus.children, sibling) {
-            PCIDevice *dev = (PCIDevice *)kid->child;
-            if (dev->devfn == devfn) {
-                return dev;
-            }
+    QTAILQ_FOREACH(kid, &phb->host_state.bus->qbus.children, sibling) {
+        PCIDevice *dev = (PCIDevice *)kid->child;
+        if (dev->devfn == devfn) {
+            return dev;
         }
     }
 
@@ -199,6 +224,191 @@ static void rtas_write_pci_config(sPAPREnvironment *spapr,
     finish_write_pci_config(spapr, 0, addr, size, val, rets);
 }
 
+/*
+ * Find an entry with config_addr or returns the empty one if not found AND
+ * alloc_new is set.
+ * At the moment the msi_table entries are never released so there is
+ * no point to look till the end of the list if we need to find the free entry.
+ */
+static int spapr_msicfg_find(sPAPRPHBState *phb, uint32_t config_addr,
+                             bool alloc_new)
+{
+    int i;
+
+    for (i = 0; i < SPAPR_MSIX_MAX_DEVS; ++i) {
+        if (!phb->msi_table[i].nvec) {
+            break;
+        }
+        if (phb->msi_table[i].config_addr == config_addr) {
+            return i;
+        }
+    }
+    if ((i < SPAPR_MSIX_MAX_DEVS) && alloc_new) {
+        trace_spapr_pci_msi("Allocating new MSI config", i, config_addr);
+        return i;
+    }
+
+    return -1;
+}
+
+/*
+ * Set MSI/MSIX message data.
+ * This is required for msi_notify()/msix_notify() which
+ * will write at the addresses via spapr_msi_write().
+ */
+static void spapr_msi_setmsg(PCIDevice *pdev, target_phys_addr_t addr,
+                             bool msix, unsigned req_num)
+{
+    unsigned i;
+    MSIMessage msg = { .address = addr, .data = 0 };
+
+    if (!msix) {
+        msi_set_message(pdev, msg);
+        trace_spapr_pci_msi_setup(pdev->name, 0, msg.address);
+        return;
+    }
+
+    for (i = 0; i < req_num; ++i) {
+        msg.address = addr | (i << 2);
+        msix_set_message(pdev, i, msg);
+        trace_spapr_pci_msi_setup(pdev->name, i, msg.address);
+    }
+}
+
+static void rtas_ibm_change_msi(sPAPREnvironment *spapr,
+                                uint32_t token, uint32_t nargs,
+                                target_ulong args, uint32_t nret,
+                                target_ulong rets)
+{
+    uint32_t config_addr = rtas_ld(args, 0);
+    uint64_t buid = ((uint64_t)rtas_ld(args, 1) << 32) | rtas_ld(args, 2);
+    unsigned int func = rtas_ld(args, 3);
+    unsigned int req_num = rtas_ld(args, 4); /* 0 == remove all */
+    unsigned int seq_num = rtas_ld(args, 5);
+    unsigned int ret_intr_type;
+    int ndev, irq;
+    sPAPRPHBState *phb = NULL;
+    PCIDevice *pdev = NULL;
+
+    switch (func) {
+    case RTAS_CHANGE_MSI_FN:
+    case RTAS_CHANGE_FN:
+        ret_intr_type = RTAS_TYPE_MSI;
+        break;
+    case RTAS_CHANGE_MSIX_FN:
+        ret_intr_type = RTAS_TYPE_MSIX;
+        break;
+    default:
+        fprintf(stderr, "rtas_ibm_change_msi(%u) is not implemented\n", func);
+        rtas_st(rets, 0, -3); /* Parameter error */
+        return;
+    }
+
+    /* Fins sPAPRPHBState */
+    phb = find_phb(spapr, buid);
+    if (phb) {
+        pdev = find_dev(spapr, buid, config_addr);
+    }
+    if (!phb || !pdev) {
+        rtas_st(rets, 0, -3); /* Parameter error */
+        return;
+    }
+
+    /* Releasing MSIs */
+    if (!req_num) {
+        ndev = spapr_msicfg_find(phb, config_addr, false);
+        if (ndev < 0) {
+            trace_spapr_pci_msi("MSI has not been enabled", -1, config_addr);
+            rtas_st(rets, 0, -1); /* Hardware error */
+            return;
+        }
+        trace_spapr_pci_msi("Released MSIs", ndev, config_addr);
+        rtas_st(rets, 0, 0);
+        rtas_st(rets, 1, 0);
+        return;
+    }
+
+    /* Enabling MSI */
+
+    /* Find a device number in the map to add or reuse the existing one */
+    ndev = spapr_msicfg_find(phb, config_addr, true);
+    if (ndev >= SPAPR_MSIX_MAX_DEVS || ndev < 0) {
+        fprintf(stderr, "No free entry for a new MSI device\n");
+        rtas_st(rets, 0, -1); /* Hardware error */
+        return;
+    }
+    trace_spapr_pci_msi("Configuring MSI", ndev, config_addr);
+
+    /* Check if there is an old config and MSI number has not changed */
+    if (phb->msi_table[ndev].nvec && (req_num != phb->msi_table[ndev].nvec)) {
+        /* Unexpected behaviour */
+        fprintf(stderr, "Cannot reuse MSI config for device#%d", ndev);
+        rtas_st(rets, 0, -1); /* Hardware error */
+        return;
+    }
+
+    /* There is no cached config, allocate MSIs */
+    if (!phb->msi_table[ndev].nvec) {
+        irq = spapr_allocate_irq_block(req_num, XICS_MSI);
+        if (irq < 0) {
+            fprintf(stderr, "Cannot allocate MSIs for device#%d", ndev);
+            rtas_st(rets, 0, -1); /* Hardware error */
+            return;
+        }
+        phb->msi_table[ndev].irq = irq;
+        phb->msi_table[ndev].nvec = req_num;
+        phb->msi_table[ndev].config_addr = config_addr;
+    }
+
+    /* Setup MSI/MSIX vectors in the device (via cfgspace or MSIX BAR) */
+    spapr_msi_setmsg(pdev, phb->msi_win_addr | (ndev << 16),
+                     ret_intr_type == RTAS_TYPE_MSIX, req_num);
+
+    rtas_st(rets, 0, 0);
+    rtas_st(rets, 1, req_num);
+    rtas_st(rets, 2, ++seq_num);
+    rtas_st(rets, 3, ret_intr_type);
+
+    trace_spapr_pci_rtas_ibm_change_msi(func, req_num);
+}
+
+static void rtas_ibm_query_interrupt_source_number(sPAPREnvironment *spapr,
+                                                   uint32_t token,
+                                                   uint32_t nargs,
+                                                   target_ulong args,
+                                                   uint32_t nret,
+                                                   target_ulong rets)
+{
+    uint32_t config_addr = rtas_ld(args, 0);
+    uint64_t buid = ((uint64_t)rtas_ld(args, 1) << 32) | rtas_ld(args, 2);
+    unsigned int intr_src_num = -1, ioa_intr_num = rtas_ld(args, 3);
+    int ndev;
+    sPAPRPHBState *phb = NULL;
+
+    /* Fins sPAPRPHBState */
+    phb = find_phb(spapr, buid);
+    if (!phb) {
+        rtas_st(rets, 0, -3); /* Parameter error */
+        return;
+    }
+
+    /* Find device descriptor and start IRQ */
+    ndev = spapr_msicfg_find(phb, config_addr, false);
+    if (ndev < 0) {
+        trace_spapr_pci_msi("MSI has not been enabled", -1, config_addr);
+        rtas_st(rets, 0, -1); /* Hardware error */
+        return;
+    }
+
+    intr_src_num = phb->msi_table[ndev].irq + ioa_intr_num;
+    trace_spapr_pci_rtas_ibm_query_interrupt_source_number(ioa_intr_num,
+                                                           intr_src_num);
+
+    rtas_st(rets, 0, 0);
+    rtas_st(rets, 1, intr_src_num);
+    rtas_st(rets, 2, 1);/* 0 == level; 1 == edge */
+}
+
 static int pci_spapr_swizzle(int slot, int pin)
 {
     return (slot + pin) % PCI_NUM_PINS;
@@ -223,7 +433,8 @@ static void pci_spapr_set_irq(void *opaque, int irq_num, int level)
      */
     sPAPRPHBState *phb = opaque;
 
-    qemu_set_irq(phb->lsi_table[irq_num].qirq, level);
+    trace_spapr_pci_lsi_set(phb->busname, irq_num, phb->lsi_table[irq_num].irq);
+    qemu_set_irq(spapr_phb_lsi_qirq(phb, irq_num), level);
 }
 
 static uint64_t spapr_io_read(void *opaque, target_phys_addr_t addr,
@@ -263,6 +474,33 @@ static const MemoryRegionOps spapr_io_ops = {
     .write = spapr_io_write
 };
 
+/*
+ * MSI/MSIX memory region implementation.
+ * The handler handles both MSI and MSIX.
+ * For MSI-X, the vector number is encoded as a part of the address,
+ * data is set to 0.
+ * For MSI, the vector number is encoded in least bits in data.
+ */
+static void spapr_msi_write(void *opaque, target_phys_addr_t addr,
+                            uint64_t data, unsigned size)
+{
+    sPAPRPHBState *phb = opaque;
+    int ndev = addr >> 16;
+    int vec = ((addr & 0xFFFF) >> 2) | data;
+    uint32_t irq = phb->msi_table[ndev].irq + vec;
+
+    trace_spapr_pci_msi_write(addr, data, irq);
+
+    qemu_irq_pulse(xics_get_qirq(spapr->icp, irq));
+}
+
+static const MemoryRegionOps spapr_msi_ops = {
+    /* There is no .read as the read result is undefined by PCI spec */
+    .read = NULL,
+    .write = spapr_msi_write,
+    .endianness = DEVICE_LITTLE_ENDIAN
+};
+
 /*
  * PHB PCI device
  */
@@ -276,11 +514,10 @@ static DMAContext *spapr_pci_dma_context_fn(PCIBus *bus, void *opaque,
 
 static int spapr_phb_init(SysBusDevice *s)
 {
-    sPAPRPHBState *phb = FROM_SYSBUS(sPAPRPHBState, s);
+    sPAPRPHBState *phb = DO_UPCAST(sPAPRPHBState, host_state.busdev, s);
     char *namebuf;
     int i;
     PCIBus *bus;
-    uint32_t liobn;
 
     phb->dtbusname = g_strdup_printf("pci@%" PRIx64, phb->buid);
     namebuf = alloca(strlen(phb->dtbusname) + 32);
@@ -314,31 +551,42 @@ static int spapr_phb_init(SysBusDevice *s)
     memory_region_add_subregion(get_system_memory(), phb->io_win_addr,
                                 &phb->iowindow);
 
-    bus = pci_register_bus(&phb->busdev.qdev,
+    /* As MSI/MSIX interrupts trigger by writing at MSI/MSIX vectors,
+     * we need to allocate some memory to catch those writes coming
+     * from msi_notify()/msix_notify() */
+    if (msi_supported) {
+        sprintf(namebuf, "%s.msi", phb->dtbusname);
+        memory_region_init_io(&phb->msiwindow, &spapr_msi_ops, phb,
+                              namebuf, SPAPR_MSIX_MAX_DEVS * 0x10000);
+        memory_region_add_subregion(get_system_memory(), phb->msi_win_addr,
+                                    &phb->msiwindow);
+    }
+
+    bus = pci_register_bus(&phb->host_state.busdev.qdev,
                            phb->busname ? phb->busname : phb->dtbusname,
                            pci_spapr_set_irq, pci_spapr_map_irq, phb,
                            &phb->memspace, &phb->iospace,
                            PCI_DEVFN(0, 0), PCI_NUM_PINS);
     phb->host_state.bus = bus;
 
-    liobn = SPAPR_PCI_BASE_LIOBN | (pci_find_domain(bus) << 16);
-    phb->dma = spapr_tce_new_dma_context(liobn, 0x40000000);
+    phb->dma_liobn = SPAPR_PCI_BASE_LIOBN | (pci_find_domain(bus) << 16);
+    phb->dma_window_start = 0;
+    phb->dma_window_size = 0x40000000;
+    phb->dma = spapr_tce_new_dma_context(phb->dma_liobn, phb->dma_window_size);
     pci_setup_iommu(bus, spapr_pci_dma_context_fn, phb);
 
     QLIST_INSERT_HEAD(&spapr->phbs, phb, list);
 
     /* Initialize the LSI table */
     for (i = 0; i < PCI_NUM_PINS; i++) {
-        qemu_irq qirq;
-        uint32_t num;
+        uint32_t irq;
 
-        qirq = spapr_allocate_lsi(0, &num);
-        if (!qirq) {
+        irq = spapr_allocate_lsi(0);
+        if (!irq) {
             return -1;
         }
 
-        phb->lsi_table[i].dt_irq = num;
-        phb->lsi_table[i].qirq = qirq;
+        phb->lsi_table[i].irq = irq;
     }
 
     return 0;
@@ -351,6 +599,7 @@ static Property spapr_phb_properties[] = {
     DEFINE_PROP_HEX64("mem_win_size", sPAPRPHBState, mem_win_size, 0x20000000),
     DEFINE_PROP_HEX64("io_win_addr", sPAPRPHBState, io_win_addr, 0),
     DEFINE_PROP_HEX64("io_win_size", sPAPRPHBState, io_win_size, 0x10000),
+    DEFINE_PROP_HEX64("msi_win_addr", sPAPRPHBState, msi_win_addr, 0),
     DEFINE_PROP_END_OF_LIST(),
 };
 
@@ -361,11 +610,6 @@ static void spapr_phb_class_init(ObjectClass *klass, void *data)
 
     sdc->init = spapr_phb_init;
     dc->props = spapr_phb_properties;
-
-    spapr_rtas_register("read-pci-config", rtas_read_pci_config);
-    spapr_rtas_register("write-pci-config", rtas_write_pci_config);
-    spapr_rtas_register("ibm,read-pci-config", rtas_ibm_read_pci_config);
-    spapr_rtas_register("ibm,write-pci-config", rtas_ibm_write_pci_config);
 }
 
 static TypeInfo spapr_phb_info = {
@@ -378,7 +622,7 @@ static TypeInfo spapr_phb_info = {
 void spapr_create_phb(sPAPREnvironment *spapr,
                       const char *busname, uint64_t buid,
                       uint64_t mem_win_addr, uint64_t mem_win_size,
-                      uint64_t io_win_addr)
+                      uint64_t io_win_addr, uint64_t msi_win_addr)
 {
     DeviceState *dev;
 
@@ -391,6 +635,7 @@ void spapr_create_phb(sPAPREnvironment *spapr,
     qdev_prop_set_uint64(dev, "mem_win_addr", mem_win_addr);
     qdev_prop_set_uint64(dev, "mem_win_size", mem_win_size);
     qdev_prop_set_uint64(dev, "io_win_addr", io_win_addr);
+    qdev_prop_set_uint64(dev, "msi_win_addr", msi_win_addr);
 
     qdev_init_nofail(dev);
 }
@@ -406,9 +651,9 @@ void spapr_create_phb(sPAPREnvironment *spapr,
 #define b_fff(x)        b_x((x), 8, 3)  /* function number */
 #define b_rrrrrrrr(x)   b_x((x), 0, 8)  /* register number */
 
-int spapr_populate_pci_devices(sPAPRPHBState *phb,
-                               uint32_t xics_phandle,
-                               void *fdt)
+int spapr_populate_pci_dt(sPAPRPHBState *phb,
+                          uint32_t xics_phandle,
+                          void *fdt)
 {
     int bus_off, i, j;
     char nodename[256];
@@ -477,7 +722,7 @@ int spapr_populate_pci_devices(sPAPRPHBState *phb,
             irqmap[2] = 0;
             irqmap[3] = cpu_to_be32(j+1);
             irqmap[4] = cpu_to_be32(xics_phandle);
-            irqmap[5] = cpu_to_be32(phb->lsi_table[lsi_num].dt_irq);
+            irqmap[5] = cpu_to_be32(phb->lsi_table[lsi_num].irq);
             irqmap[6] = cpu_to_be32(0x8);
         }
     }
@@ -485,11 +730,26 @@ int spapr_populate_pci_devices(sPAPRPHBState *phb,
     _FDT(fdt_setprop(fdt, bus_off, "interrupt-map", &interrupt_map,
                      sizeof(interrupt_map)));
 
-    spapr_dma_dt(fdt, bus_off, "ibm,dma-window", phb->dma);
+    spapr_dma_dt(fdt, bus_off, "ibm,dma-window",
+                 phb->dma_liobn, phb->dma_window_start,
+                 phb->dma_window_size);
 
     return 0;
 }
 
+void spapr_pci_rtas_init(void)
+{
+    spapr_rtas_register("read-pci-config", rtas_read_pci_config);
+    spapr_rtas_register("write-pci-config", rtas_write_pci_config);
+    spapr_rtas_register("ibm,read-pci-config", rtas_ibm_read_pci_config);
+    spapr_rtas_register("ibm,write-pci-config", rtas_ibm_write_pci_config);
+    if (msi_supported) {
+        spapr_rtas_register("ibm,query-interrupt-source-number",
+                            rtas_ibm_query_interrupt_source_number);
+        spapr_rtas_register("ibm,change-msi", rtas_ibm_change_msi);
+    }
+}
+
 static void register_types(void)
 {
     type_register_static(&spapr_phb_info);
index d9e46e22e32134b78caca0dcc35f86f00e5ceb29..7518899b852aa5db7103edb6214236d45e687239 100644 (file)
@@ -27,8 +27,9 @@
 #include "hw/pci_host.h"
 #include "hw/xics.h"
 
+#define SPAPR_MSIX_MAX_DEVS 32
+
 typedef struct sPAPRPHBState {
-    SysBusDevice busdev;
     PCIHostState host_state;
 
     uint64_t buid;
@@ -37,27 +38,44 @@ typedef struct sPAPRPHBState {
 
     MemoryRegion memspace, iospace;
     target_phys_addr_t mem_win_addr, mem_win_size, io_win_addr, io_win_size;
-    MemoryRegion memwindow, iowindow;
+    target_phys_addr_t msi_win_addr;
+    MemoryRegion memwindow, iowindow, msiwindow;
+
+    uint32_t dma_liobn;
+    uint64_t dma_window_start;
+    uint64_t dma_window_size;
     DMAContext *dma;
 
     struct {
-        uint32_t dt_irq;
-        qemu_irq qirq;
+        uint32_t irq;
     } lsi_table[PCI_NUM_PINS];
 
+    struct {
+        uint32_t config_addr;
+        uint32_t irq;
+        int nvec;
+    } msi_table[SPAPR_MSIX_MAX_DEVS];
+
     QLIST_ENTRY(sPAPRPHBState) list;
 } sPAPRPHBState;
 
+static inline qemu_irq spapr_phb_lsi_qirq(struct sPAPRPHBState *phb, int pin)
+{
+    return xics_get_qirq(spapr->icp, phb->lsi_table[pin].irq);
+}
+
 #define SPAPR_PCI_MEM_WIN_BUS_OFFSET 0x80000000ULL
 #define SPAPR_PCI_IO_WIN_SIZE        0x10000
 
 void spapr_create_phb(sPAPREnvironment *spapr,
                       const char *busname, uint64_t buid,
                       uint64_t mem_win_addr, uint64_t mem_win_size,
-                      uint64_t io_win_addr);
+                      uint64_t io_win_addr, uint64_t msi_win_addr);
+
+int spapr_populate_pci_dt(sPAPRPHBState *phb,
+                          uint32_t xics_phandle,
+                          void *fdt);
 
-int spapr_populate_pci_devices(sPAPRPHBState *phb,
-                               uint32_t xics_phandle,
-                               void *fdt);
+void spapr_pci_rtas_init(void);
 
 #endif /* __HW_SPAPR_PCI_H__ */
index 05b55032a916acc9d750672f7c9d61c036bd12aa..7ca445216d71f6c2a8d6398d9454f41d20352e11 100644 (file)
@@ -49,7 +49,7 @@
 #endif
 
 static Property spapr_vio_props[] = {
-    DEFINE_PROP_UINT32("irq", VIOsPAPRDevice, vio_irq_num, 0), \
+    DEFINE_PROP_UINT32("irq", VIOsPAPRDevice, irq, 0), \
     DEFINE_PROP_END_OF_LIST(),
 };
 
@@ -132,8 +132,8 @@ static int vio_make_devnode(VIOsPAPRDevice *dev,
         }
     }
 
-    if (dev->qirq) {
-        uint32_t ints_prop[] = {cpu_to_be32(dev->vio_irq_num), 0};
+    if (dev->irq) {
+        uint32_t ints_prop[] = {cpu_to_be32(dev->irq), 0};
 
         ret = fdt_setprop(fdt, node_off, "interrupts", ints_prop,
                           sizeof(ints_prop));
@@ -142,7 +142,7 @@ static int vio_make_devnode(VIOsPAPRDevice *dev,
         }
     }
 
-    ret = spapr_dma_dt(fdt, node_off, "ibm,my-dma-window", dev->dma);
+    ret = spapr_tcet_dma_dt(fdt, node_off, "ibm,my-dma-window", dev->dma);
     if (ret < 0) {
         return ret;
     }
@@ -306,7 +306,7 @@ int spapr_vio_send_crq(VIOsPAPRDevice *dev, uint8_t *crq)
     dev->crq.qnext = (dev->crq.qnext + 16) % dev->crq.qsize;
 
     if (dev->signal_state & 1) {
-        qemu_irq_pulse(dev->qirq);
+        qemu_irq_pulse(spapr_vio_qirq(dev));
     }
 
     return 0;
@@ -459,8 +459,8 @@ static int spapr_vio_busdev_init(DeviceState *qdev)
         dev->qdev.id = id;
     }
 
-    dev->qirq = spapr_allocate_msi(dev->vio_irq_num, &dev->vio_irq_num);
-    if (!dev->qirq) {
+    dev->irq = spapr_allocate_msi(dev->irq);
+    if (!dev->irq) {
         return -1;
     }
 
index 6f9a498ccddc003952f8f9a641690ed8bf70e5ea..ea6aa43e26083c5312df4f30e6e2a60965484b6e 100644 (file)
@@ -61,8 +61,7 @@ struct VIOsPAPRDevice {
     DeviceState qdev;
     uint32_t reg;
     uint32_t flags;
-    qemu_irq qirq;
-    uint32_t vio_irq_num;
+    uint32_t irq;
     target_ulong signal_state;
     VIOsPAPR_CRQ crq;
     DMAContext *dma;
@@ -85,6 +84,11 @@ extern int spapr_populate_chosen_stdout(void *fdt, VIOsPAPRBus *bus);
 
 extern int spapr_vio_signal(VIOsPAPRDevice *dev, target_ulong mode);
 
+static inline qemu_irq spapr_vio_qirq(VIOsPAPRDevice *dev)
+{
+    return xics_get_qirq(spapr->icp, dev->irq);
+}
+
 static inline bool spapr_vio_dma_valid(VIOsPAPRDevice *dev, uint64_t taddr,
                                        uint32_t size, DMADirection dir)
 {
index 99e52cc6b7bd968797b82acd6404b0060b592c66..5da17a3ff43835cd1c92043726e5a04e50fd0290 100644 (file)
@@ -26,7 +26,7 @@ static void vty_receive(void *opaque, const uint8_t *buf, int size)
 
     if ((dev->in == dev->out) && size) {
         /* toggle line to simulate edge interrupt */
-        qemu_irq_pulse(dev->sdev.qirq);
+        qemu_irq_pulse(spapr_vio_qirq(&dev->sdev));
     }
     for (i = 0; i < size; i++) {
         assert((dev->in - dev->out) < VTERM_BUFSIZE);
index 137a7c6666d671bbca44d22b1f220adca0f4e4cb..07cd04273a81da10444800adfc803576b4f280f7 100644 (file)
@@ -39,6 +39,7 @@
 #include "elf.h"
 #include "blockdev.h"
 #include "exec-memory.h"
+#include "vga-pci.h"
 
 //#define DEBUG_IRQ
 //#define DEBUG_EBUS
index b043e7c23e2d65903a53a9be2edcb8a00ff8d946..104c21d3156301f8174d3271d2b608eea12298a7 100644 (file)
@@ -2010,7 +2010,7 @@ static void ehci_fill_queue(EHCIPacket *p)
         p->qtdaddr = qtdaddr;
         p->qtd = qtd;
         p->usb_status = ehci_execute(p, "queue");
-        assert(p->usb_status = USB_RET_ASYNC);
+        assert(p->usb_status == USB_RET_ASYNC);
         p->async = EHCI_ASYNC_INFLIGHT;
     }
 }
index 4fd5d9b04b4281d966a93b9cfa9b6d483468b04a..7a920347184d63e7bf21b6a04ae9f3e755ce376f 100644 (file)
@@ -162,7 +162,7 @@ static int vpb_sic_init(SysBusDevice *dev)
 /* Board init.  */
 
 /* The AB and PB boards both use the same core, just with different
-   peripherans and expansion busses.  For now we emulate a subset of the
+   peripherals and expansion busses.  For now we emulate a subset of the
    PB peripherals and just change the board ID.  */
 
 static struct arm_boot_info versatile_binfo;
index 37dc019a61fee9ce9c2b204524efb17f87a7a685..9abbada8f17a8737814c1de48e6c16e3cd95c514 100644 (file)
@@ -23,8 +23,8 @@
  */
 #include "hw.h"
 #include "console.h"
-#include "pc.h"
 #include "pci.h"
+#include "vga-pci.h"
 #include "vga_int.h"
 #include "pixel_ops.h"
 #include "qemu-timer.h"
diff --git a/hw/vga-pci.h b/hw/vga-pci.h
new file mode 100644 (file)
index 0000000..49abf13
--- /dev/null
@@ -0,0 +1,12 @@
+#ifndef VGA_PCI_H
+#define VGA_PCI_H
+
+#include "qemu-common.h"
+
+/* vga-pci.c */
+DeviceState *pci_vga_init(PCIBus *bus);
+
+/* cirrus_vga.c */
+DeviceState *pci_cirrus_vga_init(PCIBus *bus);
+
+#endif
index 668a0d648412c252e5673b9e4e3aadf4b7512134..b674771dc4c3274f1a5e1ac3940fa3b954136b4d 100644 (file)
--- a/hw/xics.c
+++ b/hw/xics.c
@@ -315,18 +315,24 @@ static void ics_eoi(struct ics_state *ics, int nr)
  * Exported functions
  */
 
-qemu_irq xics_assign_irq(struct icp_state *icp, int irq,
-                         enum xics_irq_type type)
+qemu_irq xics_get_qirq(struct icp_state *icp, int irq)
 {
     if ((irq < icp->ics->offset)
         || (irq >= (icp->ics->offset + icp->ics->nr_irqs))) {
         return NULL;
     }
 
+    return icp->ics->qirqs[irq - icp->ics->offset];
+}
+
+void xics_set_irq_type(struct icp_state *icp, int irq,
+                       enum xics_irq_type type)
+{
+    assert((irq >= icp->ics->offset)
+           && (irq < (icp->ics->offset + icp->ics->nr_irqs)));
     assert((type == XICS_MSI) || (type == XICS_LSI));
 
     icp->ics->irqs[irq - icp->ics->offset].type = type;
-    return icp->ics->qirqs[irq - icp->ics->offset];
 }
 
 static target_ulong h_cppr(CPUPPCState *env, sPAPREnvironment *spapr,
index 208015939c56d224eaf353f1307e4a2d555f3bed..99b96ac85aa9648b6db4b66aa814f8a2326eeb63 100644 (file)
--- a/hw/xics.h
+++ b/hw/xics.h
@@ -36,8 +36,9 @@ enum xics_irq_type {
     XICS_LSI,        /* Level-signalled interrupt */
 };
 
-qemu_irq xics_assign_irq(struct icp_state *icp, int irq,
-                         enum xics_irq_type type);
+qemu_irq xics_get_qirq(struct icp_state *icp, int irq);
+void xics_set_irq_type(struct icp_state *icp, int irq,
+                       enum xics_irq_type type);
 
 struct icp_state *xics_system_init(int nr_irqs);
 
diff --git a/iov.c b/iov.c
index b3330610bba4fb1e72f3f87266e6fa8bec6da19a..60705c73ab118d390383d2b94b2a806b37927fee 100644 (file)
--- a/iov.c
+++ b/iov.c
@@ -146,6 +146,13 @@ ssize_t iov_send_recv(int sockfd, struct iovec *iov, unsigned iov_cnt,
 {
     ssize_t ret;
     unsigned si, ei;            /* start and end indexes */
+    if (bytes == 0) {
+        /* Catch the do-nothing case early, as otherwise we will pass an
+         * empty iovec to sendmsg/recvmsg(), and not all implementations
+         * accept this.
+         */
+        return 0;
+    }
 
     /* Find the start position, skipping `offset' bytes:
      * first, skip all full-sized vector elements, */
index dd63f1d640c3fa385a87555b9cbb54371349880b..ce42466a639a6c9dd226ba60108dfa1ae07dd98a 100644 (file)
--- a/monitor.c
+++ b/monitor.c
@@ -140,6 +140,24 @@ struct mon_fd_t {
     QLIST_ENTRY(mon_fd_t) next;
 };
 
+/* file descriptor associated with a file descriptor set */
+typedef struct MonFdsetFd MonFdsetFd;
+struct MonFdsetFd {
+    int fd;
+    bool removed;
+    char *opaque;
+    QLIST_ENTRY(MonFdsetFd) next;
+};
+
+/* file descriptor set containing fds passed via SCM_RIGHTS */
+typedef struct MonFdset MonFdset;
+struct MonFdset {
+    int64_t id;
+    QLIST_HEAD(, MonFdsetFd) fds;
+    QLIST_HEAD(, MonFdsetFd) dup_fds;
+    QLIST_ENTRY(MonFdset) next;
+};
+
 typedef struct MonitorControl {
     QObject *id;
     JSONMessageParser parser;
@@ -181,6 +199,8 @@ struct Monitor {
 #define QMP_ACCEPT_UNKNOWNS 1
 
 static QLIST_HEAD(mon_list, Monitor) mon_list;
+static QLIST_HEAD(mon_fdsets, MonFdset) mon_fdsets;
+static int mon_refcount;
 
 static mon_cmd_t mon_cmds[];
 static mon_cmd_t info_cmds[];
@@ -2366,6 +2386,271 @@ int monitor_get_fd(Monitor *mon, const char *fdname)
     return -1;
 }
 
+static void monitor_fdset_cleanup(MonFdset *mon_fdset)
+{
+    MonFdsetFd *mon_fdset_fd;
+    MonFdsetFd *mon_fdset_fd_next;
+
+    QLIST_FOREACH_SAFE(mon_fdset_fd, &mon_fdset->fds, next, mon_fdset_fd_next) {
+        if (mon_fdset_fd->removed ||
+                (QLIST_EMPTY(&mon_fdset->dup_fds) && mon_refcount == 0)) {
+            close(mon_fdset_fd->fd);
+            g_free(mon_fdset_fd->opaque);
+            QLIST_REMOVE(mon_fdset_fd, next);
+            g_free(mon_fdset_fd);
+        }
+    }
+
+    if (QLIST_EMPTY(&mon_fdset->fds) && QLIST_EMPTY(&mon_fdset->dup_fds)) {
+        QLIST_REMOVE(mon_fdset, next);
+        g_free(mon_fdset);
+    }
+}
+
+static void monitor_fdsets_cleanup(void)
+{
+    MonFdset *mon_fdset;
+    MonFdset *mon_fdset_next;
+
+    QLIST_FOREACH_SAFE(mon_fdset, &mon_fdsets, next, mon_fdset_next) {
+        monitor_fdset_cleanup(mon_fdset);
+    }
+}
+
+AddfdInfo *qmp_add_fd(bool has_fdset_id, int64_t fdset_id, bool has_opaque,
+                      const char *opaque, Error **errp)
+{
+    int fd;
+    Monitor *mon = cur_mon;
+    MonFdset *mon_fdset;
+    MonFdsetFd *mon_fdset_fd;
+    AddfdInfo *fdinfo;
+
+    fd = qemu_chr_fe_get_msgfd(mon->chr);
+    if (fd == -1) {
+        error_set(errp, QERR_FD_NOT_SUPPLIED);
+        goto error;
+    }
+
+    if (has_fdset_id) {
+        QLIST_FOREACH(mon_fdset, &mon_fdsets, next) {
+            if (mon_fdset->id == fdset_id) {
+                break;
+            }
+        }
+        if (mon_fdset == NULL) {
+            error_set(errp, QERR_INVALID_PARAMETER_VALUE, "fdset-id",
+                      "an existing fdset-id");
+            goto error;
+        }
+    } else {
+        int64_t fdset_id_prev = -1;
+        MonFdset *mon_fdset_cur = QLIST_FIRST(&mon_fdsets);
+
+        /* Use first available fdset ID */
+        QLIST_FOREACH(mon_fdset, &mon_fdsets, next) {
+            mon_fdset_cur = mon_fdset;
+            if (fdset_id_prev == mon_fdset_cur->id - 1) {
+                fdset_id_prev = mon_fdset_cur->id;
+                continue;
+            }
+            break;
+        }
+
+        mon_fdset = g_malloc0(sizeof(*mon_fdset));
+        mon_fdset->id = fdset_id_prev + 1;
+
+        /* The fdset list is ordered by fdset ID */
+        if (mon_fdset->id == 0) {
+            QLIST_INSERT_HEAD(&mon_fdsets, mon_fdset, next);
+        } else if (mon_fdset->id < mon_fdset_cur->id) {
+            QLIST_INSERT_BEFORE(mon_fdset_cur, mon_fdset, next);
+        } else {
+            QLIST_INSERT_AFTER(mon_fdset_cur, mon_fdset, next);
+        }
+    }
+
+    mon_fdset_fd = g_malloc0(sizeof(*mon_fdset_fd));
+    mon_fdset_fd->fd = fd;
+    mon_fdset_fd->removed = false;
+    if (has_opaque) {
+        mon_fdset_fd->opaque = g_strdup(opaque);
+    }
+    QLIST_INSERT_HEAD(&mon_fdset->fds, mon_fdset_fd, next);
+
+    fdinfo = g_malloc0(sizeof(*fdinfo));
+    fdinfo->fdset_id = mon_fdset->id;
+    fdinfo->fd = mon_fdset_fd->fd;
+
+    return fdinfo;
+
+error:
+    if (fd != -1) {
+        close(fd);
+    }
+    return NULL;
+}
+
+void qmp_remove_fd(int64_t fdset_id, bool has_fd, int64_t fd, Error **errp)
+{
+    MonFdset *mon_fdset;
+    MonFdsetFd *mon_fdset_fd;
+    char fd_str[60];
+
+    QLIST_FOREACH(mon_fdset, &mon_fdsets, next) {
+        if (mon_fdset->id != fdset_id) {
+            continue;
+        }
+        QLIST_FOREACH(mon_fdset_fd, &mon_fdset->fds, next) {
+            if (has_fd) {
+                if (mon_fdset_fd->fd != fd) {
+                    continue;
+                }
+                mon_fdset_fd->removed = true;
+                break;
+            } else {
+                mon_fdset_fd->removed = true;
+            }
+        }
+        if (has_fd && !mon_fdset_fd) {
+            goto error;
+        }
+        monitor_fdset_cleanup(mon_fdset);
+        return;
+    }
+
+error:
+    if (has_fd) {
+        snprintf(fd_str, sizeof(fd_str), "fdset-id:%" PRId64 ", fd:%" PRId64,
+                 fdset_id, fd);
+    } else {
+        snprintf(fd_str, sizeof(fd_str), "fdset-id:%" PRId64, fdset_id);
+    }
+    error_set(errp, QERR_FD_NOT_FOUND, fd_str);
+}
+
+FdsetInfoList *qmp_query_fdsets(Error **errp)
+{
+    MonFdset *mon_fdset;
+    MonFdsetFd *mon_fdset_fd;
+    FdsetInfoList *fdset_list = NULL;
+
+    QLIST_FOREACH(mon_fdset, &mon_fdsets, next) {
+        FdsetInfoList *fdset_info = g_malloc0(sizeof(*fdset_info));
+        FdsetFdInfoList *fdsetfd_list = NULL;
+
+        fdset_info->value = g_malloc0(sizeof(*fdset_info->value));
+        fdset_info->value->fdset_id = mon_fdset->id;
+
+        QLIST_FOREACH(mon_fdset_fd, &mon_fdset->fds, next) {
+            FdsetFdInfoList *fdsetfd_info;
+
+            fdsetfd_info = g_malloc0(sizeof(*fdsetfd_info));
+            fdsetfd_info->value = g_malloc0(sizeof(*fdsetfd_info->value));
+            fdsetfd_info->value->fd = mon_fdset_fd->fd;
+            if (mon_fdset_fd->opaque) {
+                fdsetfd_info->value->has_opaque = true;
+                fdsetfd_info->value->opaque = g_strdup(mon_fdset_fd->opaque);
+            } else {
+                fdsetfd_info->value->has_opaque = false;
+            }
+
+            fdsetfd_info->next = fdsetfd_list;
+            fdsetfd_list = fdsetfd_info;
+        }
+
+        fdset_info->value->fds = fdsetfd_list;
+
+        fdset_info->next = fdset_list;
+        fdset_list = fdset_info;
+    }
+
+    return fdset_list;
+}
+
+int monitor_fdset_get_fd(int64_t fdset_id, int flags)
+{
+    MonFdset *mon_fdset;
+    MonFdsetFd *mon_fdset_fd;
+    int mon_fd_flags;
+
+#ifndef _WIN32
+    QLIST_FOREACH(mon_fdset, &mon_fdsets, next) {
+        if (mon_fdset->id != fdset_id) {
+            continue;
+        }
+        QLIST_FOREACH(mon_fdset_fd, &mon_fdset->fds, next) {
+            mon_fd_flags = fcntl(mon_fdset_fd->fd, F_GETFL);
+            if (mon_fd_flags == -1) {
+                return -1;
+            }
+
+            if ((flags & O_ACCMODE) == (mon_fd_flags & O_ACCMODE)) {
+                return mon_fdset_fd->fd;
+            }
+        }
+        errno = EACCES;
+        return -1;
+    }
+#endif
+
+    errno = ENOENT;
+    return -1;
+}
+
+int monitor_fdset_dup_fd_add(int64_t fdset_id, int dup_fd)
+{
+    MonFdset *mon_fdset;
+    MonFdsetFd *mon_fdset_fd_dup;
+
+    QLIST_FOREACH(mon_fdset, &mon_fdsets, next) {
+        if (mon_fdset->id != fdset_id) {
+            continue;
+        }
+        QLIST_FOREACH(mon_fdset_fd_dup, &mon_fdset->dup_fds, next) {
+            if (mon_fdset_fd_dup->fd == dup_fd) {
+                return -1;
+            }
+        }
+        mon_fdset_fd_dup = g_malloc0(sizeof(*mon_fdset_fd_dup));
+        mon_fdset_fd_dup->fd = dup_fd;
+        QLIST_INSERT_HEAD(&mon_fdset->dup_fds, mon_fdset_fd_dup, next);
+        return 0;
+    }
+    return -1;
+}
+
+static int monitor_fdset_dup_fd_find_remove(int dup_fd, bool remove)
+{
+    MonFdset *mon_fdset;
+    MonFdsetFd *mon_fdset_fd_dup;
+
+    QLIST_FOREACH(mon_fdset, &mon_fdsets, next) {
+        QLIST_FOREACH(mon_fdset_fd_dup, &mon_fdset->dup_fds, next) {
+            if (mon_fdset_fd_dup->fd == dup_fd) {
+                if (remove) {
+                    QLIST_REMOVE(mon_fdset_fd_dup, next);
+                    if (QLIST_EMPTY(&mon_fdset->dup_fds)) {
+                        monitor_fdset_cleanup(mon_fdset);
+                    }
+                }
+                return mon_fdset->id;
+            }
+        }
+    }
+    return -1;
+}
+
+int monitor_fdset_dup_fd_find(int dup_fd)
+{
+    return monitor_fdset_dup_fd_find_remove(dup_fd, false);
+}
+
+int monitor_fdset_dup_fd_remove(int dup_fd)
+{
+    return monitor_fdset_dup_fd_find_remove(dup_fd, true);
+}
+
 /* mon_cmds and info_cmds would be sorted at runtime */
 static mon_cmd_t mon_cmds[] = {
 #include "hmp-commands.h"
@@ -4551,9 +4836,12 @@ static void monitor_control_event(void *opaque, int event)
         data = get_qmp_greeting();
         monitor_json_emitter(mon, data);
         qobject_decref(data);
+        mon_refcount++;
         break;
     case CHR_EVENT_CLOSED:
         json_message_parser_destroy(&mon->mc->parser);
+        mon_refcount--;
+        monitor_fdsets_cleanup();
         break;
     }
 }
@@ -4594,6 +4882,12 @@ static void monitor_event(void *opaque, int event)
             readline_show_prompt(mon->rs);
         }
         mon->reset_seen = 1;
+        mon_refcount++;
+        break;
+
+    case CHR_EVENT_CLOSED:
+        mon_refcount--;
+        monitor_fdsets_cleanup();
         break;
     }
 }
index 4ef9a046f824fafe90686dc15e5a1d6b7d50eeb0..47d556b9d19aa9a75bb4fd90ba53c77c312ff380 100644 (file)
--- a/monitor.h
+++ b/monitor.h
@@ -87,4 +87,9 @@ int qmp_qom_set(Monitor *mon, const QDict *qdict, QObject **ret);
 
 int qmp_qom_get(Monitor *mon, const QDict *qdict, QObject **ret);
 
+int monitor_fdset_get_fd(int64_t fdset_id, int flags);
+int monitor_fdset_dup_fd_add(int64_t fdset_id, int dup_fd);
+int monitor_fdset_dup_fd_remove(int dup_fd);
+int monitor_fdset_dup_fd_find(int dup_fd);
+
 #endif /* !MONITOR_H */
diff --git a/osdep.c b/osdep.c
index c07faf546e8c91b112a1c9e13ee6d896c5c43021..5b78ceebefe0925db741a99e8cc805b543e235fd 100644 (file)
--- a/osdep.c
+++ b/osdep.c
@@ -48,6 +48,7 @@ extern int madvise(caddr_t, size_t, int);
 #include "qemu-common.h"
 #include "trace.h"
 #include "qemu_socket.h"
+#include "monitor.h"
 
 static bool fips_enabled = false;
 
@@ -78,6 +79,66 @@ int qemu_madvise(void *addr, size_t len, int advice)
 #endif
 }
 
+#ifndef _WIN32
+/*
+ * Dups an fd and sets the flags
+ */
+static int qemu_dup_flags(int fd, int flags)
+{
+    int ret;
+    int serrno;
+    int dup_flags;
+    int setfl_flags;
+
+#ifdef F_DUPFD_CLOEXEC
+    ret = fcntl(fd, F_DUPFD_CLOEXEC, 0);
+#else
+    ret = dup(fd);
+    if (ret != -1) {
+        qemu_set_cloexec(ret);
+    }
+#endif
+    if (ret == -1) {
+        goto fail;
+    }
+
+    dup_flags = fcntl(ret, F_GETFL);
+    if (dup_flags == -1) {
+        goto fail;
+    }
+
+    if ((flags & O_SYNC) != (dup_flags & O_SYNC)) {
+        errno = EINVAL;
+        goto fail;
+    }
+
+    /* Set/unset flags that we can with fcntl */
+    setfl_flags = O_APPEND | O_ASYNC | O_DIRECT | O_NOATIME | O_NONBLOCK;
+    dup_flags &= ~setfl_flags;
+    dup_flags |= (flags & setfl_flags);
+    if (fcntl(ret, F_SETFL, dup_flags) == -1) {
+        goto fail;
+    }
+
+    /* Truncate the file in the cases that open() would truncate it */
+    if (flags & O_TRUNC ||
+            ((flags & (O_CREAT | O_EXCL)) == (O_CREAT | O_EXCL))) {
+        if (ftruncate(ret, 0) == -1) {
+            goto fail;
+        }
+    }
+
+    return ret;
+
+fail:
+    serrno = errno;
+    if (ret != -1) {
+        close(ret);
+    }
+    errno = serrno;
+    return -1;
+}
+#endif
 
 /*
  * Opens a file with FD_CLOEXEC set
@@ -87,6 +148,41 @@ int qemu_open(const char *name, int flags, ...)
     int ret;
     int mode = 0;
 
+#ifndef _WIN32
+    const char *fdset_id_str;
+
+    /* Attempt dup of fd from fd set */
+    if (strstart(name, "/dev/fdset/", &fdset_id_str)) {
+        int64_t fdset_id;
+        int fd, dupfd;
+
+        fdset_id = qemu_parse_fdset(fdset_id_str);
+        if (fdset_id == -1) {
+            errno = EINVAL;
+            return -1;
+        }
+
+        fd = monitor_fdset_get_fd(fdset_id, flags);
+        if (fd == -1) {
+            return -1;
+        }
+
+        dupfd = qemu_dup_flags(fd, flags);
+        if (dupfd == -1) {
+            return -1;
+        }
+
+        ret = monitor_fdset_dup_fd_add(fdset_id, dupfd);
+        if (ret == -1) {
+            close(dupfd);
+            errno = EINVAL;
+            return -1;
+        }
+
+        return dupfd;
+    }
+#endif
+
     if (flags & O_CREAT) {
         va_list ap;
 
@@ -107,6 +203,26 @@ int qemu_open(const char *name, int flags, ...)
     return ret;
 }
 
+int qemu_close(int fd)
+{
+    int64_t fdset_id;
+
+    /* Close fd that was dup'd from an fdset */
+    fdset_id = monitor_fdset_dup_fd_find(fd);
+    if (fdset_id != -1) {
+        int ret;
+
+        ret = close(fd);
+        if (ret == 0) {
+            monitor_fdset_dup_fd_remove(fd);
+        }
+
+        return ret;
+    }
+
+    return close(fd);
+}
+
 /*
  * A variant of write(2) which handles partial write.
  *
index e56e9e5f047da0b730a9290a207b1ff9347164df..f4b37d66dcd6430736d590d253fdd9bbf7cde00b 100644 (file)
@@ -17,7 +17,7 @@
 - SLOF (Slimline Open Firmware) is a free IEEE 1275 Open Firmware
   implementation for certain IBM POWER hardware.  The sources are at
   https://github.com/dgibson/SLOF, and the image currently in qemu is
-  built from git tag qemu-slof-20120217.
+  built from git tag qemu-slof-20120731.
 
 - sgabios (the Serial Graphics Adapter option ROM) provides a means for
   legacy x86 software to communicate with an attached serial console as
index 449a7bb2afaf604f6c089612e99086df0800d7dc..84ba6b83f3c7fe523cb0b0e73ae8522872d1feef 100644 (file)
Binary files a/pc-bios/slof.bin and b/pc-bios/slof.bin differ
index 53bbe46e4dd090a98776b328bc9e2f6e37d6e0ff..3d2b2d175a6f1431ff6cc8a377fec534a092cc39 100644 (file)
 # Since: 1.2.0
 ##
 { 'command': 'query-cpu-definitions', 'returns': ['CpuDefinitionInfo'] }
+
+# @AddfdInfo:
+#
+# Information about a file descriptor that was added to an fd set.
+#
+# @fdset-id: The ID of the fd set that @fd was added to.
+#
+# @fd: The file descriptor that was received via SCM rights and
+#      added to the fd set.
+#
+# Since: 1.2.0
+##
+{ 'type': 'AddfdInfo', 'data': {'fdset-id': 'int', 'fd': 'int'} }
+
+##
+# @add-fd:
+#
+# Add a file descriptor, that was passed via SCM rights, to an fd set.
+#
+# @fdset-id: #optional The ID of the fd set to add the file descriptor to.
+#
+# @opaque: #optional A free-form string that can be used to describe the fd.
+#
+# Returns: @AddfdInfo on success
+#          If file descriptor was not received, FdNotSupplied
+#          If @fdset-id does not exist, InvalidParameterValue
+#
+# Notes: The list of fd sets is shared by all monitor connections.
+#
+#        If @fdset-id is not specified, a new fd set will be created.
+#
+# Since: 1.2.0
+##
+{ 'command': 'add-fd', 'data': {'*fdset-id': 'int', '*opaque': 'str'},
+  'returns': 'AddfdInfo' }
+
+##
+# @remove-fd:
+#
+# Remove a file descriptor from an fd set.
+#
+# @fdset-id: The ID of the fd set that the file descriptor belongs to.
+#
+# @fd: #optional The file descriptor that is to be removed.
+#
+# Returns: Nothing on success
+#          If @fdset-id or @fd is not found, FdNotFound
+#
+# Since: 1.2.0
+#
+# Notes: The list of fd sets is shared by all monitor connections.
+#
+#        If @fd is not specified, all file descriptors in @fdset-id
+#        will be removed.
+##
+{ 'command': 'remove-fd', 'data': {'fdset-id': 'int', '*fd': 'int'} }
+
+##
+# @FdsetFdInfo:
+#
+# Information about a file descriptor that belongs to an fd set.
+#
+# @fd: The file descriptor value.
+#
+# @opaque: #optional A free-form string that can be used to describe the fd.
+#
+# Since: 1.2.0
+##
+{ 'type': 'FdsetFdInfo',
+  'data': {'fd': 'int', '*opaque': 'str'} }
+
+##
+# @FdsetInfo:
+#
+# Information about an fd set.
+#
+# @fdset-id: The ID of the fd set.
+#
+# @fds: A list of file descriptors that belong to this fd set.
+#
+# Since: 1.2.0
+##
+{ 'type': 'FdsetInfo',
+  'data': {'fdset-id': 'int', 'fds': ['FdsetFdInfo']} }
+
+##
+# @query-fdsets:
+#
+# Return information describing all fd sets.
+#
+# Returns: A list of @FdsetInfo
+#
+# Since: 1.2.0
+#
+# Note: The list of fd sets is shared by all monitor connections.
+#
+##
+{ 'command': 'query-fdsets', 'returns': ['FdsetInfo'] }
index 382c71ebcdff2eafd202fe9bfb68b48d9a491113..10d15049480aaed2e1f1d4d5480c0e2af464e632 100644 (file)
@@ -2238,6 +2238,9 @@ static void unix_process_msgfd(CharDriverState *chr, struct msghdr *msg)
         if (fd < 0)
             continue;
 
+#ifndef MSG_CMSG_CLOEXEC
+        qemu_set_cloexec(fd);
+#endif
         if (s->msgfd != -1)
             close(s->msgfd);
         s->msgfd = fd;
@@ -2253,6 +2256,7 @@ static ssize_t tcp_chr_recv(CharDriverState *chr, char *buf, size_t len)
         struct cmsghdr cmsg;
         char control[CMSG_SPACE(sizeof(int))];
     } msg_control;
+    int flags = 0;
     ssize_t ret;
 
     iov[0].iov_base = buf;
@@ -2263,9 +2267,13 @@ static ssize_t tcp_chr_recv(CharDriverState *chr, char *buf, size_t len)
     msg.msg_control = &msg_control;
     msg.msg_controllen = sizeof(msg_control);
 
-    ret = recvmsg(s->fd, &msg, 0);
-    if (ret > 0 && s->is_unix)
+#ifdef MSG_CMSG_CLOEXEC
+    flags |= MSG_CMSG_CLOEXEC;
+#endif
+    ret = recvmsg(s->fd, &msg, flags);
+    if (ret > 0 && s->is_unix) {
         unix_process_msgfd(chr, &msg);
+    }
 
     return ret;
 }
index 095e28d89a1106688b03a2f1e24d06c543f235f6..e5c2bcd204a715ded8b1de1fb675db79ba184d43 100644 (file)
@@ -167,6 +167,7 @@ int qemu_fls(int i);
 int qemu_fdatasync(int fd);
 int fcntl_setfl(int fd, int flag);
 int qemu_parse_fd(const char *param);
+int qemu_parse_fdset(const char *param);
 
 /*
  * strtosz() suffixes used to specify the default treatment of an
@@ -208,6 +209,7 @@ const char *path(const char *pathname);
 void *qemu_oom_check(void *ptr);
 
 int qemu_open(const char *name, int flags, ...);
+int qemu_close(int fd);
 ssize_t qemu_write_full(int fd, const void *buf, size_t count)
     QEMU_WARN_UNUSED_RESULT;
 ssize_t qemu_send_full(int fd, const void *buf, size_t count, int flags)
index 64b5e88bc7a684a39625c37cc0ce2c7a299d306d..18205bababe093b9582d2a4ed962f3584a895700 100644 (file)
@@ -62,6 +62,26 @@ void monitor_protocol_event(MonitorEvent event, QObject *data)
 {
 }
 
+int monitor_fdset_get_fd(int64_t fdset_id, int flags)
+{
+    return -1;
+}
+
+int monitor_fdset_dup_fd_add(int64_t fdset_id, int dup_fd)
+{
+    return -1;
+}
+
+int monitor_fdset_dup_fd_remove(int dup_fd)
+{
+    return -1;
+}
+
+int monitor_fdset_dup_fd_find(int dup_fd)
+{
+    return -1;
+}
+
 int64_t cpu_get_clock(void)
 {
     return qemu_get_clock_ns(rt_clock);
index 08ccb0fe8e0b5dd44d6ea6ab7e64890bea74fdaf..13fb9ae77befd72c49d653943568db42bd533f96 100644 (file)
@@ -35,3 +35,23 @@ void monitor_vprintf(Monitor *mon, const char *fmt, va_list ap)
 void monitor_set_error(Monitor *mon, QError *qerror)
 {
 }
+
+int monitor_fdset_get_fd(int64_t fdset_id, int flags)
+{
+    return -1;
+}
+
+int monitor_fdset_dup_fd_add(int64_t fdset_id, int dup_fd)
+{
+    return -1;
+}
+
+int monitor_fdset_dup_fd_remove(int dup_fd)
+{
+    return -1;
+}
+
+int monitor_fdset_dup_fd_find(int dup_fd)
+{
+    return -1;
+}
index 527b9f7c2499feb213c562c1373d772202e83b36..2ce4ce6556edcf6af609097dd5b626bfe5d7fae9 100644 (file)
@@ -968,6 +968,128 @@ Example:
 -> { "execute": "closefd", "arguments": { "fdname": "fd1" } }
 <- { "return": {} }
 
+EQMP
+
+     {
+        .name       = "add-fd",
+        .args_type  = "fdset-id:i?,opaque:s?",
+        .params     = "add-fd fdset-id opaque",
+        .help       = "Add a file descriptor, that was passed via SCM rights, to an fd set",
+        .mhandler.cmd_new = qmp_marshal_input_add_fd,
+    },
+
+SQMP
+add-fd
+-------
+
+Add a file descriptor, that was passed via SCM rights, to an fd set.
+
+Arguments:
+
+- "fdset-id": The ID of the fd set to add the file descriptor to.
+              (json-int, optional)
+- "opaque": A free-form string that can be used to describe the fd.
+            (json-string, optional)
+
+Return a json-object with the following information:
+
+- "fdset-id": The ID of the fd set that the fd was added to. (json-int)
+- "fd": The file descriptor that was received via SCM rights and added to the
+        fd set. (json-int)
+
+Example:
+
+-> { "execute": "add-fd", "arguments": { "fdset-id": 1 } }
+<- { "return": { "fdset-id": 1, "fd": 3 } }
+
+Notes:
+
+(1) The list of fd sets is shared by all monitor connections.
+(2) If "fdset-id" is not specified, a new fd set will be created.
+
+EQMP
+
+     {
+        .name       = "remove-fd",
+        .args_type  = "fdset-id:i,fd:i?",
+        .params     = "remove-fd fdset-id fd",
+        .help       = "Remove a file descriptor from an fd set",
+        .mhandler.cmd_new = qmp_marshal_input_remove_fd,
+    },
+
+SQMP
+remove-fd
+---------
+
+Remove a file descriptor from an fd set.
+
+Arguments:
+
+- "fdset-id": The ID of the fd set that the file descriptor belongs to.
+              (json-int)
+- "fd": The file descriptor that is to be removed. (json-int, optional)
+
+Example:
+
+-> { "execute": "remove-fd", "arguments": { "fdset-id": 1, "fd": 3 } }
+<- { "return": {} }
+
+Notes:
+
+(1) The list of fd sets is shared by all monitor connections.
+(2) If "fd" is not specified, all file descriptors in "fdset-id" will be
+    removed.
+
+EQMP
+
+    {
+        .name       = "query-fdsets",
+        .args_type  = "",
+        .help       = "Return information describing all fd sets",
+        .mhandler.cmd_new = qmp_marshal_input_query_fdsets,
+    },
+
+SQMP
+query-fdsets
+-------------
+
+Return information describing all fd sets.
+
+Arguments: None
+
+Example:
+
+-> { "execute": "query-fdsets" }
+<- { "return": [
+       {
+         "fds": [
+           {
+             "fd": 30,
+             "opaque": "rdonly:/path/to/file"
+           },
+           {
+             "fd": 24,
+             "opaque": "rdwr:/path/to/file"
+           }
+         ],
+         "fdset-id": 1
+       },
+       {
+         "fds": [
+           {
+             "fd": 28
+           },
+           {
+             "fd": 29
+           }
+         ],
+         "fdset-id": 0
+       }
+     ]
+   }
+
+Note: The list of fd sets is shared by all monitor connections.
+
 EQMP
 
     {
diff --git a/qmp.c b/qmp.c
index 6c1e4e89787bfe87ee990196020ce8d8be6c0d1e..84639220d0342d2772a222dcf267ceda4086914f 100644 (file)
--- a/qmp.c
+++ b/qmp.c
@@ -468,8 +468,14 @@ DevicePropertyInfoList *qmp_device_list_properties(const char *typename,
     return prop_list;
 }
 
-CpuDefinitionInfoList GCC_WEAK *qmp_query_cpu_definitions(Error **errp)
+CpuDefinitionInfoList GCC_WEAK *arch_query_cpu_definitions(Error **errp)
 {
     error_set(errp, QERR_NOT_SUPPORTED);
     return NULL;
 }
+
+CpuDefinitionInfoList *qmp_query_cpu_definitions(Error **errp)
+{
+    return arch_query_cpu_definitions(errp);
+}
+
index d153364253548d6cd91403711f84996e6a7dab31..f21f7a3f46b557eb5923f899ce8b4401b3cc6d91 160000 (submodule)
--- a/roms/SLOF
+++ b/roms/SLOF
@@ -1 +1 @@
-Subproject commit d153364253548d6cd91403711f84996e6a7dab31
+Subproject commit f21f7a3f46b557eb5923f899ce8b4401b3cc6d91
index 0ea10c9b664807d9775607897a04ceda5f82239b..c7fe28314567e444f69112d0e3a6551a775895cf 100644 (file)
--- a/savevm.c
+++ b/savevm.c
@@ -513,7 +513,7 @@ static void qemu_fill_buffer(QEMUFile *f)
  *
  * Returns f->close() return value, or 0 if close function is not set.
  */
-static int qemu_close(QEMUFile *f)
+static int qemu_fclose_internal(QEMUFile *f)
 {
     int ret = 0;
     if (f->close) {
@@ -535,7 +535,7 @@ int qemu_fclose(QEMUFile *f)
 {
     int ret;
     qemu_fflush(f);
-    ret = qemu_close(f);
+    ret = qemu_fclose_internal(f);
     /* If any error was spotted before closing, we should report it
      * instead of the close() return value.
      */
@@ -2473,7 +2473,7 @@ int xbzrle_encode_buffer(uint8_t *old_buf, uint8_t *new_buf, int slen,
         /* word at a time for speed, use of 32-bit long okay */
         if (!res) {
             /* truncation to 32-bit long okay */
-            long mask = 0x0101010101010101ULL;
+            long mask = (long)0x0101010101010101ULL;
             while (i < slen) {
                 xor = *(long *)(old_buf + i) ^ *(long *)(new_buf + i);
                 if ((xor - mask) & ~xor & (mask << 7)) {
index 9b4419f7c31056250d4db8343c699805a11b7917..8bbcb42cc4126dad27b43259f84b40161bcba088 100755 (executable)
@@ -71,7 +71,7 @@ def read_trace_file(edict, fobj):
 
     log_version = header[2]
     if log_version == 0:
-        raise ValueError('Older log format, not supported with this Qemu release!')
+        raise ValueError('Older log format, not supported with this QEMU release!')
 
     while True:
         rec = read_record(edict, fobj)
index c7e47d6d72d2cbb3beafc9dd8285afca20b53f4c..e4b4a7f05d1835b1e5ff9a36aefd18bed58484fc 100644 (file)
@@ -79,7 +79,7 @@ def c(events):
                        )
                 # pointer var (not string)
                 elif type_.endswith('*'):
-                    out('    trace_record_write_u64(&rec, (uint64_t)(uint64_t *)%(name)s);',
+                    out('    trace_record_write_u64(&rec, (uintptr_t)(uint64_t *)%(name)s);',
                         name = name,
                        )
                 # primitive data type
index 9d2a4bc4b4c167b4112c313ac9f09389526f5102..a639c5bff0d7c2d1bb65de82b50a70608d0e3b2a 100755 (executable)
@@ -46,6 +46,11 @@ mkdir -p "$output/linux-headers/linux"
 for header in kvm.h kvm_para.h vhost.h virtio_config.h virtio_ring.h; do
     cp "$tmpdir/include/linux/$header" "$output/linux-headers/linux"
 done
+rm -rf "$output/linux-headers/asm-generic"
+mkdir -p "$output/linux-headers/asm-generic"
+for header in kvm_para.h; do
+    cp "$tmpdir/include/asm-generic/$header" "$output/linux-headers/asm-generic"
+done
 if [ -L "$linux/source" ]; then
     cp "$linux/source/COPYING" "$output/linux-headers"
 else
index 6d5d0d6e108b02fbcf159a2f9aeea17087d9901a..120a2e3d3e32a97cc72531ee1670fe702cfdff6d 100644 (file)
@@ -28,7 +28,7 @@
 #include "qemu-config.h"
 
 #include "qapi/qapi-visit-core.h"
-#include "qmp-commands.h"
+#include "arch_init.h"
 
 #include "hyperv.h"
 
@@ -1126,7 +1126,7 @@ void x86_cpu_list(FILE *f, fprintf_function cpu_fprintf, const char *optarg)
     }
 }
 
-CpuDefinitionInfoList *qmp_query_cpu_definitions(Error **errp)
+CpuDefinitionInfoList *arch_query_cpu_definitions(Error **errp)
 {
     CpuDefinitionInfoList *cpu_list = NULL;
     x86_def_t *def;
index 829e180f8b3c97b7526d9950dfd5ec441fccbb46..a31d278a5f4979f31892643c523b6118bd794e33 100644 (file)
@@ -766,7 +766,7 @@ int kvm_arch_handle_exit(CPUPPCState *env, struct kvm_run *run)
         dprintf("handle PAPR hypercall\n");
         run->papr_hcall.ret = spapr_hypercall(env, run->papr_hcall.nr,
                                               run->papr_hcall.args);
-        ret = 1;
+        ret = 0;
         break;
 #endif
     default:
index 6fe4168dc0c88699cf1524bdcd5aacf3b4c943a6..fba2b4242771a1aa252cdbcb126d5651e07360d2 100644 (file)
@@ -27,7 +27,7 @@
 #include "gdbstub.h"
 #include <kvm.h>
 #include "kvm_ppc.h"
-#include "qmp-commands.h"
+#include "arch_init.h"
 
 //#define PPC_DUMP_CPU
 //#define PPC_DEBUG_SPR
@@ -10346,7 +10346,7 @@ void ppc_cpu_list (FILE *f, fprintf_function cpu_fprintf)
     }
 }
 
-CpuDefinitionInfoList *qmp_query_cpu_definitions(Error **errp)
+CpuDefinitionInfoList *arch_query_cpu_definitions(Error **errp)
 {
     CpuDefinitionInfoList *cpu_list = NULL;
     int i;
index f3f4159c2501d0f56002fb2869ae0a375d63e2ff..26a67ce6f5b7d849f4200bdb6ad5500561f72b2f 100644 (file)
@@ -81,7 +81,7 @@ TARGETS=$(patsubst %-softmmu,%, $(filter %-softmmu,$(TARGET_DIRS)))
 QTEST_TARGETS=$(foreach TARGET,$(TARGETS), $(if $(check-qtest-$(TARGET)-y), $(TARGET),))
 check-qtest-$(CONFIG_POSIX)=$(foreach TARGET,$(TARGETS), $(check-qtest-$(TARGET)-y))
 
-qtest-obj-y = tests/libqtest.o $(oslib-obj-y)
+qtest-obj-y = tests/libqtest.o $(oslib-obj-y) $(tools-obj-y)
 $(check-qtest-y): $(qtest-obj-y)
 
 .PHONY: check-help
index cc671dd7aac6ee8dc1b11a16f349598ecd1d1644..f71ab8dd102c4d7d95c91efbb8e0e254c007ddd0 100755 (executable)
@@ -225,8 +225,7 @@ class TestSetSpeed(ImageStreamingTestCase):
         self.assert_no_active_streams()
 
         result = self.vm.qmp('block-stream', device='drive0', speed=-1)
-        self.assert_qmp(result, 'error/class', 'InvalidParameter')
-        self.assert_qmp(result, 'error/data/name', 'speed')
+        self.assert_qmp(result, 'error/class', 'GenericError')
 
         self.assert_no_active_streams()
 
@@ -234,8 +233,7 @@ class TestSetSpeed(ImageStreamingTestCase):
         self.assert_qmp(result, 'return', {})
 
         result = self.vm.qmp('block-job-set-speed', device='drive0', speed=-1)
-        self.assert_qmp(result, 'error/class', 'InvalidParameter')
-        self.assert_qmp(result, 'error/data/name', 'speed')
+        self.assert_qmp(result, 'error/class', 'GenericError')
 
         self.cancel_and_wait()
 
index 6b12f83de0a920011b1178249654857ccf91df9f..04b07239270343251e050246fe941dd2b325ed7c 100644 (file)
@@ -970,3 +970,11 @@ qxl_render_blit_guest_primary_initialized(void) ""
 qxl_render_blit(int32_t stride, int32_t left, int32_t right, int32_t top, int32_t bottom) "stride=%d [%d, %d, %d, %d]"
 qxl_render_guest_primary_resized(int32_t width, int32_t height, int32_t stride, int32_t bytes_pp, int32_t bits_pp) "%dx%d, stride %d, bpp %d, depth %d"
 qxl_render_update_area_done(void *cookie) "%p"
+
+# hw/spapr_pci.c
+spapr_pci_msi(const char *msg, uint32_t n, uint32_t ca) "%s (device#%d, cfg=%x)"
+spapr_pci_msi_setup(const char *name, unsigned vector, uint64_t addr) "dev\"%s\" vector %u, addr=%"PRIx64
+spapr_pci_rtas_ibm_change_msi(unsigned func, unsigned req) "func %u, requested %u"
+spapr_pci_rtas_ibm_query_interrupt_source_number(unsigned ioa, unsigned intr) "queries for #%u, IRQ%u"
+spapr_pci_msi_write(uint64_t addr, uint64_t data, uint32_t dt_irq) "@%"PRIx64"<=%"PRIx64" IRQ %u"
+spapr_pci_lsi_set(const char *busname, int pin, uint32_t irq) "%s PIN%d IRQ %u"
index b700ea317cfce211f628f58d31ae65eaa97268c5..d83681b2270ddc4584ccad08f62dbdd301c117a5 100644 (file)
@@ -55,7 +55,7 @@ static unsigned int trace_idx;
 static unsigned int writeout_idx;
 static uint64_t dropped_events;
 static FILE *trace_fp;
-static char *trace_file_name = NULL;
+static char *trace_file_name;
 
 /* * Trace buffer entry */
 typedef struct {
@@ -70,7 +70,7 @@ typedef struct {
     uint64_t header_event_id; /* HEADER_EVENT_ID */
     uint64_t header_magic;    /* HEADER_MAGIC    */
     uint64_t header_version;  /* HEADER_VERSION  */
-} TraceRecordHeader;
+} TraceLogHeader;
 
 
 static void read_from_buffer(unsigned int idx, void *dataptr, size_t size);
@@ -231,13 +231,11 @@ int trace_record_start(TraceBufferRecord *rec, TraceEventID event, size_t datasi
     }
 
     idx = old_idx % TRACE_BUF_LEN;
-    /*  To check later if threshold crossed */
-    rec->next_tbuf_idx = new_idx % TRACE_BUF_LEN;
 
     rec_off = idx;
-    rec_off = write_to_buffer(rec_off, (uint8_t*)&event, sizeof(event));
-    rec_off = write_to_buffer(rec_off, (uint8_t*)&timestamp_ns, sizeof(timestamp_ns));
-    rec_off = write_to_buffer(rec_off, (uint8_t*)&rec_len, sizeof(rec_len));
+    rec_off = write_to_buffer(rec_off, &event, sizeof(event));
+    rec_off = write_to_buffer(rec_off, &timestamp_ns, sizeof(timestamp_ns));
+    rec_off = write_to_buffer(rec_off, &rec_len, sizeof(rec_len));
 
     rec->tbuf_idx = idx;
     rec->rec_off  = (idx + sizeof(TraceRecord)) % TRACE_BUF_LEN;
@@ -271,12 +269,11 @@ static unsigned int write_to_buffer(unsigned int idx, void *dataptr, size_t size
 
 void trace_record_finish(TraceBufferRecord *rec)
 {
-    uint8_t temp_rec[sizeof(TraceRecord)];
-    TraceRecord *record = (TraceRecord *) temp_rec;
-    read_from_buffer(rec->tbuf_idx, temp_rec, sizeof(TraceRecord));
+    TraceRecord record;
+    read_from_buffer(rec->tbuf_idx, &record, sizeof(TraceRecord));
     smp_wmb(); /* write barrier before marking as valid */
-    record->event |= TRACE_RECORD_VALID;
-    write_to_buffer(rec->tbuf_idx, temp_rec, sizeof(TraceRecord));
+    record.event |= TRACE_RECORD_VALID;
+    write_to_buffer(rec->tbuf_idx, &record, sizeof(TraceRecord));
 
     if ((trace_idx - writeout_idx) > TRACE_BUF_FLUSH_THRESHOLD) {
         flush_trace_file(false);
@@ -295,7 +292,7 @@ void st_set_trace_file_enabled(bool enable)
     flush_trace_file(true);
 
     if (enable) {
-        static const TraceRecordHeader header = {
+        static const TraceLogHeader header = {
             .header_event_id = HEADER_EVENT_ID,
             .header_magic = HEADER_MAGIC,
             /* Older log readers will check for version at next location */
@@ -332,18 +329,12 @@ bool st_set_trace_file(const char *file)
 {
     st_set_trace_file_enabled(false);
 
-    free(trace_file_name);
+    g_free(trace_file_name);
 
     if (!file) {
-        if (asprintf(&trace_file_name, CONFIG_TRACE_FILE, getpid()) < 0) {
-            trace_file_name = NULL;
-            return false;
-        }
+        trace_file_name = g_strdup_printf(CONFIG_TRACE_FILE, getpid());
     } else {
-        if (asprintf(&trace_file_name, "%s", file) < 0) {
-            trace_file_name = NULL;
-            return false;
-        }
+        trace_file_name = g_strdup_printf("%s", file);
     }
 
     st_set_trace_file_enabled(true);
index 7e521c1e1fe75fa62a78cd0807d3f1b95338e5bf..2ab96a81479d5148d0b37daa112d5d191cfee2e6 100644 (file)
@@ -29,7 +29,6 @@ void st_flush_trace_buffer(void);
 
 typedef struct {
     unsigned int tbuf_idx;
-    unsigned int next_tbuf_idx;
     unsigned int rec_off;
 } TraceBufferRecord;