diff options
240 files changed, 4239 insertions, 2088 deletions
diff --git a/MAINTAINERS b/MAINTAINERS index 35d4496186..6115e4ec08 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -480,7 +480,7 @@ S: Maintained F: tcg/ia64/ MIPS target -M: Aurelien Jarno <aurelien@aurel32.ne> +M: Aurelien Jarno <aurelien@aurel32.net> S: Maintained F: tcg/mips/ diff --git a/Makefile.objs b/Makefile.objs index cea15e4a82..1635df6e2f 100644 --- a/Makefile.objs +++ b/Makefile.objs @@ -155,8 +155,8 @@ slirp-obj-y += tcp_subr.o tcp_timer.o udp.o bootp.o tftp.o common-obj-$(CONFIG_SLIRP) += $(addprefix slirp/, $(slirp-obj-y)) # xen backend driver support -common-obj-$(CONFIG_XEN) += xen_backend.o xen_devconfig.o -common-obj-$(CONFIG_XEN) += xen_console.o xenfb.o xen_disk.o xen_nic.o +common-obj-$(CONFIG_XEN_BACKEND) += xen_backend.o xen_devconfig.o +common-obj-$(CONFIG_XEN_BACKEND) += xen_console.o xenfb.o xen_disk.o xen_nic.o ###################################################################### # libuser diff --git a/Makefile.target b/Makefile.target index 37bb28ed8a..fe785161cb 100644 --- a/Makefile.target +++ b/Makefile.target @@ -3,6 +3,7 @@ GENERATED_HEADERS = config-target.h CONFIG_NO_PCI = $(if $(subst n,,$(CONFIG_PCI)),n,y) CONFIG_NO_KVM = $(if $(subst n,,$(CONFIG_KVM)),n,y) +CONFIG_NO_XEN = $(if $(subst n,,$(CONFIG_XEN)),n,y) include ../config-host.mak include config-devices.mak @@ -14,7 +15,10 @@ endif TARGET_PATH=$(SRC_PATH)/target-$(TARGET_BASE_ARCH) $(call set-vpath, $(SRC_PATH):$(TARGET_PATH):$(SRC_PATH)/hw) -QEMU_CFLAGS+= -I.. -I../linux-headers -I$(TARGET_PATH) -DNEED_CPU_H +ifdef CONFIG_LINUX +QEMU_CFLAGS += -I../linux-headers +endif +QEMU_CFLAGS += -I.. -I$(TARGET_PATH) -DNEED_CPU_H include $(SRC_PATH)/Makefile.objs @@ -91,7 +95,7 @@ tcg/tcg.o: cpu.h # HELPER_CFLAGS is used for all the code compiled with static register # variables -op_helper.o cpu-exec.o user-exec.o: QEMU_CFLAGS += $(HELPER_CFLAGS) +op_helper.o user-exec.o: QEMU_CFLAGS += $(HELPER_CFLAGS) # Note: this is a workaround. The real fix is to avoid compiling # cpu_signal_handler() in user-exec.c. @@ -201,20 +205,9 @@ QEMU_CFLAGS += $(VNC_SASL_CFLAGS) QEMU_CFLAGS += $(VNC_JPEG_CFLAGS) QEMU_CFLAGS += $(VNC_PNG_CFLAGS) -# xen backend driver support -obj-i386-$(CONFIG_XEN) += xen_machine_pv.o xen_domainbuild.o - -ifeq ($(TARGET_BASE_ARCH), i386) - CONFIG_NO_XEN = $(if $(subst n,,$(CONFIG_XEN)),n,y) -else - CONFIG_NO_XEN = y -endif # xen support -CONFIG_NO_XEN_MAPCACHE = $(if $(subst n,,$(CONFIG_XEN_MAPCACHE)),n,y) -obj-i386-$(CONFIG_XEN) += xen-all.o +obj-$(CONFIG_XEN) += xen-all.o xen_machine_pv.o xen_domainbuild.o xen-mapcache.o obj-$(CONFIG_NO_XEN) += xen-stub.o -obj-i386-$(CONFIG_XEN_MAPCACHE) += xen-mapcache.o -obj-$(CONFIG_NO_XEN_MAPCACHE) += xen-mapcache-stub.o obj-i386-$(CONFIG_XEN) += xen_platform.o @@ -234,7 +227,8 @@ obj-i386-y += cirrus_vga.o sga.o apic.o ioapic.o piix_pci.o obj-i386-y += vmport.o obj-i386-y += device-hotplug.o pci-hotplug.o smbios.o wdt_ib700.o obj-i386-y += debugcon.o multiboot.o -obj-i386-y += pc_piix.o kvmclock.o +obj-i386-y += pc_piix.o +obj-i386-$(CONFIG_KVM) += kvmclock.o obj-i386-$(CONFIG_SPICE) += qxl.o qxl-logger.o qxl-render.o # shared objects @@ -256,7 +250,7 @@ endif obj-ppc-y += ppc4xx_devs.o ppc4xx_pci.o ppc405_uc.o ppc405_boards.o obj-ppc-y += ppc440.o ppc440_bamboo.o # PowerPC E500 boards -obj-ppc-y += ppce500_mpc8544ds.o +obj-ppc-y += ppce500_mpc8544ds.o mpc8544_guts.o # PowerPC 440 Xilinx ML507 reference board. obj-ppc-y += virtex_ml507.o obj-ppc-$(CONFIG_KVM) += kvm_ppc.o diff --git a/arm-semi.c b/arm-semi.c index e9e6f8993f..873518a20e 100644 --- a/arm-semi.c +++ b/arm-semi.c @@ -34,6 +34,7 @@ #else #include "qemu-common.h" #include "gdbstub.h" +#include "hw/arm-misc.h" #endif #define SYS_OPEN 0x01 @@ -369,68 +370,88 @@ uint32_t do_arm_semihosting(CPUState *env) return syscall_err; #endif case SYS_GET_CMDLINE: -#ifdef CONFIG_USER_ONLY - /* Build a commandline from the original argv. */ { - char *arm_cmdline_buffer; - const char *host_cmdline_buffer; + /* Build a command-line from the original argv. + * + * The inputs are: + * * ARG(0), pointer to a buffer of at least the size + * specified in ARG(1). + * * ARG(1), size of the buffer pointed to by ARG(0) in + * bytes. + * + * The outputs are: + * * ARG(0), pointer to null-terminated string of the + * command line. + * * ARG(1), length of the string pointed to by ARG(0). + */ - unsigned int i; - unsigned int arm_cmdline_len = ARG(1); - unsigned int host_cmdline_len = - ts->info->arg_end-ts->info->arg_start; + char *output_buffer; + size_t input_size = ARG(1); + size_t output_size; + int status = 0; - if (!arm_cmdline_len || host_cmdline_len > arm_cmdline_len) { - return -1; /* not enough space to store command line */ - } + /* Compute the size of the output string. */ +#if !defined(CONFIG_USER_ONLY) + output_size = strlen(ts->boot_info->kernel_filename) + + 1 /* Separating space. */ + + strlen(ts->boot_info->kernel_cmdline) + + 1; /* Terminating null byte. */ +#else + unsigned int i; - if (!host_cmdline_len) { + output_size = ts->info->arg_end - ts->info->arg_start; + if (!output_size) { /* We special-case the "empty command line" case (argc==0). Just provide the terminating 0. */ - arm_cmdline_buffer = lock_user(VERIFY_WRITE, ARG(0), 1, 0); - arm_cmdline_buffer[0] = 0; - unlock_user(arm_cmdline_buffer, ARG(0), 1); + output_size = 1; + } +#endif - /* Adjust the commandline length argument. */ - SET_ARG(1, 0); - return 0; + if (output_size > input_size) { + /* Not enough space to store command-line arguments. */ + return -1; } - /* lock the buffers on the ARM side */ - arm_cmdline_buffer = - lock_user(VERIFY_WRITE, ARG(0), host_cmdline_len, 0); - host_cmdline_buffer = - lock_user(VERIFY_READ, ts->info->arg_start, - host_cmdline_len, 1); + /* Adjust the command-line length. */ + SET_ARG(1, output_size - 1); - if (arm_cmdline_buffer && host_cmdline_buffer) - { - /* the last argument is zero-terminated; - no need for additional termination */ - memcpy(arm_cmdline_buffer, host_cmdline_buffer, - host_cmdline_len); + /* Lock the buffer on the ARM side. */ + output_buffer = lock_user(VERIFY_WRITE, ARG(0), output_size, 0); + if (!output_buffer) { + return -1; + } - /* separate arguments by white spaces */ - for (i = 0; i < host_cmdline_len-1; i++) { - if (arm_cmdline_buffer[i] == 0) { - arm_cmdline_buffer[i] = ' '; - } - } + /* Copy the command-line arguments. */ +#if !defined(CONFIG_USER_ONLY) + pstrcpy(output_buffer, output_size, ts->boot_info->kernel_filename); + pstrcat(output_buffer, output_size, " "); + pstrcat(output_buffer, output_size, ts->boot_info->kernel_cmdline); +#else + if (output_size == 1) { + /* Empty command-line. */ + output_buffer[0] = '\0'; + goto out; + } - /* Adjust the commandline length argument. */ - SET_ARG(1, host_cmdline_len-1); + if (copy_from_user(output_buffer, ts->info->arg_start, + output_size)) { + status = -1; + goto out; } - /* Unlock the buffers on the ARM side. */ - unlock_user(arm_cmdline_buffer, ARG(0), host_cmdline_len); - unlock_user((void*)host_cmdline_buffer, ts->info->arg_start, 0); + /* Separate arguments by white spaces. */ + for (i = 0; i < output_size - 1; i++) { + if (output_buffer[i] == 0) { + output_buffer[i] = ' '; + } + } + out: +#endif + /* Unlock the buffer on the ARM side. */ + unlock_user(output_buffer, ARG(0), output_size); - /* Return success if we could return a commandline. */ - return (arm_cmdline_buffer && host_cmdline_buffer) ? 0 : -1; + return status; } -#else - return -1; -#endif case SYS_HEAPINFO: { uint32_t *ptr; @@ -440,15 +461,16 @@ uint32_t do_arm_semihosting(CPUState *env) /* Some C libraries assume the heap immediately follows .bss, so allocate it using sbrk. */ if (!ts->heap_limit) { - long ret; + abi_ulong ret; ts->heap_base = do_brk(0); limit = ts->heap_base + ARM_ANGEL_HEAP_SIZE; /* Try a big heap, and reduce the size if that fails. */ for (;;) { ret = do_brk(limit); - if (ret != -1) + if (ret >= limit) { break; + } limit = (ts->heap_base >> 1) + (limit >> 1); } ts->heap_limit = limit; diff --git a/audio/coreaudio.c b/audio/coreaudio.c index 3bd75cdda4..5964c62eaf 100644 --- a/audio/coreaudio.c +++ b/audio/coreaudio.c @@ -104,7 +104,7 @@ static void coreaudio_logstatus (OSStatus status) break; default: - AUD_log (AUDIO_CAP, "Reason: status code %ld\n", status); + AUD_log (AUDIO_CAP, "Reason: status code %" PRId32 "\n", (int32_t)status); return; } @@ -360,8 +360,8 @@ static int coreaudio_init_out (HWVoiceOut *hw, struct audsettings *as) &core->audioDevicePropertyBufferFrameSize); if (status != kAudioHardwareNoError) { coreaudio_logerr2 (status, typ, - "Could not set device buffer frame size %ld\n", - core->audioDevicePropertyBufferFrameSize); + "Could not set device buffer frame size %" PRIu32 "\n", + (uint32_t)core->audioDevicePropertyBufferFrameSize); return -1; } diff --git a/block-migration.c b/block-migration.c index 8d06a23649..0936c7d5ea 100644 --- a/block-migration.c +++ b/block-migration.c @@ -671,7 +671,7 @@ static int block_load(QEMUFile *f, void *opaque, int version_id) bs_prev = bs; total_sectors = bdrv_getlength(bs) >> BDRV_SECTOR_BITS; if (total_sectors <= 0) { - error_report("Error getting length of block device %s\n", + error_report("Error getting length of block device %s", device_name); return -EINVAL; } diff --git a/block/qcow2.c b/block/qcow2.c index 2c51e7ccbd..48e1b95689 100644 --- a/block/qcow2.c +++ b/block/qcow2.c @@ -936,7 +936,7 @@ static int qcow2_create2(const char *filename, int64_t total_size, (1 << cluster_bits) != cluster_size) { error_report( - "Cluster size must be a power of two between %d and %dk\n", + "Cluster size must be a power of two between %d and %dk", 1 << MIN_CLUSTER_BITS, 1 << (MAX_CLUSTER_BITS - 10)); return -EINVAL; } diff --git a/block/raw-posix.c b/block/raw-posix.c index 4cd7d7afbb..34b64aa205 100644 --- a/block/raw-posix.c +++ b/block/raw-posix.c @@ -46,6 +46,8 @@ #include <sys/dkio.h> #endif #ifdef __linux__ +#include <sys/types.h> +#include <sys/stat.h> #include <sys/ioctl.h> #include <sys/param.h> #include <linux/cdrom.h> @@ -1188,6 +1190,7 @@ static int floppy_probe_device(const char *filename) int fd, ret; int prio = 0; struct floppy_struct fdparam; + struct stat st; if (strstart(filename, "/dev/fd", NULL)) prio = 50; @@ -1196,12 +1199,17 @@ static int floppy_probe_device(const char *filename) if (fd < 0) { goto out; } + ret = fstat(fd, &st); + if (ret == -1 || !S_ISBLK(st.st_mode)) { + goto outc; + } /* Attempt to detect via a floppy specific ioctl */ ret = ioctl(fd, FDGETPRM, &fdparam); if (ret >= 0) prio = 100; +outc: close(fd); out: return prio; @@ -1290,17 +1298,23 @@ static int cdrom_probe_device(const char *filename) { int fd, ret; int prio = 0; + struct stat st; fd = open(filename, O_RDONLY | O_NONBLOCK); if (fd < 0) { goto out; } + ret = fstat(fd, &st); + if (ret == -1 || !S_ISBLK(st.st_mode)) { + goto outc; + } /* Attempt to detect via a CDROM specific ioctl */ ret = ioctl(fd, CDROM_DRIVE_STATUS, CDSL_CURRENT); if (ret >= 0) prio = 100; +outc: close(fd); out: return prio; diff --git a/block/sheepdog.c b/block/sheepdog.c index 0392ca8c9c..80d106c2b2 100644 --- a/block/sheepdog.c +++ b/block/sheepdog.c @@ -444,18 +444,12 @@ static SheepdogAIOCB *sd_aio_setup(BlockDriverState *bs, QEMUIOVector *qiov, static int sd_schedule_bh(QEMUBHFunc *cb, SheepdogAIOCB *acb) { if (acb->bh) { - error_report("bug: %d %d\n", acb->aiocb_type, acb->aiocb_type); + error_report("bug: %d %d", acb->aiocb_type, acb->aiocb_type); return -EIO; } acb->bh = qemu_bh_new(cb, acb); - if (!acb->bh) { - error_report("oom: %d %d\n", acb->aiocb_type, acb->aiocb_type); - return -EIO; - } - qemu_bh_schedule(acb->bh); - return 0; } @@ -598,7 +592,7 @@ static int connect_to_sdog(const char *addr, const char *port) ret = getaddrinfo(addr, port, &hints, &res0); if (ret) { - error_report("unable to get address info %s, %s\n", + error_report("unable to get address info %s, %s", addr, strerror(errno)); return -1; } @@ -628,7 +622,7 @@ static int connect_to_sdog(const char *addr, const char *port) goto success; } fd = -1; - error_report("failed connect to %s:%s\n", addr, port); + error_report("failed connect to %s:%s", addr, port); success: freeaddrinfo(res0); return fd; @@ -644,7 +638,7 @@ again: if (errno == EINTR || errno == EAGAIN) { goto again; } - error_report("failed to recv a rsp, %s\n", strerror(errno)); + error_report("failed to recv a rsp, %s", strerror(errno)); return 1; } @@ -703,7 +697,7 @@ static int send_req(int sockfd, SheepdogReq *hdr, void *data, ret = do_writev(sockfd, iov, sizeof(*hdr) + *wlen, 0); if (ret) { - error_report("failed to send a req, %s\n", strerror(errno)); + error_report("failed to send a req, %s", strerror(errno)); ret = -1; } @@ -723,7 +717,7 @@ static int do_req(int sockfd, SheepdogReq *hdr, void *data, ret = do_read(sockfd, hdr, sizeof(*hdr)); if (ret) { - error_report("failed to get a rsp, %s\n", strerror(errno)); + error_report("failed to get a rsp, %s", strerror(errno)); ret = -1; goto out; } @@ -735,7 +729,7 @@ static int do_req(int sockfd, SheepdogReq *hdr, void *data, if (*rlen) { ret = do_read(sockfd, data, *rlen); if (ret) { - error_report("failed to get the data, %s\n", strerror(errno)); + error_report("failed to get the data, %s", strerror(errno)); ret = -1; goto out; } @@ -772,7 +766,7 @@ static void send_pending_req(BDRVSheepdogState *s, uint64_t oid, uint32_t id) ret = add_aio_request(s, aio_req, acb->qiov->iov, acb->qiov->niov, 0, acb->aiocb_type); if (ret < 0) { - error_report("add_aio_request is failed\n"); + error_report("add_aio_request is failed"); free_aio_req(s, aio_req); if (QLIST_EMPTY(&acb->aioreq_head)) { sd_finish_aiocb(acb); @@ -805,7 +799,7 @@ static void aio_read_response(void *opaque) /* read a header */ ret = do_read(fd, &rsp, sizeof(rsp)); if (ret) { - error_report("failed to get the header, %s\n", strerror(errno)); + error_report("failed to get the header, %s", strerror(errno)); return; } @@ -816,7 +810,7 @@ static void aio_read_response(void *opaque) } } if (!aio_req) { - error_report("cannot find aio_req %x\n", rsp.id); + error_report("cannot find aio_req %x", rsp.id); return; } @@ -852,7 +846,7 @@ static void aio_read_response(void *opaque) ret = do_readv(fd, acb->qiov->iov, rsp.data_length, aio_req->iov_offset); if (ret) { - error_report("failed to get the data, %s\n", strerror(errno)); + error_report("failed to get the data, %s", strerror(errno)); return; } break; @@ -860,7 +854,7 @@ static void aio_read_response(void *opaque) if (rsp.result != SD_RES_SUCCESS) { acb->ret = -EIO; - error_report("%s\n", sd_strerror(rsp.result)); + error_report("%s", sd_strerror(rsp.result)); } rest = free_aio_req(s, aio_req); @@ -917,7 +911,7 @@ static int get_sheep_fd(BDRVSheepdogState *s) fd = connect_to_sdog(s->addr, s->port); if (fd < 0) { - error_report("%s\n", strerror(errno)); + error_report("%s", strerror(errno)); return -1; } @@ -925,7 +919,7 @@ static int get_sheep_fd(BDRVSheepdogState *s) ret = set_nodelay(fd); if (ret) { - error_report("%s\n", strerror(errno)); + error_report("%s", strerror(errno)); closesocket(fd); return -1; } @@ -1041,7 +1035,7 @@ static int find_vdi_name(BDRVSheepdogState *s, char *filename, uint32_t snapid, } if (rsp->result != SD_RES_SUCCESS) { - error_report("cannot get vdi info, %s, %s %d %s\n", + error_report("cannot get vdi info, %s, %s %d %s", sd_strerror(rsp->result), filename, snapid, tag); ret = -1; goto out; @@ -1069,7 +1063,7 @@ static int add_aio_request(BDRVSheepdogState *s, AIOReq *aio_req, uint64_t old_oid = aio_req->base_oid; if (!nr_copies) { - error_report("bug\n"); + error_report("bug"); } memset(&hdr, 0, sizeof(hdr)); @@ -1102,14 +1096,14 @@ static int add_aio_request(BDRVSheepdogState *s, AIOReq *aio_req, /* send a header */ ret = do_write(s->fd, &hdr, sizeof(hdr)); if (ret) { - error_report("failed to send a req, %s\n", strerror(errno)); + error_report("failed to send a req, %s", strerror(errno)); return -EIO; } if (wlen) { ret = do_writev(s->fd, iov, wlen, aio_req->iov_offset); if (ret) { - error_report("failed to send a data, %s\n", strerror(errno)); + error_report("failed to send a data, %s", strerror(errno)); return -EIO; } } @@ -1151,7 +1145,7 @@ static int read_write_object(int fd, char *buf, uint64_t oid, int copies, ret = do_req(fd, (SheepdogReq *)&hdr, buf, &wlen, &rlen); if (ret) { - error_report("failed to send a request to the sheep\n"); + error_report("failed to send a request to the sheep"); return -1; } @@ -1159,7 +1153,7 @@ static int read_write_object(int fd, char *buf, uint64_t oid, int copies, case SD_RES_SUCCESS: return 0; default: - error_report("%s\n", sd_strerror(rsp->result)); + error_report("%s", sd_strerror(rsp->result)); return -1; } } @@ -1212,7 +1206,7 @@ static int sd_open(BlockDriverState *bs, const char *filename, int flags) fd = connect_to_sdog(s->addr, s->port); if (fd < 0) { - error_report("failed to connect\n"); + error_report("failed to connect"); goto out; } @@ -1281,7 +1275,7 @@ static int do_sd_create(char *filename, int64_t vdi_size, } if (rsp->result != SD_RES_SUCCESS) { - error_report("%s, %s\n", sd_strerror(rsp->result), filename); + error_report("%s, %s", sd_strerror(rsp->result), filename); return -EIO; } @@ -1308,7 +1302,7 @@ static int sd_create(const char *filename, QEMUOptionParameter *options) memset(vdi, 0, sizeof(vdi)); memset(tag, 0, sizeof(tag)); if (parse_vdiname(&s, filename, vdi, &snapid, tag) < 0) { - error_report("invalid filename\n"); + error_report("invalid filename"); return -EINVAL; } @@ -1322,7 +1316,7 @@ static int sd_create(const char *filename, QEMUOptionParameter *options) } if (vdi_size > SD_MAX_VDI_SIZE) { - error_report("too big image size\n"); + error_report("too big image size"); return -EINVAL; } @@ -1334,7 +1328,7 @@ static int sd_create(const char *filename, QEMUOptionParameter *options) /* Currently, only Sheepdog backing image is supported. */ drv = bdrv_find_protocol(backing_file); if (!drv || strcmp(drv->protocol_name, "sheepdog") != 0) { - error_report("backing_file must be a sheepdog image\n"); + error_report("backing_file must be a sheepdog image"); return -EINVAL; } @@ -1345,7 +1339,7 @@ static int sd_create(const char *filename, QEMUOptionParameter *options) s = bs->opaque; if (!is_snapshot(&s->inode)) { - error_report("cannot clone from a non snapshot vdi\n"); + error_report("cannot clone from a non snapshot vdi"); bdrv_delete(bs); return -EINVAL; } @@ -1385,7 +1379,7 @@ static void sd_close(BlockDriverState *bs) if (!ret && rsp->result != SD_RES_SUCCESS && rsp->result != SD_RES_VDI_NOT_LOCKED) { - error_report("%s, %s\n", sd_strerror(rsp->result), s->name); + error_report("%s, %s", sd_strerror(rsp->result), s->name); } qemu_aio_set_fd_handler(s->fd, NULL, NULL, NULL, NULL, NULL); @@ -1407,10 +1401,10 @@ static int sd_truncate(BlockDriverState *bs, int64_t offset) unsigned int datalen; if (offset < s->inode.vdi_size) { - error_report("shrinking is not supported\n"); + error_report("shrinking is not supported"); return -EINVAL; } else if (offset > SD_MAX_VDI_SIZE) { - error_report("too big image size\n"); + error_report("too big image size"); return -EINVAL; } @@ -1427,7 +1421,7 @@ static int sd_truncate(BlockDriverState *bs, int64_t offset) close(fd); if (ret < 0) { - error_report("failed to update an inode.\n"); + error_report("failed to update an inode."); return -EIO; } @@ -1500,7 +1494,7 @@ static int sd_create_branch(BDRVSheepdogState *s) fd = connect_to_sdog(s->addr, s->port); if (fd < 0) { - error_report("failed to connect\n"); + error_report("failed to connect"); goto out; } @@ -1618,7 +1612,7 @@ static void sd_readv_writev_bh_cb(void *p) ret = add_aio_request(s, aio_req, acb->qiov->iov, acb->qiov->niov, create, acb->aiocb_type); if (ret < 0) { - error_report("add_aio_request is failed\n"); + error_report("add_aio_request is failed"); free_aio_req(s, aio_req); acb->ret = -EIO; goto out; @@ -1695,7 +1689,7 @@ static int sd_snapshot_create(BlockDriverState *bs, QEMUSnapshotInfo *sn_info) if (s->is_snapshot) { error_report("You can't create a snapshot of a snapshot VDI, " - "%s (%" PRIu32 ").\n", s->name, s->inode.vdi_id); + "%s (%" PRIu32 ").", s->name, s->inode.vdi_id); return -EINVAL; } @@ -1718,7 +1712,7 @@ static int sd_snapshot_create(BlockDriverState *bs, QEMUSnapshotInfo *sn_info) ret = write_object(fd, (char *)&s->inode, vid_to_vdi_oid(s->inode.vdi_id), s->inode.nr_copies, datalen, 0, 0); if (ret < 0) { - error_report("failed to write snapshot's inode.\n"); + error_report("failed to write snapshot's inode."); ret = -EIO; goto cleanup; } @@ -1726,7 +1720,7 @@ static int sd_snapshot_create(BlockDriverState *bs, QEMUSnapshotInfo *sn_info) ret = do_sd_create(s->name, s->inode.vdi_size, s->inode.vdi_id, &new_vid, 1, s->addr, s->port); if (ret < 0) { - error_report("failed to create inode for snapshot. %s\n", + error_report("failed to create inode for snapshot. %s", strerror(errno)); ret = -EIO; goto cleanup; @@ -1738,7 +1732,7 @@ static int sd_snapshot_create(BlockDriverState *bs, QEMUSnapshotInfo *sn_info) s->inode.nr_copies, datalen, 0); if (ret < 0) { - error_report("failed to read new inode info. %s\n", strerror(errno)); + error_report("failed to read new inode info. %s", strerror(errno)); ret = -EIO; goto cleanup; } @@ -1777,14 +1771,14 @@ static int sd_snapshot_goto(BlockDriverState *bs, const char *snapshot_id) ret = find_vdi_name(s, vdi, snapid, tag, &vid, 1); if (ret) { - error_report("Failed to find_vdi_name\n"); + error_report("Failed to find_vdi_name"); ret = -ENOENT; goto out; } fd = connect_to_sdog(s->addr, s->port); if (fd < 0) { - error_report("failed to connect\n"); + error_report("failed to connect"); goto out; } @@ -1802,7 +1796,7 @@ static int sd_snapshot_goto(BlockDriverState *bs, const char *snapshot_id) memcpy(&s->inode, buf, sizeof(s->inode)); if (!s->inode.vm_state_size) { - error_report("Invalid snapshot\n"); + error_report("Invalid snapshot"); ret = -ENOENT; goto out; } @@ -1819,7 +1813,7 @@ out: qemu_free(buf); qemu_free(old_s); - error_report("failed to open. recover old bdrv_sd_state.\n"); + error_report("failed to open. recover old bdrv_sd_state."); return ret; } @@ -1874,7 +1868,7 @@ static int sd_snapshot_list(BlockDriverState *bs, QEMUSnapshotInfo **psn_tab) fd = connect_to_sdog(s->addr, s->port); if (fd < 0) { - error_report("failed to connect\n"); + error_report("failed to connect"); goto out; } @@ -1948,7 +1942,7 @@ static int do_load_save_vmstate(BDRVSheepdogState *s, uint8_t *data, } if (ret < 0) { - error_report("failed to save vmstate %s\n", strerror(errno)); + error_report("failed to save vmstate %s", strerror(errno)); ret = -EIO; goto cleanup; } diff --git a/blockdev.c b/blockdev.c index 1502575acb..a97a801e95 100644 --- a/blockdev.c +++ b/blockdev.c @@ -240,14 +240,6 @@ DriveInfo *drive_init(QemuOpts *opts, int default_to_scsi) int ret; translation = BIOS_ATA_TRANSLATION_AUTO; - - if (default_to_scsi) { - type = IF_SCSI; - pstrcpy(devname, sizeof(devname), "scsi"); - } else { - type = IF_IDE; - pstrcpy(devname, sizeof(devname), "ide"); - } media = MEDIA_DISK; /* extract parameters */ @@ -273,7 +265,11 @@ DriveInfo *drive_init(QemuOpts *opts, int default_to_scsi) error_report("unsupported bus type '%s'", buf); return NULL; } + } else { + type = default_to_scsi ? IF_SCSI : IF_IDE; + pstrcpy(devname, sizeof(devname), if_name[type]); } + max_devs = if_max_devs[type]; if (cyls || heads || secs) { @@ -293,7 +289,7 @@ DriveInfo *drive_init(QemuOpts *opts, int default_to_scsi) if ((buf = qemu_opt_get(opts, "trans")) != NULL) { if (!cyls) { - error_report("'%s' trans must be used with cyls,heads and secs", + error_report("'%s' trans must be used with cyls, heads and secs", buf); return NULL; } @@ -314,7 +310,7 @@ DriveInfo *drive_init(QemuOpts *opts, int default_to_scsi) media = MEDIA_DISK; } else if (!strcmp(buf, "cdrom")) { if (cyls || secs || heads) { - error_report("'%s' invalid physical CHS format", buf); + error_report("CHS can't be set with media=%s", buf); return NULL; } media = MEDIA_CDROM; diff --git a/bsd-user/main.c b/bsd-user/main.c index 0af8a7e7f1..6018a419ed 100644 --- a/bsd-user/main.c +++ b/bsd-user/main.c @@ -29,7 +29,7 @@ #include "qemu.h" #include "qemu-common.h" /* For tb_lock */ -#include "exec-all.h" +#include "cpu.h" #include "tcg.h" #include "qemu-timer.h" #include "envlist.h" @@ -866,7 +866,7 @@ int main(int argc, char **argv) int mask; const CPULogItem *item; - mask = cpu_str_to_log_mask(r); + mask = cpu_str_to_log_mask(log_mask); if (!mask) { printf("Log items (comma separated):\n"); for (item = cpu_log_items; item->mask != 0; item++) { @@ -113,7 +113,7 @@ curl="" curses="" docs="" fdt="" -kvm="yes" +kvm="" nptl="" sdl="" vnc="yes" @@ -129,7 +129,7 @@ xen="" xen_ctrl_version="" linux_aio="" attr="" -vhost_net="yes" +vhost_net="" xfs="" gprof="no" @@ -457,6 +457,8 @@ Haiku) linux="yes" linux_user="yes" usb="linux" + kvm="yes" + vhost_net="yes" if [ "$cpu" = "i386" -o "$cpu" = "x86_64" ] ; then audio_possible_drivers="$audio_possible_drivers fmod" fi @@ -1638,7 +1640,7 @@ for drv in $audio_drv_list; do pa) audio_drv_probe $drv pulse/simple.h "-lpulse-simple -lpulse" \ - "pa_simple *s = NULL; pa_simple_free(s); return 0;" + "pa_simple *s = 0; pa_simple_free(s); return 0;" libs_softmmu="-lpulse -lpulse-simple $libs_softmmu" audio_pt_int="yes" ;; @@ -2848,7 +2850,7 @@ if test "$bluez" = "yes" ; then echo "BLUEZ_CFLAGS=$bluez_cflags" >> $config_host_mak fi if test "$xen" = "yes" ; then - echo "CONFIG_XEN=y" >> $config_host_mak + echo "CONFIG_XEN_BACKEND=y" >> $config_host_mak echo "CONFIG_XEN_CTRL_INTERFACE_VERSION=$xen_ctrl_version" >> $config_host_mak fi if test "$io_thread" = "yes" ; then @@ -3444,19 +3446,21 @@ if test "$target_linux_user" = "yes" -o "$target_bsd_user" = "yes" ; then fi # use included Linux headers -includes="-I\$(SRC_PATH)/linux-headers $includes" -mkdir -p linux-headers -case "$cpu" in -i386|x86_64) - symlink $source_path/linux-headers/asm-x86 linux-headers/asm - ;; -ppcemb|ppc|ppc64) - symlink $source_path/linux-headers/asm-x86 linux-headers/asm - ;; -s390x) - symlink $source_path/linux-headers/asm-s390 linux-headers/asm - ;; -esac +if test "$linux" = "yes" ; then + includes="-I\$(SRC_PATH)/linux-headers $includes" + mkdir -p linux-headers + case "$cpu" in + i386|x86_64) + symlink $source_path/linux-headers/asm-x86 linux-headers/asm + ;; + ppcemb|ppc|ppc64) + symlink $source_path/linux-headers/asm-powerpc linux-headers/asm + ;; + s390x) + symlink $source_path/linux-headers/asm-s390 linux-headers/asm + ;; + esac +fi echo "LDFLAGS+=$ldflags" >> $config_target_mak echo "QEMU_CFLAGS+=$cflags" >> $config_target_mak @@ -3479,7 +3483,9 @@ for bios_file in $source_path/pc-bios/*.bin $source_path/pc-bios/*.rom $source_p done mkdir -p $DIRS for f in $FILES ; do - test -e $f || symlink $source_path/$f $f + if [ -e "$source_path/$f" ] && ! [ -e "$f" ]; then + symlink "$source_path/$f" "$f" + fi done # temporary config to build submodules @@ -1349,8 +1349,15 @@ static struct DisplayAllocator default_allocator = { static void dumb_display_init(void) { DisplayState *ds = qemu_mallocz(sizeof(DisplayState)); + int width = 640; + int height = 480; + ds->allocator = &default_allocator; - ds->surface = qemu_create_displaysurface(ds, 640, 480); + if (is_fixedsize_console()) { + width = active_console->g_width; + height = active_console->g_height; + } + ds->surface = qemu_create_displaysurface(ds, width, height); register_displaystate(ds); } @@ -847,7 +847,7 @@ void cpu_reset_interrupt(CPUState *env, int mask); void cpu_exit(CPUState *s); -int qemu_cpu_has_work(CPUState *env); +bool qemu_cpu_has_work(CPUState *env); /* Breakpoint/watchpoint flags */ #define BP_MEM_READ 0x01 diff --git a/cpu-common.h b/cpu-common.h index b027e43088..a5b80e1351 100644 --- a/cpu-common.h +++ b/cpu-common.h @@ -65,7 +65,7 @@ void qemu_ram_free_from_ptr(ram_addr_t addr); void qemu_ram_remap(ram_addr_t addr, ram_addr_t length); /* This should only be used for ram local to a device. */ void *qemu_get_ram_ptr(ram_addr_t addr); -void *qemu_ram_ptr_length(target_phys_addr_t addr, target_phys_addr_t *size); +void *qemu_ram_ptr_length(ram_addr_t addr, ram_addr_t *size); /* Same but slower, to use for migration, where the order of * RAMBlocks must not change. */ void *qemu_safe_ram_ptr(ram_addr_t addr); @@ -135,14 +135,26 @@ void qemu_flush_coalesced_mmio_buffer(void); uint32_t ldub_phys(target_phys_addr_t addr); uint32_t lduw_phys(target_phys_addr_t addr); +uint32_t lduw_le_phys(target_phys_addr_t addr); +uint32_t lduw_be_phys(target_phys_addr_t addr); uint32_t ldl_phys(target_phys_addr_t addr); +uint32_t ldl_le_phys(target_phys_addr_t addr); +uint32_t ldl_be_phys(target_phys_addr_t addr); uint64_t ldq_phys(target_phys_addr_t addr); +uint64_t ldq_le_phys(target_phys_addr_t addr); +uint64_t ldq_be_phys(target_phys_addr_t addr); void stl_phys_notdirty(target_phys_addr_t addr, uint32_t val); void stq_phys_notdirty(target_phys_addr_t addr, uint64_t val); void stb_phys(target_phys_addr_t addr, uint32_t val); void stw_phys(target_phys_addr_t addr, uint32_t val); +void stw_le_phys(target_phys_addr_t addr, uint32_t val); +void stw_be_phys(target_phys_addr_t addr, uint32_t val); void stl_phys(target_phys_addr_t addr, uint32_t val); +void stl_le_phys(target_phys_addr_t addr, uint32_t val); +void stl_be_phys(target_phys_addr_t addr, uint32_t val); void stq_phys(target_phys_addr_t addr, uint64_t val); +void stq_le_phys(target_phys_addr_t addr, uint64_t val); +void stq_be_phys(target_phys_addr_t addr, uint64_t val); void cpu_physical_memory_write_rom(target_phys_addr_t addr, const uint8_t *buf, int len); diff --git a/cpu-exec.c b/cpu-exec.c index 7aa1d004e8..de0d716da0 100644 --- a/cpu-exec.c +++ b/cpu-exec.c @@ -17,27 +17,21 @@ * License along with this library; if not, see <http://www.gnu.org/licenses/>. */ #include "config.h" -#include "exec.h" +#include "cpu.h" #include "disas.h" #include "tcg.h" #include "qemu-barrier.h" -#if defined(__sparc__) && !defined(CONFIG_SOLARIS) -// Work around ugly bugs in glibc that mangle global register contents -#undef env -#define env cpu_single_env -#endif - int tb_invalidated_flag; //#define CONFIG_DEBUG_EXEC -int qemu_cpu_has_work(CPUState *env) +bool qemu_cpu_has_work(CPUState *env) { return cpu_has_work(env); } -void cpu_loop_exit(void) +void cpu_loop_exit(CPUState *env) { env->current_tb = NULL; longjmp(env->jmp_env, 1); @@ -47,10 +41,8 @@ void cpu_loop_exit(void) restored in a state compatible with the CPU emulator */ #if defined(CONFIG_SOFTMMU) -void cpu_resume_from_signal(CPUState *env1, void *puc) +void cpu_resume_from_signal(CPUState *env, void *puc) { - env = env1; - /* XXX: restore cpu registers saved in host registers */ env->exception_index = -1; @@ -60,7 +52,8 @@ void cpu_resume_from_signal(CPUState *env1, void *puc) /* Execute the code without caching the generated code. An interpreter could be used if available. */ -static void cpu_exec_nocache(int max_cycles, TranslationBlock *orig_tb) +static void cpu_exec_nocache(CPUState *env, int max_cycles, + TranslationBlock *orig_tb) { unsigned long next_tb; TranslationBlock *tb; @@ -74,7 +67,7 @@ static void cpu_exec_nocache(int max_cycles, TranslationBlock *orig_tb) max_cycles); env->current_tb = tb; /* execute the generated code */ - next_tb = tcg_qemu_tb_exec(tb->tc_ptr); + next_tb = tcg_qemu_tb_exec(env, tb->tc_ptr); env->current_tb = NULL; if ((next_tb & 3) == 2) { @@ -86,7 +79,8 @@ static void cpu_exec_nocache(int max_cycles, TranslationBlock *orig_tb) tb_free(tb); } -static TranslationBlock *tb_find_slow(target_ulong pc, +static TranslationBlock *tb_find_slow(CPUState *env, + target_ulong pc, target_ulong cs_base, uint64_t flags) { @@ -140,7 +134,7 @@ static TranslationBlock *tb_find_slow(target_ulong pc, return tb; } -static inline TranslationBlock *tb_find_fast(void) +static inline TranslationBlock *tb_find_fast(CPUState *env) { TranslationBlock *tb; target_ulong cs_base, pc; @@ -153,7 +147,7 @@ static inline TranslationBlock *tb_find_fast(void) tb = env->tb_jmp_cache[tb_jmp_cache_hash_func(pc)]; if (unlikely(!tb || tb->pc != pc || tb->cs_base != cs_base || tb->flags != flags)) { - tb = tb_find_slow(pc, cs_base, flags); + tb = tb_find_slow(env, pc, cs_base, flags); } return tb; } @@ -186,31 +180,22 @@ static void cpu_handle_debug_exception(CPUState *env) volatile sig_atomic_t exit_request; -int cpu_exec(CPUState *env1) +int cpu_exec(CPUState *env) { - volatile host_reg_t saved_env_reg; int ret, interrupt_request; TranslationBlock *tb; uint8_t *tc_ptr; unsigned long next_tb; - if (env1->halted) { - if (!cpu_has_work(env1)) { + if (env->halted) { + if (!cpu_has_work(env)) { return EXCP_HALTED; } - env1->halted = 0; + env->halted = 0; } - cpu_single_env = env1; - - /* the access to env below is actually saving the global register's - value, so that files not including target-xyz/exec.h are free to - use it. */ - QEMU_BUILD_BUG_ON (sizeof (saved_env_reg) != sizeof (env)); - saved_env_reg = (host_reg_t) env; - barrier(); - env = env1; + cpu_single_env = env; if (unlikely(exit_request)) { env->exit_request = 1; @@ -246,11 +231,6 @@ int cpu_exec(CPUState *env1) /* prepare setjmp context for exception handling */ for(;;) { if (setjmp(env->jmp_env) == 0) { -#if defined(__sparc__) && !defined(CONFIG_SOLARIS) -#undef env - env = cpu_single_env; -#define env cpu_single_env -#endif /* if an exception is pending, we execute it here */ if (env->exception_index >= 0) { if (env->exception_index >= EXCP_INTERRUPT) { @@ -266,51 +246,12 @@ int cpu_exec(CPUState *env1) which will be handled outside the cpu execution loop */ #if defined(TARGET_I386) - do_interrupt_user(env->exception_index, - env->exception_is_int, - env->error_code, - env->exception_next_eip); - /* successfully delivered */ - env->old_exception = -1; + do_interrupt(env); #endif ret = env->exception_index; break; #else -#if defined(TARGET_I386) - /* simulate a real cpu exception. On i386, it can - trigger new exceptions, but we do not handle - double or triple faults yet. */ - do_interrupt(env->exception_index, - env->exception_is_int, - env->error_code, - env->exception_next_eip, 0); - /* successfully delivered */ - env->old_exception = -1; -#elif defined(TARGET_PPC) - do_interrupt(env); -#elif defined(TARGET_LM32) - do_interrupt(env); -#elif defined(TARGET_MICROBLAZE) - do_interrupt(env); -#elif defined(TARGET_MIPS) - do_interrupt(env); -#elif defined(TARGET_SPARC) do_interrupt(env); -#elif defined(TARGET_ARM) - do_interrupt(env); -#elif defined(TARGET_UNICORE32) - do_interrupt(env); -#elif defined(TARGET_SH4) - do_interrupt(env); -#elif defined(TARGET_ALPHA) - do_interrupt(env); -#elif defined(TARGET_CRIS) - do_interrupt(env); -#elif defined(TARGET_M68K) - do_interrupt(0); -#elif defined(TARGET_S390X) - do_interrupt(env); -#endif env->exception_index = -1; #endif } @@ -327,7 +268,7 @@ int cpu_exec(CPUState *env1) if (interrupt_request & CPU_INTERRUPT_DEBUG) { env->interrupt_request &= ~CPU_INTERRUPT_DEBUG; env->exception_index = EXCP_DEBUG; - cpu_loop_exit(); + cpu_loop_exit(env); } #if defined(TARGET_ARM) || defined(TARGET_SPARC) || defined(TARGET_MIPS) || \ defined(TARGET_PPC) || defined(TARGET_ALPHA) || defined(TARGET_CRIS) || \ @@ -336,33 +277,33 @@ int cpu_exec(CPUState *env1) env->interrupt_request &= ~CPU_INTERRUPT_HALT; env->halted = 1; env->exception_index = EXCP_HLT; - cpu_loop_exit(); + cpu_loop_exit(env); } #endif #if defined(TARGET_I386) if (interrupt_request & CPU_INTERRUPT_INIT) { - svm_check_intercept(SVM_EXIT_INIT); + svm_check_intercept(env, SVM_EXIT_INIT); do_cpu_init(env); env->exception_index = EXCP_HALTED; - cpu_loop_exit(); + cpu_loop_exit(env); } else if (interrupt_request & CPU_INTERRUPT_SIPI) { do_cpu_sipi(env); } else if (env->hflags2 & HF2_GIF_MASK) { if ((interrupt_request & CPU_INTERRUPT_SMI) && !(env->hflags & HF_SMM_MASK)) { - svm_check_intercept(SVM_EXIT_SMI); + svm_check_intercept(env, SVM_EXIT_SMI); env->interrupt_request &= ~CPU_INTERRUPT_SMI; - do_smm_enter(); + do_smm_enter(env); next_tb = 0; } else if ((interrupt_request & CPU_INTERRUPT_NMI) && !(env->hflags2 & HF2_NMI_MASK)) { env->interrupt_request &= ~CPU_INTERRUPT_NMI; env->hflags2 |= HF2_NMI_MASK; - do_interrupt(EXCP02_NMI, 0, 0, 0, 1); + do_interrupt_x86_hardirq(env, EXCP02_NMI, 1); next_tb = 0; } else if (interrupt_request & CPU_INTERRUPT_MCE) { env->interrupt_request &= ~CPU_INTERRUPT_MCE; - do_interrupt(EXCP12_MCHK, 0, 0, 0, 0); + do_interrupt_x86_hardirq(env, EXCP12_MCHK, 0); next_tb = 0; } else if ((interrupt_request & CPU_INTERRUPT_HARD) && (((env->hflags2 & HF2_VINTR_MASK) && @@ -371,16 +312,11 @@ int cpu_exec(CPUState *env1) (env->eflags & IF_MASK && !(env->hflags & HF_INHIBIT_IRQ_MASK))))) { int intno; - svm_check_intercept(SVM_EXIT_INTR); + svm_check_intercept(env, SVM_EXIT_INTR); env->interrupt_request &= ~(CPU_INTERRUPT_HARD | CPU_INTERRUPT_VIRQ); intno = cpu_get_pic_interrupt(env); qemu_log_mask(CPU_LOG_TB_IN_ASM, "Servicing hardware INT=0x%02x\n", intno); -#if defined(__sparc__) && !defined(CONFIG_SOLARIS) -#undef env - env = cpu_single_env; -#define env cpu_single_env -#endif - do_interrupt(intno, 0, 0, 0, 1); + do_interrupt_x86_hardirq(env, intno, 1); /* ensure that no TB jump will be modified as the program flow was changed */ next_tb = 0; @@ -390,10 +326,10 @@ int cpu_exec(CPUState *env1) !(env->hflags & HF_INHIBIT_IRQ_MASK)) { int intno; /* FIXME: this should respect TPR */ - svm_check_intercept(SVM_EXIT_VINTR); + svm_check_intercept(env, SVM_EXIT_VINTR); intno = ldl_phys(env->vm_vmcb + offsetof(struct vmcb, control.int_vector)); qemu_log_mask(CPU_LOG_TB_IN_ASM, "Servicing virtual hardware INT=0x%02x\n", intno); - do_interrupt(intno, 0, 0, 0, 1); + do_interrupt_x86_hardirq(env, intno, 1); env->interrupt_request &= ~CPU_INTERRUPT_VIRQ; next_tb = 0; #endif @@ -542,7 +478,7 @@ int cpu_exec(CPUState *env1) provide/save the vector when the interrupt is first signalled. */ env->exception_index = env->pending_vector; - do_interrupt(1); + do_interrupt_m68k_hardirq(env); next_tb = 0; } #elif defined(TARGET_S390X) && !defined(CONFIG_USER_ONLY) @@ -564,13 +500,14 @@ int cpu_exec(CPUState *env1) if (unlikely(env->exit_request)) { env->exit_request = 0; env->exception_index = EXCP_INTERRUPT; - cpu_loop_exit(); + cpu_loop_exit(env); } #if defined(DEBUG_DISAS) || defined(CONFIG_DEBUG_EXEC) if (qemu_loglevel_mask(CPU_LOG_TB_CPU)) { /* restore flags in standard format */ #if defined(TARGET_I386) - env->eflags = env->eflags | helper_cc_compute_all(CC_OP) | (DF & DF_MASK); + env->eflags = env->eflags | cpu_cc_compute_all(env, CC_OP) + | (DF & DF_MASK); log_cpu_state(env, X86_DUMP_CCOP); env->eflags &= ~(DF_MASK | CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C); #elif defined(TARGET_M68K) @@ -585,7 +522,7 @@ int cpu_exec(CPUState *env1) } #endif /* DEBUG_DISAS || CONFIG_DEBUG_EXEC */ spin_lock(&tb_lock); - tb = tb_find_fast(); + tb = tb_find_fast(env); /* Note: we do it here to avoid a gcc bug on Mac OS X when doing it in tb_find_slow */ if (tb_invalidated_flag) { @@ -617,12 +554,7 @@ int cpu_exec(CPUState *env1) if (likely(!env->exit_request)) { tc_ptr = tb->tc_ptr; /* execute the generated code */ -#if defined(__sparc__) && !defined(CONFIG_SOLARIS) -#undef env - env = cpu_single_env; -#define env cpu_single_env -#endif - next_tb = tcg_qemu_tb_exec(tc_ptr); + next_tb = tcg_qemu_tb_exec(env, tc_ptr); if ((next_tb & 3) == 2) { /* Instruction counter expired. */ int insns_left; @@ -643,11 +575,11 @@ int cpu_exec(CPUState *env1) } else { if (insns_left > 0) { /* Execute remaining instructions. */ - cpu_exec_nocache(insns_left, tb); + cpu_exec_nocache(env, insns_left, tb); } env->exception_index = EXCP_INTERRUPT; next_tb = 0; - cpu_loop_exit(); + cpu_loop_exit(env); } } } @@ -655,13 +587,18 @@ int cpu_exec(CPUState *env1) /* reset soft MMU for next block (it can currently only be set by a memory fault) */ } /* for(;;) */ + } else { + /* Reload env after longjmp - the compiler may have smashed all + * local variables as longjmp is marked 'noreturn'. */ + env = cpu_single_env; } } /* for(;;) */ #if defined(TARGET_I386) /* restore flags in standard format */ - env->eflags = env->eflags | helper_cc_compute_all(CC_OP) | (DF & DF_MASK); + env->eflags = env->eflags | cpu_cc_compute_all(env, CC_OP) + | (DF & DF_MASK); #elif defined(TARGET_ARM) /* XXX: Save/restore host fpu exception state?. */ #elif defined(TARGET_UNICORE32) @@ -684,10 +621,6 @@ int cpu_exec(CPUState *env1) #error unsupported target CPU #endif - /* restore global registers */ - barrier(); - env = (void *) saved_env_reg; - /* fail safe : never use cpu_single_env outside cpu_exec() */ cpu_single_env = NULL; return ret; @@ -30,11 +30,13 @@ #include "gdbstub.h" #include "dma.h" #include "kvm.h" -#include "exec-all.h" #include "qemu-thread.h" #include "cpus.h" + +#ifndef _WIN32 #include "compatfd.h" +#endif #ifdef SIGRTMIN #define SIG_IPI (SIGRTMIN+4) @@ -394,12 +396,19 @@ static int qemu_signal_init(void) sigaddset(&set, SIGUSR2); pthread_sigmask(SIG_UNBLOCK, &set, NULL); + /* + * SIG_IPI must be blocked in the main thread and must not be caught + * by sigwait() in the signal thread. Otherwise, the cpu thread will + * not catch it reliably. + */ + sigemptyset(&set); + sigaddset(&set, SIG_IPI); + pthread_sigmask(SIG_BLOCK, &set, NULL); + sigemptyset(&set); sigaddset(&set, SIGIO); sigaddset(&set, SIGALRM); - sigaddset(&set, SIG_IPI); sigaddset(&set, SIGBUS); - pthread_sigmask(SIG_BLOCK, &set, NULL); #else sigemptyset(&set); sigaddset(&set, SIGBUS); @@ -412,6 +421,7 @@ static int qemu_signal_init(void) sigaddset(&set, SIGALRM); } #endif + pthread_sigmask(SIG_BLOCK, &set, NULL); sigfd = qemu_signalfd(&set); if (sigfd == -1) { diff --git a/darwin-user/main.c b/darwin-user/main.c index a6dc859219..35196a12cc 100644 --- a/darwin-user/main.c +++ b/darwin-user/main.c @@ -819,7 +819,7 @@ int main(int argc, char **argv) int mask; CPULogItem *item; - mask = cpu_str_to_log_mask(r); + mask = cpu_str_to_log_mask(log_mask); if (!mask) { printf("Log items (comma separated):\n"); for (item = cpu_log_items; item->mask != 0; item++) { @@ -5,7 +5,6 @@ #include <errno.h> #include "cpu.h" -#include "exec-all.h" #include "disas.h" /* Filled in by elfload.c. Simplistic, but will do for now. */ diff --git a/docs/ich9-ehci-uhci.cfg b/docs/ich9-ehci-uhci.cfg new file mode 100644 index 0000000000..a0e9b96f4d --- /dev/null +++ b/docs/ich9-ehci-uhci.cfg @@ -0,0 +1,37 @@ +########################################################################### +# +# You can pass this file directly to qemu using the -readconfig +# command line switch. +# +# This config file creates a EHCI adapter with companion UHCI +# controllers as multifunction device in PCI slot "1d". +# +# Specify "bus=ehci.0" when creating usb devices to hook them up +# there. +# + +[device "ehci"] + driver = "ich9-usb-ehci1" + addr = "1d.7" + multifunction = "on" + +[device "uhci-1"] + driver = "ich9-usb-uhci1" + addr = "1d.0" + multifunction = "on" + masterbus = "ehci.0" + firstport = "0" + +[device "uhci-2"] + driver = "ich9-usb-uhci2" + addr = "1d.1" + multifunction = "on" + masterbus = "ehci.0" + firstport = "2" + +[device "uhci-3"] + driver = "ich9-usb-uhci3" + addr = "1d.2" + multifunction = "on" + masterbus = "ehci.0" + firstport = "4" diff --git a/docs/usb2.txt b/docs/usb2.txt index 5950c713e9..228aa33ceb 100644 --- a/docs/usb2.txt +++ b/docs/usb2.txt @@ -2,11 +2,13 @@ USB 2.0 Quick Start =================== -The QEMU EHCI Adapter does *not* support companion controllers. That -implies there are two completely separate USB busses: One USB 1.1 bus -driven by the UHCI controller and one USB 2.0 bus driven by the EHCI -controller. Devices must be attached to the correct controller -manually. +The QEMU EHCI Adapter can be used with and without companion +controllers. See below for the companion controller mode. + +When not running in companion controller mode there are two completely +separate USB busses: One USB 1.1 bus driven by the UHCI controller and +one USB 2.0 bus driven by the EHCI controller. Devices must be +attached to the correct controller manually. The '-usb' switch will make qemu create the UHCI controller as part of the PIIX3 chipset. The USB 1.1 bus will carry the name "usb.0". @@ -32,6 +34,27 @@ This attaches a usb tablet to the UHCI adapter and a usb mass storage device to the EHCI adapter. +Companion controller support +---------------------------- + +Companion controller support has been added recently. The operational +model described above with two completely separate busses still works +fine. Additionally the UHCI and OHCI controllers got the ability to +attach to a usb bus created by EHCI as companion controllers. This is +done by specifying the masterbus and firstport properties. masterbus +specifies the bus name the controller should attach to. firstport +specifies the first port the controller should attach to, which is +needed as usually one ehci controller with six ports has three uhci +companion controllers with two ports each. + +There is a config file in docs which will do all this for you, just +try ... + + qemu -readconfig docs/ich9-ehci-uhci.cfg + +... then use "bus=ehci.0" to assign your usb devices to that bus. + + More USB tips & tricks ====================== diff --git a/exec-all.h b/exec-all.h index 2a13a9535e..69acf3b97d 100644 --- a/exec-all.h +++ b/exec-all.h @@ -40,14 +40,11 @@ typedef ram_addr_t tb_page_addr_t; #define DISAS_UPDATE 2 /* cpu state was modified dynamically */ #define DISAS_TB_JUMP 3 /* only pc was modified statically */ +struct TranslationBlock; typedef struct TranslationBlock TranslationBlock; /* XXX: make safe guess about sizes */ -#if (HOST_LONG_BITS == 32) && (TARGET_LONG_BITS == 64) -#define MAX_OP_PER_INSTR 128 -#else -#define MAX_OP_PER_INSTR 96 -#endif +#define MAX_OP_PER_INSTR 208 #if HOST_LONG_BITS == 32 #define MAX_OPC_PARAM_PER_ARG 2 @@ -95,7 +92,7 @@ TranslationBlock *tb_gen_code(CPUState *env, target_ulong pc, target_ulong cs_base, int flags, int cflags); void cpu_exec_init(CPUState *env); -void QEMU_NORETURN cpu_loop_exit(void); +void QEMU_NORETURN cpu_loop_exit(CPUState *env1); int page_unprotect(target_ulong address, unsigned long pc, void *puc); void tb_invalidate_phys_page_range(tb_page_addr_t start, tb_page_addr_t end, int is_cpu_write_access); @@ -26,7 +26,6 @@ #include "qemu-common.h" #include "cpu.h" -#include "exec-all.h" #include "tcg.h" #include "hw/hw.h" #include "hw/qdev.h" @@ -556,8 +555,8 @@ static void code_gen_alloc(unsigned long tb_size) #endif #endif /* !USE_STATIC_CODE_GEN_BUFFER */ map_exec(code_gen_prologue, sizeof(code_gen_prologue)); - code_gen_buffer_max_size = code_gen_buffer_size - - (TCG_MAX_OP_SIZE * OPC_MAX_SIZE); + code_gen_buffer_max_size = code_gen_buffer_size - + (TCG_MAX_OP_SIZE * OPC_BUF_SIZE); code_gen_max_blocks = code_gen_buffer_size / CODE_GEN_AVG_BLOCK_SIZE; tbs = qemu_malloc(code_gen_max_blocks * sizeof(TranslationBlock)); } @@ -1208,12 +1207,16 @@ static inline void tb_alloc_page(TranslationBlock *tb, unsigned int n, tb_page_addr_t page_addr) { PageDesc *p; - TranslationBlock *last_first_tb; +#ifndef CONFIG_USER_ONLY + bool page_already_protected; +#endif tb->page_addr[n] = page_addr; p = page_find_alloc(page_addr >> TARGET_PAGE_BITS, 1); tb->page_next[n] = p->first_tb; - last_first_tb = p->first_tb; +#ifndef CONFIG_USER_ONLY + page_already_protected = p->first_tb != NULL; +#endif p->first_tb = (TranslationBlock *)((long)tb | n); invalidate_page_bitmap(p); @@ -1249,7 +1252,7 @@ static inline void tb_alloc_page(TranslationBlock *tb, /* if some code is already present, then the pages are already protected. So we handle the case where only the first TB is allocated in a physical page */ - if (!last_first_tb) { + if (!page_already_protected) { tlb_protect_code(page_addr); } #endif @@ -2950,7 +2953,7 @@ ram_addr_t qemu_ram_alloc_from_ptr(DeviceState *dev, const char *name, abort(); } #else - if (xen_mapcache_enabled()) { + if (xen_enabled()) { xen_ram_alloc(new_block->offset, size); } else { new_block->host = qemu_vmalloc(size); @@ -3016,8 +3019,8 @@ void qemu_ram_free(ram_addr_t addr) #if defined(TARGET_S390X) && defined(CONFIG_KVM) munmap(block->host, block->length); #else - if (xen_mapcache_enabled()) { - qemu_invalidate_entry(block->host); + if (xen_enabled()) { + xen_invalidate_map_cache_entry(block->host); } else { qemu_vfree(block->host); } @@ -3109,15 +3112,16 @@ void *qemu_get_ram_ptr(ram_addr_t addr) QLIST_REMOVE(block, next); QLIST_INSERT_HEAD(&ram_list.blocks, block, next); } - if (xen_mapcache_enabled()) { + if (xen_enabled()) { /* We need to check if the requested address is in the RAM * because we don't want to map the entire memory in QEMU. * In that case just map until the end of the page. */ if (block->offset == 0) { - return qemu_map_cache(addr, 0, 0); + return xen_map_cache(addr, 0, 0); } else if (block->host == NULL) { - block->host = qemu_map_cache(block->offset, block->length, 1); + block->host = + xen_map_cache(block->offset, block->length, 1); } } return block->host + (addr - block->offset); @@ -3139,15 +3143,16 @@ void *qemu_safe_ram_ptr(ram_addr_t addr) QLIST_FOREACH(block, &ram_list.blocks, next) { if (addr - block->offset < block->length) { - if (xen_mapcache_enabled()) { + if (xen_enabled()) { /* We need to check if the requested address is in the RAM * because we don't want to map the entire memory in QEMU. * In that case just map until the end of the page. */ if (block->offset == 0) { - return qemu_map_cache(addr, 0, 0); + return xen_map_cache(addr, 0, 0); } else if (block->host == NULL) { - block->host = qemu_map_cache(block->offset, block->length, 1); + block->host = + xen_map_cache(block->offset, block->length, 1); } } return block->host + (addr - block->offset); @@ -3162,11 +3167,14 @@ void *qemu_safe_ram_ptr(ram_addr_t addr) /* Return a host pointer to guest's ram. Similar to qemu_get_ram_ptr * but takes a size argument */ -void *qemu_ram_ptr_length(target_phys_addr_t addr, target_phys_addr_t *size) +void *qemu_ram_ptr_length(ram_addr_t addr, ram_addr_t *size) { - if (xen_mapcache_enabled()) - return qemu_map_cache(addr, *size, 1); - else { + if (*size == 0) { + return NULL; + } + if (xen_enabled()) { + return xen_map_cache(addr, *size, 1); + } else { RAMBlock *block; QLIST_FOREACH(block, &ram_list.blocks, next) { @@ -3179,9 +3187,6 @@ void *qemu_ram_ptr_length(target_phys_addr_t addr, target_phys_addr_t *size) fprintf(stderr, "Bad ram offset %" PRIx64 "\n", (uint64_t)addr); abort(); - - *size = 0; - return NULL; } } @@ -3195,8 +3200,8 @@ int qemu_ram_addr_from_host(void *ptr, ram_addr_t *ram_addr) RAMBlock *block; uint8_t *host = ptr; - if (xen_mapcache_enabled()) { - *ram_addr = qemu_ram_addr_from_mapcache(ptr); + if (xen_enabled()) { + *ram_addr = xen_ram_addr_from_mapcache(ptr); return 0; } @@ -4047,7 +4052,9 @@ void *cpu_physical_memory_map(target_phys_addr_t addr, target_phys_addr_t page; unsigned long pd; PhysPageDesc *p; - target_phys_addr_t addr1 = addr; + ram_addr_t raddr = ULONG_MAX; + ram_addr_t rlen; + void *ret; while (len > 0) { page = addr & TARGET_PAGE_MASK; @@ -4075,13 +4082,18 @@ void *cpu_physical_memory_map(target_phys_addr_t addr, *plen = l; return bounce.buffer; } + if (!todo) { + raddr = (pd & TARGET_PAGE_MASK) + (addr & ~TARGET_PAGE_MASK); + } len -= l; addr += l; todo += l; } - *plen = todo; - return qemu_ram_ptr_length(addr1, plen); + rlen = todo; + ret = qemu_ram_ptr_length(raddr, &rlen); + *plen = rlen; + return ret; } /* Unmaps a memory region previously mapped by cpu_physical_memory_map(). @@ -4110,8 +4122,8 @@ void cpu_physical_memory_unmap(void *buffer, target_phys_addr_t len, access_len -= l; } } - if (xen_mapcache_enabled()) { - qemu_invalidate_entry(buffer); + if (xen_enabled()) { + xen_invalidate_map_cache_entry(buffer); } return; } @@ -4124,7 +4136,8 @@ void cpu_physical_memory_unmap(void *buffer, target_phys_addr_t len, } /* warning: addr must be aligned */ -uint32_t ldl_phys(target_phys_addr_t addr) +static inline uint32_t ldl_phys_internal(target_phys_addr_t addr, + enum device_endian endian) { int io_index; uint8_t *ptr; @@ -4146,17 +4159,52 @@ uint32_t ldl_phys(target_phys_addr_t addr) if (p) addr = (addr & ~TARGET_PAGE_MASK) + p->region_offset; val = io_mem_read[io_index][2](io_mem_opaque[io_index], addr); +#if defined(TARGET_WORDS_BIGENDIAN) + if (endian == DEVICE_LITTLE_ENDIAN) { + val = bswap32(val); + } +#else + if (endian == DEVICE_BIG_ENDIAN) { + val = bswap32(val); + } +#endif } else { /* RAM case */ ptr = qemu_get_ram_ptr(pd & TARGET_PAGE_MASK) + (addr & ~TARGET_PAGE_MASK); - val = ldl_p(ptr); + switch (endian) { + case DEVICE_LITTLE_ENDIAN: + val = ldl_le_p(ptr); + break; + case DEVICE_BIG_ENDIAN: + val = ldl_be_p(ptr); + break; + default: + val = ldl_p(ptr); + break; + } } return val; } +uint32_t ldl_phys(target_phys_addr_t addr) +{ + return ldl_phys_internal(addr, DEVICE_NATIVE_ENDIAN); +} + +uint32_t ldl_le_phys(target_phys_addr_t addr) +{ + return ldl_phys_internal(addr, DEVICE_LITTLE_ENDIAN); +} + +uint32_t ldl_be_phys(target_phys_addr_t addr) +{ + return ldl_phys_internal(addr, DEVICE_BIG_ENDIAN); +} + /* warning: addr must be aligned */ -uint64_t ldq_phys(target_phys_addr_t addr) +static inline uint64_t ldq_phys_internal(target_phys_addr_t addr, + enum device_endian endian) { int io_index; uint8_t *ptr; @@ -4177,6 +4225,9 @@ uint64_t ldq_phys(target_phys_addr_t addr) io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1); if (p) addr = (addr & ~TARGET_PAGE_MASK) + p->region_offset; + + /* XXX This is broken when device endian != cpu endian. + Fix and add "endian" variable check */ #ifdef TARGET_WORDS_BIGENDIAN val = (uint64_t)io_mem_read[io_index][2](io_mem_opaque[io_index], addr) << 32; val |= io_mem_read[io_index][2](io_mem_opaque[io_index], addr + 4); @@ -4188,11 +4239,36 @@ uint64_t ldq_phys(target_phys_addr_t addr) /* RAM case */ ptr = qemu_get_ram_ptr(pd & TARGET_PAGE_MASK) + (addr & ~TARGET_PAGE_MASK); - val = ldq_p(ptr); + switch (endian) { + case DEVICE_LITTLE_ENDIAN: + val = ldq_le_p(ptr); + break; + case DEVICE_BIG_ENDIAN: + val = ldq_be_p(ptr); + break; + default: + val = ldq_p(ptr); + break; + } } return val; } +uint64_t ldq_phys(target_phys_addr_t addr) +{ + return ldq_phys_internal(addr, DEVICE_NATIVE_ENDIAN); +} + +uint64_t ldq_le_phys(target_phys_addr_t addr) +{ + return ldq_phys_internal(addr, DEVICE_LITTLE_ENDIAN); +} + +uint64_t ldq_be_phys(target_phys_addr_t addr) +{ + return ldq_phys_internal(addr, DEVICE_BIG_ENDIAN); +} + /* XXX: optimize */ uint32_t ldub_phys(target_phys_addr_t addr) { @@ -4202,7 +4278,8 @@ uint32_t ldub_phys(target_phys_addr_t addr) } /* warning: addr must be aligned */ -uint32_t lduw_phys(target_phys_addr_t addr) +static inline uint32_t lduw_phys_internal(target_phys_addr_t addr, + enum device_endian endian) { int io_index; uint8_t *ptr; @@ -4224,15 +4301,49 @@ uint32_t lduw_phys(target_phys_addr_t addr) if (p) addr = (addr & ~TARGET_PAGE_MASK) + p->region_offset; val = io_mem_read[io_index][1](io_mem_opaque[io_index], addr); +#if defined(TARGET_WORDS_BIGENDIAN) + if (endian == DEVICE_LITTLE_ENDIAN) { + val = bswap16(val); + } +#else + if (endian == DEVICE_BIG_ENDIAN) { + val = bswap16(val); + } +#endif } else { /* RAM case */ ptr = qemu_get_ram_ptr(pd & TARGET_PAGE_MASK) + (addr & ~TARGET_PAGE_MASK); - val = lduw_p(ptr); + switch (endian) { + case DEVICE_LITTLE_ENDIAN: + val = lduw_le_p(ptr); + break; + case DEVICE_BIG_ENDIAN: + val = lduw_be_p(ptr); + break; + default: + val = lduw_p(ptr); + break; + } } return val; } +uint32_t lduw_phys(target_phys_addr_t addr) +{ + return lduw_phys_internal(addr, DEVICE_NATIVE_ENDIAN); +} + +uint32_t lduw_le_phys(target_phys_addr_t addr) +{ + return lduw_phys_internal(addr, DEVICE_LITTLE_ENDIAN); +} + +uint32_t lduw_be_phys(target_phys_addr_t addr) +{ + return lduw_phys_internal(addr, DEVICE_BIG_ENDIAN); +} + /* warning: addr must be aligned. The ram page is not masked as dirty and the code inside is not invalidated. It is useful if the dirty bits are used to track modified PTEs */ @@ -4305,7 +4416,8 @@ void stq_phys_notdirty(target_phys_addr_t addr, uint64_t val) } /* warning: addr must be aligned */ -void stl_phys(target_phys_addr_t addr, uint32_t val) +static inline void stl_phys_internal(target_phys_addr_t addr, uint32_t val, + enum device_endian endian) { int io_index; uint8_t *ptr; @@ -4323,13 +4435,32 @@ void stl_phys(target_phys_addr_t addr, uint32_t val) io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1); if (p) addr = (addr & ~TARGET_PAGE_MASK) + p->region_offset; +#if defined(TARGET_WORDS_BIGENDIAN) + if (endian == DEVICE_LITTLE_ENDIAN) { + val = bswap32(val); + } +#else + if (endian == DEVICE_BIG_ENDIAN) { + val = bswap32(val); + } +#endif io_mem_write[io_index][2](io_mem_opaque[io_index], addr, val); } else { unsigned long addr1; addr1 = (pd & TARGET_PAGE_MASK) + (addr & ~TARGET_PAGE_MASK); /* RAM case */ ptr = qemu_get_ram_ptr(addr1); - stl_p(ptr, val); + switch (endian) { + case DEVICE_LITTLE_ENDIAN: + stl_le_p(ptr, val); + break; + case DEVICE_BIG_ENDIAN: + stl_be_p(ptr, val); + break; + default: + stl_p(ptr, val); + break; + } if (!cpu_physical_memory_is_dirty(addr1)) { /* invalidate code */ tb_invalidate_phys_page_range(addr1, addr1 + 4, 0); @@ -4340,6 +4471,21 @@ void stl_phys(target_phys_addr_t addr, uint32_t val) } } +void stl_phys(target_phys_addr_t addr, uint32_t val) +{ + stl_phys_internal(addr, val, DEVICE_NATIVE_ENDIAN); +} + +void stl_le_phys(target_phys_addr_t addr, uint32_t val) +{ + stl_phys_internal(addr, val, DEVICE_LITTLE_ENDIAN); +} + +void stl_be_phys(target_phys_addr_t addr, uint32_t val) +{ + stl_phys_internal(addr, val, DEVICE_BIG_ENDIAN); +} + /* XXX: optimize */ void stb_phys(target_phys_addr_t addr, uint32_t val) { @@ -4348,7 +4494,8 @@ void stb_phys(target_phys_addr_t addr, uint32_t val) } /* warning: addr must be aligned */ -void stw_phys(target_phys_addr_t addr, uint32_t val) +static inline void stw_phys_internal(target_phys_addr_t addr, uint32_t val, + enum device_endian endian) { int io_index; uint8_t *ptr; @@ -4366,13 +4513,32 @@ void stw_phys(target_phys_addr_t addr, uint32_t val) io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1); if (p) addr = (addr & ~TARGET_PAGE_MASK) + p->region_offset; +#if defined(TARGET_WORDS_BIGENDIAN) + if (endian == DEVICE_LITTLE_ENDIAN) { + val = bswap16(val); + } +#else + if (endian == DEVICE_BIG_ENDIAN) { + val = bswap16(val); + } +#endif io_mem_write[io_index][1](io_mem_opaque[io_index], addr, val); } else { unsigned long addr1; addr1 = (pd & TARGET_PAGE_MASK) + (addr & ~TARGET_PAGE_MASK); /* RAM case */ ptr = qemu_get_ram_ptr(addr1); - stw_p(ptr, val); + switch (endian) { + case DEVICE_LITTLE_ENDIAN: + stw_le_p(ptr, val); + break; + case DEVICE_BIG_ENDIAN: + stw_be_p(ptr, val); + break; + default: + stw_p(ptr, val); + break; + } if (!cpu_physical_memory_is_dirty(addr1)) { /* invalidate code */ tb_invalidate_phys_page_range(addr1, addr1 + 2, 0); @@ -4383,6 +4549,21 @@ void stw_phys(target_phys_addr_t addr, uint32_t val) } } +void stw_phys(target_phys_addr_t addr, uint32_t val) +{ + stw_phys_internal(addr, val, DEVICE_NATIVE_ENDIAN); +} + +void stw_le_phys(target_phys_addr_t addr, uint32_t val) +{ + stw_phys_internal(addr, val, DEVICE_LITTLE_ENDIAN); +} + +void stw_be_phys(target_phys_addr_t addr, uint32_t val) +{ + stw_phys_internal(addr, val, DEVICE_BIG_ENDIAN); +} + /* XXX: optimize */ void stq_phys(target_phys_addr_t addr, uint64_t val) { @@ -4390,6 +4571,18 @@ void stq_phys(target_phys_addr_t addr, uint64_t val) cpu_physical_memory_write(addr, &val, 8); } +void stq_le_phys(target_phys_addr_t addr, uint64_t val) +{ + val = cpu_to_le64(val); + cpu_physical_memory_write(addr, &val, 8); +} + +void stq_be_phys(target_phys_addr_t addr, uint64_t val) +{ + val = cpu_to_be64(val); + cpu_physical_memory_write(addr, &val, 8); +} + /* virtual memory access for debug (includes writing to ROM) */ int cpu_memory_rw_debug(CPUState *env, target_ulong addr, uint8_t *buf, int len, int is_write) @@ -37,7 +37,7 @@ #define MAX_PACKET_LENGTH 4096 -#include "exec-all.h" +#include "cpu.h" #include "qemu_socket.h" #include "kvm.h" diff --git a/hppa-dis.c b/hppa-dis.c index a5760a9584..435da73553 100644 --- a/hppa-dis.c +++ b/hppa-dis.c @@ -1771,13 +1771,13 @@ static const char *const add_compl_names[] = { 0, "", ",l", ",tsv" }; static void fput_reg (unsigned reg, disassemble_info *info) { - (*info->fprintf_func) (info->stream, reg ? reg_names[reg] : "r0"); + (*info->fprintf_func) (info->stream, "%s", reg ? reg_names[reg] : "r0"); } static void fput_fp_reg (unsigned reg, disassemble_info *info) { - (*info->fprintf_func) (info->stream, reg ? fp_reg_names[reg] : "fr0"); + (*info->fprintf_func) (info->stream, "%s", reg ? fp_reg_names[reg] : "fr0"); } static void @@ -1794,7 +1794,7 @@ fput_fp_reg_r (unsigned reg, disassemble_info *info) static void fput_creg (unsigned reg, disassemble_info *info) { - (*info->fprintf_func) (info->stream, control_reg[reg]); + (*info->fprintf_func) (info->stream, "%s", control_reg[reg]); } /* Print constants with sign. */ diff --git a/hw/arm-misc.h b/hw/arm-misc.h index 010acb4cf9..9aeeaea759 100644 --- a/hw/arm-misc.h +++ b/hw/arm-misc.h @@ -31,7 +31,7 @@ struct arm_boot_info { target_phys_addr_t smp_priv_base; int nb_cpus; int board_id; - int (*atag_board)(struct arm_boot_info *info, void *p); + int (*atag_board)(const struct arm_boot_info *info, void *p); /* Used internally by arm_boot.c */ int is_linux; target_phys_addr_t initrd_size; diff --git a/hw/arm_boot.c b/hw/arm_boot.c index bfac982e65..e0215768b1 100644 --- a/hw/arm_boot.c +++ b/hw/arm_boot.c @@ -49,7 +49,7 @@ static uint32_t smpboot[] = { p += 4; \ } while (0) -static void set_kernel_args(struct arm_boot_info *info, +static void set_kernel_args(const struct arm_boot_info *info, int initrd_size, target_phys_addr_t base) { target_phys_addr_t p; @@ -102,7 +102,7 @@ static void set_kernel_args(struct arm_boot_info *info, WRITE_WORD(p, 0); } -static void set_kernel_args_old(struct arm_boot_info *info, +static void set_kernel_args_old(const struct arm_boot_info *info, int initrd_size, target_phys_addr_t base) { target_phys_addr_t p; @@ -178,7 +178,7 @@ static void set_kernel_args_old(struct arm_boot_info *info, static void do_cpu_reset(void *opaque) { CPUState *env = opaque; - struct arm_boot_info *info = env->boot_info; + const struct arm_boot_info *info = env->boot_info; cpu_reset(env); if (info) { diff --git a/hw/armv7m.c b/hw/armv7m.c index 72d010a63b..83f3393eab 100644 --- a/hw/armv7m.c +++ b/hw/armv7m.c @@ -4,7 +4,7 @@ * Copyright (c) 2006-2007 CodeSourcery. * Written by Paul Brook * - * This code is licenced under the GPL. + * This code is licensed under the GPL. */ #include "sysbus.h" @@ -14,7 +14,7 @@ /* Bitbanded IO. Each word corresponds to a single bit. */ -/* Get the byte address of the real memory for a bitband acess. */ +/* Get the byte address of the real memory for a bitband access. */ static inline uint32_t bitband_addr(void * opaque, uint32_t addr) { uint32_t res; @@ -211,7 +211,7 @@ static uint32_t get_cmd(ESPState *s, uint8_t *buf) } else { dmalen = s->ti_size; memcpy(buf, s->ti_buf, dmalen); - buf[0] = 0; + buf[0] = buf[2] >> 5; } DPRINTF("get_cmd: len %d target %d\n", dmalen, target); @@ -219,7 +219,7 @@ static uint32_t get_cmd(ESPState *s, uint8_t *buf) s->ti_rptr = 0; s->ti_wptr = 0; - if (s->current_dev) { + if (s->current_req) { /* Started a new command before the old one finished. Cancel it. */ scsi_req_cancel(s->current_req); s->async_len = 0; diff --git a/hw/etraxfs_ser.c b/hw/etraxfs_ser.c index 2787ebd5c8..b917d4db11 100644 --- a/hw/etraxfs_ser.c +++ b/hw/etraxfs_ser.c @@ -190,15 +190,23 @@ static void serial_event(void *opaque, int event) } -static int etraxfs_ser_init(SysBusDevice *dev) +static void etraxfs_ser_reset(DeviceState *d) { - struct etrax_serial *s = FROM_SYSBUS(typeof (*s), dev); - int ser_regs; + struct etrax_serial *s = container_of(d, typeof(*s), busdev.qdev); /* transmitter begins ready and idle. */ s->regs[RS_STAT_DIN] |= (1 << STAT_TR_RDY); s->regs[RS_STAT_DIN] |= (1 << STAT_TR_IDLE); + s->regs[RW_REC_CTRL] = 0x10000; + +} + +static int etraxfs_ser_init(SysBusDevice *dev) +{ + struct etrax_serial *s = FROM_SYSBUS(typeof (*s), dev); + int ser_regs; + sysbus_init_irq(dev, &s->irq); ser_regs = cpu_register_io_memory(ser_read, ser_write, s, DEVICE_NATIVE_ENDIAN); @@ -211,10 +219,16 @@ static int etraxfs_ser_init(SysBusDevice *dev) return 0; } +static SysBusDeviceInfo etraxfs_ser_info = { + .init = etraxfs_ser_init, + .qdev.name = "etraxfs,serial", + .qdev.size = sizeof(struct etrax_serial), + .qdev.reset = etraxfs_ser_reset, +}; + static void etraxfs_serial_register(void) { - sysbus_register_dev("etraxfs,serial", sizeof (struct etrax_serial), - etraxfs_ser_init); + sysbus_register_withprop(&etraxfs_ser_info); } device_init(etraxfs_serial_register) diff --git a/hw/framebuffer.c b/hw/framebuffer.c index 24cdf25d0b..56cf16e27a 100644 --- a/hw/framebuffer.c +++ b/hw/framebuffer.c @@ -78,6 +78,9 @@ void framebuffer_update_display( dest = ds_get_data(ds); if (dest_col_pitch < 0) dest -= dest_col_pitch * (cols - 1); + if (dest_row_pitch < 0) { + dest -= dest_row_pitch * (rows - 1); + } first = -1; addr = pd; @@ -192,7 +192,7 @@ static void update_irq(struct HPETTimer *timer, int set) qemu_irq_lower(s->irqs[route]); } } else if (timer_fsb_route(timer)) { - stl_phys(timer->fsb >> 32, timer->fsb & 0xffffffff); + stl_le_phys(timer->fsb >> 32, timer->fsb & 0xffffffff); } else if (timer->config & HPET_TN_TYPE_LEVEL) { s->isr |= mask; qemu_irq_raise(s->irqs[route]); diff --git a/hw/ide/core.c b/hw/ide/core.c index ca17a436c0..d145b19b0c 100644 --- a/hw/ide/core.c +++ b/hw/ide/core.c @@ -56,6 +56,7 @@ static const int smart_attributes[][12] = { }; static int ide_handle_rw_error(IDEState *s, int error, int op); +static void ide_dummy_transfer_stop(IDEState *s); static void padstr(char *str, const char *src, int len) { @@ -1532,15 +1533,36 @@ void ide_cmd_write(void *opaque, uint32_t addr, uint32_t val) bus->cmd = val; } +/* + * Returns true if the running PIO transfer is a PIO out (i.e. data is + * transferred from the device to the guest), false if it's a PIO in + */ +static bool ide_is_pio_out(IDEState *s) +{ + if (s->end_transfer_func == ide_sector_write || + s->end_transfer_func == ide_atapi_cmd) { + return false; + } else if (s->end_transfer_func == ide_sector_read || + s->end_transfer_func == ide_transfer_stop || + s->end_transfer_func == ide_atapi_cmd_reply_end || + s->end_transfer_func == ide_dummy_transfer_stop) { + return true; + } + + abort(); +} + void ide_data_writew(void *opaque, uint32_t addr, uint32_t val) { IDEBus *bus = opaque; IDEState *s = idebus_active_if(bus); uint8_t *p; - /* PIO data access allowed only when DRQ bit is set */ - if (!(s->status & DRQ_STAT)) + /* PIO data access allowed only when DRQ bit is set. The result of a write + * during PIO out is indeterminate, just ignore it. */ + if (!(s->status & DRQ_STAT) || ide_is_pio_out(s)) { return; + } p = s->data_ptr; *(uint16_t *)p = le16_to_cpu(val); @@ -1557,9 +1579,11 @@ uint32_t ide_data_readw(void *opaque, uint32_t addr) uint8_t *p; int ret; - /* PIO data access allowed only when DRQ bit is set */ - if (!(s->status & DRQ_STAT)) + /* PIO data access allowed only when DRQ bit is set. The result of a read + * during PIO in is indeterminate, return 0 and don't move forward. */ + if (!(s->status & DRQ_STAT) || !ide_is_pio_out(s)) { return 0; + } p = s->data_ptr; ret = cpu_to_le16(*(uint16_t *)p); @@ -1576,9 +1600,11 @@ void ide_data_writel(void *opaque, uint32_t addr, uint32_t val) IDEState *s = idebus_active_if(bus); uint8_t *p; - /* PIO data access allowed only when DRQ bit is set */ - if (!(s->status & DRQ_STAT)) + /* PIO data access allowed only when DRQ bit is set. The result of a write + * during PIO out is indeterminate, just ignore it. */ + if (!(s->status & DRQ_STAT) || ide_is_pio_out(s)) { return; + } p = s->data_ptr; *(uint32_t *)p = le32_to_cpu(val); @@ -1595,9 +1621,11 @@ uint32_t ide_data_readl(void *opaque, uint32_t addr) uint8_t *p; int ret; - /* PIO data access allowed only when DRQ bit is set */ - if (!(s->status & DRQ_STAT)) + /* PIO data access allowed only when DRQ bit is set. The result of a read + * during PIO in is indeterminate, return 0 and don't move forward. */ + if (!(s->status & DRQ_STAT) || !ide_is_pio_out(s)) { return 0; + } p = s->data_ptr; ret = cpu_to_le32(*(uint32_t *)p); @@ -1761,9 +1789,13 @@ static void ide_init1(IDEBus *bus, int unit) s->unit = unit; s->drive_serial = drive_serial++; /* we need at least 2k alignment for accessing CDROMs using O_DIRECT */ - s->io_buffer = qemu_memalign(2048, IDE_DMA_BUF_SECTORS*512 + 4); s->io_buffer_total_len = IDE_DMA_BUF_SECTORS*512 + 4; + s->io_buffer = qemu_memalign(2048, s->io_buffer_total_len); + memset(s->io_buffer, 0, s->io_buffer_total_len); + s->smart_selftest_data = qemu_blockalign(s->bs, 512); + memset(s->smart_selftest_data, 0, 512); + s->sector_write_timer = qemu_new_timer_ns(vm_clock, ide_sector_write_timer_cb, s); } diff --git a/hw/intel-hda.c b/hw/intel-hda.c index 0ffffce90e..5a2bc3aaa9 100644 --- a/hw/intel-hda.c +++ b/hw/intel-hda.c @@ -224,19 +224,6 @@ static target_phys_addr_t intel_hda_addr(uint32_t lbase, uint32_t ubase) return addr; } -static void stl_phys_le(target_phys_addr_t addr, uint32_t value) -{ - uint32_t value_le = cpu_to_le32(value); - cpu_physical_memory_write(addr, (uint8_t*)(&value_le), sizeof(value_le)); -} - -static uint32_t ldl_phys_le(target_phys_addr_t addr) -{ - uint32_t value_le; - cpu_physical_memory_read(addr, (uint8_t*)(&value_le), sizeof(value_le)); - return le32_to_cpu(value_le); -} - static void intel_hda_update_int_sts(IntelHDAState *d) { uint32_t sts = 0; @@ -341,7 +328,7 @@ static void intel_hda_corb_run(IntelHDAState *d) rp = (d->corb_rp + 1) & 0xff; addr = intel_hda_addr(d->corb_lbase, d->corb_ubase); - verb = ldl_phys_le(addr + 4*rp); + verb = ldl_le_phys(addr + 4*rp); d->corb_rp = rp; dprint(d, 2, "%s: [rp 0x%x] verb 0x%08x\n", __FUNCTION__, rp, verb); @@ -373,8 +360,8 @@ static void intel_hda_response(HDACodecDevice *dev, bool solicited, uint32_t res ex = (solicited ? 0 : (1 << 4)) | dev->cad; wp = (d->rirb_wp + 1) & 0xff; addr = intel_hda_addr(d->rirb_lbase, d->rirb_ubase); - stl_phys_le(addr + 8*wp, response); - stl_phys_le(addr + 8*wp + 4, ex); + stl_le_phys(addr + 8*wp, response); + stl_le_phys(addr + 8*wp + 4, ex); d->rirb_wp = wp; dprint(d, 2, "%s: [wp 0x%x] response 0x%x, extra 0x%x\n", @@ -461,7 +448,7 @@ static bool intel_hda_xfer(HDACodecDevice *dev, uint32_t stnr, bool output, } if (d->dp_lbase & 0x01) { addr = intel_hda_addr(d->dp_lbase & ~0x01, d->dp_ubase); - stl_phys_le(addr + 8*s, st->lpib); + stl_le_phys(addr + 8*s, st->lpib); } dprint(d, 3, "dma: --\n"); diff --git a/hw/kvmclock.h b/hw/kvmclock.h index 7a83cbe8f6..252ea13461 100644 --- a/hw/kvmclock.h +++ b/hw/kvmclock.h @@ -11,4 +11,14 @@ * */ +#ifdef CONFIG_KVM + void kvmclock_create(void); + +#else /* CONFIG_KVM */ + +static inline void kvmclock_create(void) +{ +} + +#endif /* !CONFIG_KVM */ diff --git a/hw/lm32_sys.c b/hw/lm32_sys.c index 427b05fe1a..e5ff962f43 100644 --- a/hw/lm32_sys.c +++ b/hw/lm32_sys.c @@ -83,7 +83,7 @@ static void sys_write(void *opaque, target_phys_addr_t addr, uint32_t value) break; default: - error_report("lm32_sys: write access to unkown register 0x" + error_report("lm32_sys: write access to unknown register 0x" TARGET_FMT_plx, addr << 2); break; } diff --git a/hw/lm32_timer.c b/hw/lm32_timer.c index ed289847ac..49cbb22993 100644 --- a/hw/lm32_timer.c +++ b/hw/lm32_timer.c @@ -86,7 +86,7 @@ static uint32_t timer_read(void *opaque, target_phys_addr_t addr) r = (uint32_t)ptimer_get_count(s->ptimer); break; default: - error_report("lm32_timer: read access to unkown register 0x" + error_report("lm32_timer: read access to unknown register 0x" TARGET_FMT_plx, addr << 2); break; } @@ -124,7 +124,7 @@ static void timer_write(void *opaque, target_phys_addr_t addr, uint32_t value) TARGET_FMT_plx, addr << 2); break; default: - error_report("lm32_timer: write access to unkown register 0x" + error_report("lm32_timer: write access to unknown register 0x" TARGET_FMT_plx, addr << 2); break; } diff --git a/hw/lm32_uart.c b/hw/lm32_uart.c index e225087b99..09090e93b2 100644 --- a/hw/lm32_uart.c +++ b/hw/lm32_uart.c @@ -149,7 +149,7 @@ static uint32_t uart_read(void *opaque, target_phys_addr_t addr) TARGET_FMT_plx, addr << 2); break; default: - error_report("lm32_uart: read access to unkown register 0x" + error_report("lm32_uart: read access to unknown register 0x" TARGET_FMT_plx, addr << 2); break; } @@ -185,7 +185,7 @@ static void uart_write(void *opaque, target_phys_addr_t addr, uint32_t value) TARGET_FMT_plx, addr << 2); break; default: - error_report("lm32_uart: write access to unkown register 0x" + error_report("lm32_uart: write access to unknown register 0x" TARGET_FMT_plx, addr << 2); break; } diff --git a/hw/milkymist-ac97.c b/hw/milkymist-ac97.c index 6c9e318aa2..6104732f7d 100644 --- a/hw/milkymist-ac97.c +++ b/hw/milkymist-ac97.c @@ -103,7 +103,7 @@ static uint32_t ac97_read(void *opaque, target_phys_addr_t addr) break; default: - error_report("milkymist_ac97: read access to unkown register 0x" + error_report("milkymist_ac97: read access to unknown register 0x" TARGET_FMT_plx, addr << 2); break; } @@ -152,7 +152,7 @@ static void ac97_write(void *opaque, target_phys_addr_t addr, uint32_t value) break; default: - error_report("milkymist_ac97: write access to unkown register 0x" + error_report("milkymist_ac97: write access to unknown register 0x" TARGET_FMT_plx, addr); break; } diff --git a/hw/milkymist-memcard.c b/hw/milkymist-memcard.c index 06077af82a..22dc377d79 100644 --- a/hw/milkymist-memcard.c +++ b/hw/milkymist-memcard.c @@ -154,7 +154,7 @@ static uint32_t memcard_read(void *opaque, target_phys_addr_t addr) break; default: - error_report("milkymist_memcard: read access to unkown register 0x" + error_report("milkymist_memcard: read access to unknown register 0x" TARGET_FMT_plx, addr << 2); break; } @@ -210,7 +210,7 @@ static void memcard_write(void *opaque, target_phys_addr_t addr, uint32_t value) break; default: - error_report("milkymist_memcard: write access to unkown register 0x" + error_report("milkymist_memcard: write access to unknown register 0x" TARGET_FMT_plx, addr << 2); break; } diff --git a/hw/milkymist-minimac2.c b/hw/milkymist-minimac2.c index c4e28187b3..cd360264c1 100644 --- a/hw/milkymist-minimac2.c +++ b/hw/milkymist-minimac2.c @@ -234,20 +234,20 @@ static void minimac2_tx(MilkymistMinimac2State *s) uint8_t *buf = s->tx_buf; if (txcount < 64) { - error_report("milkymist_minimac2: ethernet frame too small (%u < %u)\n", + error_report("milkymist_minimac2: ethernet frame too small (%u < %u)", txcount, 64); goto err; } if (txcount > MINIMAC2_MTU) { - error_report("milkymist_minimac2: MTU exceeded (%u > %u)\n", + error_report("milkymist_minimac2: MTU exceeded (%u > %u)", txcount, MINIMAC2_MTU); goto err; } if (memcmp(buf, preamble_sfd, 8) != 0) { error_report("milkymist_minimac2: frame doesn't contain the preamble " - "and/or the SFD (%02x %02x %02x %02x %02x %02x %02x %02x)\n", + "and/or the SFD (%02x %02x %02x %02x %02x %02x %02x %02x)", buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6], buf[7]); goto err; } diff --git a/hw/milkymist-pfpu.c b/hw/milkymist-pfpu.c index 94e631510f..306d1ce287 100644 --- a/hw/milkymist-pfpu.c +++ b/hw/milkymist-pfpu.c @@ -301,7 +301,7 @@ static int pfpu_decode_insn(MilkymistPFPUState *s) } break; default: - error_report("milkymist_pfpu: unknown opcode %d\n", op); + error_report("milkymist_pfpu: unknown opcode %d", op); break; } @@ -358,7 +358,7 @@ static void pfpu_start(MilkymistPFPUState *s) /* decode at most MICROCODE_WORDS instructions */ if (i++ >= MICROCODE_WORDS) { error_report("milkymist_pfpu: too many instructions " - "executed in microcode. No VECTOUT?\n"); + "executed in microcode. No VECTOUT?"); break; } } diff --git a/hw/milkymist-softusb.c b/hw/milkymist-softusb.c index 028f3b79ac..ce2bfc60f2 100644 --- a/hw/milkymist-softusb.c +++ b/hw/milkymist-softusb.c @@ -131,7 +131,7 @@ static inline void softusb_read_dmem(MilkymistSoftUsbState *s, { if (offset + len >= s->dmem_size) { error_report("milkymist_softusb: read dmem out of bounds " - "at offset 0x%x, len %d\n", offset, len); + "at offset 0x%x, len %d", offset, len); return; } @@ -143,7 +143,7 @@ static inline void softusb_write_dmem(MilkymistSoftUsbState *s, { if (offset + len >= s->dmem_size) { error_report("milkymist_softusb: write dmem out of bounds " - "at offset 0x%x, len %d\n", offset, len); + "at offset 0x%x, len %d", offset, len); return; } @@ -155,7 +155,7 @@ static inline void softusb_read_pmem(MilkymistSoftUsbState *s, { if (offset + len >= s->pmem_size) { error_report("milkymist_softusb: read pmem out of bounds " - "at offset 0x%x, len %d\n", offset, len); + "at offset 0x%x, len %d", offset, len); return; } @@ -167,7 +167,7 @@ static inline void softusb_write_pmem(MilkymistSoftUsbState *s, { if (offset + len >= s->pmem_size) { error_report("milkymist_softusb: write pmem out of bounds " - "at offset 0x%x, len %d\n", offset, len); + "at offset 0x%x, len %d", offset, len); return; } @@ -247,16 +247,21 @@ static void softusb_attach(USBPort *port) { } -static void softusb_device_destroy(USBBus *bus, USBDevice *dev) +static void softusb_detach(USBPort *port) +{ +} + +static void softusb_child_detach(USBPort *port, USBDevice *child) { } static USBPortOps softusb_ops = { .attach = softusb_attach, + .detach = softusb_detach, + .child_detach = softusb_child_detach, }; static USBBusOps softusb_bus_ops = { - .device_destroy = softusb_device_destroy, }; static void milkymist_softusb_reset(DeviceState *d) diff --git a/hw/milkymist-sysctl.c b/hw/milkymist-sysctl.c index 6bd0cb9740..7b2d544ac3 100644 --- a/hw/milkymist-sysctl.c +++ b/hw/milkymist-sysctl.c @@ -119,7 +119,7 @@ static uint32_t sysctl_read(void *opaque, target_phys_addr_t addr) break; default: - error_report("milkymist_sysctl: read access to unkown register 0x" + error_report("milkymist_sysctl: read access to unknown register 0x" TARGET_FMT_plx, addr << 2); break; } @@ -189,7 +189,7 @@ static void sysctl_write(void *opaque, target_phys_addr_t addr, uint32_t value) break; default: - error_report("milkymist_sysctl: write access to unkown register 0x" + error_report("milkymist_sysctl: write access to unknown register 0x" TARGET_FMT_plx, addr << 2); break; } diff --git a/hw/milkymist-tmu2.c b/hw/milkymist-tmu2.c index 9cebe3173b..790cdcb41c 100644 --- a/hw/milkymist-tmu2.c +++ b/hw/milkymist-tmu2.c @@ -352,21 +352,21 @@ static uint32_t tmu2_read(void *opaque, target_phys_addr_t addr) static void tmu2_check_registers(MilkymistTMU2State *s) { if (s->regs[R_BRIGHTNESS] > MAX_BRIGHTNESS) { - error_report("milkymist_tmu2: max brightness is %d\n", MAX_BRIGHTNESS); + error_report("milkymist_tmu2: max brightness is %d", MAX_BRIGHTNESS); } if (s->regs[R_ALPHA] > MAX_ALPHA) { - error_report("milkymist_tmu2: max alpha is %d\n", MAX_ALPHA); + error_report("milkymist_tmu2: max alpha is %d", MAX_ALPHA); } if (s->regs[R_VERTICESADDR] & 0x07) { error_report("milkymist_tmu2: vertex mesh address has to be 64-bit " - "aligned\n"); + "aligned"); } if (s->regs[R_TEXFBUF] & 0x01) { error_report("milkymist_tmu2: texture buffer address has to be " - "16-bit aligned\n"); + "16-bit aligned"); } } diff --git a/hw/mpc8544_guts.c b/hw/mpc8544_guts.c new file mode 100644 index 0000000000..c685f3e08c --- /dev/null +++ b/hw/mpc8544_guts.c @@ -0,0 +1,135 @@ +/* + * QEMU PowerPC MPC8544 global util pseudo-device + * + * Copyright (C) 2011 Freescale Semiconductor, Inc. All rights reserved. + * + * Author: Alexander Graf, <alex@csgraf.de> + * + * 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. + * + * ***************************************************************** + * + * The documentation for this device is noted in the MPC8544 documentation, + * file name "MPC8544ERM.pdf". You can easily find it on the web. + * + */ + +#include "hw.h" +#include "sysemu.h" +#include "sysbus.h" + +#define MPC8544_GUTS_MMIO_SIZE 0x1000 +#define MPC8544_GUTS_RSTCR_RESET 0x02 + +#define MPC8544_GUTS_ADDR_PORPLLSR 0x00 +#define MPC8544_GUTS_ADDR_PORBMSR 0x04 +#define MPC8544_GUTS_ADDR_PORIMPSCR 0x08 +#define MPC8544_GUTS_ADDR_PORDEVSR 0x0C +#define MPC8544_GUTS_ADDR_PORDBGMSR 0x10 +#define MPC8544_GUTS_ADDR_PORDEVSR2 0x14 +#define MPC8544_GUTS_ADDR_GPPORCR 0x20 +#define MPC8544_GUTS_ADDR_GPIOCR 0x30 +#define MPC8544_GUTS_ADDR_GPOUTDR 0x40 +#define MPC8544_GUTS_ADDR_GPINDR 0x50 +#define MPC8544_GUTS_ADDR_PMUXCR 0x60 +#define MPC8544_GUTS_ADDR_DEVDISR 0x70 +#define MPC8544_GUTS_ADDR_POWMGTCSR 0x80 +#define MPC8544_GUTS_ADDR_MCPSUMR 0x90 +#define MPC8544_GUTS_ADDR_RSTRSCR 0x94 +#define MPC8544_GUTS_ADDR_PVR 0xA0 +#define MPC8544_GUTS_ADDR_SVR 0xA4 +#define MPC8544_GUTS_ADDR_RSTCR 0xB0 +#define MPC8544_GUTS_ADDR_IOVSELSR 0xC0 +#define MPC8544_GUTS_ADDR_DDRCSR 0xB20 +#define MPC8544_GUTS_ADDR_DDRCDR 0xB24 +#define MPC8544_GUTS_ADDR_DDRCLKDR 0xB28 +#define MPC8544_GUTS_ADDR_CLKOCR 0xE00 +#define MPC8544_GUTS_ADDR_SRDS1CR1 0xF04 +#define MPC8544_GUTS_ADDR_SRDS2CR1 0xF10 +#define MPC8544_GUTS_ADDR_SRDS2CR3 0xF18 + +struct GutsState { + SysBusDevice busdev; +}; + +typedef struct GutsState GutsState; + +static uint32_t mpc8544_guts_read32(void *opaque, target_phys_addr_t addr) +{ + uint32_t value = 0; + CPUState *env = cpu_single_env; + + addr &= MPC8544_GUTS_MMIO_SIZE - 1; + switch (addr) { + case MPC8544_GUTS_ADDR_PVR: + value = env->spr[SPR_PVR]; + break; + case MPC8544_GUTS_ADDR_SVR: + value = env->spr[SPR_E500_SVR]; + break; + default: + fprintf(stderr, "guts: Unknown register read: %x\n", (int)addr); + break; + } + + return value; +} + +static CPUReadMemoryFunc * const mpc8544_guts_read[] = { + NULL, + NULL, + &mpc8544_guts_read32, +}; + +static void mpc8544_guts_write32(void *opaque, target_phys_addr_t addr, + uint32_t value) +{ + addr &= MPC8544_GUTS_MMIO_SIZE - 1; + + switch (addr) { + case MPC8544_GUTS_ADDR_RSTCR: + if (value & MPC8544_GUTS_RSTCR_RESET) { + qemu_system_reset_request(); + } + break; + default: + fprintf(stderr, "guts: Unknown register write: %x = %x\n", + (int)addr, value); + break; + } +} + +static CPUWriteMemoryFunc * const mpc8544_guts_write[] = { + NULL, + NULL, + &mpc8544_guts_write32, +}; + +static int mpc8544_guts_initfn(SysBusDevice *dev) +{ + GutsState *s; + int iomem; + + s = FROM_SYSBUS(GutsState, sysbus_from_qdev(dev)); + + iomem = cpu_register_io_memory(mpc8544_guts_read, mpc8544_guts_write, s, + DEVICE_BIG_ENDIAN); + sysbus_init_mmio(dev, MPC8544_GUTS_MMIO_SIZE, iomem); + + return 0; +} + +static SysBusDeviceInfo mpc8544_guts_info = { + .init = mpc8544_guts_initfn, + .qdev.name = "mpc8544-guts", + .qdev.size = sizeof(GutsState), +}; + +static void mpc8544_guts_register(void) +{ + sysbus_register_withprop(&mpc8544_guts_info); +} +device_init(mpc8544_guts_register); @@ -249,7 +249,7 @@ void msi_notify(PCIDevice *dev, unsigned int vector) "notify vector 0x%x" " address: 0x%"PRIx64" data: 0x%"PRIx32"\n", vector, address, data); - stl_phys(address, data); + stl_le_phys(address, data); } /* call this function after updating configs by pci_default_write_config(). */ @@ -359,7 +359,7 @@ void msix_notify(PCIDevice *dev, unsigned vector) address = pci_get_quad(table_entry + PCI_MSIX_ENTRY_LOWER_ADDR); data = pci_get_long(table_entry + PCI_MSIX_ENTRY_DATA); - stl_phys(address, data); + stl_le_phys(address, data); } void msix_reset(PCIDevice *dev) diff --git a/hw/nseries.c b/hw/nseries.c index 2f6f473d64..2f84f5305b 100644 --- a/hw/nseries.c +++ b/hw/nseries.c @@ -1254,12 +1254,12 @@ static int n8x0_atag_setup(void *p, int model) return (void *) w - p; } -static int n800_atag_setup(struct arm_boot_info *info, void *p) +static int n800_atag_setup(const struct arm_boot_info *info, void *p) { return n8x0_atag_setup(p, 800); } -static int n810_atag_setup(struct arm_boot_info *info, void *p) +static int n810_atag_setup(const struct arm_boot_info *info, void *p) { return n8x0_atag_setup(p, 810); } diff --git a/hw/pci_ids.h b/hw/pci_ids.h index d94578c87d..83f38934ec 100644 --- a/hw/pci_ids.h +++ b/hw/pci_ids.h @@ -109,5 +109,14 @@ #define PCI_DEVICE_ID_INTEL_82371AB 0x7111 #define PCI_DEVICE_ID_INTEL_82371AB_2 0x7112 #define PCI_DEVICE_ID_INTEL_82371AB_3 0x7113 - -#define PCI_VENDOR_ID_XENSOURCE 0x5853 +#define PCI_DEVICE_ID_INTEL_82801I_UHCI1 0x2934 +#define PCI_DEVICE_ID_INTEL_82801I_UHCI2 0x2935 +#define PCI_DEVICE_ID_INTEL_82801I_UHCI3 0x2936 +#define PCI_DEVICE_ID_INTEL_82801I_UHCI4 0x2937 +#define PCI_DEVICE_ID_INTEL_82801I_UHCI5 0x2938 +#define PCI_DEVICE_ID_INTEL_82801I_UHCI6 0x2939 +#define PCI_DEVICE_ID_INTEL_82801I_EHCI1 0x293a +#define PCI_DEVICE_ID_INTEL_82801I_EHCI2 0x293c + +#define PCI_VENDOR_ID_XEN 0x5853 +#define PCI_DEVICE_ID_XEN_PLATFORM 0x0001 diff --git a/hw/piix_pci.c b/hw/piix_pci.c index 26ce90451a..d08b31a266 100644 --- a/hw/piix_pci.c +++ b/hw/piix_pci.c @@ -478,6 +478,9 @@ static PCIDeviceInfo i440fx_info[] = { .no_hotplug = 1, .init = piix3_initfn, .config_write = piix3_write_config_xen, + .vendor_id = PCI_VENDOR_ID_INTEL, + .device_id = PCI_DEVICE_ID_INTEL_82371SB_0, // 82371SB PIIX3 PCI-to-ISA bridge (Step A1) + .class_id = PCI_CLASS_BRIDGE_ISA, },{ /* end of list */ } diff --git a/hw/pl080.c b/hw/pl080.c index 901f04a844..dd8139ba96 100644 --- a/hw/pl080.c +++ b/hw/pl080.c @@ -199,10 +199,10 @@ again: if (size == 0) { /* Transfer complete. */ if (ch->lli) { - ch->src = ldl_phys(ch->lli); - ch->dest = ldl_phys(ch->lli + 4); - ch->ctrl = ldl_phys(ch->lli + 12); - ch->lli = ldl_phys(ch->lli + 8); + ch->src = ldl_le_phys(ch->lli); + ch->dest = ldl_le_phys(ch->lli + 4); + ch->ctrl = ldl_le_phys(ch->lli + 12); + ch->lli = ldl_le_phys(ch->lli + 8); } else { ch->conf &= ~PL080_CCONF_E; } diff --git a/hw/ppc405_uc.c b/hw/ppc405_uc.c index 2ce79ee053..06a053bf07 100644 --- a/hw/ppc405_uc.c +++ b/hw/ppc405_uc.c @@ -51,39 +51,42 @@ ram_addr_t ppc405_set_bootinfo (CPUState *env, ppc4xx_bd_info_t *bd, bdloc = 0x01000000UL - sizeof(struct ppc4xx_bd_info_t); else bdloc = bd->bi_memsize - sizeof(struct ppc4xx_bd_info_t); - stl_phys(bdloc + 0x00, bd->bi_memstart); - stl_phys(bdloc + 0x04, bd->bi_memsize); - stl_phys(bdloc + 0x08, bd->bi_flashstart); - stl_phys(bdloc + 0x0C, bd->bi_flashsize); - stl_phys(bdloc + 0x10, bd->bi_flashoffset); - stl_phys(bdloc + 0x14, bd->bi_sramstart); - stl_phys(bdloc + 0x18, bd->bi_sramsize); - stl_phys(bdloc + 0x1C, bd->bi_bootflags); - stl_phys(bdloc + 0x20, bd->bi_ipaddr); - for (i = 0; i < 6; i++) + stl_be_phys(bdloc + 0x00, bd->bi_memstart); + stl_be_phys(bdloc + 0x04, bd->bi_memsize); + stl_be_phys(bdloc + 0x08, bd->bi_flashstart); + stl_be_phys(bdloc + 0x0C, bd->bi_flashsize); + stl_be_phys(bdloc + 0x10, bd->bi_flashoffset); + stl_be_phys(bdloc + 0x14, bd->bi_sramstart); + stl_be_phys(bdloc + 0x18, bd->bi_sramsize); + stl_be_phys(bdloc + 0x1C, bd->bi_bootflags); + stl_be_phys(bdloc + 0x20, bd->bi_ipaddr); + for (i = 0; i < 6; i++) { stb_phys(bdloc + 0x24 + i, bd->bi_enetaddr[i]); - stw_phys(bdloc + 0x2A, bd->bi_ethspeed); - stl_phys(bdloc + 0x2C, bd->bi_intfreq); - stl_phys(bdloc + 0x30, bd->bi_busfreq); - stl_phys(bdloc + 0x34, bd->bi_baudrate); - for (i = 0; i < 4; i++) + } + stw_be_phys(bdloc + 0x2A, bd->bi_ethspeed); + stl_be_phys(bdloc + 0x2C, bd->bi_intfreq); + stl_be_phys(bdloc + 0x30, bd->bi_busfreq); + stl_be_phys(bdloc + 0x34, bd->bi_baudrate); + for (i = 0; i < 4; i++) { stb_phys(bdloc + 0x38 + i, bd->bi_s_version[i]); + } for (i = 0; i < 32; i++) { stb_phys(bdloc + 0x3C + i, bd->bi_r_version[i]); } - stl_phys(bdloc + 0x5C, bd->bi_plb_busfreq); - stl_phys(bdloc + 0x60, bd->bi_pci_busfreq); - for (i = 0; i < 6; i++) + stl_be_phys(bdloc + 0x5C, bd->bi_plb_busfreq); + stl_be_phys(bdloc + 0x60, bd->bi_pci_busfreq); + for (i = 0; i < 6; i++) { stb_phys(bdloc + 0x64 + i, bd->bi_pci_enetaddr[i]); + } n = 0x6A; if (flags & 0x00000001) { for (i = 0; i < 6; i++) stb_phys(bdloc + n++, bd->bi_pci_enetaddr2[i]); } - stl_phys(bdloc + n, bd->bi_opbfreq); + stl_be_phys(bdloc + n, bd->bi_opbfreq); n += 4; for (i = 0; i < 2; i++) { - stl_phys(bdloc + n, bd->bi_iic_fast[i]); + stl_be_phys(bdloc + n, bd->bi_iic_fast[i]); n += 4; } diff --git a/hw/ppc440.c b/hw/ppc440.c index 1ed001a031..90abc91929 100644 --- a/hw/ppc440.c +++ b/hw/ppc440.c @@ -45,8 +45,9 @@ CPUState *ppc440ep_init(ram_addr_t *ram_size, PCIBus **pcip, qemu_irq *irqs; qemu_irq *pci_irqs; - if (cpu_model == NULL) - cpu_model = "405"; // XXX: should be 440EP + if (cpu_model == NULL) { + cpu_model = "440-Xilinx"; // XXX: should be 440EP + } env = cpu_init(cpu_model); if (!env) { fprintf(stderr, "Unable to initialize CPU!\n"); diff --git a/hw/ppc_mac.h b/hw/ppc_mac.h index ea8759324c..68dade7e40 100644 --- a/hw/ppc_mac.h +++ b/hw/ppc_mac.h @@ -35,8 +35,7 @@ #define PROM_ADDR 0xfff00000 #define KERNEL_LOAD_ADDR 0x01000000 -#define CMDLINE_ADDR 0x027ff000 -#define INITRD_LOAD_ADDR 0x02800000 +#define KERNEL_GAP 0x00100000 #define ESCC_CLOCK 3686400 diff --git a/hw/ppc_newworld.c b/hw/ppc_newworld.c index 86f1cfbee9..5bce709bab 100644 --- a/hw/ppc_newworld.c +++ b/hw/ppc_newworld.c @@ -120,6 +120,11 @@ static uint64_t translate_kernel_address(void *opaque, uint64_t addr) return (addr & 0x0fffffff) + KERNEL_LOAD_ADDR; } +static target_phys_addr_t round_page(target_phys_addr_t addr) +{ + return (addr + TARGET_PAGE_SIZE - 1) & TARGET_PAGE_MASK; +} + /* PowerPC Mac99 hardware initialisation */ static void ppc_core99_init (ram_addr_t ram_size, const char *boot_device, @@ -134,7 +139,7 @@ static void ppc_core99_init (ram_addr_t ram_size, int unin_memory; int linux_boot, i; ram_addr_t ram_offset, bios_offset; - uint32_t kernel_base, initrd_base; + target_phys_addr_t kernel_base, initrd_base, cmdline_base = 0; long kernel_size, initrd_size; PCIBus *pci_bus; MacIONVRAMState *nvr; @@ -220,7 +225,7 @@ static void ppc_core99_init (ram_addr_t ram_size, } /* load initrd */ if (initrd_filename) { - initrd_base = INITRD_LOAD_ADDR; + initrd_base = round_page(kernel_base + kernel_size + KERNEL_GAP); initrd_size = load_image_targphys(initrd_filename, initrd_base, ram_size - initrd_base); if (initrd_size < 0) { @@ -228,9 +233,11 @@ static void ppc_core99_init (ram_addr_t ram_size, initrd_filename); exit(1); } + cmdline_base = round_page(initrd_base + initrd_size); } else { initrd_base = 0; initrd_size = 0; + cmdline_base = round_page(kernel_base + kernel_size + KERNEL_GAP); } ppc_boot_device = 'm'; } else { @@ -373,8 +380,8 @@ static void ppc_core99_init (ram_addr_t ram_size, fw_cfg_add_i32(fw_cfg, FW_CFG_KERNEL_ADDR, kernel_base); fw_cfg_add_i32(fw_cfg, FW_CFG_KERNEL_SIZE, kernel_size); if (kernel_cmdline) { - fw_cfg_add_i32(fw_cfg, FW_CFG_KERNEL_CMDLINE, CMDLINE_ADDR); - pstrcpy_targphys("cmdline", CMDLINE_ADDR, TARGET_PAGE_SIZE, kernel_cmdline); + fw_cfg_add_i32(fw_cfg, FW_CFG_KERNEL_CMDLINE, cmdline_base); + pstrcpy_targphys("cmdline", cmdline_base, TARGET_PAGE_SIZE, kernel_cmdline); } else { fw_cfg_add_i32(fw_cfg, FW_CFG_KERNEL_CMDLINE, 0); } diff --git a/hw/ppc_oldworld.c b/hw/ppc_oldworld.c index 75a312742e..20cd8e1a8d 100644 --- a/hw/ppc_oldworld.c +++ b/hw/ppc_oldworld.c @@ -59,6 +59,11 @@ static uint64_t translate_kernel_address(void *opaque, uint64_t addr) return (addr & 0x0fffffff) + KERNEL_LOAD_ADDR; } +static target_phys_addr_t round_page(target_phys_addr_t addr) +{ + return (addr + TARGET_PAGE_SIZE - 1) & TARGET_PAGE_MASK; +} + static void ppc_heathrow_init (ram_addr_t ram_size, const char *boot_device, const char *kernel_filename, @@ -71,7 +76,7 @@ static void ppc_heathrow_init (ram_addr_t ram_size, qemu_irq *pic, **heathrow_irqs; int linux_boot, i; ram_addr_t ram_offset, bios_offset; - uint32_t kernel_base, initrd_base; + uint32_t kernel_base, initrd_base, cmdline_base = 0; int32_t kernel_size, initrd_size; PCIBus *pci_bus; MacIONVRAMState *nvr; @@ -157,7 +162,7 @@ static void ppc_heathrow_init (ram_addr_t ram_size, } /* load initrd */ if (initrd_filename) { - initrd_base = INITRD_LOAD_ADDR; + initrd_base = round_page(kernel_base + kernel_size + KERNEL_GAP); initrd_size = load_image_targphys(initrd_filename, initrd_base, ram_size - initrd_base); if (initrd_size < 0) { @@ -165,9 +170,11 @@ static void ppc_heathrow_init (ram_addr_t ram_size, initrd_filename); exit(1); } + cmdline_base = round_page(initrd_base + initrd_size); } else { initrd_base = 0; initrd_size = 0; + cmdline_base = round_page(kernel_base + kernel_size + KERNEL_GAP); } ppc_boot_device = 'm'; } else { @@ -278,8 +285,8 @@ static void ppc_heathrow_init (ram_addr_t ram_size, fw_cfg_add_i32(fw_cfg, FW_CFG_KERNEL_ADDR, kernel_base); fw_cfg_add_i32(fw_cfg, FW_CFG_KERNEL_SIZE, kernel_size); if (kernel_cmdline) { - fw_cfg_add_i32(fw_cfg, FW_CFG_KERNEL_CMDLINE, CMDLINE_ADDR); - pstrcpy_targphys("cmdline", CMDLINE_ADDR, TARGET_PAGE_SIZE, kernel_cmdline); + fw_cfg_add_i32(fw_cfg, FW_CFG_KERNEL_CMDLINE, cmdline_base); + pstrcpy_targphys("cmdline", cmdline_base, TARGET_PAGE_SIZE, kernel_cmdline); } else { fw_cfg_add_i32(fw_cfg, FW_CFG_KERNEL_CMDLINE, 0); } diff --git a/hw/ppce500_mpc8544ds.c b/hw/ppce500_mpc8544ds.c index 6b57fbf597..b739ce27ed 100644 --- a/hw/ppce500_mpc8544ds.c +++ b/hw/ppce500_mpc8544ds.c @@ -50,6 +50,7 @@ #define MPC8544_PCI_REGS_SIZE 0x1000 #define MPC8544_PCI_IO 0xE1000000 #define MPC8544_PCI_IOLEN 0x10000 +#define MPC8544_UTIL_BASE (MPC8544_CCSRBAR_BASE + 0xe0000) struct boot_info { @@ -81,11 +82,12 @@ out: } #endif -static int mpc8544_load_device_tree(target_phys_addr_t addr, - uint32_t ramsize, - target_phys_addr_t initrd_base, - target_phys_addr_t initrd_size, - const char *kernel_cmdline) +static int mpc8544_load_device_tree(CPUState *env, + target_phys_addr_t addr, + uint32_t ramsize, + target_phys_addr_t initrd_base, + target_phys_addr_t initrd_size, + const char *kernel_cmdline) { int ret = -1; #ifdef CONFIG_FDT @@ -93,6 +95,7 @@ static int mpc8544_load_device_tree(target_phys_addr_t addr, char *filename; int fdt_size; void *fdt; + uint8_t hypercall[16]; filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, BINARY_DEVICE_TREE_FILE); if (!filename) { @@ -156,6 +159,13 @@ static int mpc8544_load_device_tree(target_phys_addr_t addr, mpc8544_copy_soc_cell(fdt, buf, "clock-frequency"); mpc8544_copy_soc_cell(fdt, buf, "timebase-frequency"); + + /* indicate KVM hypercall interface */ + 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)); } else { const uint32_t freq = 400000000; @@ -175,18 +185,23 @@ out: } /* Create -kernel TLB entries for BookE, linearly spanning 256MB. */ +static inline target_phys_addr_t booke206_page_size_to_tlb(uint64_t size) +{ + return (ffs(size >> 10) - 1) >> 1; +} + static void mmubooke_create_initial_mapping(CPUState *env, target_ulong va, target_phys_addr_t pa) { - ppcemb_tlb_t *tlb = booke206_get_tlbe(env, 1, 0, 0); - - tlb->attr = 0; - tlb->prot = PAGE_VALID | ((PAGE_READ | PAGE_WRITE | PAGE_EXEC) << 4); - tlb->size = 256 * 1024 * 1024; - tlb->EPN = va & TARGET_PAGE_MASK; - tlb->RPN = pa & TARGET_PAGE_MASK; - tlb->PID = 0; + ppcmas_tlb_t *tlb = booke206_get_tlbm(env, 1, 0, 0); + target_phys_addr_t size; + + size = (booke206_page_size_to_tlb(256 * 1024 * 1024) << MAS1_TSIZE_SHIFT); + tlb->mas1 = MAS1_VALID | size; + tlb->mas2 = va & TARGET_PAGE_MASK; + tlb->mas7_3 = pa & TARGET_PAGE_MASK; + tlb->mas7_3 |= MAS3_UR | MAS3_UW | MAS3_UX | MAS3_SR | MAS3_SW | MAS3_SX; } static void mpc8544ds_cpu_reset(void *opaque) @@ -270,6 +285,9 @@ static void mpc8544ds_init(ram_addr_t ram_size, serial_hds[0], 1, 1); } + /* 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]], @@ -326,7 +344,7 @@ static void mpc8544ds_init(ram_addr_t ram_size, cpu_abort(env, "Compiled without FDT support - can't load kernel\n"); #endif dt_base = (kernel_size + DTC_LOAD_PAD) & ~DTC_PAD_MASK; - if (mpc8544_load_device_tree(dt_base, ram_size, + if (mpc8544_load_device_tree(env, dt_base, ram_size, initrd_base, initrd_size, kernel_cmdline) < 0) { fprintf(stderr, "couldn't load device tree\n"); exit(1); diff --git a/hw/pxa2xx_lcd.c b/hw/pxa2xx_lcd.c index e5248023f8..a5f8c51169 100644 --- a/hw/pxa2xx_lcd.c +++ b/hw/pxa2xx_lcd.c @@ -665,7 +665,7 @@ static void pxa2xx_palette_parse(PXA2xxLCDState *s, int ch, int bpp) } } -static void pxa2xx_lcdc_dma0_redraw_horiz(PXA2xxLCDState *s, +static void pxa2xx_lcdc_dma0_redraw_rot0(PXA2xxLCDState *s, target_phys_addr_t addr, int *miny, int *maxy) { int src_width, dest_width; @@ -692,7 +692,7 @@ static void pxa2xx_lcdc_dma0_redraw_horiz(PXA2xxLCDState *s, fn, s->dma_ch[0].palette, miny, maxy); } -static void pxa2xx_lcdc_dma0_redraw_vert(PXA2xxLCDState *s, +static void pxa2xx_lcdc_dma0_redraw_rot90(PXA2xxLCDState *s, target_phys_addr_t addr, int *miny, int *maxy) { int src_width, dest_width; @@ -720,6 +720,67 @@ static void pxa2xx_lcdc_dma0_redraw_vert(PXA2xxLCDState *s, miny, maxy); } +static void pxa2xx_lcdc_dma0_redraw_rot180(PXA2xxLCDState *s, + target_phys_addr_t addr, int *miny, int *maxy) +{ + int src_width, dest_width; + drawfn fn = NULL; + if (s->dest_width) { + fn = s->line_fn[s->transp][s->bpp]; + } + if (!fn) { + return; + } + + src_width = (s->xres + 3) & ~3; /* Pad to a 4 pixels multiple */ + if (s->bpp == pxa_lcdc_19pbpp || s->bpp == pxa_lcdc_18pbpp) { + src_width *= 3; + } else if (s->bpp > pxa_lcdc_16bpp) { + src_width *= 4; + } else if (s->bpp > pxa_lcdc_8bpp) { + src_width *= 2; + } + + dest_width = s->xres * s->dest_width; + *miny = 0; + framebuffer_update_display(s->ds, + addr, s->xres, s->yres, + src_width, -dest_width, -s->dest_width, + s->invalidated, + fn, s->dma_ch[0].palette, miny, maxy); +} + +static void pxa2xx_lcdc_dma0_redraw_rot270(PXA2xxLCDState *s, + target_phys_addr_t addr, int *miny, int *maxy) +{ + int src_width, dest_width; + drawfn fn = NULL; + if (s->dest_width) { + fn = s->line_fn[s->transp][s->bpp]; + } + if (!fn) { + return; + } + + src_width = (s->xres + 3) & ~3; /* Pad to a 4 pixels multiple */ + if (s->bpp == pxa_lcdc_19pbpp || s->bpp == pxa_lcdc_18pbpp) { + src_width *= 3; + } else if (s->bpp > pxa_lcdc_16bpp) { + src_width *= 4; + } else if (s->bpp > pxa_lcdc_8bpp) { + src_width *= 2; + } + + dest_width = s->yres * s->dest_width; + *miny = 0; + framebuffer_update_display(s->ds, + addr, s->xres, s->yres, + src_width, -s->dest_width, dest_width, + s->invalidated, + fn, s->dma_ch[0].palette, + miny, maxy); +} + static void pxa2xx_lcdc_resize(PXA2xxLCDState *s) { int width, height; @@ -730,10 +791,11 @@ static void pxa2xx_lcdc_resize(PXA2xxLCDState *s) height = LCCR2_LPP(s->control[2]) + 1; if (width != s->xres || height != s->yres) { - if (s->orientation) + if (s->orientation == 90 || s->orientation == 270) { qemu_console_resize(s->ds, height, width); - else + } else { qemu_console_resize(s->ds, width, height); + } s->invalidated = 1; s->xres = width; s->yres = height; @@ -797,10 +859,24 @@ static void pxa2xx_update_display(void *opaque) } if (miny >= 0) { - if (s->orientation) - dpy_update(s->ds, miny, 0, maxy - miny, s->xres); - else - dpy_update(s->ds, 0, miny, s->xres, maxy - miny); + switch (s->orientation) { + case 0: + dpy_update(s->ds, 0, miny, s->xres, maxy - miny + 1); + break; + case 90: + dpy_update(s->ds, miny, 0, maxy - miny + 1, s->xres); + break; + case 180: + maxy = s->yres - maxy - 1; + miny = s->yres - miny - 1; + dpy_update(s->ds, 0, maxy, s->xres, miny - maxy + 1); + break; + case 270: + maxy = s->yres - maxy - 1; + miny = s->yres - miny - 1; + dpy_update(s->ds, maxy, 0, miny - maxy + 1, s->xres); + break; + } } pxa2xx_lcdc_int_update(s); @@ -822,10 +898,19 @@ static void pxa2xx_lcdc_orientation(void *opaque, int angle) { PXA2xxLCDState *s = (PXA2xxLCDState *) opaque; - if (angle) { - s->dma_ch[0].redraw = pxa2xx_lcdc_dma0_redraw_vert; - } else { - s->dma_ch[0].redraw = pxa2xx_lcdc_dma0_redraw_horiz; + switch (angle) { + case 0: + s->dma_ch[0].redraw = pxa2xx_lcdc_dma0_redraw_rot0; + break; + case 90: + s->dma_ch[0].redraw = pxa2xx_lcdc_dma0_redraw_rot90; + break; + case 180: + s->dma_ch[0].redraw = pxa2xx_lcdc_dma0_redraw_rot180; + break; + case 270: + s->dma_ch[0].redraw = pxa2xx_lcdc_dma0_redraw_rot270; + break; } s->orientation = angle; @@ -371,7 +371,7 @@ void qdev_init_nofail(DeviceState *dev) DeviceInfo *info = dev->info; if (qdev_init(dev) < 0) { - error_report("Initialization of device %s failed\n", info->name); + error_report("Initialization of device %s failed", info->name); exit(1); } } diff --git a/hw/qxl-logger.c b/hw/qxl-logger.c index 76f43e646c..74cadba302 100644 --- a/hw/qxl-logger.c +++ b/hw/qxl-logger.c @@ -19,6 +19,7 @@ * along with this program; if not, see <http://www.gnu.org/licenses/>. */ +#include "qemu-timer.h" #include "qxl.h" static const char *qxl_type[] = { @@ -223,7 +224,8 @@ void qxl_log_command(PCIQXLDevice *qxl, const char *ring, QXLCommandExt *ext) if (!qxl->cmdlog) { return; } - fprintf(stderr, "qxl-%d/%s:", qxl->id, ring); + fprintf(stderr, "%ld qxl-%d/%s:", qemu_get_clock_ns(vm_clock), + qxl->id, ring); fprintf(stderr, " cmd @ 0x%" PRIx64 " %s%s", ext->cmd.data, qxl_name(qxl_type, ext->cmd.type), compat ? "(compat)" : ""); @@ -336,6 +336,21 @@ static void interface_get_init_info(QXLInstance *sin, QXLDevInitInfo *info) info->n_surfaces = NUM_SURFACES; } +static const char *qxl_mode_to_string(int mode) +{ + switch (mode) { + case QXL_MODE_COMPAT: + return "compat"; + case QXL_MODE_NATIVE: + return "native"; + case QXL_MODE_UNDEFINED: + return "undefined"; + case QXL_MODE_VGA: + return "vga"; + } + return "INVALID"; +} + /* called from spice server thread context only */ static int interface_get_command(QXLInstance *sin, struct QXLCommandExt *ext) { @@ -358,18 +373,19 @@ static int interface_get_command(QXLInstance *sin, struct QXLCommandExt *ext) } qemu_mutex_unlock(&qxl->ssd.lock); if (ret) { + dprint(qxl, 2, "%s %s\n", __FUNCTION__, qxl_mode_to_string(qxl->mode)); qxl_log_command(qxl, "vga", ext); } return ret; case QXL_MODE_COMPAT: case QXL_MODE_NATIVE: case QXL_MODE_UNDEFINED: - dprint(qxl, 2, "%s: %s\n", __FUNCTION__, - qxl->cmdflags ? "compat" : "native"); + dprint(qxl, 4, "%s: %s\n", __FUNCTION__, qxl_mode_to_string(qxl->mode)); ring = &qxl->ram->cmd_ring; if (SPICE_RING_IS_EMPTY(ring)) { return false; } + dprint(qxl, 2, "%s: %s\n", __FUNCTION__, qxl_mode_to_string(qxl->mode)); SPICE_RING_CONS_ITEM(ring, cmd); ext->cmd = *cmd; ext->group_id = MEMSLOT_GROUP_GUEST; @@ -926,6 +942,8 @@ static void ioport_write(void *opaque, uint32_t addr, uint32_t val) case QXL_IO_MEMSLOT_ADD: case QXL_IO_MEMSLOT_DEL: case QXL_IO_CREATE_PRIMARY: + case QXL_IO_UPDATE_IRQ: + case QXL_IO_LOG: break; default: if (d->mode == QXL_MODE_NATIVE || d->mode == QXL_MODE_COMPAT) @@ -969,7 +987,8 @@ static void ioport_write(void *opaque, uint32_t addr, uint32_t val) break; case QXL_IO_LOG: if (d->guestdebug) { - fprintf(stderr, "qxl/guest: %s", d->ram->log_buf); + fprintf(stderr, "qxl/guest-%d: %ld: %s", d->id, + qemu_get_clock_ns(vm_clock), d->ram->log_buf); } break; case QXL_IO_RESET: @@ -993,7 +1012,7 @@ static void ioport_write(void *opaque, uint32_t addr, uint32_t val) break; case QXL_IO_DESTROY_PRIMARY: PANIC_ON(val != 0); - dprint(d, 1, "QXL_IO_DESTROY_PRIMARY\n"); + dprint(d, 1, "QXL_IO_DESTROY_PRIMARY (%s)\n", qxl_mode_to_string(d->mode)); qxl_destroy_primary(d); break; case QXL_IO_DESTROY_SURFACE_WAIT: @@ -1167,11 +1186,14 @@ static void qxl_vm_change_state_handler(void *opaque, int running, int reason) qemu_spice_vm_change_state_handler(&qxl->ssd, running, reason); if (!running && qxl->mode == QXL_MODE_NATIVE) { - /* dirty all vram (which holds surfaces) to make sure it is saved */ + /* dirty all vram (which holds surfaces) and devram (primary surface) + * to make sure they are saved */ /* FIXME #1: should go out during "live" stage */ /* FIXME #2: we only need to save the areas which are actually used */ - ram_addr_t addr = qxl->vram_offset; - qxl_set_dirty(addr, addr + qxl->vram_size); + ram_addr_t vram_addr = qxl->vram_offset; + ram_addr_t surface0_addr = qxl->vga.vram_offset + qxl->shadow_rom.draw_area_offset; + qxl_set_dirty(vram_addr, vram_addr + qxl->vram_size); + qxl_set_dirty(surface0_addr, surface0_addr + qxl->shadow_rom.surface0_area_size); } } @@ -1207,7 +1229,6 @@ static DisplayChangeListener display_listener = { static int qxl_init_common(PCIQXLDevice *qxl) { uint8_t* config = qxl->pci.config; - uint32_t pci_device_id; uint32_t pci_device_rev; uint32_t io_size; @@ -1218,20 +1239,14 @@ static int qxl_init_common(PCIQXLDevice *qxl) switch (qxl->revision) { case 1: /* spice 0.4 -- qxl-1 */ - pci_device_id = QXL_DEVICE_ID_STABLE; pci_device_rev = QXL_REVISION_STABLE_V04; break; case 2: /* spice 0.6 -- qxl-2 */ - pci_device_id = QXL_DEVICE_ID_STABLE; + default: pci_device_rev = QXL_REVISION_STABLE_V06; break; - default: /* experimental */ - pci_device_id = QXL_DEVICE_ID_DEVEL; - pci_device_rev = 1; - break; } - pci_config_set_device_id(config, pci_device_id); pci_set_byte(&config[PCI_REVISION_ID], pci_device_rev); pci_set_byte(&config[PCI_INTERRUPT_PIN], 1); @@ -1375,7 +1390,8 @@ static int qxl_post_load(void *opaque, int version) d->modes = (QXLModes*)((uint8_t*)d->rom + d->rom->modes_offset); - dprint(d, 1, "%s: restore mode\n", __FUNCTION__); + dprint(d, 1, "%s: restore mode (%s)\n", __FUNCTION__, + qxl_mode_to_string(d->mode)); newmode = d->mode; d->mode = QXL_MODE_UNDEFINED; switch (newmode) { @@ -1492,6 +1508,7 @@ static PCIDeviceInfo qxl_info_primary = { .config_write = qxl_write_config, .romfile = "vgabios-qxl.bin", .vendor_id = REDHAT_PCI_VENDOR_ID, + .device_id = QXL_DEVICE_ID_STABLE, .class_id = PCI_CLASS_DISPLAY_VGA, .qdev.props = (Property[]) { DEFINE_PROP_UINT32("ram_size", PCIQXLDevice, vga.vram_size, 64 * 1024 * 1024), @@ -1512,6 +1529,7 @@ static PCIDeviceInfo qxl_info_secondary = { .qdev.vmsd = &qxl_vmstate, .init = qxl_init_secondary, .vendor_id = REDHAT_PCI_VENDOR_ID, + .device_id = QXL_DEVICE_ID_STABLE, .class_id = PCI_CLASS_DISPLAY_OTHER, .qdev.props = (Property[]) { DEFINE_PROP_UINT32("ram_size", PCIQXLDevice, vga.vram_size, 64 * 1024 * 1024), diff --git a/hw/s390-virtio-bus.c b/hw/s390-virtio-bus.c index d4a12f7531..e2f3e32aca 100644 --- a/hw/s390-virtio-bus.c +++ b/hw/s390-virtio-bus.c @@ -128,7 +128,8 @@ static int s390_virtio_blk_init(VirtIOS390Device *dev) { VirtIODevice *vdev; - vdev = virtio_blk_init((DeviceState *)dev, &dev->block); + vdev = virtio_blk_init((DeviceState *)dev, &dev->block, + &dev->block_serial); if (!vdev) { return -1; } @@ -165,7 +166,7 @@ static uint64_t s390_virtio_device_vq_token(VirtIOS390Device *dev, int vq) (vq * VIRTIO_VQCONFIG_LEN) + VIRTIO_VQCONFIG_OFFS_TOKEN; - return ldq_phys(token_off); + return ldq_be_phys(token_off); } static ram_addr_t s390_virtio_device_num_vq(VirtIOS390Device *dev) @@ -219,8 +220,8 @@ void s390_virtio_device_sync(VirtIOS390Device *dev) vring = s390_virtio_next_ring(bus); virtio_queue_set_addr(dev->vdev, i, vring); virtio_queue_set_vector(dev->vdev, i, i); - stq_phys(vq + VIRTIO_VQCONFIG_OFFS_ADDRESS, vring); - stw_phys(vq + VIRTIO_VQCONFIG_OFFS_NUM, virtio_queue_get_num(dev->vdev, i)); + stq_be_phys(vq + VIRTIO_VQCONFIG_OFFS_ADDRESS, vring); + stw_be_phys(vq + VIRTIO_VQCONFIG_OFFS_NUM, virtio_queue_get_num(dev->vdev, i)); } cur_offs = dev->dev_offs; @@ -228,7 +229,7 @@ void s390_virtio_device_sync(VirtIOS390Device *dev) cur_offs += num_vq * VIRTIO_VQCONFIG_LEN; /* Sync feature bitmap */ - stl_phys(cur_offs, bswap32(dev->host_features)); + stl_le_phys(cur_offs, dev->host_features); dev->feat_offs = cur_offs + dev->feat_len; cur_offs += dev->feat_len * 2; @@ -252,7 +253,7 @@ void s390_virtio_device_update_status(VirtIOS390Device *dev) /* Update guest supported feature bitmap */ - features = bswap32(ldl_phys(dev->feat_offs)); + features = bswap32(ldl_be_phys(dev->feat_offs)); if (vdev->set_features) { vdev->set_features(vdev, features); } @@ -355,6 +356,7 @@ static VirtIOS390DeviceInfo s390_virtio_blk = { .qdev.size = sizeof(VirtIOS390Device), .qdev.props = (Property[]) { DEFINE_BLOCK_PROPERTIES(VirtIOS390Device, block), + DEFINE_PROP_STRING("serial", VirtIOS390Device, block_serial), DEFINE_PROP_END_OF_LIST(), }, }; diff --git a/hw/s390-virtio-bus.h b/hw/s390-virtio-bus.h index 0c412d08e1..f1bece738b 100644 --- a/hw/s390-virtio-bus.h +++ b/hw/s390-virtio-bus.h @@ -42,6 +42,7 @@ typedef struct VirtIOS390Device { uint8_t feat_len; VirtIODevice *vdev; BlockConf block; + char *block_serial; NICConf nic; uint32_t host_features; virtio_serial_conf serial; diff --git a/hw/s390-virtio.c b/hw/s390-virtio.c index 3eba7ea1e8..abe954dc88 100644 --- a/hw/s390-virtio.c +++ b/hw/s390-virtio.c @@ -193,7 +193,7 @@ static void s390_init(ram_addr_t my_ram_size, if (kernel_filename) { kernel_size = load_image(kernel_filename, qemu_get_ram_ptr(0)); - if (lduw_phys(KERN_IMAGE_START) != 0x0dd0) { + if (lduw_be_phys(KERN_IMAGE_START) != 0x0dd0) { fprintf(stderr, "Specified image is not an s390 boot image\n"); exit(1); } @@ -232,8 +232,8 @@ static void s390_init(ram_addr_t my_ram_size, } initrd_size = load_image(initrd_filename, qemu_get_ram_ptr(initrd_offset)); - stq_phys(INITRD_PARM_START, initrd_offset); - stq_phys(INITRD_PARM_SIZE, initrd_size); + stq_be_phys(INITRD_PARM_START, initrd_offset); + stq_be_phys(INITRD_PARM_SIZE, initrd_size); } if (kernel_cmdline) { diff --git a/hw/sh7750.c b/hw/sh7750.c index 19d5bf8537..4f279e7e51 100644 --- a/hw/sh7750.c +++ b/hw/sh7750.c @@ -29,7 +29,6 @@ #include "sh7750_regs.h" #include "sh7750_regnames.h" #include "sh_intc.h" -#include "exec-all.h" #include "cpu.h" #define NB_DEVICES 4 diff --git a/hw/spapr.h b/hw/spapr.h index b52133a4aa..263691b6fb 100644 --- a/hw/spapr.h +++ b/hw/spapr.h @@ -280,12 +280,12 @@ target_ulong spapr_hypercall(CPUState *env, target_ulong opcode, static inline uint32_t rtas_ld(target_ulong phys, int n) { - return ldl_phys(phys + 4*n); + return ldl_be_phys(phys + 4*n); } static inline void rtas_st(target_ulong phys, int n, uint32_t val) { - stl_phys(phys + 4*n, val); + stl_be_phys(phys + 4*n, val); } typedef void (*spapr_rtas_fn)(sPAPREnvironment *spapr, uint32_t token, diff --git a/hw/spapr_hcall.c b/hw/spapr_hcall.c index 43c441dc7d..5cd8d8f5ae 100644 --- a/hw/spapr_hcall.c +++ b/hw/spapr_hcall.c @@ -3,7 +3,6 @@ #include "qemu-char.h" #include "sysemu.h" #include "qemu-char.h" -#include "exec-all.h" #include "exec.h" #include "helper_regs.h" #include "hw/spapr.h" @@ -279,7 +278,7 @@ static target_ulong register_vpa(CPUState *env, target_ulong vpa) } /* FIXME: bounds check the address */ - size = lduw_phys(vpa + 0x4); + size = lduw_be_phys(vpa + 0x4); if (size < VPA_MIN_SIZE) { return H_PARAMETER; @@ -322,7 +321,7 @@ static target_ulong register_slb_shadow(CPUState *env, target_ulong addr) return H_HARDWARE; } - size = ldl_phys(addr + 0x4); + size = ldl_be_phys(addr + 0x4); if (size < 0x8) { return H_PARAMETER; } @@ -355,7 +354,7 @@ static target_ulong register_dtl(CPUState *env, target_ulong addr) return H_HARDWARE; } - size = ldl_phys(addr + 0x4); + size = ldl_be_phys(addr + 0x4); if (size < 48) { return H_PARAMETER; @@ -442,9 +441,9 @@ static target_ulong h_rtas(CPUState *env, sPAPREnvironment *spapr, target_ulong opcode, target_ulong *args) { target_ulong rtas_r3 = args[0]; - uint32_t token = ldl_phys(rtas_r3); - uint32_t nargs = ldl_phys(rtas_r3 + 4); - uint32_t nret = ldl_phys(rtas_r3 + 8); + uint32_t token = ldl_be_phys(rtas_r3); + uint32_t nargs = ldl_be_phys(rtas_r3 + 4); + uint32_t nret = ldl_be_phys(rtas_r3 + 8); return spapr_rtas_call(spapr, token, nargs, rtas_r3 + 12, nret, rtas_r3 + 12 + 4*nargs); diff --git a/hw/strongarm.c b/hw/strongarm.c index de08bdf674..0e03d61a1f 100644 --- a/hw/strongarm.c +++ b/hw/strongarm.c @@ -1536,14 +1536,14 @@ StrongARMState *sa1110_init(unsigned int sdram_size, const char *rev) } if (strncmp(rev, "sa1110", 6)) { - error_report("Machine requires a SA1110 processor.\n"); + error_report("Machine requires a SA1110 processor."); exit(1); } s->env = cpu_init(rev); if (!s->env) { - error_report("Unable to find CPU definition\n"); + error_report("Unable to find CPU definition"); exit(1); } diff --git a/hw/usb-bt.c b/hw/usb-bt.c index baae4876ea..e364513a01 100644 --- a/hw/usb-bt.c +++ b/hw/usb-bt.c @@ -99,13 +99,13 @@ static const USBDescIface desc_iface_bluetooth[] = { .eps = (USBDescEndpoint[]) { { .bEndpointAddress = USB_DIR_OUT | USB_SCO_EP, - .bmAttributes = USB_ENDPOINT_XFER_INT, + .bmAttributes = USB_ENDPOINT_XFER_ISOC, .wMaxPacketSize = 0, .bInterval = 0x01, }, { .bEndpointAddress = USB_DIR_IN | USB_SCO_EP, - .bmAttributes = USB_ENDPOINT_XFER_INT, + .bmAttributes = USB_ENDPOINT_XFER_ISOC, .wMaxPacketSize = 0, .bInterval = 0x01, }, @@ -120,13 +120,13 @@ static const USBDescIface desc_iface_bluetooth[] = { .eps = (USBDescEndpoint[]) { { .bEndpointAddress = USB_DIR_OUT | USB_SCO_EP, - .bmAttributes = USB_ENDPOINT_XFER_INT, + .bmAttributes = USB_ENDPOINT_XFER_ISOC, .wMaxPacketSize = 0x09, .bInterval = 0x01, }, { .bEndpointAddress = USB_DIR_IN | USB_SCO_EP, - .bmAttributes = USB_ENDPOINT_XFER_INT, + .bmAttributes = USB_ENDPOINT_XFER_ISOC, .wMaxPacketSize = 0x09, .bInterval = 0x01, }, @@ -141,13 +141,13 @@ static const USBDescIface desc_iface_bluetooth[] = { .eps = (USBDescEndpoint[]) { { .bEndpointAddress = USB_DIR_OUT | USB_SCO_EP, - .bmAttributes = USB_ENDPOINT_XFER_INT, + .bmAttributes = USB_ENDPOINT_XFER_ISOC, .wMaxPacketSize = 0x11, .bInterval = 0x01, }, { .bEndpointAddress = USB_DIR_IN | USB_SCO_EP, - .bmAttributes = USB_ENDPOINT_XFER_INT, + .bmAttributes = USB_ENDPOINT_XFER_ISOC, .wMaxPacketSize = 0x11, .bInterval = 0x01, }, @@ -162,13 +162,13 @@ static const USBDescIface desc_iface_bluetooth[] = { .eps = (USBDescEndpoint[]) { { .bEndpointAddress = USB_DIR_OUT | USB_SCO_EP, - .bmAttributes = USB_ENDPOINT_XFER_INT, + .bmAttributes = USB_ENDPOINT_XFER_ISOC, .wMaxPacketSize = 0x19, .bInterval = 0x01, }, { .bEndpointAddress = USB_DIR_IN | USB_SCO_EP, - .bmAttributes = USB_ENDPOINT_XFER_INT, + .bmAttributes = USB_ENDPOINT_XFER_ISOC, .wMaxPacketSize = 0x19, .bInterval = 0x01, }, @@ -183,13 +183,13 @@ static const USBDescIface desc_iface_bluetooth[] = { .eps = (USBDescEndpoint[]) { { .bEndpointAddress = USB_DIR_OUT | USB_SCO_EP, - .bmAttributes = USB_ENDPOINT_XFER_INT, + .bmAttributes = USB_ENDPOINT_XFER_ISOC, .wMaxPacketSize = 0x21, .bInterval = 0x01, }, { .bEndpointAddress = USB_DIR_IN | USB_SCO_EP, - .bmAttributes = USB_ENDPOINT_XFER_INT, + .bmAttributes = USB_ENDPOINT_XFER_ISOC, .wMaxPacketSize = 0x21, .bInterval = 0x01, }, @@ -204,13 +204,13 @@ static const USBDescIface desc_iface_bluetooth[] = { .eps = (USBDescEndpoint[]) { { .bEndpointAddress = USB_DIR_OUT | USB_SCO_EP, - .bmAttributes = USB_ENDPOINT_XFER_INT, + .bmAttributes = USB_ENDPOINT_XFER_ISOC, .wMaxPacketSize = 0x31, .bInterval = 0x01, }, { .bEndpointAddress = USB_DIR_IN | USB_SCO_EP, - .bmAttributes = USB_ENDPOINT_XFER_INT, + .bmAttributes = USB_ENDPOINT_XFER_ISOC, .wMaxPacketSize = 0x31, .bInterval = 0x01, }, diff --git a/hw/usb-bus.c b/hw/usb-bus.c index 480956dfcf..f1dd55eccd 100644 --- a/hw/usb-bus.c +++ b/hw/usb-bus.c @@ -75,19 +75,17 @@ static int usb_qdev_init(DeviceState *qdev, DeviceInfo *base) QLIST_INIT(&dev->strings); rc = dev->info->init(dev); if (rc == 0 && dev->auto_attach) - usb_device_attach(dev); + rc = usb_device_attach(dev); return rc; } static int usb_qdev_exit(DeviceState *qdev) { USBDevice *dev = DO_UPCAST(USBDevice, qdev, qdev); - USBBus *bus = usb_bus_from_device(dev); if (dev->attached) { usb_device_detach(dev); } - bus->ops->device_destroy(bus, dev); if (dev->info->handle_destroy) { dev->info->handle_destroy(dev); } @@ -121,7 +119,7 @@ USBDevice *usb_create(USBBus *bus, const char *name) bus = usb_bus_find(-1); if (!bus) return NULL; - fprintf(stderr, "%s: no bus specified, using \"%s\" for \"%s\"\n", + error_report("%s: no bus specified, using \"%s\" for \"%s\"\n", __FUNCTION__, bus->qbus.name, name); } #endif @@ -140,19 +138,55 @@ USBDevice *usb_create_simple(USBBus *bus, const char *name) return dev; } -void usb_register_port(USBBus *bus, USBPort *port, void *opaque, int index, - USBPortOps *ops, int speedmask) +static void usb_fill_port(USBPort *port, void *opaque, int index, + USBPortOps *ops, int speedmask) { port->opaque = opaque; port->index = index; - port->opaque = opaque; - port->index = index; port->ops = ops; port->speedmask = speedmask; + usb_port_location(port, NULL, index + 1); +} + +void usb_register_port(USBBus *bus, USBPort *port, void *opaque, int index, + USBPortOps *ops, int speedmask) +{ + usb_fill_port(port, opaque, index, ops, speedmask); QTAILQ_INSERT_TAIL(&bus->free, port, next); bus->nfree++; } +int usb_register_companion(const char *masterbus, USBPort *ports[], + uint32_t portcount, uint32_t firstport, + void *opaque, USBPortOps *ops, int speedmask) +{ + USBBus *bus; + int i; + + QTAILQ_FOREACH(bus, &busses, next) { + if (strcmp(bus->qbus.name, masterbus) == 0) { + break; + } + } + + if (!bus || !bus->ops->register_companion) { + qerror_report(QERR_INVALID_PARAMETER_VALUE, "masterbus", + "an USB masterbus"); + if (bus) { + error_printf_unless_qmp( + "USB bus '%s' does not allow companion controllers\n", + masterbus); + } + return -1; + } + + for (i = 0; i < portcount; i++) { + usb_fill_port(ports[i], opaque, i, ops, speedmask); + } + + return bus->ops->register_companion(bus, ports, portcount, firstport); +} + void usb_port_location(USBPort *downstream, USBPort *upstream, int portnr) { if (upstream) { @@ -171,15 +205,20 @@ void usb_unregister_port(USBBus *bus, USBPort *port) bus->nfree--; } -static void do_attach(USBDevice *dev) +static int do_attach(USBDevice *dev) { USBBus *bus = usb_bus_from_device(dev); USBPort *port; if (dev->attached) { - fprintf(stderr, "Warning: tried to attach usb device %s twice\n", + error_report("Error: tried to attach usb device %s twice\n", dev->product_desc); - return; + return -1; + } + if (bus->nfree == 0) { + error_report("Error: tried to attach usb device %s to a bus with no free ports\n", + dev->product_desc); + return -1; } if (dev->port_path) { QTAILQ_FOREACH(port, &bus->free, next) { @@ -188,13 +227,18 @@ static void do_attach(USBDevice *dev) } } if (port == NULL) { - fprintf(stderr, "Warning: usb port %s (bus %s) not found\n", + error_report("Error: usb port %s (bus %s) not found\n", dev->port_path, bus->qbus.name); - return; + return -1; } } else { port = QTAILQ_FIRST(&bus->free); } + if (!(port->speedmask & dev->speedmask)) { + error_report("Warning: speed mismatch trying to attach usb device %s to bus %s\n", + dev->product_desc, bus->qbus.name); + return -1; + } dev->attached++; QTAILQ_REMOVE(&bus->free, port, next); @@ -204,6 +248,8 @@ static void do_attach(USBDevice *dev) QTAILQ_INSERT_TAIL(&bus->used, port, next); bus->nused++; + + return 0; } int usb_device_attach(USBDevice *dev) @@ -215,8 +261,7 @@ int usb_device_attach(USBDevice *dev) (unless a physical port location is specified). */ usb_create_simple(bus, "usb-hub"); } - do_attach(dev); - return 0; + return do_attach(dev); } int usb_device_detach(USBDevice *dev) @@ -225,7 +270,7 @@ int usb_device_detach(USBDevice *dev) USBPort *port; if (!dev->attached) { - fprintf(stderr, "Warning: tried to detach unattached usb device %s\n", + error_report("Error: tried to detach unattached usb device %s\n", dev->product_desc); return -1; } diff --git a/hw/usb-ccid.c b/hw/usb-ccid.c index 59c6431676..d3922998c5 100644 --- a/hw/usb-ccid.c +++ b/hw/usb-ccid.c @@ -1240,7 +1240,7 @@ static int ccid_card_init(DeviceState *qdev, DeviceInfo *base) return -1; } if (s->card != NULL) { - error_report("Warning: usb-ccid card already full, not adding\n"); + error_report("Warning: usb-ccid card already full, not adding"); return -1; } ret = info->initfn ? info->initfn(card) : ret; @@ -1271,6 +1271,7 @@ static int ccid_initfn(USBDevice *dev) s->migration_target_ip = 0; s->migration_target_port = 0; s->dev.speed = USB_SPEED_FULL; + s->dev.speedmask = USB_SPEED_MASK_FULL; s->notify_slot_change = false; s->powered = true; s->pending_answers_num = 0; diff --git a/hw/usb-desc.c b/hw/usb-desc.c index e4a4680fee..bc6858f62f 100644 --- a/hw/usb-desc.c +++ b/hw/usb-desc.c @@ -242,7 +242,17 @@ static void usb_desc_setdefaults(USBDevice *dev) void usb_desc_init(USBDevice *dev) { + const USBDesc *desc = dev->info->usb_desc; + + assert(desc != NULL); dev->speed = USB_SPEED_FULL; + dev->speedmask = 0; + if (desc->full) { + dev->speedmask |= USB_SPEED_MASK_FULL; + } + if (desc->high) { + dev->speedmask |= USB_SPEED_MASK_HIGH; + } usb_desc_setdefaults(dev); } @@ -375,6 +385,10 @@ int usb_desc_get_descriptor(USBDevice *dev, int value, uint8_t *dest, size_t len trace_usb_desc_other_speed_config(dev->addr, index, len, ret); break; + case USB_DT_DEBUG: + /* ignore silently */ + break; + default: fprintf(stderr, "%s: %d unknown type %d (len %zd)\n", __FUNCTION__, dev->addr, type, len); diff --git a/hw/usb-ehci.c b/hw/usb-ehci.c index e33e546b43..a4758f976e 100644 --- a/hw/usb-ehci.c +++ b/hw/usb-ehci.c @@ -20,9 +20,6 @@ * * You should have received a copy of the GNU General Public License * along with this program; if not, see <http://www.gnu.org/licenses/>. - * - * TODO: - * o Downstream port handoff */ #include "hw.h" @@ -103,10 +100,10 @@ #define PORTSC_BEGIN PORTSC #define PORTSC_END (PORTSC + 4 * NB_PORTS) /* - * Bits that are reserverd or are read-only are masked out of values + * Bits that are reserved or are read-only are masked out of values * written to us by software */ -#define PORTSC_RO_MASK 0x007021c5 +#define PORTSC_RO_MASK 0x007001c0 #define PORTSC_RWC_MASK 0x0000002a #define PORTSC_WKOC_E (1 << 22) // Wake on Over Current Enable #define PORTSC_WKDS_E (1 << 21) // Wake on Disconnect Enable @@ -130,10 +127,10 @@ #define PORTSC_CONNECT (1 << 0) // Current Connect Status #define FRAME_TIMER_FREQ 1000 -#define FRAME_TIMER_USEC (1000000 / FRAME_TIMER_FREQ) +#define FRAME_TIMER_NS (1000000000 / FRAME_TIMER_FREQ) #define NB_MAXINTRATE 8 // Max rate at which controller issues ints -#define NB_PORTS 4 // Number of downstream ports +#define NB_PORTS 6 // Number of downstream ports #define BUFF_SIZE 5*4096 // Max bytes to transfer per transaction #define MAX_ITERATIONS 20 // Max number of QH before we break the loop #define MAX_QH 100 // Max allowable queue heads in a chain @@ -348,7 +345,8 @@ struct EHCIQueue { EHCIState *ehci; QTAILQ_ENTRY(EHCIQueue) next; bool async_schedule; - uint32_t seen, ts; + uint32_t seen; + uint64_t ts; /* cached data from guest - needs to be flushed * when guest removes an entry (doorbell, handshake sequence) @@ -372,7 +370,12 @@ struct EHCIState { qemu_irq irq; target_phys_addr_t mem_base; int mem; - int num_ports; + int companion_count; + + /* properties */ + uint32_t freq; + uint32_t maxframes; + /* * EHCI spec version 1.0 Section 2.3 * Host Controller Operational Registers @@ -403,6 +406,7 @@ struct EHCIState { int astate; // Current state in asynchronous schedule int pstate; // Current state in periodic schedule USBPort ports[NB_PORTS]; + USBPort *companion_ports[NB_PORTS]; uint32_t usbsts_pending; QTAILQ_HEAD(, EHCIQueue) queues; @@ -413,12 +417,11 @@ struct EHCIState { uint8_t ibuffer[BUFF_SIZE]; int isoch_pause; - uint32_t last_run_usec; - uint32_t frame_end_usec; + uint64_t last_run_ns; }; #define SET_LAST_RUN_CLOCK(s) \ - (s)->last_run_usec = qemu_get_clock_ns(vm_clock) / 1000; + (s)->last_run_ns = qemu_get_clock_ns(vm_clock); /* nifty macros from Arnon's EHCI version */ #define get_field(data, field) \ @@ -685,10 +688,10 @@ static void ehci_queues_rip_unused(EHCIState *ehci) QTAILQ_FOREACH_SAFE(q, &ehci->queues, next, tmp) { if (q->seen) { q->seen = 0; - q->ts = ehci->last_run_usec; + q->ts = ehci->last_run_ns; continue; } - if (ehci->last_run_usec < q->ts + 250000) { + if (ehci->last_run_ns < q->ts + 250000000) { /* allow 0.25 sec idle */ continue; } @@ -726,17 +729,17 @@ static void ehci_attach(USBPort *port) trace_usb_ehci_port_attach(port->index, port->dev->product_desc); + if (*portsc & PORTSC_POWNER) { + USBPort *companion = s->companion_ports[port->index]; + companion->dev = port->dev; + companion->ops->attach(companion); + return; + } + *portsc |= PORTSC_CONNECT; *portsc |= PORTSC_CSC; - /* - * If a high speed device is attached then we own this port(indicated - * by zero in the PORTSC_POWNER bit field) so set the status bit - * and set an interrupt if enabled. - */ - if ( !(*portsc & PORTSC_POWNER)) { - ehci_set_interrupt(s, USBSTS_PCD); - } + ehci_set_interrupt(s, USBSTS_PCD); } static void ehci_detach(USBPort *port) @@ -746,17 +749,88 @@ static void ehci_detach(USBPort *port) trace_usb_ehci_port_detach(port->index); - *portsc &= ~PORTSC_CONNECT; + if (*portsc & PORTSC_POWNER) { + USBPort *companion = s->companion_ports[port->index]; + companion->ops->detach(companion); + companion->dev = NULL; + return; + } + + ehci_queues_rip_device(s, port->dev); + + *portsc &= ~(PORTSC_CONNECT|PORTSC_PED); *portsc |= PORTSC_CSC; - /* - * If a high speed device is attached then we own this port(indicated - * by zero in the PORTSC_POWNER bit field) so set the status bit - * and set an interrupt if enabled. - */ - if ( !(*portsc & PORTSC_POWNER)) { - ehci_set_interrupt(s, USBSTS_PCD); + ehci_set_interrupt(s, USBSTS_PCD); +} + +static void ehci_child_detach(USBPort *port, USBDevice *child) +{ + EHCIState *s = port->opaque; + uint32_t portsc = s->portsc[port->index]; + + if (portsc & PORTSC_POWNER) { + USBPort *companion = s->companion_ports[port->index]; + companion->ops->child_detach(companion, child); + companion->dev = NULL; + return; } + + ehci_queues_rip_device(s, child); +} + +static void ehci_wakeup(USBPort *port) +{ + EHCIState *s = port->opaque; + uint32_t portsc = s->portsc[port->index]; + + if (portsc & PORTSC_POWNER) { + USBPort *companion = s->companion_ports[port->index]; + if (companion->ops->wakeup) { + companion->ops->wakeup(companion); + } + } +} + +static int ehci_register_companion(USBBus *bus, USBPort *ports[], + uint32_t portcount, uint32_t firstport) +{ + EHCIState *s = container_of(bus, EHCIState, bus); + uint32_t i; + + if (firstport + portcount > NB_PORTS) { + qerror_report(QERR_INVALID_PARAMETER_VALUE, "firstport", + "firstport on masterbus"); + error_printf_unless_qmp( + "firstport value of %u makes companion take ports %u - %u, which " + "is outside of the valid range of 0 - %u\n", firstport, firstport, + firstport + portcount - 1, NB_PORTS - 1); + return -1; + } + + for (i = 0; i < portcount; i++) { + if (s->companion_ports[firstport + i]) { + qerror_report(QERR_INVALID_PARAMETER_VALUE, "masterbus", + "an USB masterbus"); + error_printf_unless_qmp( + "port %u on masterbus %s already has a companion assigned\n", + firstport + i, bus->qbus.name); + return -1; + } + } + + for (i = 0; i < portcount; i++) { + s->companion_ports[firstport + i] = ports[i]; + s->ports[firstport + i].speedmask |= + USB_SPEED_MASK_LOW | USB_SPEED_MASK_FULL; + /* Ensure devs attached before the initial reset go to the companion */ + s->portsc[firstport + i] = PORTSC_POWNER; + } + + s->companion_count++; + s->mmio[0x05] = (s->companion_count << 4) | portcount; + + return 0; } /* 4.1 host controller initialization */ @@ -764,9 +838,21 @@ static void ehci_reset(void *opaque) { EHCIState *s = opaque; int i; + USBDevice *devs[NB_PORTS]; trace_usb_ehci_reset(); + /* + * Do the detach before touching portsc, so that it correctly gets send to + * us or to our companion based on PORTSC_POWNER before the reset. + */ + for(i = 0; i < NB_PORTS; i++) { + devs[i] = s->ports[i].dev; + if (devs[i]) { + usb_attach(&s->ports[i], NULL); + } + } + memset(&s->mmio[OPREGBASE], 0x00, MMIO_SIZE - OPREGBASE); s->usbcmd = NB_MAXINTRATE << USBCMD_ITC_SH; @@ -778,10 +864,13 @@ static void ehci_reset(void *opaque) s->attach_poll_counter = 0; for(i = 0; i < NB_PORTS; i++) { - s->portsc[i] = PORTSC_POWNER | PORTSC_PPOWER; - - if (s->ports[i].dev) { - usb_attach(&s->ports[i], s->ports[i].dev); + if (s->companion_ports[i]) { + s->portsc[i] = PORTSC_POWNER | PORTSC_PPOWER; + } else { + s->portsc[i] = PORTSC_PPOWER; + } + if (devs[i]) { + usb_attach(&s->ports[i], devs[i]); } } ehci_queues_rip_all(s); @@ -831,43 +920,67 @@ static void ehci_mem_writew(void *ptr, target_phys_addr_t addr, uint32_t val) exit(1); } +static void handle_port_owner_write(EHCIState *s, int port, uint32_t owner) +{ + USBDevice *dev = s->ports[port].dev; + uint32_t *portsc = &s->portsc[port]; + uint32_t orig; + + if (s->companion_ports[port] == NULL) + return; + + owner = owner & PORTSC_POWNER; + orig = *portsc & PORTSC_POWNER; + + if (!(owner ^ orig)) { + return; + } + + if (dev) { + usb_attach(&s->ports[port], NULL); + } + + *portsc &= ~PORTSC_POWNER; + *portsc |= owner; + + if (dev) { + usb_attach(&s->ports[port], dev); + } +} + static void handle_port_status_write(EHCIState *s, int port, uint32_t val) { uint32_t *portsc = &s->portsc[port]; - int rwc; USBDevice *dev = s->ports[port].dev; - rwc = val & PORTSC_RWC_MASK; + /* Clear rwc bits */ + *portsc &= ~(val & PORTSC_RWC_MASK); + /* The guest may clear, but not set the PED bit */ + *portsc &= val | ~PORTSC_PED; + /* POWNER is masked out by RO_MASK as it is RO when we've no companion */ + handle_port_owner_write(s, port, val); + /* And finally apply RO_MASK */ val &= PORTSC_RO_MASK; - // handle_read_write_clear(&val, portsc, PORTSC_PEDC | PORTSC_CSC); - - *portsc &= ~rwc; - if ((val & PORTSC_PRESET) && !(*portsc & PORTSC_PRESET)) { trace_usb_ehci_port_reset(port, 1); } if (!(val & PORTSC_PRESET) &&(*portsc & PORTSC_PRESET)) { trace_usb_ehci_port_reset(port, 0); - usb_attach(&s->ports[port], dev); - - // TODO how to handle reset of ports with no device if (dev) { + usb_attach(&s->ports[port], dev); usb_send_msg(dev, USB_MSG_RESET); - } - - if (s->ports[port].dev) { *portsc &= ~PORTSC_CSC; } - /* Table 2.16 Set the enable bit(and enable bit change) to indicate + /* + * Table 2.16 Set the enable bit(and enable bit change) to indicate * to SW that this port has a high speed device attached - * - * TODO - when to disable? */ - val |= PORTSC_PED; - val |= PORTSC_PEDC; + if (dev && (dev->speedmask & USB_SPEED_MASK_HIGH)) { + val |= PORTSC_PED; + } } *portsc &= ~PORTSC_RO_MASK; @@ -950,7 +1063,7 @@ static void ehci_mem_writel(void *ptr, target_phys_addr_t addr, uint32_t val) val &= 0x1; if (val) { for(i = 0; i < NB_PORTS; i++) - s->portsc[i] &= ~PORTSC_POWNER; + handle_port_owner_write(s, i, 0); } break; @@ -1106,10 +1219,19 @@ static int ehci_buffer_rw(EHCIQueue *q, int bytes, int rw) return 0; } -static void ehci_async_complete_packet(USBDevice *dev, USBPacket *packet) +static void ehci_async_complete_packet(USBPort *port, USBPacket *packet) { - EHCIQueue *q = container_of(packet, EHCIQueue, packet); + EHCIQueue *q; + EHCIState *s = port->opaque; + uint32_t portsc = s->portsc[port->index]; + + if (portsc & PORTSC_POWNER) { + USBPort *companion = s->companion_ports[port->index]; + companion->ops->complete(companion, packet); + return; + } + q = container_of(packet, EHCIQueue, packet); trace_usb_ehci_queue_action(q, "wakeup"); assert(q->async == EHCI_ASYNC_INFLIGHT); q->async = EHCI_ASYNC_FINISHED; @@ -1239,8 +1361,6 @@ static int ehci_execute(EHCIQueue *q) port = &q->ehci->ports[i]; dev = port->dev; - // TODO sometime we will also need to check if we are the port owner - if (!(q->ehci->portsc[i] &(PORTSC_CONNECT))) { DPRINTF("Port %d, no exec, not connected(%08X)\n", i, q->ehci->portsc[i]); @@ -1333,8 +1453,6 @@ static int ehci_process_itd(EHCIState *ehci, port = &ehci->ports[j]; dev = port->dev; - // TODO sometime we will also need to check if we are the port owner - if (!(ehci->portsc[j] &(PORTSC_CONNECT))) { continue; } @@ -2040,23 +2158,16 @@ static void ehci_frame_timer(void *opaque) { EHCIState *ehci = opaque; int64_t expire_time, t_now; - int usec_elapsed; + uint64_t ns_elapsed; int frames; - int usec_now; int i; int skipped_frames = 0; - t_now = qemu_get_clock_ns(vm_clock); - expire_time = t_now + (get_ticks_per_sec() / FRAME_TIMER_FREQ); - if (expire_time == t_now) { - expire_time++; - } + expire_time = t_now + (get_ticks_per_sec() / ehci->freq); - usec_now = t_now / 1000; - usec_elapsed = usec_now - ehci->last_run_usec; - frames = usec_elapsed / FRAME_TIMER_USEC; - ehci->frame_end_usec = usec_now + FRAME_TIMER_USEC - 10; + ns_elapsed = t_now - ehci->last_run_ns; + frames = ns_elapsed / FRAME_TIMER_NS; for (i = 0; i < frames; i++) { if ( !(ehci->usbsts & USBSTS_HALT)) { @@ -2073,13 +2184,13 @@ static void ehci_frame_timer(void *opaque) ehci->sofv &= 0x000003ff; } - if (frames - i > 10) { + if (frames - i > ehci->maxframes) { skipped_frames++; } else { ehci_advance_periodic_state(ehci); } - ehci->last_run_usec += FRAME_TIMER_USEC; + ehci->last_run_ns += FRAME_TIMER_NS; } #if 0 @@ -2119,33 +2230,48 @@ static void ehci_map(PCIDevice *pci_dev, int region_num, cpu_register_physical_memory(addr, size, s->mem); } -static void ehci_device_destroy(USBBus *bus, USBDevice *dev) -{ - EHCIState *s = container_of(bus, EHCIState, bus); - - ehci_queues_rip_device(s, dev); -} - static int usb_ehci_initfn(PCIDevice *dev); static USBPortOps ehci_port_ops = { .attach = ehci_attach, .detach = ehci_detach, + .child_detach = ehci_child_detach, + .wakeup = ehci_wakeup, .complete = ehci_async_complete_packet, }; static USBBusOps ehci_bus_ops = { - .device_destroy = ehci_device_destroy, + .register_companion = ehci_register_companion, }; -static PCIDeviceInfo ehci_info = { - .qdev.name = "usb-ehci", - .qdev.size = sizeof(EHCIState), - .init = usb_ehci_initfn, - .vendor_id = PCI_VENDOR_ID_INTEL, - .device_id = PCI_DEVICE_ID_INTEL_82801D, - .revision = 0x10, - .class_id = PCI_CLASS_SERIAL_USB, +static Property ehci_properties[] = { + DEFINE_PROP_UINT32("freq", EHCIState, freq, FRAME_TIMER_FREQ), + DEFINE_PROP_UINT32("maxframes", EHCIState, maxframes, 128), + DEFINE_PROP_END_OF_LIST(), +}; + +static PCIDeviceInfo ehci_info[] = { + { + .qdev.name = "usb-ehci", + .qdev.size = sizeof(EHCIState), + .init = usb_ehci_initfn, + .vendor_id = PCI_VENDOR_ID_INTEL, + .device_id = PCI_DEVICE_ID_INTEL_82801D, /* ich4 */ + .revision = 0x10, + .class_id = PCI_CLASS_SERIAL_USB, + .qdev.props = ehci_properties, + },{ + .qdev.name = "ich9-usb-ehci1", + .qdev.size = sizeof(EHCIState), + .init = usb_ehci_initfn, + .vendor_id = PCI_VENDOR_ID_INTEL, + .device_id = PCI_DEVICE_ID_INTEL_82801I_EHCI1, + .revision = 0x03, + .class_id = PCI_CLASS_SERIAL_USB, + .qdev.props = ehci_properties, + },{ + /* end of list */ + } }; static int usb_ehci_initfn(PCIDevice *dev) @@ -2203,7 +2329,6 @@ static int usb_ehci_initfn(PCIDevice *dev) for(i = 0; i < NB_PORTS; i++) { usb_register_port(&s->bus, &s->ports[i], s, i, &ehci_port_ops, USB_SPEED_MASK_HIGH); - usb_port_location(&s->ports[i], NULL, i+1); s->ports[i].dev = 0; } @@ -2225,7 +2350,7 @@ static int usb_ehci_initfn(PCIDevice *dev) static void ehci_register(void) { - pci_qdev_register(&ehci_info); + pci_qdev_register_many(ehci_info); } device_init(ehci_register); diff --git a/hw/usb-hub.c b/hw/usb-hub.c index 6e2a35839d..b49a2fe882 100644 --- a/hw/usb-hub.c +++ b/hw/usb-hub.c @@ -138,74 +138,6 @@ static const USBDesc desc_hub = { .str = desc_strings, }; -static const uint8_t qemu_hub_dev_descriptor[] = { - 0x12, /* u8 bLength; */ - 0x01, /* u8 bDescriptorType; Device */ - 0x10, 0x01, /* u16 bcdUSB; v1.1 */ - - 0x09, /* u8 bDeviceClass; HUB_CLASSCODE */ - 0x00, /* u8 bDeviceSubClass; */ - 0x00, /* u8 bDeviceProtocol; [ low/full speeds only ] */ - 0x08, /* u8 bMaxPacketSize0; 8 Bytes */ - - 0x00, 0x00, /* u16 idVendor; */ - 0x00, 0x00, /* u16 idProduct; */ - 0x01, 0x01, /* u16 bcdDevice */ - - 0x03, /* u8 iManufacturer; */ - 0x02, /* u8 iProduct; */ - 0x01, /* u8 iSerialNumber; */ - 0x01 /* u8 bNumConfigurations; */ -}; - -/* XXX: patch interrupt size */ -static const uint8_t qemu_hub_config_descriptor[] = { - - /* one configuration */ - 0x09, /* u8 bLength; */ - 0x02, /* u8 bDescriptorType; Configuration */ - 0x19, 0x00, /* u16 wTotalLength; */ - 0x01, /* u8 bNumInterfaces; (1) */ - 0x01, /* u8 bConfigurationValue; */ - 0x00, /* u8 iConfiguration; */ - 0xe0, /* u8 bmAttributes; - Bit 7: must be set, - 6: Self-powered, - 5: Remote wakeup, - 4..0: resvd */ - 0x00, /* u8 MaxPower; */ - - /* USB 1.1: - * USB 2.0, single TT organization (mandatory): - * one interface, protocol 0 - * - * USB 2.0, multiple TT organization (optional): - * two interfaces, protocols 1 (like single TT) - * and 2 (multiple TT mode) ... config is - * sometimes settable - * NOT IMPLEMENTED - */ - - /* one interface */ - 0x09, /* u8 if_bLength; */ - 0x04, /* u8 if_bDescriptorType; Interface */ - 0x00, /* u8 if_bInterfaceNumber; */ - 0x00, /* u8 if_bAlternateSetting; */ - 0x01, /* u8 if_bNumEndpoints; */ - 0x09, /* u8 if_bInterfaceClass; HUB_CLASSCODE */ - 0x00, /* u8 if_bInterfaceSubClass; */ - 0x00, /* u8 if_bInterfaceProtocol; [usb1.1 or single tt] */ - 0x00, /* u8 if_iInterface; */ - - /* one endpoint (status change endpoint) */ - 0x07, /* u8 ep_bLength; */ - 0x05, /* u8 ep_bDescriptorType; Endpoint */ - 0x81, /* u8 ep_bEndpointAddress; IN Endpoint 1 */ - 0x03, /* u8 ep_bmAttributes; Interrupt */ - 0x02, 0x00, /* u16 ep_wMaxPacketSize; 1 + (MAX_ROOT_PORTS / 8) */ - 0xff /* u8 ep_bInterval; (255ms -- usb 2.0 spec) */ -}; - static const uint8_t qemu_hub_hub_descriptor[] = { 0x00, /* u8 bLength; patched in later */ @@ -238,6 +170,9 @@ static void usb_hub_detach(USBPort *port1) USBHubState *s = port1->opaque; USBHubPort *port = &s->ports[port1->index]; + /* Let upstream know the device on this port is gone */ + s->dev.port->ops->child_detach(s->dev.port, port1->dev); + port->wPortStatus &= ~PORT_STAT_CONNECTION; port->wPortChange |= PORT_STAT_C_CONNECTION; if (port->wPortStatus & PORT_STAT_ENABLE) { @@ -246,10 +181,18 @@ static void usb_hub_detach(USBPort *port1) } } -static void usb_hub_wakeup(USBDevice *dev) +static void usb_hub_child_detach(USBPort *port1, USBDevice *child) +{ + USBHubState *s = port1->opaque; + + /* Pass along upstream */ + s->dev.port->ops->child_detach(s->dev.port, child); +} + +static void usb_hub_wakeup(USBPort *port1) { - USBHubState *s = dev->port->opaque; - USBHubPort *port = &s->ports[dev->port->index]; + USBHubState *s = port1->opaque; + USBHubPort *port = &s->ports[port1->index]; if (port->wPortStatus & PORT_STAT_SUSPEND) { port->wPortChange |= PORT_STAT_C_SUSPEND; @@ -257,9 +200,9 @@ static void usb_hub_wakeup(USBDevice *dev) } } -static void usb_hub_complete(USBDevice *dev, USBPacket *packet) +static void usb_hub_complete(USBPort *port, USBPacket *packet) { - USBHubState *s = dev->port->opaque; + USBHubState *s = port->opaque; /* * Just pass it along upstream for now. @@ -537,6 +480,7 @@ static void usb_hub_handle_destroy(USBDevice *dev) static USBPortOps usb_hub_port_ops = { .attach = usb_hub_attach, .detach = usb_hub_detach, + .child_detach = usb_hub_child_detach, .wakeup = usb_hub_wakeup, .complete = usb_hub_complete, }; diff --git a/hw/usb-msd.c b/hw/usb-msd.c index c59797b27e..86582cc723 100644 --- a/hw/usb-msd.c +++ b/hw/usb-msd.c @@ -51,6 +51,7 @@ typedef struct { SCSIRequest *req; SCSIBus bus; BlockConf conf; + char *serial; SCSIDevice *scsi_dev; uint32_t removable; int result; @@ -497,8 +498,9 @@ static void usb_msd_password_cb(void *opaque, int err) MSDState *s = opaque; if (!err) - usb_device_attach(&s->dev); - else + err = usb_device_attach(&s->dev); + + if (err) qdev_unplug(&s->dev.qdev); } @@ -531,9 +533,15 @@ static int usb_msd_initfn(USBDevice *dev) bdrv_detach(bs, &s->dev.qdev); s->conf.bs = NULL; - dinfo = drive_get_by_blockdev(bs); - if (dinfo && dinfo->serial) { - usb_desc_set_string(dev, STR_SERIALNUMBER, dinfo->serial); + if (!s->serial) { + /* try to fall back to value set with legacy -drive serial=... */ + dinfo = drive_get_by_blockdev(bs); + if (*dinfo->serial) { + s->serial = strdup(dinfo->serial); + } + } + if (s->serial) { + usb_desc_set_string(dev, STR_SERIALNUMBER, s->serial); } usb_desc_init(dev); @@ -632,6 +640,7 @@ static struct USBDeviceInfo msd_info = { .usbdevice_init = usb_msd_init, .qdev.props = (Property[]) { DEFINE_BLOCK_PROPERTIES(MSDState, conf), + DEFINE_PROP_STRING("serial", MSDState, serial), DEFINE_PROP_BIT("removable", MSDState, removable, 0, false), DEFINE_PROP_END_OF_LIST(), }, diff --git a/hw/usb-musb.c b/hw/usb-musb.c index 21f35afa92..035dda8372 100644 --- a/hw/usb-musb.c +++ b/hw/usb-musb.c @@ -261,17 +261,18 @@ static void musb_attach(USBPort *port); static void musb_detach(USBPort *port); -static void musb_schedule_cb(USBDevice *dev, USBPacket *p); -static void musb_device_destroy(USBBus *bus, USBDevice *dev); +static void musb_child_detach(USBPort *port, USBDevice *child); +static void musb_schedule_cb(USBPort *port, USBPacket *p); +static void musb_async_cancel_device(MUSBState *s, USBDevice *dev); static USBPortOps musb_port_ops = { .attach = musb_attach, .detach = musb_detach, + .child_detach = musb_child_detach, .complete = musb_schedule_cb, }; static USBBusOps musb_bus_ops = { - .device_destroy = musb_device_destroy, }; typedef struct MUSBPacket MUSBPacket; @@ -369,7 +370,6 @@ struct MUSBState *musb_init(qemu_irq *irqs) usb_bus_new(&s->bus, &musb_bus_ops, NULL /* FIXME */); usb_register_port(&s->bus, &s->port, s, 0, &musb_port_ops, USB_SPEED_MASK_LOW | USB_SPEED_MASK_FULL); - usb_port_location(&s->port, NULL, 1); return s; } @@ -498,10 +498,19 @@ static void musb_detach(USBPort *port) { MUSBState *s = (MUSBState *) port->opaque; + musb_async_cancel_device(s, port->dev); + musb_intr_set(s, musb_irq_disconnect, 1); musb_session_update(s, 1, s->session); } +static void musb_child_detach(USBPort *port, USBDevice *child) +{ + MUSBState *s = (MUSBState *) port->opaque; + + musb_async_cancel_device(s, child); +} + static void musb_cb_tick0(void *opaque) { MUSBEndPoint *ep = (MUSBEndPoint *) opaque; @@ -518,7 +527,7 @@ static void musb_cb_tick1(void *opaque) #define musb_cb_tick (dir ? musb_cb_tick1 : musb_cb_tick0) -static void musb_schedule_cb(USBDevice *dev, USBPacket *packey) +static void musb_schedule_cb(USBPort *port, USBPacket *packey) { MUSBPacket *p = container_of(packey, MUSBPacket, p); MUSBEndPoint *ep = p->ep; @@ -616,7 +625,7 @@ static void musb_packet(MUSBState *s, MUSBEndPoint *ep, } ep->status[dir] = ret; - usb_packet_complete(s->port.dev, &ep->packey[dir].p); + musb_schedule_cb(&s->port, &ep->packey[dir].p); } static void musb_tx_packet_complete(USBPacket *packey, void *opaque) @@ -783,9 +792,8 @@ static void musb_rx_packet_complete(USBPacket *packey, void *opaque) musb_rx_intr_set(s, epnum, 1); } -static void musb_device_destroy(USBBus *bus, USBDevice *dev) +static void musb_async_cancel_device(MUSBState *s, USBDevice *dev) { - MUSBState *s = container_of(bus, MUSBState, bus); int ep, dir; for (ep = 0; ep < 16; ep++) { diff --git a/hw/usb-ohci.c b/hw/usb-ohci.c index 5d2ae01235..8491d59928 100644 --- a/hw/usb-ohci.c +++ b/hw/usb-ohci.c @@ -124,6 +124,7 @@ struct ohci_hcca { }; static void ohci_bus_stop(OHCIState *ohci); +static void ohci_async_cancel_device(OHCIState *ohci, USBDevice *dev); /* Bitfields for the first word of an Endpoint Desciptor. */ #define OHCI_ED_FA_SHIFT 0 @@ -326,6 +327,7 @@ static void ohci_attach(USBPort *port1) { OHCIState *s = port1->opaque; OHCIPort *port = &s->rhport[port1->index]; + uint32_t old_state = port->ctrl; /* set connect status */ port->ctrl |= OHCI_PORT_CCS | OHCI_PORT_CSC; @@ -343,6 +345,10 @@ static void ohci_attach(USBPort *port1) } DPRINTF("usb-ohci: Attached port %d\n", port1->index); + + if (old_state != port->ctrl) { + ohci_set_interrupt(s, OHCI_INTR_RHSC); + } } static void ohci_detach(USBPort *port1) @@ -351,6 +357,8 @@ static void ohci_detach(USBPort *port1) OHCIPort *port = &s->rhport[port1->index]; uint32_t old_state = port->ctrl; + ohci_async_cancel_device(s, port1->dev); + /* set connect status */ if (port->ctrl & OHCI_PORT_CCS) { port->ctrl &= ~OHCI_PORT_CCS; @@ -363,24 +371,41 @@ static void ohci_detach(USBPort *port1) } DPRINTF("usb-ohci: Detached port %d\n", port1->index); - if (old_state != port->ctrl) + if (old_state != port->ctrl) { ohci_set_interrupt(s, OHCI_INTR_RHSC); + } } -static void ohci_wakeup(USBDevice *dev) +static void ohci_wakeup(USBPort *port1) { - USBBus *bus = usb_bus_from_device(dev); - OHCIState *s = container_of(bus, OHCIState, bus); - int portnum = dev->port->index; - OHCIPort *port = &s->rhport[portnum]; + OHCIState *s = port1->opaque; + OHCIPort *port = &s->rhport[port1->index]; + uint32_t intr = 0; if (port->ctrl & OHCI_PORT_PSS) { - DPRINTF("usb-ohci: port %d: wakeup\n", portnum); + DPRINTF("usb-ohci: port %d: wakeup\n", port1->index); port->ctrl |= OHCI_PORT_PSSC; port->ctrl &= ~OHCI_PORT_PSS; - if ((s->ctl & OHCI_CTL_HCFS) == OHCI_USB_SUSPEND) { - ohci_set_interrupt(s, OHCI_INTR_RD); - } + intr = OHCI_INTR_RHSC; + } + /* Note that the controller can be suspended even if this port is not */ + if ((s->ctl & OHCI_CTL_HCFS) == OHCI_USB_SUSPEND) { + DPRINTF("usb-ohci: remote-wakeup: SUSPEND->RESUME\n"); + /* This is the one state transition the controller can do by itself */ + s->ctl &= ~OHCI_CTL_HCFS; + s->ctl |= OHCI_USB_RESUME; + /* In suspend mode only ResumeDetected is possible, not RHSC: + * see the OHCI spec 5.1.2.3. + */ + intr = OHCI_INTR_RD; } + ohci_set_interrupt(s, intr); +} + +static void ohci_child_detach(USBPort *port1, USBDevice *child) +{ + OHCIState *s = port1->opaque; + + ohci_async_cancel_device(s, child); } /* Reset the controller */ @@ -591,7 +616,7 @@ static void ohci_copy_iso_td(OHCIState *ohci, static void ohci_process_lists(OHCIState *ohci, int completion); -static void ohci_async_complete_packet(USBDevice *dev, USBPacket *packet) +static void ohci_async_complete_packet(USBPort *port, USBPacket *packet) { OHCIState *ohci = container_of(packet, OHCIState, usb_packet); #ifdef DEBUG_PACKET @@ -1664,10 +1689,8 @@ static void ohci_mem_write(void *ptr, target_phys_addr_t addr, uint32_t val) } } -static void ohci_device_destroy(USBBus *bus, USBDevice *dev) +static void ohci_async_cancel_device(OHCIState *ohci, USBDevice *dev) { - OHCIState *ohci = container_of(bus, OHCIState, bus); - if (ohci->async_td && ohci->usb_packet.owner == dev) { usb_cancel_packet(&ohci->usb_packet); ohci->async_td = 0; @@ -1691,16 +1714,17 @@ static CPUWriteMemoryFunc * const ohci_writefn[3]={ static USBPortOps ohci_port_ops = { .attach = ohci_attach, .detach = ohci_detach, + .child_detach = ohci_child_detach, .wakeup = ohci_wakeup, .complete = ohci_async_complete_packet, }; static USBBusOps ohci_bus_ops = { - .device_destroy = ohci_device_destroy, }; -static void usb_ohci_init(OHCIState *ohci, DeviceState *dev, - int num_ports, uint32_t localmem_base) +static int usb_ohci_init(OHCIState *ohci, DeviceState *dev, + int num_ports, uint32_t localmem_base, + char *masterbus, uint32_t firstport) { int i; @@ -1720,39 +1744,58 @@ static void usb_ohci_init(OHCIState *ohci, DeviceState *dev, usb_frame_time, usb_bit_time); } + ohci->num_ports = num_ports; + if (masterbus) { + USBPort *ports[OHCI_MAX_PORTS]; + for(i = 0; i < num_ports; i++) { + ports[i] = &ohci->rhport[i].port; + } + if (usb_register_companion(masterbus, ports, num_ports, + firstport, ohci, &ohci_port_ops, + USB_SPEED_MASK_LOW | USB_SPEED_MASK_FULL) != 0) { + return -1; + } + } else { + usb_bus_new(&ohci->bus, &ohci_bus_ops, dev); + for (i = 0; i < num_ports; i++) { + usb_register_port(&ohci->bus, &ohci->rhport[i].port, + ohci, i, &ohci_port_ops, + USB_SPEED_MASK_LOW | USB_SPEED_MASK_FULL); + } + } + ohci->mem = cpu_register_io_memory(ohci_readfn, ohci_writefn, ohci, DEVICE_LITTLE_ENDIAN); ohci->localmem_base = localmem_base; ohci->name = dev->info->name; - usb_bus_new(&ohci->bus, &ohci_bus_ops, dev); - ohci->num_ports = num_ports; - for (i = 0; i < num_ports; i++) { - usb_register_port(&ohci->bus, &ohci->rhport[i].port, ohci, i, &ohci_port_ops, - USB_SPEED_MASK_LOW | USB_SPEED_MASK_FULL); - usb_port_location(&ohci->rhport[i].port, NULL, i+1); - } - ohci->async_td = 0; qemu_register_reset(ohci_reset, ohci); + + return 0; } typedef struct { PCIDevice pci_dev; OHCIState state; + char *masterbus; + uint32_t num_ports; + uint32_t firstport; } OHCIPCIState; static int usb_ohci_initfn_pci(struct PCIDevice *dev) { OHCIPCIState *ohci = DO_UPCAST(OHCIPCIState, pci_dev, dev); - int num_ports = 3; ohci->pci_dev.config[PCI_CLASS_PROG] = 0x10; /* OHCI */ /* TODO: RST# value should be 0. */ ohci->pci_dev.config[PCI_INTERRUPT_PIN] = 0x01; /* interrupt pin 1 */ - usb_ohci_init(&ohci->state, &dev->qdev, num_ports, 0); + if (usb_ohci_init(&ohci->state, &dev->qdev, ohci->num_ports, 0, + ohci->masterbus, ohci->firstport) != 0) { + return -1; + } ohci->state.irq = ohci->pci_dev.irq[0]; /* TODO: avoid cast below by using dev */ @@ -1776,7 +1819,8 @@ static int ohci_init_pxa(SysBusDevice *dev) { OHCISysBusState *s = FROM_SYSBUS(OHCISysBusState, dev); - usb_ohci_init(&s->ohci, &dev->qdev, s->num_ports, s->dma_offset); + /* Cannot fail as we pass NULL for masterbus */ + usb_ohci_init(&s->ohci, &dev->qdev, s->num_ports, s->dma_offset, NULL, 0); sysbus_init_irq(dev, &s->ohci.irq); sysbus_init_mmio(dev, 0x1000, s->ohci.mem); @@ -1791,6 +1835,12 @@ static PCIDeviceInfo ohci_pci_info = { .vendor_id = PCI_VENDOR_ID_APPLE, .device_id = PCI_DEVICE_ID_APPLE_IPID_USB, .class_id = PCI_CLASS_SERIAL_USB, + .qdev.props = (Property[]) { + DEFINE_PROP_STRING("masterbus", OHCIPCIState, masterbus), + DEFINE_PROP_UINT32("num-ports", OHCIPCIState, num_ports, 3), + DEFINE_PROP_UINT32("firstport", OHCIPCIState, firstport, 0), + DEFINE_PROP_END_OF_LIST(), + }, }; static SysBusDeviceInfo ohci_sysbus_info = { diff --git a/hw/usb-uhci.c b/hw/usb-uhci.c index 405fa7b65e..2ef4c5b747 100644 --- a/hw/usb-uhci.c +++ b/hw/usb-uhci.c @@ -132,7 +132,7 @@ typedef struct UHCIPort { struct UHCIState { PCIDevice dev; - USBBus bus; + USBBus bus; /* Note unused when we're a companion controller */ uint16_t cmd; /* cmd register */ uint16_t status; uint16_t intr; /* interrupt enable register */ @@ -150,6 +150,10 @@ struct UHCIState { /* Active packets */ QTAILQ_HEAD(,UHCIAsync) async_pending; uint8_t num_ports_vmstate; + + /* Properties */ + char *masterbus; + uint32_t firstport; }; typedef struct UHCI_TD { @@ -606,6 +610,8 @@ static void uhci_detach(USBPort *port1) UHCIState *s = port1->opaque; UHCIPort *port = &s->ports[port1->index]; + uhci_async_cancel_device(s, port1->dev); + /* set connect status */ if (port->ctrl & UHCI_PORT_CCS) { port->ctrl &= ~UHCI_PORT_CCS; @@ -620,11 +626,17 @@ static void uhci_detach(USBPort *port1) uhci_resume(s); } -static void uhci_wakeup(USBDevice *dev) +static void uhci_child_detach(USBPort *port1, USBDevice *child) +{ + UHCIState *s = port1->opaque; + + uhci_async_cancel_device(s, child); +} + +static void uhci_wakeup(USBPort *port1) { - USBBus *bus = usb_bus_from_device(dev); - UHCIState *s = container_of(bus, UHCIState, bus); - UHCIPort *port = s->ports + dev->port->index; + UHCIState *s = port1->opaque; + UHCIPort *port = &s->ports[port1->index]; if (port->ctrl & UHCI_PORT_SUSPEND && !(port->ctrl & UHCI_PORT_RD)) { port->ctrl |= UHCI_PORT_RD; @@ -657,7 +669,7 @@ static int uhci_broadcast_packet(UHCIState *s, USBPacket *p) return ret; } -static void uhci_async_complete(USBDevice *dev, USBPacket *packet); +static void uhci_async_complete(USBPort *port, USBPacket *packet); static void uhci_process_frame(UHCIState *s); /* return -1 if fatal error (frame must be stopped) @@ -849,7 +861,7 @@ done: return len; } -static void uhci_async_complete(USBDevice *dev, USBPacket *packet) +static void uhci_async_complete(USBPort *port, USBPacket *packet) { UHCIAsync *async = container_of(packet, UHCIAsync, packet); UHCIState *s = async->uhci; @@ -1096,22 +1108,15 @@ static void uhci_map(PCIDevice *pci_dev, int region_num, register_ioport_read(addr, 32, 1, uhci_ioport_readb, s); } -static void uhci_device_destroy(USBBus *bus, USBDevice *dev) -{ - UHCIState *s = container_of(bus, UHCIState, bus); - - uhci_async_cancel_device(s, dev); -} - static USBPortOps uhci_port_ops = { .attach = uhci_attach, .detach = uhci_detach, + .child_detach = uhci_child_detach, .wakeup = uhci_wakeup, .complete = uhci_async_complete, }; static USBBusOps uhci_bus_ops = { - .device_destroy = uhci_device_destroy, }; static int usb_uhci_common_initfn(PCIDevice *dev) @@ -1125,11 +1130,22 @@ static int usb_uhci_common_initfn(PCIDevice *dev) pci_conf[PCI_INTERRUPT_PIN] = 4; // interrupt pin 3 pci_conf[USB_SBRN] = USB_RELEASE_1; // release number - usb_bus_new(&s->bus, &uhci_bus_ops, &s->dev.qdev); - for(i = 0; i < NB_PORTS; i++) { - usb_register_port(&s->bus, &s->ports[i].port, s, i, &uhci_port_ops, - USB_SPEED_MASK_LOW | USB_SPEED_MASK_FULL); - usb_port_location(&s->ports[i].port, NULL, i+1); + if (s->masterbus) { + USBPort *ports[NB_PORTS]; + for(i = 0; i < NB_PORTS; i++) { + ports[i] = &s->ports[i].port; + } + if (usb_register_companion(s->masterbus, ports, NB_PORTS, + s->firstport, s, &uhci_port_ops, + USB_SPEED_MASK_LOW | USB_SPEED_MASK_FULL) != 0) { + return -1; + } + } else { + usb_bus_new(&s->bus, &uhci_bus_ops, &s->dev.qdev); + for (i = 0; i < NB_PORTS; i++) { + usb_register_port(&s->bus, &s->ports[i].port, s, i, &uhci_port_ops, + USB_SPEED_MASK_LOW | USB_SPEED_MASK_FULL); + } } s->frame_timer = qemu_new_timer_ns(vm_clock, uhci_frame_timer, s); s->num_ports_vmstate = NB_PORTS; @@ -1160,6 +1176,12 @@ static int usb_uhci_vt82c686b_initfn(PCIDevice *dev) return usb_uhci_common_initfn(dev); } +static Property uhci_properties[] = { + DEFINE_PROP_STRING("masterbus", UHCIState, masterbus), + DEFINE_PROP_UINT32("firstport", UHCIState, firstport, 0), + DEFINE_PROP_END_OF_LIST(), +}; + static PCIDeviceInfo uhci_info[] = { { .qdev.name = "piix3-usb-uhci", @@ -1170,6 +1192,7 @@ static PCIDeviceInfo uhci_info[] = { .device_id = PCI_DEVICE_ID_INTEL_82371SB_2, .revision = 0x01, .class_id = PCI_CLASS_SERIAL_USB, + .qdev.props = uhci_properties, },{ .qdev.name = "piix4-usb-uhci", .qdev.size = sizeof(UHCIState), @@ -1179,6 +1202,7 @@ static PCIDeviceInfo uhci_info[] = { .device_id = PCI_DEVICE_ID_INTEL_82371AB_2, .revision = 0x01, .class_id = PCI_CLASS_SERIAL_USB, + .qdev.props = uhci_properties, },{ .qdev.name = "vt82c686b-usb-uhci", .qdev.size = sizeof(UHCIState), @@ -1188,6 +1212,37 @@ static PCIDeviceInfo uhci_info[] = { .device_id = PCI_DEVICE_ID_VIA_UHCI, .revision = 0x01, .class_id = PCI_CLASS_SERIAL_USB, + .qdev.props = uhci_properties, + },{ + .qdev.name = "ich9-usb-uhci1", + .qdev.size = sizeof(UHCIState), + .qdev.vmsd = &vmstate_uhci, + .init = usb_uhci_common_initfn, + .vendor_id = PCI_VENDOR_ID_INTEL, + .device_id = PCI_DEVICE_ID_INTEL_82801I_UHCI1, + .revision = 0x03, + .class_id = PCI_CLASS_SERIAL_USB, + .qdev.props = uhci_properties, + },{ + .qdev.name = "ich9-usb-uhci2", + .qdev.size = sizeof(UHCIState), + .qdev.vmsd = &vmstate_uhci, + .init = usb_uhci_common_initfn, + .vendor_id = PCI_VENDOR_ID_INTEL, + .device_id = PCI_DEVICE_ID_INTEL_82801I_UHCI2, + .revision = 0x03, + .class_id = PCI_CLASS_SERIAL_USB, + .qdev.props = uhci_properties, + },{ + .qdev.name = "ich9-usb-uhci3", + .qdev.size = sizeof(UHCIState), + .qdev.vmsd = &vmstate_uhci, + .init = usb_uhci_common_initfn, + .vendor_id = PCI_VENDOR_ID_INTEL, + .device_id = PCI_DEVICE_ID_INTEL_82801I_UHCI3, + .revision = 0x03, + .class_id = PCI_CLASS_SERIAL_USB, + .qdev.props = uhci_properties, },{ /* end of list */ } @@ -40,19 +40,18 @@ void usb_attach(USBPort *port, USBDevice *dev) } else { /* detach */ dev = port->dev; + assert(dev); port->ops->detach(port); - if (dev) { - usb_send_msg(dev, USB_MSG_DETACH); - dev->port = NULL; - port->dev = NULL; - } + usb_send_msg(dev, USB_MSG_DETACH); + dev->port = NULL; + port->dev = NULL; } } void usb_wakeup(USBDevice *dev) { if (dev->remote_wakeup && dev->port && dev->port->ops->wakeup) { - dev->port->ops->wakeup(dev); + dev->port->ops->wakeup(dev->port); } } @@ -335,7 +334,7 @@ void usb_packet_complete(USBDevice *dev, USBPacket *p) { /* Note: p->owner != dev is possible in case dev is a hub */ assert(p->owner != NULL); - dev->port->ops->complete(dev, p); + dev->port->ops->complete(dev->port, p); p->owner = NULL; } @@ -130,6 +130,7 @@ #define USB_DT_ENDPOINT 0x05 #define USB_DT_DEVICE_QUALIFIER 0x06 #define USB_DT_OTHER_SPEED_CONFIG 0x07 +#define USB_DT_DEBUG 0x0A #define USB_DT_INTERFACE_ASSOC 0x0B #define USB_ENDPOINT_XFER_CONTROL 0 @@ -168,7 +169,10 @@ struct USBDevice { char *port_path; void *opaque; + /* Actual connected speed */ int speed; + /* Supported speeds, not in info because it may be variable (hostdevs) */ + int speedmask; uint8_t addr; char product_desc[32]; int auto_attach; @@ -248,8 +252,18 @@ struct USBDeviceInfo { typedef struct USBPortOps { void (*attach)(USBPort *port); void (*detach)(USBPort *port); - void (*wakeup)(USBDevice *dev); - void (*complete)(USBDevice *dev, USBPacket *p); + /* + * This gets called when a device downstream from the device attached to + * the port (iow attached through a hub) gets detached. + */ + void (*child_detach)(USBPort *port, USBDevice *child); + void (*wakeup)(USBPort *port); + /* + * Note that port->dev will be different then the device from which + * the packet originated when a hub is involved, if you want the orginating + * device use p->owner + */ + void (*complete)(USBPort *port, USBPacket *p); } USBPortOps; /* USB port on which a device can be connected */ @@ -340,7 +354,8 @@ struct USBBus { }; struct USBBusOps { - void (*device_destroy)(USBBus *bus, USBDevice *dev); + int (*register_companion)(USBBus *bus, USBPort *ports[], + uint32_t portcount, uint32_t firstport); }; void usb_bus_new(USBBus *bus, USBBusOps *ops, DeviceState *host); @@ -352,6 +367,9 @@ USBDevice *usb_create_simple(USBBus *bus, const char *name); USBDevice *usbdevice_create(const char *cmdline); void usb_register_port(USBBus *bus, USBPort *port, void *opaque, int index, USBPortOps *ops, int speedmask); +int usb_register_companion(const char *masterbus, USBPort *ports[], + uint32_t portcount, uint32_t firstport, + void *opaque, USBPortOps *ops, int speedmask); void usb_port_location(USBPort *downstream, USBPort *upstream, int portnr); void usb_unregister_port(USBBus *bus, USBPort *port); int usb_device_attach(USBDevice *dev); diff --git a/hw/vhost.c b/hw/vhost.c index 80f771e448..c3d88214fe 100644 --- a/hw/vhost.c +++ b/hw/vhost.c @@ -784,5 +784,6 @@ void vhost_dev_stop(struct vhost_dev *hdev, VirtIODevice *vdev) hdev->started = false; qemu_free(hdev->log); + hdev->log = NULL; hdev->log_size = 0; } diff --git a/hw/virtex_ml507.c b/hw/virtex_ml507.c index fa605158e7..7bde8c79de 100644 --- a/hw/virtex_ml507.c +++ b/hw/virtex_ml507.c @@ -60,7 +60,7 @@ static void mmubooke_create_initial_mapping(CPUState *env, target_ulong va, target_phys_addr_t pa) { - ppcemb_tlb_t *tlb = &env->tlb[0].tlbe; + ppcemb_tlb_t *tlb = &env->tlb.tlbe[0]; tlb->attr = 0; tlb->prot = PAGE_VALID | ((PAGE_READ | PAGE_WRITE | PAGE_EXEC) << 4); @@ -69,7 +69,7 @@ static void mmubooke_create_initial_mapping(CPUState *env, tlb->RPN = pa & TARGET_PAGE_MASK; tlb->PID = 0; - tlb = &env->tlb[1].tlbe; + tlb = &env->tlb.tlbe[1]; tlb->attr = 0; tlb->prot = PAGE_VALID | ((PAGE_READ | PAGE_WRITE | PAGE_EXEC) << 4); tlb->size = 1 << 31; /* up to 0xffffffff */ diff --git a/hw/virtio-blk.c b/hw/virtio-blk.c index 91e0394af9..6471ac85ab 100644 --- a/hw/virtio-blk.c +++ b/hw/virtio-blk.c @@ -28,8 +28,8 @@ typedef struct VirtIOBlock void *rq; QEMUBH *bh; BlockConf *conf; + char *serial; unsigned short sector_mask; - char sn[BLOCK_SERIAL_STRLEN]; DeviceState *qdev; } VirtIOBlock; @@ -362,8 +362,13 @@ static void virtio_blk_handle_request(VirtIOBlockReq *req, } else if (type & VIRTIO_BLK_T_GET_ID) { VirtIOBlock *s = req->dev; - memcpy(req->elem.in_sg[0].iov_base, s->sn, - MIN(req->elem.in_sg[0].iov_len, sizeof(s->sn))); + /* + * NB: per existing s/n string convention the string is + * terminated by '\0' only when shorter than buffer. + */ + strncpy(req->elem.in_sg[0].iov_base, + s->serial ? s->serial : "", + MIN(req->elem.in_sg[0].iov_len, VIRTIO_BLK_ID_BYTES)); virtio_blk_req_complete(req, VIRTIO_BLK_S_OK); } else if (type & VIRTIO_BLK_T_OUT) { qemu_iovec_init_external(&req->qiov, &req->elem.out_sg[1], @@ -531,7 +536,8 @@ static void virtio_blk_change_cb(void *opaque, int reason) } } -VirtIODevice *virtio_blk_init(DeviceState *dev, BlockConf *conf) +VirtIODevice *virtio_blk_init(DeviceState *dev, BlockConf *conf, + char **serial) { VirtIOBlock *s; int cylinders, heads, secs; @@ -547,6 +553,14 @@ VirtIODevice *virtio_blk_init(DeviceState *dev, BlockConf *conf) return NULL; } + if (!*serial) { + /* try to fall back to value set with legacy -drive serial=... */ + dinfo = drive_get_by_blockdev(conf->bs); + if (*dinfo->serial) { + *serial = strdup(dinfo->serial); + } + } + s = (VirtIOBlock *)virtio_common_init("virtio-blk", VIRTIO_ID_BLOCK, sizeof(struct virtio_blk_config), sizeof(VirtIOBlock)); @@ -556,16 +570,11 @@ VirtIODevice *virtio_blk_init(DeviceState *dev, BlockConf *conf) s->vdev.reset = virtio_blk_reset; s->bs = conf->bs; s->conf = conf; + s->serial = *serial; s->rq = NULL; s->sector_mask = (s->conf->logical_block_size / BDRV_SECTOR_SIZE) - 1; bdrv_guess_geometry(s->bs, &cylinders, &heads, &secs); - /* NB: per existing s/n string convention the string is terminated - * by '\0' only when less than sizeof (s->sn) - */ - dinfo = drive_get_by_blockdev(s->bs); - strncpy(s->sn, dinfo->serial, sizeof (s->sn)); - s->vq = virtio_add_queue(&s->vdev, 128, virtio_blk_handle_output); qemu_add_vm_change_state_handler(virtio_blk_dma_restart_cb, s); diff --git a/hw/virtio-blk.h b/hw/virtio-blk.h index fff46da7db..5645d2bf3c 100644 --- a/hw/virtio-blk.h +++ b/hw/virtio-blk.h @@ -34,6 +34,8 @@ #define VIRTIO_BLK_F_WCACHE 9 /* write cache enabled */ #define VIRTIO_BLK_F_TOPOLOGY 10 /* Topology information is available */ +#define VIRTIO_BLK_ID_BYTES 20 /* ID string length */ + struct virtio_blk_config { uint64_t capacity; diff --git a/hw/virtio-console.c b/hw/virtio-console.c index b076331d37..7ebfa26516 100644 --- a/hw/virtio-console.c +++ b/hw/virtio-console.c @@ -12,6 +12,7 @@ #include "qemu-char.h" #include "qemu-error.h" +#include "trace.h" #include "virtio-serial.h" typedef struct VirtConsole { @@ -24,8 +25,26 @@ typedef struct VirtConsole { static ssize_t flush_buf(VirtIOSerialPort *port, const uint8_t *buf, size_t len) { VirtConsole *vcon = DO_UPCAST(VirtConsole, port, port); - - return qemu_chr_write(vcon->chr, buf, len); + ssize_t ret; + + ret = qemu_chr_write(vcon->chr, buf, len); + trace_virtio_console_flush_buf(port->id, len, ret); + + if (ret < 0) { + /* + * Ideally we'd get a better error code than just -1, but + * that's what the chardev interface gives us right now. If + * we had a finer-grained message, like -EPIPE, we could close + * this connection. Absent such error messages, the most we + * can do is to return 0 here. + * + * This will prevent stray -1 values to go to + * virtio-serial-bus.c and cause abort()s in + * do_flush_queued_data(). + */ + ret = 0; + } + return ret; } /* Callback function that's called when the guest opens the port */ @@ -57,6 +76,7 @@ static void chr_read(void *opaque, const uint8_t *buf, int size) { VirtConsole *vcon = opaque; + trace_virtio_console_chr_read(vcon->port.id, size); virtio_serial_write(&vcon->port, buf, size); } @@ -64,6 +84,7 @@ static void chr_event(void *opaque, int event) { VirtConsole *vcon = opaque; + trace_virtio_console_chr_event(vcon->port.id, event); switch (event) { case CHR_EVENT_OPENED: virtio_serial_open(&vcon->port); diff --git a/hw/virtio-pci.c b/hw/virtio-pci.c index b3e7ba5d12..d685243728 100644 --- a/hw/virtio-pci.c +++ b/hw/virtio-pci.c @@ -700,7 +700,8 @@ static int virtio_blk_init_pci(PCIDevice *pci_dev) proxy->class_code != PCI_CLASS_STORAGE_OTHER) proxy->class_code = PCI_CLASS_STORAGE_SCSI; - vdev = virtio_blk_init(&pci_dev->qdev, &proxy->block); + vdev = virtio_blk_init(&pci_dev->qdev, &proxy->block, + &proxy->block_serial); if (!vdev) { return -1; } @@ -805,6 +806,7 @@ static PCIDeviceInfo virtio_info[] = { .qdev.props = (Property[]) { DEFINE_PROP_HEX32("class", VirtIOPCIProxy, class_code, 0), DEFINE_BLOCK_PROPERTIES(VirtIOPCIProxy, block), + DEFINE_PROP_STRING("serial", VirtIOPCIProxy, block_serial), DEFINE_PROP_BIT("ioeventfd", VirtIOPCIProxy, flags, VIRTIO_PCI_FLAG_USE_IOEVENTFD_BIT, true), DEFINE_PROP_UINT32("vectors", VirtIOPCIProxy, nvectors, 2), diff --git a/hw/virtio-pci.h b/hw/virtio-pci.h index b5189172de..1f0de5684d 100644 --- a/hw/virtio-pci.h +++ b/hw/virtio-pci.h @@ -26,6 +26,7 @@ typedef struct { uint32_t class_code; uint32_t nvectors; BlockConf block; + char *block_serial; NICConf nic; uint32_t host_features; #ifdef CONFIG_LINUX diff --git a/hw/virtio-serial-bus.c b/hw/virtio-serial-bus.c index 9a12104982..6d73386441 100644 --- a/hw/virtio-serial-bus.c +++ b/hw/virtio-serial-bus.c @@ -19,6 +19,7 @@ #include "monitor.h" #include "qemu-queue.h" #include "sysbus.h" +#include "trace.h" #include "virtio-serial.h" /* The virtio-serial bus on top of which the ports will ride as devices */ @@ -221,6 +222,7 @@ static size_t send_control_event(VirtIOSerialPort *port, uint16_t event, stw_p(&cpkt.event, event); stw_p(&cpkt.value, value); + trace_virtio_serial_send_control_event(port->id, event, value); return send_control_msg(port, &cpkt, sizeof(cpkt)); } @@ -302,6 +304,7 @@ void virtio_serial_throttle_port(VirtIOSerialPort *port, bool throttle) return; } + trace_virtio_serial_throttle_port(port->id, throttle); port->throttled = throttle; if (throttle) { return; @@ -328,18 +331,13 @@ static void handle_control_message(VirtIOSerial *vser, void *buf, size_t len) cpkt.event = lduw_p(&gcpkt->event); cpkt.value = lduw_p(&gcpkt->value); - port = find_port_by_id(vser, ldl_p(&gcpkt->id)); - if (!port && cpkt.event != VIRTIO_CONSOLE_DEVICE_READY) - return; + trace_virtio_serial_handle_control_message(cpkt.event, cpkt.value); - info = DO_UPCAST(VirtIOSerialPortInfo, qdev, port->dev.info); - - switch(cpkt.event) { - case VIRTIO_CONSOLE_DEVICE_READY: + if (cpkt.event == VIRTIO_CONSOLE_DEVICE_READY) { if (!cpkt.value) { - error_report("virtio-serial-bus: Guest failure in adding device %s\n", + error_report("virtio-serial-bus: Guest failure in adding device %s", vser->bus.qbus.name); - break; + return; } /* * The device is up, we can now tell the device about all the @@ -348,11 +346,24 @@ static void handle_control_message(VirtIOSerial *vser, void *buf, size_t len) QTAILQ_FOREACH(port, &vser->ports, next) { send_control_event(port, VIRTIO_CONSOLE_PORT_ADD, 1); } - break; + return; + } + port = find_port_by_id(vser, ldl_p(&gcpkt->id)); + if (!port) { + error_report("virtio-serial-bus: Unexpected port id %u for device %s", + ldl_p(&gcpkt->id), vser->bus.qbus.name); + return; + } + + trace_virtio_serial_handle_control_message_port(port->id); + + info = DO_UPCAST(VirtIOSerialPortInfo, qdev, port->dev.info); + + switch(cpkt.event) { case VIRTIO_CONSOLE_PORT_READY: if (!cpkt.value) { - error_report("virtio-serial-bus: Guest failure in adding port %u for device %s\n", + error_report("virtio-serial-bus: Guest failure in adding port %u for device %s", port->id, vser->bus.qbus.name); break; } @@ -741,7 +752,7 @@ static int virtser_port_qdev_init(DeviceState *qdev, DeviceInfo *base) plugging_port0 = info->is_console && !find_port_by_id(port->vser, 0); if (find_port_by_id(port->vser, port->id)) { - error_report("virtio-serial-bus: A port already exists at id %u\n", + error_report("virtio-serial-bus: A port already exists at id %u", port->id); return -1; } @@ -752,7 +763,7 @@ static int virtser_port_qdev_init(DeviceState *qdev, DeviceInfo *base) } else { port->id = find_free_port_id(port->vser); if (port->id == VIRTIO_CONSOLE_BAD_ID) { - error_report("virtio-serial-bus: Maximum port limit for this device reached\n"); + error_report("virtio-serial-bus: Maximum port limit for this device reached"); return -1; } } @@ -760,7 +771,7 @@ static int virtser_port_qdev_init(DeviceState *qdev, DeviceInfo *base) max_nr_ports = tswap32(port->vser->config.max_nr_ports); if (port->id >= max_nr_ports) { - error_report("virtio-serial-bus: Out-of-range port id specified, max. allowed: %u\n", + error_report("virtio-serial-bus: Out-of-range port id specified, max. allowed: %u", max_nr_ports - 1); return -1; } diff --git a/hw/virtio.c b/hw/virtio.c index e6043de827..a8f4940da2 100644 --- a/hw/virtio.c +++ b/hw/virtio.c @@ -449,9 +449,17 @@ int virtqueue_pop(VirtQueue *vq, VirtQueueElement *elem) struct iovec *sg; if (vring_desc_flags(desc_pa, i) & VRING_DESC_F_WRITE) { + if (elem->in_num >= ARRAY_SIZE(elem->in_sg)) { + error_report("Too many write descriptors in indirect table"); + exit(1); + } elem->in_addr[elem->in_num] = vring_desc_addr(desc_pa, i); sg = &elem->in_sg[elem->in_num++]; } else { + if (elem->out_num >= ARRAY_SIZE(elem->out_sg)) { + error_report("Too many read descriptors in indirect table"); + exit(1); + } elem->out_addr[elem->out_num] = vring_desc_addr(desc_pa, i); sg = &elem->out_sg[elem->out_num++]; } @@ -797,7 +805,7 @@ int virtio_load(VirtIODevice *vdev, QEMUFile *f) /* Check it isn't doing very strange things with descriptor numbers. */ if (nheads > vdev->vq[i].vring.num) { error_report("VQ %d size 0x%x Guest index 0x%x " - "inconsistent with Host index 0x%x: delta 0x%x\n", + "inconsistent with Host index 0x%x: delta 0x%x", i, vdev->vq[i].vring.num, vring_avail_idx(&vdev->vq[i]), vdev->vq[i].last_avail_idx, nheads); @@ -805,7 +813,7 @@ int virtio_load(VirtIODevice *vdev, QEMUFile *f) } } else if (vdev->vq[i].last_avail_idx) { error_report("VQ %d address 0x0 " - "inconsistent with Host index 0x%x\n", + "inconsistent with Host index 0x%x", i, vdev->vq[i].last_avail_idx); return -1; } diff --git a/hw/virtio.h b/hw/virtio.h index 69e6bb1a4e..0fd0bb0ac5 100644 --- a/hw/virtio.h +++ b/hw/virtio.h @@ -197,7 +197,8 @@ void virtio_bind_device(VirtIODevice *vdev, const VirtIOBindings *binding, void *opaque); /* Base devices. */ -VirtIODevice *virtio_blk_init(DeviceState *dev, BlockConf *conf); +VirtIODevice *virtio_blk_init(DeviceState *dev, BlockConf *conf, + char **serial); struct virtio_net_conf; VirtIODevice *virtio_net_init(DeviceState *dev, NICConf *conf, struct virtio_net_conf *net); @@ -31,15 +31,6 @@ static inline int xen_enabled(void) #endif } -static inline int xen_mapcache_enabled(void) -{ -#ifdef CONFIG_XEN_MAPCACHE - return xen_enabled(); -#else - return 0; -#endif -} - int xen_pci_slot_get_pirq(PCIDevice *pci_dev, int irq_num); void xen_piix3_set_irq(void *opaque, int irq_num, int level); void xen_piix_pci_write_config_client(uint32_t address, uint32_t val, int len); @@ -50,6 +41,7 @@ qemu_irq *xen_interrupt_controller_init(void); int xen_init(void); int xen_hvm_init(void); void xen_vcpu_init(void); +void xenstore_store_pv_console_info(int i, struct CharDriverState *chr); #if defined(NEED_CPU_H) && !defined(CONFIG_USER_ONLY) void xen_ram_alloc(ram_addr_t ram_addr, ram_addr_t size); diff --git a/hw/xen_common.h b/hw/xen_common.h index 2c79af64d0..0409ac7971 100644 --- a/hw/xen_common.h +++ b/hw/xen_common.h @@ -85,6 +85,18 @@ static inline int xc_domain_add_to_physmap(int xc_handle, uint32_t domid, return xc_memory_op(xc_handle, XENMEM_add_to_physmap, &xatp); } +static inline struct xs_handle *xs_open(unsigned long flags) +{ + return xs_daemon_open(); +} + +static inline void xs_close(struct xs_handle *xsh) +{ + if (xsh != NULL) { + xs_daemon_close(xsh); + } +} + /* Xen 4.1 */ #else diff --git a/hw/xen_console.c b/hw/xen_console.c index c6c8163813..8ef104c9ac 100644 --- a/hw/xen_console.c +++ b/hw/xen_console.c @@ -179,7 +179,9 @@ static void xencons_send(struct XenConsole *con) static int con_init(struct XenDevice *xendev) { struct XenConsole *con = container_of(xendev, struct XenConsole, xendev); - char *type, *dom; + char *type, *dom, label[32]; + int ret = 0; + const char *output; /* setup */ dom = xs_get_domain_path(xenstore, con->xendev.dom); @@ -189,16 +191,25 @@ static int con_init(struct XenDevice *xendev) type = xenstore_read_str(con->console, "type"); if (!type || strcmp(type, "ioemu") != 0) { xen_be_printf(xendev, 1, "not for me (type=%s)\n", type); - return -1; + ret = -1; + goto out; } - if (!serial_hds[con->xendev.dev]) - xen_be_printf(xendev, 1, "WARNING: serial line %d not configured\n", - con->xendev.dev); - else + output = xenstore_read_str(con->console, "output"); + + /* no Xen override, use qemu output device */ + if (output == NULL) { con->chr = serial_hds[con->xendev.dev]; + } else { + snprintf(label, sizeof(label), "xencons%d", con->xendev.dev); + con->chr = qemu_chr_open(label, output, NULL); + } - return 0; + xenstore_store_pv_console_info(con->xendev.dev, con->chr); + +out: + qemu_free(type); + return ret; } static int con_connect(struct XenDevice *xendev) diff --git a/hw/xen_disk.c b/hw/xen_disk.c index 0c298afa8d..add815f273 100644 --- a/hw/xen_disk.c +++ b/hw/xen_disk.c @@ -616,12 +616,14 @@ static int blk_init(struct XenDevice *xendev) { struct XenBlkDev *blkdev = container_of(xendev, struct XenBlkDev, xendev); int index, qflags, have_barriers, info = 0; - char *h; /* read xenstore entries */ if (blkdev->params == NULL) { + char *h = NULL; blkdev->params = xenstore_read_be_str(&blkdev->xendev, "params"); - h = strchr(blkdev->params, ':'); + if (blkdev->params != NULL) { + h = strchr(blkdev->params, ':'); + } if (h != NULL) { blkdev->fileproto = blkdev->params; blkdev->filename = h+1; @@ -631,6 +633,9 @@ static int blk_init(struct XenDevice *xendev) blkdev->filename = blkdev->params; } } + if (!strcmp("aio", blkdev->fileproto)) { + blkdev->fileproto = "raw"; + } if (blkdev->mode == NULL) { blkdev->mode = xenstore_read_be_str(&blkdev->xendev, "mode"); } @@ -649,7 +654,7 @@ static int blk_init(struct XenDevice *xendev) blkdev->mode == NULL || blkdev->type == NULL || blkdev->dev == NULL) { - return -1; + goto out_error; } /* read-only ? */ @@ -672,10 +677,15 @@ static int blk_init(struct XenDevice *xendev) /* setup via xenbus -> create new block driver instance */ xen_be_printf(&blkdev->xendev, 2, "create new bdrv (xenbus setup)\n"); blkdev->bs = bdrv_new(blkdev->dev); - if (bdrv_open(blkdev->bs, blkdev->filename, qflags, - bdrv_find_whitelisted_format(blkdev->fileproto)) != 0) { - bdrv_delete(blkdev->bs); - return -1; + if (blkdev->bs) { + if (bdrv_open(blkdev->bs, blkdev->filename, qflags, + bdrv_find_whitelisted_format(blkdev->fileproto)) != 0) { + bdrv_delete(blkdev->bs); + blkdev->bs = NULL; + } + } + if (!blkdev->bs) { + goto out_error; } } else { /* setup via qemu cmdline -> already setup for us */ @@ -704,6 +714,19 @@ static int blk_init(struct XenDevice *xendev) xenstore_write_be_int(&blkdev->xendev, "sectors", blkdev->file_size / blkdev->file_blk); return 0; + +out_error: + qemu_free(blkdev->params); + blkdev->params = NULL; + qemu_free(blkdev->mode); + blkdev->mode = NULL; + qemu_free(blkdev->type); + blkdev->type = NULL; + qemu_free(blkdev->dev); + blkdev->dev = NULL; + qemu_free(blkdev->devtype); + blkdev->devtype = NULL; + return -1; } static int blk_connect(struct XenDevice *xendev) diff --git a/hw/xen_platform.c b/hw/xen_platform.c index b167eee1ff..f43e175b4e 100644 --- a/hw/xen_platform.c +++ b/hw/xen_platform.c @@ -290,18 +290,10 @@ static int xen_platform_initfn(PCIDevice *dev) pci_conf = d->pci_dev.config; - pci_config_set_vendor_id(pci_conf, PCI_VENDOR_ID_XENSOURCE); - pci_config_set_device_id(pci_conf, 0x0001); - pci_set_word(pci_conf + PCI_SUBSYSTEM_VENDOR_ID, PCI_VENDOR_ID_XENSOURCE); - pci_set_word(pci_conf + PCI_SUBSYSTEM_ID, 0x0001); - pci_set_word(pci_conf + PCI_COMMAND, PCI_COMMAND_IO | PCI_COMMAND_MEMORY); - pci_config_set_revision(pci_conf, 1); pci_config_set_prog_interface(pci_conf, 0); - pci_config_set_class(pci_conf, PCI_CLASS_OTHERS << 8 | 0x80); - pci_conf[PCI_INTERRUPT_PIN] = 1; pci_register_bar(&d->pci_dev, 0, 0x100, @@ -330,6 +322,13 @@ static PCIDeviceInfo xen_platform_info = { .qdev.size = sizeof(PCIXenPlatformState), .qdev.vmsd = &vmstate_xen_platform, .qdev.reset = platform_reset, + + .vendor_id = PCI_VENDOR_ID_XEN, + .device_id = PCI_DEVICE_ID_XEN_PLATFORM, + .class_id = PCI_CLASS_OTHERS << 8 | 0x80, + .subsystem_vendor_id = PCI_VENDOR_ID_XEN, + .subsystem_id = PCI_DEVICE_ID_XEN_PLATFORM, + .revision = 1, }; static void xen_platform_register(void) diff --git a/hw/xenfb.c b/hw/xenfb.c index 1db75fbe49..0a01ae30cc 100644 --- a/hw/xenfb.c +++ b/hw/xenfb.c @@ -347,13 +347,6 @@ static void xenfb_mouse_event(void *opaque, static int input_init(struct XenDevice *xendev) { - struct XenInput *in = container_of(xendev, struct XenInput, c.xendev); - - if (!in->c.ds) { - xen_be_printf(xendev, 1, "ds not set (yet)\n"); - return -1; - } - xenstore_write_be_int(xendev, "feature-abs-pointer", 1); return 0; } @@ -367,6 +360,18 @@ static int input_connect(struct XenDevice *xendev) &in->abs_pointer_wanted) == -1) in->abs_pointer_wanted = 0; + if (!in->c.ds) { + char *vfb = xenstore_read_str(NULL, "device/vfb"); + if (vfb == NULL) { + /* there is no vfb, run vkbd on its own */ + in->c.ds = get_displaystate(); + } else { + qemu_free(vfb); + xen_be_printf(xendev, 1, "ds not set (yet)\n"); + return -1; + } + } + rc = common_bind(&in->c); if (rc != 0) return rc; @@ -148,7 +148,7 @@ void kbd_mouse_event(int dx, int dy, int dz, int buttons_state) QEMUPutMouseEntry *entry; QEMUPutMouseEvent *mouse_event; void *mouse_event_opaque; - int width; + int width, height; if (QTAILQ_EMPTY(&mouse_handlers)) { return; @@ -160,15 +160,31 @@ void kbd_mouse_event(int dx, int dy, int dz, int buttons_state) mouse_event_opaque = entry->qemu_put_mouse_event_opaque; if (mouse_event) { - if (graphic_rotate) { - if (entry->qemu_put_mouse_event_absolute) { - width = 0x7fff; - } else { - width = graphic_width - 1; - } - mouse_event(mouse_event_opaque, width - dy, dx, dz, buttons_state); + if (entry->qemu_put_mouse_event_absolute) { + width = 0x7fff; + height = 0x7fff; } else { - mouse_event(mouse_event_opaque, dx, dy, dz, buttons_state); + width = graphic_width - 1; + height = graphic_height - 1; + } + + switch (graphic_rotate) { + case 0: + mouse_event(mouse_event_opaque, + dx, dy, dz, buttons_state); + break; + case 90: + mouse_event(mouse_event_opaque, + width - dy, dx, dz, buttons_state); + break; + case 180: + mouse_event(mouse_event_opaque, + width - dx, height - dy, dz, buttons_state); + break; + case 270: + mouse_event(mouse_event_opaque, + dy, height - dx, dz, buttons_state); + break; } } } diff --git a/kvm-stub.c b/kvm-stub.c index 1e835c6715..06064b9a86 100644 --- a/kvm-stub.c +++ b/kvm-stub.c @@ -12,7 +12,7 @@ #include "qemu-common.h" #include "hw/hw.h" -#include "exec-all.h" +#include "cpu.h" #include "gdbstub.h" #include "kvm.h" diff --git a/linux-user/alpha/syscall_nr.h b/linux-user/alpha/syscall_nr.h index e3127df4ac..f6284db22f 100644 --- a/linux-user/alpha/syscall_nr.h +++ b/linux-user/alpha/syscall_nr.h @@ -411,4 +411,25 @@ #define TARGET_NR_signalfd 476 #define TARGET_NR_timerfd 477 #define TARGET_NR_eventfd 478 - +#define TARGET_NR_recvmmsg 479 +#define TARGET_NR_fallocate 480 +#define TARGET_NR_timerfd_create 481 +#define TARGET_NR_timerfd_settime 482 +#define TARGET_NR_timerfd_gettime 483 +#define TARGET_NR_signalfd4 484 +#define TARGET_NR_eventfd2 485 +#define TARGET_NR_epoll_create1 486 +#define TARGET_NR_dup3 487 +#define TARGET_NR_pipe2 488 +#define TARGET_NR_inotify_init1 489 +#define TARGET_NR_preadv 490 +#define TARGET_NR_pwritev 491 +#define TARGET_NR_rt_tgsigqueueinfo 492 +#define TARGET_NR_perf_event_open 493 +#define TARGET_NR_fanotify_init 494 +#define TARGET_NR_fanotify_mark 495 +#define TARGET_NR_prlimit64 496 +#define TARGET_NR_name_to_handle_at 497 +#define TARGET_NR_open_by_handle_at 498 +#define TARGET_NR_clock_adjtime 499 +#define TARGET_NR_syncfs 500 diff --git a/linux-user/arm/syscall_nr.h b/linux-user/arm/syscall_nr.h index 79a216a137..7f05879ea3 100644 --- a/linux-user/arm/syscall_nr.h +++ b/linux-user/arm/syscall_nr.h @@ -365,3 +365,16 @@ #define TARGET_NR_dup3 (358) #define TARGET_NR_pipe2 (359) #define TARGET_NR_inotify_init1 (360) +#define TARGET_NR_preadv (361) +#define TARGET_NR_pwritev (362) +#define TARGET_NR_rt_tgsigqueueinfo (363) +#define TARGET_NR_perf_event_open (364) +#define TARGET_NR_recvmmsg (365) +#define TARGET_NR_accept4 (366) +#define TARGET_NR_fanotify_init (367) +#define TARGET_NR_fanotify_mark (368) +#define TARGET_NR_prlimit64 (369) +#define TARGET_NR_name_to_handle_at (370) +#define TARGET_NR_open_by_handle_at (371) +#define TARGET_NR_clock_adjtime (372) +#define TARGET_NR_syncfs (373) diff --git a/linux-user/cris/syscall_nr.h b/linux-user/cris/syscall_nr.h index 6132817105..98f1a0b415 100644 --- a/linux-user/cris/syscall_nr.h +++ b/linux-user/cris/syscall_nr.h @@ -333,3 +333,5 @@ #define TARGET_NR_dup3 330 #define TARGET_NR_pipe2 331 #define TARGET_NR_inotify_init1 332 +#define TARGET_NR_preadv 333 +#define TARGET_NR_pwritev 334 diff --git a/linux-user/elfload.c b/linux-user/elfload.c index dcfeb7a286..443d246ada 100644 --- a/linux-user/elfload.c +++ b/linux-user/elfload.c @@ -417,7 +417,8 @@ static void elf_core_copy_regs(target_elf_gregset_t *regs, const CPUState *env) #ifdef TARGET_SPARC64 #define ELF_START_MMAP 0x80000000 - +#define ELF_HWCAP (HWCAP_SPARC_FLUSH | HWCAP_SPARC_STBAR | HWCAP_SPARC_SWAP \ + | HWCAP_SPARC_MULDIV | HWCAP_SPARC_V9) #ifndef TARGET_ABI32 #define elf_check_arch(x) ( (x) == EM_SPARCV9 || (x) == EM_SPARC32PLUS ) #else @@ -450,7 +451,8 @@ static inline void init_thread(struct target_pt_regs *regs, #else #define ELF_START_MMAP 0x80000000 - +#define ELF_HWCAP (HWCAP_SPARC_FLUSH | HWCAP_SPARC_STBAR | HWCAP_SPARC_SWAP \ + | HWCAP_SPARC_MULDIV) #define elf_check_arch(x) ( (x) == EM_SPARC ) #define ELF_CLASS ELFCLASS32 @@ -927,7 +929,7 @@ struct exec #define TARGET_ELF_PAGESTART(_v) ((_v) & ~(unsigned long)(TARGET_ELF_EXEC_PAGESIZE-1)) #define TARGET_ELF_PAGEOFFSET(_v) ((_v) & (TARGET_ELF_EXEC_PAGESIZE-1)) -#define DLINFO_ITEMS 12 +#define DLINFO_ITEMS 13 static inline void memcpy_fromfs(void * to, const void * from, unsigned long n) { @@ -1202,6 +1204,9 @@ static abi_ulong create_elf_tables(abi_ulong p, int argc, int envc, { abi_ulong sp; int size; + int i; + abi_ulong u_rand_bytes; + uint8_t k_rand_bytes[16]; abi_ulong u_platform; const char *k_platform; const int n = sizeof(elf_addr_t); @@ -1231,6 +1236,20 @@ static abi_ulong create_elf_tables(abi_ulong p, int argc, int envc, /* FIXME - check return value of memcpy_to_target() for failure */ memcpy_to_target(sp, k_platform, len); } + + /* + * Generate 16 random bytes for userspace PRNG seeding (not + * cryptically secure but it's not the aim of QEMU). + */ + srand((unsigned int) time(NULL)); + for (i = 0; i < 16; i++) { + k_rand_bytes[i] = rand(); + } + sp -= 16; + u_rand_bytes = sp; + /* FIXME - check return value of memcpy_to_target() for failure */ + memcpy_to_target(sp, k_rand_bytes, 16); + /* * Force 16 byte _final_ alignment here for generality. */ @@ -1271,6 +1290,8 @@ static abi_ulong create_elf_tables(abi_ulong p, int argc, int envc, NEW_AUX_ENT(AT_EGID, (abi_ulong) getegid()); NEW_AUX_ENT(AT_HWCAP, (abi_ulong) ELF_HWCAP); NEW_AUX_ENT(AT_CLKTCK, (abi_ulong) sysconf(_SC_CLK_TCK)); + NEW_AUX_ENT(AT_RANDOM, (abi_ulong) u_rand_bytes); + if (k_platform) NEW_AUX_ENT(AT_PLATFORM, u_platform); #ifdef ARCH_DLINFO @@ -1288,6 +1309,78 @@ static abi_ulong create_elf_tables(abi_ulong p, int argc, int envc, return sp; } +static void probe_guest_base(const char *image_name, + abi_ulong loaddr, abi_ulong hiaddr) +{ + /* Probe for a suitable guest base address, if the user has not set + * it explicitly, and set guest_base appropriately. + * In case of error we will print a suitable message and exit. + */ +#if defined(CONFIG_USE_GUEST_BASE) + const char *errmsg; + if (!have_guest_base && !reserved_va) { + unsigned long host_start, real_start, host_size; + + /* Round addresses to page boundaries. */ + loaddr &= qemu_host_page_mask; + hiaddr = HOST_PAGE_ALIGN(hiaddr); + + if (loaddr < mmap_min_addr) { + host_start = HOST_PAGE_ALIGN(mmap_min_addr); + } else { + host_start = loaddr; + if (host_start != loaddr) { + errmsg = "Address overflow loading ELF binary"; + goto exit_errmsg; + } + } + host_size = hiaddr - loaddr; + while (1) { + /* Do not use mmap_find_vma here because that is limited to the + guest address space. We are going to make the + guest address space fit whatever we're given. */ + real_start = (unsigned long) + mmap((void *)host_start, host_size, PROT_NONE, + MAP_ANONYMOUS | MAP_PRIVATE | MAP_NORESERVE, -1, 0); + if (real_start == (unsigned long)-1) { + goto exit_perror; + } + if (real_start == host_start) { + break; + } + /* That address didn't work. Unmap and try a different one. + The address the host picked because is typically right at + the top of the host address space and leaves the guest with + no usable address space. Resort to a linear search. We + already compensated for mmap_min_addr, so this should not + happen often. Probably means we got unlucky and host + address space randomization put a shared library somewhere + inconvenient. */ + munmap((void *)real_start, host_size); + host_start += qemu_host_page_size; + if (host_start == loaddr) { + /* Theoretically possible if host doesn't have any suitably + aligned areas. Normally the first mmap will fail. */ + errmsg = "Unable to find space for application"; + goto exit_errmsg; + } + } + qemu_log("Relocating guest address space from 0x" + TARGET_ABI_FMT_lx " to 0x%lx\n", + loaddr, real_start); + guest_base = real_start - loaddr; + } + return; + +exit_perror: + errmsg = strerror(errno); +exit_errmsg: + fprintf(stderr, "%s: %s\n", image_name, errmsg); + exit(-1); +#endif +} + + /* Load an ELF image into the address space. IMAGE_NAME is the filename of the image, to use in error messages. @@ -1373,63 +1466,7 @@ static void load_elf_image(const char *image_name, int image_fd, /* This is the main executable. Make sure that the low address does not conflict with MMAP_MIN_ADDR or the QEMU application itself. */ -#if defined(CONFIG_USE_GUEST_BASE) - /* - * In case where user has not explicitly set the guest_base, we - * probe here that should we set it automatically. - */ - if (!have_guest_base && !reserved_va) { - unsigned long host_start, real_start, host_size; - - /* Round addresses to page boundaries. */ - loaddr &= qemu_host_page_mask; - hiaddr = HOST_PAGE_ALIGN(hiaddr); - - if (loaddr < mmap_min_addr) { - host_start = HOST_PAGE_ALIGN(mmap_min_addr); - } else { - host_start = loaddr; - if (host_start != loaddr) { - errmsg = "Address overflow loading ELF binary"; - goto exit_errmsg; - } - } - host_size = hiaddr - loaddr; - while (1) { - /* Do not use mmap_find_vma here because that is limited to the - guest address space. We are going to make the - guest address space fit whatever we're given. */ - real_start = (unsigned long) - mmap((void *)host_start, host_size, PROT_NONE, - MAP_ANONYMOUS | MAP_PRIVATE | MAP_NORESERVE, -1, 0); - if (real_start == (unsigned long)-1) { - goto exit_perror; - } - if (real_start == host_start) { - break; - } - /* That address didn't work. Unmap and try a different one. - The address the host picked because is typically right at - the top of the host address space and leaves the guest with - no usable address space. Resort to a linear search. We - already compensated for mmap_min_addr, so this should not - happen often. Probably means we got unlucky and host - address space randomization put a shared library somewhere - inconvenient. */ - munmap((void *)real_start, host_size); - host_start += qemu_host_page_size; - if (host_start == loaddr) { - /* Theoretically possible if host doesn't have any suitably - aligned areas. Normally the first mmap will fail. */ - errmsg = "Unable to find space for application"; - goto exit_errmsg; - } - } - qemu_log("Relocating guest address space from 0x" - TARGET_ABI_FMT_lx " to 0x%lx\n", loaddr, real_start); - guest_base = real_start - loaddr; - } -#endif + probe_guest_base(image_name, loaddr, hiaddr); } load_bias = load_addr - loaddr; @@ -1643,9 +1680,9 @@ static void load_symbols(struct elfhdr *hdr, int fd, abi_ulong load_bias) { int i, shnum, nsyms, sym_idx = 0, str_idx = 0; struct elf_shdr *shdr; - char *strings; - struct syminfo *s; - struct elf_sym *syms, *new_syms; + char *strings = NULL; + struct syminfo *s = NULL; + struct elf_sym *new_syms, *syms = NULL; shnum = hdr->e_shnum; i = shnum * sizeof(struct elf_shdr); @@ -1670,24 +1707,19 @@ static void load_symbols(struct elfhdr *hdr, int fd, abi_ulong load_bias) /* Now know where the strtab and symtab are. Snarf them. */ s = malloc(sizeof(*s)); if (!s) { - return; + goto give_up; } i = shdr[str_idx].sh_size; s->disas_strtab = strings = malloc(i); if (!strings || pread(fd, strings, i, shdr[str_idx].sh_offset) != i) { - free(s); - free(strings); - return; + goto give_up; } i = shdr[sym_idx].sh_size; syms = malloc(i); if (!syms || pread(fd, syms, i, shdr[sym_idx].sh_offset) != i) { - free(s); - free(strings); - free(syms); - return; + goto give_up; } nsyms = i / sizeof(struct elf_sym); @@ -1710,16 +1742,18 @@ static void load_symbols(struct elfhdr *hdr, int fd, abi_ulong load_bias) } } + /* No "useful" symbol. */ + if (nsyms == 0) { + goto give_up; + } + /* Attempt to free the storage associated with the local symbols that we threw away. Whether or not this has any effect on the memory allocation depends on the malloc implementation and how many symbols we managed to discard. */ new_syms = realloc(syms, nsyms * sizeof(*syms)); if (new_syms == NULL) { - free(s); - free(syms); - free(strings); - return; + goto give_up; } syms = new_syms; @@ -1734,6 +1768,13 @@ static void load_symbols(struct elfhdr *hdr, int fd, abi_ulong load_bias) s->lookup_symbol = lookup_symbolxx; s->next = syminfos; syminfos = s; + + return; + +give_up: + free(s); + free(strings); + free(syms); } int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * regs, diff --git a/linux-user/flatload.c b/linux-user/flatload.c index cd7af7cdff..1062da3852 100644 --- a/linux-user/flatload.c +++ b/linux-user/flatload.c @@ -379,12 +379,11 @@ static int load_flat_file(struct linux_binprm * bprm, abi_long result; abi_ulong realdatastart = 0; abi_ulong text_len, data_len, bss_len, stack_len, flags; - abi_ulong memp = 0; /* for finding the brk area */ abi_ulong extra; abi_ulong reloc = 0, rp; int i, rev, relocs = 0; abi_ulong fpos; - abi_ulong start_code, end_code; + abi_ulong start_code; abi_ulong indx_len; hdr = ((struct flat_hdr *) bprm->buf); /* exec-header */ @@ -491,7 +490,6 @@ static int load_flat_file(struct linux_binprm * bprm, } reloc = datapos + (ntohl(hdr->reloc_start) - text_len); - memp = realdatastart; } else { @@ -506,7 +504,6 @@ static int load_flat_file(struct linux_binprm * bprm, realdatastart = textpos + ntohl(hdr->data_start); datapos = realdatastart + indx_len; reloc = (textpos + ntohl(hdr->reloc_start) + indx_len); - memp = textpos; #ifdef CONFIG_BINFMT_ZFLAT #error code needs checking @@ -552,11 +549,10 @@ static int load_flat_file(struct linux_binprm * bprm, /* The main program needs a little extra setup in the task structure */ start_code = textpos + sizeof (struct flat_hdr); - end_code = textpos + text_len; DBG_FLT("%s %s: TEXT=%x-%x DATA=%x-%x BSS=%x-%x\n", id ? "Lib" : "Load", bprm->filename, - (int) start_code, (int) end_code, + (int) start_code, (int) (textpos + text_len), (int) datapos, (int) (datapos + data_len), (int) (datapos + data_len), diff --git a/linux-user/i386/syscall_nr.h b/linux-user/i386/syscall_nr.h index 3ef71ce004..74abfcacb4 100644 --- a/linux-user/i386/syscall_nr.h +++ b/linux-user/i386/syscall_nr.h @@ -335,3 +335,15 @@ #define TARGET_NR_dup3 330 #define TARGET_NR_pipe2 331 #define TARGET_NR_inotify_init1 332 +#define TARGET_NR_preadv 333 +#define TARGET_NR_pwritev 334 +#define TARGET_NR_rt_tgsigqueueinfo 335 +#define TARGET_NR_perf_event_open 336 +#define TARGET_NR_recvmmsg 337 +#define TARGET_NR_fanotify_init 338 +#define TARGET_NR_fanotify_mark 339 +#define TARGET_NR_prlimit64 340 +#define TARGET_NR_name_to_handle_at 341 +#define TARGET_NR_open_by_handle_at 342 +#define TARGET_NR_clock_adjtime 343 +#define TARGET_NR_syncfs 344 diff --git a/linux-user/ioctls.h b/linux-user/ioctls.h index 42b3ae3725..6514502dc4 100644 --- a/linux-user/ioctls.h +++ b/linux-user/ioctls.h @@ -59,6 +59,10 @@ IOCTL(KDSKBMODE, 0, TYPE_INT) IOCTL(KDGKBENT, IOC_RW, MK_PTR(MK_STRUCT(STRUCT_kbentry))) IOCTL(KDGKBSENT, IOC_RW, MK_PTR(MK_STRUCT(STRUCT_kbsentry))) + IOCTL(KDGKBLED, 0, TYPE_INT) + IOCTL(KDSKBLED, 0, TYPE_INT) + IOCTL(KDGETLED, 0, TYPE_INT) + IOCTL(KDSETLED, 0, TYPE_INT) IOCTL(BLKROSET, IOC_W, MK_PTR(TYPE_INT)) IOCTL(BLKROGET, IOC_R, MK_PTR(TYPE_INT)) @@ -325,6 +329,11 @@ IOCTL(FBIOGET_FSCREENINFO, IOC_R, MK_PTR(MK_STRUCT(STRUCT_fb_fix_screeninfo))) IOCTL(FBIOGET_VSCREENINFO, IOC_R, MK_PTR(MK_STRUCT(STRUCT_fb_var_screeninfo))) IOCTL(FBIOPUT_VSCREENINFO, IOC_W, MK_PTR(MK_STRUCT(STRUCT_fb_var_screeninfo))) + IOCTL(FBIOGETCMAP, IOC_RW, MK_PTR(MK_STRUCT(STRUCT_fb_cmap))) + IOCTL(FBIOPUTCMAP, IOC_RW, MK_PTR(MK_STRUCT(STRUCT_fb_cmap))) + IOCTL(FBIOPAN_DISPLAY, IOC_RW, MK_PTR(MK_STRUCT(STRUCT_fb_var_screeninfo))) + IOCTL(FBIOGET_CON2FBMAP, IOC_RW, MK_PTR(MK_STRUCT(STRUCT_fb_con2fbmap))) + IOCTL(FBIOPUT_CON2FBMAP, IOC_RW, MK_PTR(MK_STRUCT(STRUCT_fb_con2fbmap))) IOCTL(VT_OPENQRY, IOC_R, MK_PTR(TYPE_INT)) IOCTL(VT_GETSTATE, IOC_R, MK_PTR(MK_STRUCT(STRUCT_vt_stat))) @@ -332,3 +341,7 @@ IOCTL(VT_WAITACTIVE, 0, TYPE_INT) IOCTL(VT_LOCKSWITCH, 0, TYPE_INT) IOCTL(VT_UNLOCKSWITCH, 0, TYPE_INT) + IOCTL(VT_GETMODE, IOC_RW, MK_PTR(MK_STRUCT(STRUCT_vt_mode))) + IOCTL(VT_SETMODE, IOC_RW, MK_PTR(MK_STRUCT(STRUCT_vt_mode))) + IOCTL(VT_RELDISP, 0, TYPE_INT) + IOCTL(VT_DISALLOCATE, 0, TYPE_INT) diff --git a/linux-user/linuxload.c b/linux-user/linuxload.c index ac8c486c5f..62ebc7ed41 100644 --- a/linux-user/linuxload.c +++ b/linux-user/linuxload.c @@ -26,22 +26,6 @@ abi_long memcpy_to_target(abi_ulong dest, const void *src, return 0; } -static int in_group_p(gid_t g) -{ - /* return TRUE if we're in the specified group, FALSE otherwise */ - int ngroup; - int i; - gid_t grouplist[NGROUPS]; - - ngroup = getgroups(NGROUPS, grouplist); - for(i = 0; i < ngroup; i++) { - if(grouplist[i] == g) { - return 1; - } - } - return 0; -} - static int count(char ** vec) { int i; @@ -57,7 +41,7 @@ static int prepare_binprm(struct linux_binprm *bprm) { struct stat st; int mode; - int retval, id_change; + int retval; if(fstat(bprm->fd, &st) < 0) { return(-errno); @@ -73,14 +57,10 @@ static int prepare_binprm(struct linux_binprm *bprm) bprm->e_uid = geteuid(); bprm->e_gid = getegid(); - id_change = 0; /* Set-uid? */ if(mode & S_ISUID) { bprm->e_uid = st.st_uid; - if(bprm->e_uid != geteuid()) { - id_change = 1; - } } /* Set-gid? */ @@ -91,9 +71,6 @@ static int prepare_binprm(struct linux_binprm *bprm) */ if ((mode & (S_ISGID | S_IXGRP)) == (S_ISGID | S_IXGRP)) { bprm->e_gid = st.st_gid; - if (!in_group_p(bprm->e_gid)) { - id_change = 1; - } } retval = read(bprm->fd, bprm->buf, BPRM_BUF_SIZE); diff --git a/linux-user/m68k/syscall_nr.h b/linux-user/m68k/syscall_nr.h index 1c0ba07bfb..4d0937e505 100644 --- a/linux-user/m68k/syscall_nr.h +++ b/linux-user/m68k/syscall_nr.h @@ -328,3 +328,19 @@ #define TARGET_NR_dup3 326 #define TARGET_NR_pipe2 327 #define TARGET_NR_inotify_init1 328 +#define TARGET_NR_inotify_init1 328 +#define TARGET_NR_preadv 329 +#define TARGET_NR_pwritev 330 +#define TARGET_NR_rt_tgsigqueueinfo 331 +#define TARGET_NR_perf_event_open 332 +#define TARGET_NR_get_thread_area 333 +#define TARGET_NR_set_thread_area 334 +#define TARGET_NR_atomic_cmpxchg_32 335 +#define TARGET_NR_atomic_barrier 336 +#define TARGET_NR_fanotify_init 337 +#define TARGET_NR_fanotify_mark 338 +#define TARGET_NR_prlimit64 339 +#define TARGET_NR_name_to_handle_at 340 +#define TARGET_NR_open_by_handle_at 341 +#define TARGET_NR_clock_adjtime 342 +#define TARGET_NR_syncfs 343 diff --git a/linux-user/main.c b/linux-user/main.c index 71dd253786..2135b9c714 100644 --- a/linux-user/main.c +++ b/linux-user/main.c @@ -29,8 +29,7 @@ #include "qemu.h" #include "qemu-common.h" #include "cache-utils.h" -/* For tb_lock */ -#include "exec-all.h" +#include "cpu.h" #include "tcg.h" #include "qemu-timer.h" #include "envlist.h" @@ -319,7 +318,8 @@ void cpu_loop(CPUX86State *env) env->regs[R_EDX], env->regs[R_ESI], env->regs[R_EDI], - env->regs[R_EBP]); + env->regs[R_EBP], + 0, 0); break; #ifndef TARGET_ABI32 case EXCP_SYSCALL: @@ -331,7 +331,8 @@ void cpu_loop(CPUX86State *env) env->regs[R_EDX], env->regs[10], env->regs[8], - env->regs[9]); + env->regs[9], + 0, 0); env->eip = env->exception_next_eip; break; #endif @@ -735,7 +736,8 @@ void cpu_loop(CPUARMState *env) env->regs[2], env->regs[3], env->regs[4], - env->regs[5]); + env->regs[5], + 0, 0); } } else { goto error; @@ -831,7 +833,8 @@ void cpu_loop(CPUState *env) env->regs[2], env->regs[3], env->regs[4], - env->regs[5]); + env->regs[5], + 0, 0); } } else { goto error; @@ -1018,7 +1021,8 @@ void cpu_loop (CPUSPARCState *env) ret = do_syscall (env, env->gregs[1], env->regwptr[0], env->regwptr[1], env->regwptr[2], env->regwptr[3], - env->regwptr[4], env->regwptr[5]); + env->regwptr[4], env->regwptr[5], + 0, 0); if ((abi_ulong)ret >= (abi_ulong)(-515)) { #if defined(TARGET_SPARC64) && !defined(TARGET_ABI32) env->xcc |= PSR_CARRY; @@ -1611,7 +1615,7 @@ void cpu_loop(CPUPPCState *env) env->crf[0] &= ~0x1; ret = do_syscall(env, env->gpr[0], env->gpr[3], env->gpr[4], env->gpr[5], env->gpr[6], env->gpr[7], - env->gpr[8]); + env->gpr[8], 0, 0); if (ret == (uint32_t)(-TARGET_QEMU_ESIGRETURN)) { /* Returning from a successful sigreturn syscall. Avoid corrupting register state. */ @@ -1871,7 +1875,7 @@ static const uint8_t mips_syscall_args[] = { MIPS_SYS(sys_getcwd , 2) MIPS_SYS(sys_capget , 2) MIPS_SYS(sys_capset , 2) /* 4205 */ - MIPS_SYS(sys_sigaltstack , 0) + MIPS_SYS(sys_sigaltstack , 2) MIPS_SYS(sys_sendfile , 4) MIPS_SYS(sys_ni_syscall , 0) MIPS_SYS(sys_ni_syscall , 0) @@ -1981,6 +1985,33 @@ static const uint8_t mips_syscall_args[] = { MIPS_SYS(sys_epoll_pwait, 6) MIPS_SYS(sys_ioprio_set, 3) MIPS_SYS(sys_ioprio_get, 2) + MIPS_SYS(sys_utimensat, 4) + MIPS_SYS(sys_signalfd, 3) + MIPS_SYS(sys_ni_syscall, 0) /* was timerfd */ + MIPS_SYS(sys_eventfd, 1) + MIPS_SYS(sys_fallocate, 6) /* 4320 */ + MIPS_SYS(sys_timerfd_create, 2) + MIPS_SYS(sys_timerfd_gettime, 2) + MIPS_SYS(sys_timerfd_settime, 4) + MIPS_SYS(sys_signalfd4, 4) + MIPS_SYS(sys_eventfd2, 2) /* 4325 */ + MIPS_SYS(sys_epoll_create1, 1) + MIPS_SYS(sys_dup3, 3) + MIPS_SYS(sys_pipe2, 2) + MIPS_SYS(sys_inotify_init1, 1) + MIPS_SYS(sys_preadv, 6) /* 4330 */ + MIPS_SYS(sys_pwritev, 6) + MIPS_SYS(sys_rt_tgsigqueueinfo, 4) + MIPS_SYS(sys_perf_event_open, 5) + MIPS_SYS(sys_accept4, 4) + MIPS_SYS(sys_recvmmsg, 5) /* 4335 */ + MIPS_SYS(sys_fanotify_init, 2) + MIPS_SYS(sys_fanotify_mark, 6) + MIPS_SYS(sys_prlimit64, 4) + MIPS_SYS(sys_name_to_handle_at, 5) + MIPS_SYS(sys_open_by_handle_at, 3) /* 4340 */ + MIPS_SYS(sys_clock_adjtime, 2) + MIPS_SYS(sys_syncfs, 1) }; #undef MIPS_SYS @@ -2049,7 +2080,7 @@ void cpu_loop(CPUMIPSState *env) syscall_num = env->active_tc.gpr[2] - 4000; env->active_tc.PC += 4; if (syscall_num >= sizeof(mips_syscall_args)) { - ret = -ENOSYS; + ret = -TARGET_ENOSYS; } else { int nb_args; abi_ulong sp_reg; @@ -2072,7 +2103,7 @@ void cpu_loop(CPUMIPSState *env) env->active_tc.gpr[5], env->active_tc.gpr[6], env->active_tc.gpr[7], - arg5, arg6/*, arg7, arg8*/); + arg5, arg6, arg7, arg8); } if (ret == -TARGET_QEMU_ESIGRETURN) { /* Returning from a successful sigreturn syscall. @@ -2089,6 +2120,8 @@ void cpu_loop(CPUMIPSState *env) break; case EXCP_TLBL: case EXCP_TLBS: + case EXCP_AdEL: + case EXCP_AdES: info.si_signo = TARGET_SIGSEGV; info.si_errno = 0; /* XXX: check env->error_code */ @@ -2160,7 +2193,8 @@ void cpu_loop (CPUState *env) env->gregs[6], env->gregs[7], env->gregs[0], - env->gregs[1]); + env->gregs[1], + 0, 0); env->gregs[0] = ret; break; case EXCP_INTERRUPT: @@ -2229,7 +2263,8 @@ void cpu_loop (CPUState *env) env->regs[12], env->regs[13], env->pregs[7], - env->pregs[11]); + env->pregs[11], + 0, 0); env->regs[10] = ret; break; case EXCP_DEBUG: @@ -2288,7 +2323,8 @@ void cpu_loop (CPUState *env) env->regs[7], env->regs[8], env->regs[9], - env->regs[10]); + env->regs[10], + 0, 0); env->regs[3] = ret; env->sregs[SR_PC] = env->regs[14]; break; @@ -2398,7 +2434,8 @@ void cpu_loop(CPUM68KState *env) env->dregs[3], env->dregs[4], env->dregs[5], - env->aregs[0]); + env->aregs[0], + 0, 0); } break; case EXCP_INTERRUPT: @@ -2576,7 +2613,8 @@ void cpu_loop (CPUState *env) sysret = do_syscall(env, trapnr, env->ir[IR_A0], env->ir[IR_A1], env->ir[IR_A2], env->ir[IR_A3], - env->ir[IR_A4], env->ir[IR_A5]); + env->ir[IR_A4], env->ir[IR_A5], + 0, 0); if (trapnr == TARGET_NR_sigreturn || trapnr == TARGET_NR_rt_sigreturn) { break; @@ -2707,7 +2745,8 @@ void cpu_loop(CPUS390XState *env) env->regs[4], env->regs[5], env->regs[6], - env->regs[7]); + env->regs[7], + 0, 0); } break; case EXCP_ADDR: @@ -3020,7 +3059,7 @@ int main(int argc, char **argv, char **envp) int mask; const CPULogItem *item; - mask = cpu_str_to_log_mask(r); + mask = cpu_str_to_log_mask(log_mask); if (!mask) { printf("Log items (comma separated):\n"); for (item = cpu_log_items; item->mask != 0; item++) { diff --git a/linux-user/microblaze/syscall_nr.h b/linux-user/microblaze/syscall_nr.h index 3e641cdb4d..f1fe0e7d8f 100644 --- a/linux-user/microblaze/syscall_nr.h +++ b/linux-user/microblaze/syscall_nr.h @@ -364,6 +364,16 @@ #define TARGET_NR_sendmsg 360 /* new */ #define TARGET_NR_recvmsg 361 /* new */ #define TARGET_NR_accept04 362 /* new */ - -#define TARGET_NR_syscalls 363 +#define TARGET_NR_preadv 363 /* new */ +#define TARGET_NR_pwritev 364 /* new */ +#define TARGET_NR_rt_tgsigqueueinfo 365 /* new */ +#define TARGET_NR_perf_event_open 366 /* new */ +#define TARGET_NR_recvmmsg 367 /* new */ +#define TARGET_NR_fanotify_init 368 +#define TARGET_NR_fanotify_mark 369 +#define TARGET_NR_prlimit64 370 +#define TARGET_NR_name_to_handle_at 371 +#define TARGET_NR_open_by_handle_at 372 +#define TARGET_NR_clock_adjtime 373 +#define TARGET_NR_syncfs 374 diff --git a/linux-user/mips/syscall_nr.h b/linux-user/mips/syscall_nr.h index 059530801b..fbdc348ffc 100644 --- a/linux-user/mips/syscall_nr.h +++ b/linux-user/mips/syscall_nr.h @@ -332,3 +332,16 @@ #define TARGET_NR_dup3 (TARGET_NR_Linux + 327) #define TARGET_NR_pipe2 (TARGET_NR_Linux + 328) #define TARGET_NR_inotify_init1 (TARGET_NR_Linux + 329) +#define TARGET_NR_preadv (TARGET_NR_Linux + 330) +#define TARGET_NR_pwritev (TARGET_NR_Linux + 331) +#define TARGET_NR_rt_tgsigqueueinfo (TARGET_NR_Linux + 332) +#define TARGET_NR_perf_event_open (TARGET_NR_Linux + 333) +#define TARGET_NR_accept4 (TARGET_NR_Linux + 334) +#define TARGET_NR_recvmmsg (TARGET_NR_Linux + 335) +#define TARGET_NR_fanotify_init (TARGET_NR_Linux + 336) +#define TARGET_NR_fanotify_mark (TARGET_NR_Linux + 337) +#define TARGET_NR_prlimit64 (TARGET_NR_Linux + 338) +#define TARGET_NR_name_to_handle_at (TARGET_NR_Linux + 339) +#define TARGET_NR_open_by_handle_at (TARGET_NR_Linux + 340) +#define TARGET_NR_clock_adjtime (TARGET_NR_Linux + 341) +#define TARGET_NR_syncfs (TARGET_NR_Linux + 342) diff --git a/linux-user/mips64/syscall_nr.h b/linux-user/mips64/syscall_nr.h index ee1d134146..36d27b5159 100644 --- a/linux-user/mips64/syscall_nr.h +++ b/linux-user/mips64/syscall_nr.h @@ -291,3 +291,16 @@ #define TARGET_NR_dup3 (TARGET_NR_Linux + 286) #define TARGET_NR_pipe2 (TARGET_NR_Linux + 287) #define TARGET_NR_inotify_init1 (TARGET_NR_Linux + 288) +#define TARGET_NR_preadv (TARGET_NR_Linux + 289) +#define TARGET_NR_pwritev (TARGET_NR_Linux + 290) +#define TARGET_NR_rt_tgsigqueueinfo (TARGET_NR_Linux + 291) +#define TARGET_NR_perf_event_open (TARGET_NR_Linux + 292) +#define TARGET_NR_accept4 (TARGET_NR_Linux + 293) +#define TARGET_NR_recvmmsg (TARGET_NR_Linux + 294) +#define TARGET_NR_fanotify_init (TARGET_NR_Linux + 295) +#define TARGET_NR_fanotify_mark (TARGET_NR_Linux + 296) +#define TARGET_NR_prlimit64 (TARGET_NR_Linux + 297) +#define TARGET_NR_name_to_handle_at (TARGET_NR_Linux + 298) +#define TARGET_NR_open_by_handle_at (TARGET_NR_Linux + 299) +#define TARGET_NR_clock_adjtime (TARGET_NR_Linux + 300) +#define TARGET_NR_syncfs (TARGET_NR_Linux + 301) diff --git a/linux-user/mipsn32/syscall_nr.h b/linux-user/mipsn32/syscall_nr.h index 60a99ddf6e..4e1aca3a9b 100644 --- a/linux-user/mipsn32/syscall_nr.h +++ b/linux-user/mipsn32/syscall_nr.h @@ -295,3 +295,17 @@ #define TARGET_NR_dup3 (TARGET_NR_Linux + 290) #define TARGET_NR_pipe2 (TARGET_NR_Linux + 291) #define TARGET_NR_inotify_init1 (TARGET_NR_Linux + 292) +#define TARGET_NR_preadv (TARGET_NR_Linux + 293) +#define TARGET_NR_pwritev (TARGET_NR_Linux + 294) +#define TARGET_NR_rt_tgsigqueueinfo (TARGET_NR_Linux + 295) +#define TARGET_NR_perf_event_open (TARGET_NR_Linux + 296) +#define TARGET_NR_accept4 (TARGET_NR_Linux + 297) +#define TARGET_NR_recvmmsg (TARGET_NR_Linux + 298) +#define TARGET_NR_getdents64 (TARGET_NR_Linux + 299) +#define TARGET_NR_fanotify_init (TARGET_NR_Linux + 300) +#define TARGET_NR_fanotify_mark (TARGET_NR_Linux + 301) +#define TARGET_NR_prlimit64 (TARGET_NR_Linux + 302) +#define TARGET_NR_name_to_handle_at (TARGET_NR_Linux + 303) +#define TARGET_NR_open_by_handle_at (TARGET_NR_Linux + 304) +#define TARGET_NR_clock_adjtime (TARGET_NR_Linux + 305) +#define TARGET_NR_syncfs (TARGET_NR_Linux + 306) diff --git a/linux-user/ppc/syscall_nr.h b/linux-user/ppc/syscall_nr.h index cc84a4c04d..0673b7d169 100644 --- a/linux-user/ppc/syscall_nr.h +++ b/linux-user/ppc/syscall_nr.h @@ -332,3 +332,33 @@ #define TARGET_NR_dup3 316 #define TARGET_NR_pipe2 317 #define TARGET_NR_inotify_init1 318 +#define TARGET_NR_perf_event_open 319 +#define TARGET_NR_preadv 320 +#define TARGET_NR_pwritev 321 +#define TARGET_NR_rt_tgsigqueueinfo 322 +#define TARGET_NR_fanotify_init 323 +#define TARGET_NR_fanotify_mark 324 +#define TARGET_NR_prlimit64 325 +#define TARGET_NR_socket 326 +#define TARGET_NR_bind 327 +#define TARGET_NR_connect 328 +#define TARGET_NR_listen 329 +#define TARGET_NR_accept 330 +#define TARGET_NR_getsockname 331 +#define TARGET_NR_getpeername 332 +#define TARGET_NR_socketpair 333 +#define TARGET_NR_send 334 +#define TARGET_NR_sendto 335 +#define TARGET_NR_recv 336 +#define TARGET_NR_recvfrom 337 +#define TARGET_NR_shutdown 338 +#define TARGET_NR_setsockopt 339 +#define TARGET_NR_getsockopt 340 +#define TARGET_NR_sendmsg 341 +#define TARGET_NR_recvmsg 342 +#define TARGET_NR_recvmmsg 343 +#define TARGET_NR_accept4 344 +#define TARGET_NR_name_to_handle_at 345 +#define TARGET_NR_open_by_handle_at 346 +#define TARGET_NR_clock_adjtime 347 +#define TARGET_NR_syncfs 348 diff --git a/linux-user/qemu.h b/linux-user/qemu.h index 237386caac..627c8b3423 100644 --- a/linux-user/qemu.h +++ b/linux-user/qemu.h @@ -192,7 +192,8 @@ abi_long do_brk(abi_ulong new_brk); void syscall_init(void); abi_long do_syscall(void *cpu_env, int num, abi_long arg1, abi_long arg2, abi_long arg3, abi_long arg4, - abi_long arg5, abi_long arg6); + abi_long arg5, abi_long arg6, abi_long arg7, + abi_long arg8); void gemu_log(const char *fmt, ...) GCC_FMT_ATTR(1, 2); extern THREAD CPUState *thread_env; void cpu_loop(CPUState *env); diff --git a/linux-user/s390x/syscall_nr.h b/linux-user/s390x/syscall_nr.h index 7cc6db2e1b..d4529ac03c 100644 --- a/linux-user/s390x/syscall_nr.h +++ b/linux-user/s390x/syscall_nr.h @@ -254,8 +254,17 @@ #define TARGET_NR_pipe2 325 #define TARGET_NR_dup3 326 #define TARGET_NR_epoll_create1 327 -#undef NR_syscalls -#define NR_syscalls 328 +#define TARGET_NR_preadv 328 +#define TARGET_NR_pwritev 329 +#define TARGET_NR_rt_tgsigqueueinfo 330 +#define TARGET_NR_perf_event_open 331 +#define TARGET_NR_fanotify_init 332 +#define TARGET_NR_fanotify_mark 333 +#define TARGET_NR_prlimit64 334 +#define TARGET_NR_name_to_handle_at 335 +#define TARGET_NR_open_by_handle_at 336 +#define TARGET_NR_clock_adjtime 337 +#define TARGET_NR_syncfs 338 /* * There are some system calls that are not present on 64 bit, some diff --git a/linux-user/sh4/syscall_nr.h b/linux-user/sh4/syscall_nr.h index 262b236333..365db586c7 100644 --- a/linux-user/sh4/syscall_nr.h +++ b/linux-user/sh4/syscall_nr.h @@ -125,7 +125,7 @@ #define TARGET_NR_clone 120 #define TARGET_NR_setdomainname 121 #define TARGET_NR_uname 122 -#define TARGET_NR_modify_ldt 123 +#define TARGET_NR_cacheflush 123 #define TARGET_NR_adjtimex 124 #define TARGET_NR_mprotect 125 #define TARGET_NR_sigprocmask 126 @@ -334,3 +334,35 @@ #define TARGET_NR_dup3 330 #define TARGET_NR_pipe2 331 #define TARGET_NR_inotify_init1 332 +#define TARGET_NR_preadv 333 +#define TARGET_NR_pwritev 334 +#define TARGET_NR_rt_tgsigqueueinfo 335 +#define TARGET_NR_perf_event_open 336 +#define TARGET_NR_fanotify_init 337 +#define TARGET_NR_fanotify_mark 338 +#define TARGET_NR_prlimit64 339 + +/* Non-multiplexed socket family */ +#define TARGET_NR_socket 340 +#define TARGET_NR_bind 341 +#define TARGET_NR_connect 342 +#define TARGET_NR_listen 343 +#define TARGET_NR_accept 344 +#define TARGET_NR_getsockname 345 +#define TARGET_NR_getpeername 346 +#define TARGET_NR_socketpair 347 +#define TARGET_NR_send 348 +#define TARGET_NR_sendto 349 +#define TARGET_NR_recv 350 +#define TARGET_NR_recvfrom 351 +#define TARGET_NR_shutdown 352 +#define TARGET_NR_setsockopt 353 +#define TARGET_NR_getsockopt 354 +#define TARGET_NR_sendmsg 355 +#define TARGET_NR_recvmsg 356 +#define TARGET_NR_recvmmsg 357 +#define TARGET_NR_accept4 358 +#define TARGET_NR_name_to_handle_at 359 +#define TARGET_NR_open_by_handle_at 360 +#define TARGET_NR_clock_adjtime 361 +#define TARGET_NR_syncfs 362 diff --git a/linux-user/signal.c b/linux-user/signal.c index 11b25be7b8..07ad07a58f 100644 --- a/linux-user/signal.c +++ b/linux-user/signal.c @@ -981,8 +981,8 @@ restore_sigcontext(CPUX86State *env, struct target_sigcontext *sc, int *peax) env->regs[R_ECX] = tswapl(sc->ecx); env->eip = tswapl(sc->eip); - cpu_x86_load_seg(env, R_CS, lduw(&sc->cs) | 3); - cpu_x86_load_seg(env, R_SS, lduw(&sc->ss) | 3); + cpu_x86_load_seg(env, R_CS, lduw_p(&sc->cs) | 3); + cpu_x86_load_seg(env, R_SS, lduw_p(&sc->ss) | 3); tmpflags = tswapl(sc->eflags); env->eflags = (env->eflags & ~0x40DD5) | (tmpflags & 0x40DD5); @@ -2080,7 +2080,6 @@ long do_sigreturn(CPUState *env) uint32_t up_psr, pc, npc; target_sigset_t set; sigset_t host_set; - abi_ulong fpu_save_addr; int err, i; sf_addr = env->regwptr[UREG_FP]; @@ -2120,10 +2119,11 @@ long do_sigreturn(CPUState *env) err |= __get_user(env->regwptr[i + UREG_I0], &sf->info.si_regs.u_regs[i+8]); } - err |= __get_user(fpu_save_addr, &sf->fpu_save); - - //if (fpu_save) - // err |= restore_fpu_state(env, fpu_save); + /* FIXME: implement FPU save/restore: + * __get_user(fpu_save, &sf->fpu_save); + * if (fpu_save) + * err |= restore_fpu_state(env, fpu_save); + */ /* This is pretty much atomic, no amount locking would prevent * the races which exist anyways. @@ -2228,7 +2228,6 @@ void sparc64_set_context(CPUSPARCState *env) target_mc_gregset_t *grp; abi_ulong pc, npc, tstate; abi_ulong fp, i7, w_addr; - unsigned char fenab; int err; unsigned int i; @@ -2293,7 +2292,11 @@ void sparc64_set_context(CPUSPARCState *env) if (put_user(i7, w_addr + offsetof(struct target_reg_window, ins[7]), abi_ulong) != 0) goto do_sigsegv; - err |= __get_user(fenab, &(ucp->tuc_mcontext.mc_fpregs.mcfpu_enab)); + /* FIXME this does not match how the kernel handles the FPU in + * its sparc64_set_context implementation. In particular the FPU + * is only restored if fenab is non-zero in: + * __get_user(fenab, &(ucp->tuc_mcontext.mc_fpregs.mcfpu_enab)); + */ err |= __get_user(env->fprs, &(ucp->tuc_mcontext.mc_fpregs.mcfpu_fprs)); { uint32_t *src, *dst; @@ -3659,11 +3662,11 @@ typedef struct { } sigframe; struct target_ucontext { - target_ulong uc_flags; - struct target_ucontext *uc_link; - target_stack_t uc_stack; - target_sigregs uc_mcontext; - target_sigset_t uc_sigmask; /* mask last for extensibility */ + target_ulong tuc_flags; + struct target_ucontext *tuc_link; + target_stack_t tuc_stack; + target_sigregs tuc_mcontext; + target_sigset_t tuc_sigmask; /* mask last for extensibility */ }; typedef struct { @@ -3811,16 +3814,16 @@ static void setup_rt_frame(int sig, struct target_sigaction *ka, } /* Create the ucontext. */ - __put_user(0, &frame->uc.uc_flags); - __put_user((abi_ulong)0, (abi_ulong *)&frame->uc.uc_link); - __put_user(target_sigaltstack_used.ss_sp, &frame->uc.uc_stack.ss_sp); + __put_user(0, &frame->uc.tuc_flags); + __put_user((abi_ulong)0, (abi_ulong *)&frame->uc.tuc_link); + __put_user(target_sigaltstack_used.ss_sp, &frame->uc.tuc_stack.ss_sp); __put_user(sas_ss_flags(get_sp_from_cpustate(env)), - &frame->uc.uc_stack.ss_flags); - __put_user(target_sigaltstack_used.ss_size, &frame->uc.uc_stack.ss_size); - save_sigregs(env, &frame->uc.uc_mcontext); + &frame->uc.tuc_stack.ss_flags); + __put_user(target_sigaltstack_used.ss_size, &frame->uc.tuc_stack.ss_size); + save_sigregs(env, &frame->uc.tuc_mcontext); for (i = 0; i < TARGET_NSIG_WORDS; i++) { __put_user((abi_ulong)set->sig[i], - (abi_ulong *)&frame->uc.uc_sigmask.sig[i]); + (abi_ulong *)&frame->uc.tuc_sigmask.sig[i]); } /* Set up to return from userspace. If provided, use a stub @@ -3925,15 +3928,15 @@ long do_rt_sigreturn(CPUState *env) if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1)) { goto badframe; } - target_to_host_sigset(&set, &frame->uc.uc_sigmask); + target_to_host_sigset(&set, &frame->uc.tuc_sigmask); sigprocmask(SIG_SETMASK, &set, NULL); /* ~_BLOCKABLE? */ - if (restore_sigregs(env, &frame->uc.uc_mcontext)) { + if (restore_sigregs(env, &frame->uc.tuc_mcontext)) { goto badframe; } - if (do_sigaltstack(frame_addr + offsetof(rt_sigframe, uc.uc_stack), 0, + if (do_sigaltstack(frame_addr + offsetof(rt_sigframe, uc.tuc_stack), 0, get_sp_from_cpustate(env)) == -EFAULT) { goto badframe; } diff --git a/linux-user/sparc/syscall_nr.h b/linux-user/sparc/syscall_nr.h index 5d1ac21ac9..be503f23dd 100644 --- a/linux-user/sparc/syscall_nr.h +++ b/linux-user/sparc/syscall_nr.h @@ -285,3 +285,15 @@ #define TARGET_NR_pipe2 321 #define TARGET_NR_inotify_init1 322 #define TARGET_NR_accept4 323 +#define TARGET_NR_preadv 324 +#define TARGET_NR_pwritev 325 +#define TARGET_NR_rt_tgsigqueueinfo 326 +#define TARGET_NR_perf_event_open 327 +#define TARGET_NR_recvmmsg 328 +#define TARGET_NR_fanotify_init 329 +#define TARGET_NR_fanotify_mark 330 +#define TARGET_NR_prlimit64 331 +#define TARGET_NR_name_to_handle_at 332 +#define TARGET_NR_open_by_handle_at 333 +#define TARGET_NR_clock_adjtime 334 +#define TARGET_NR_syncfs 335 diff --git a/linux-user/sparc64/syscall_nr.h b/linux-user/sparc64/syscall_nr.h index bdca2a7331..70988b2ec9 100644 --- a/linux-user/sparc64/syscall_nr.h +++ b/linux-user/sparc64/syscall_nr.h @@ -322,3 +322,15 @@ #define TARGET_NR_pipe2 321 #define TARGET_NR_inotify_init1 322 #define TARGET_NR_accept4 323 +#define TARGET_NR_preadv 324 +#define TARGET_NR_pwritev 325 +#define TARGET_NR_rt_tgsigqueueinfo 326 +#define TARGET_NR_perf_event_open 327 +#define TARGET_NR_recvmmsg 328 +#define TARGET_NR_fanotify_init 329 +#define TARGET_NR_fanotify_mark 330 +#define TARGET_NR_prlimit64 331 +#define TARGET_NR_name_to_handle_at 332 +#define TARGET_NR_open_by_handle_at 333 +#define TARGET_NR_clock_adjtime 334 +#define TARGET_NR_syncfs 335 diff --git a/linux-user/syscall.c b/linux-user/syscall.c index 5cb27c7f9f..1dd7aad43c 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -550,12 +550,47 @@ _syscall5(int, sys_ppoll, struct pollfd *, fds, nfds_t, nfds, size_t, sigsetsize) #endif +#if defined(TARGET_NR_pselect6) +#ifndef __NR_pselect6 +# define __NR_pselect6 -1 +#endif +#define __NR_sys_pselect6 __NR_pselect6 +_syscall6(int, sys_pselect6, int, nfds, fd_set *, readfds, fd_set *, writefds, + fd_set *, exceptfds, struct timespec *, timeout, void *, sig); +#endif + +#if defined(TARGET_NR_prlimit64) +#ifndef __NR_prlimit64 +# define __NR_prlimit64 -1 +#endif +#define __NR_sys_prlimit64 __NR_prlimit64 +/* The glibc rlimit structure may not be that used by the underlying syscall */ +struct host_rlimit64 { + uint64_t rlim_cur; + uint64_t rlim_max; +}; +_syscall4(int, sys_prlimit64, pid_t, pid, int, resource, + const struct host_rlimit64 *, new_limit, + struct host_rlimit64 *, old_limit) +#endif + extern int personality(int); extern int flock(int, int); extern int setfsuid(int); extern int setfsgid(int); extern int setgroups(int, gid_t *); +/* ARM EABI and MIPS expect 64bit types aligned even on pairs or registers */ +#ifdef TARGET_ARM +static inline int regpairs_aligned(void *cpu_env) { + return ((((CPUARMState *)cpu_env)->eabi) == 1) ; +} +#elif defined(TARGET_MIPS) +static inline int regpairs_aligned(void *cpu_env) { return 1; } +#else +static inline int regpairs_aligned(void *cpu_env) { return 0; } +#endif + #define ERRNO_TABLE_SIZE 1200 /* target_to_host_errno_table[] is initialized from @@ -709,49 +744,81 @@ char *target_strerror(int err) static abi_ulong target_brk; static abi_ulong target_original_brk; +static abi_ulong brk_page; void target_set_brk(abi_ulong new_brk) { target_original_brk = target_brk = HOST_PAGE_ALIGN(new_brk); + brk_page = HOST_PAGE_ALIGN(target_brk); } +//#define DEBUGF_BRK(message, args...) do { fprintf(stderr, (message), ## args); } while (0) +#define DEBUGF_BRK(message, args...) + /* do_brk() must return target values and target errnos. */ abi_long do_brk(abi_ulong new_brk) { - abi_ulong brk_page; abi_long mapped_addr; int new_alloc_size; - if (!new_brk) + DEBUGF_BRK("do_brk(%#010x) -> ", new_brk); + + if (!new_brk) { + DEBUGF_BRK("%#010x (!new_brk)\n", target_brk); return target_brk; - if (new_brk < target_original_brk) + } + if (new_brk < target_original_brk) { + DEBUGF_BRK("%#010x (new_brk < target_original_brk)\n", target_brk); return target_brk; + } - brk_page = HOST_PAGE_ALIGN(target_brk); - - /* If the new brk is less than this, set it and we're done... */ - if (new_brk < brk_page) { + /* If the new brk is less than the highest page reserved to the + * target heap allocation, set it and we're almost done... */ + if (new_brk <= brk_page) { + /* Heap contents are initialized to zero, as for anonymous + * mapped pages. */ + if (new_brk > target_brk) { + memset(g2h(target_brk), 0, new_brk - target_brk); + } target_brk = new_brk; + DEBUGF_BRK("%#010x (new_brk <= brk_page)\n", target_brk); return target_brk; } - /* We need to allocate more memory after the brk... */ - new_alloc_size = HOST_PAGE_ALIGN(new_brk - brk_page + 1); + /* We need to allocate more memory after the brk... Note that + * we don't use MAP_FIXED because that will map over the top of + * any existing mapping (like the one with the host libc or qemu + * itself); instead we treat "mapped but at wrong address" as + * a failure and unmap again. + */ + new_alloc_size = HOST_PAGE_ALIGN(new_brk - brk_page); mapped_addr = get_errno(target_mmap(brk_page, new_alloc_size, PROT_READ|PROT_WRITE, - MAP_ANON|MAP_FIXED|MAP_PRIVATE, 0, 0)); + MAP_ANON|MAP_PRIVATE, 0, 0)); + + if (mapped_addr == brk_page) { + target_brk = new_brk; + brk_page = HOST_PAGE_ALIGN(target_brk); + DEBUGF_BRK("%#010x (mapped_addr == brk_page)\n", target_brk); + return target_brk; + } else if (mapped_addr != -1) { + /* Mapped but at wrong address, meaning there wasn't actually + * enough space for this brk. + */ + target_munmap(mapped_addr, new_alloc_size); + mapped_addr = -1; + DEBUGF_BRK("%#010x (mapped_addr != -1)\n", target_brk); + } + else { + DEBUGF_BRK("%#010x (otherwise)\n", target_brk); + } #if defined(TARGET_ALPHA) /* We (partially) emulate OSF/1 on Alpha, which requires we return a proper errno, not an unchanged brk value. */ - if (is_error(mapped_addr)) { - return -TARGET_ENOMEM; - } + return -TARGET_ENOMEM; #endif - - if (!is_error(mapped_addr)) { - target_brk = new_brk; - } + /* For everything else, return the previous break. */ return target_brk; } @@ -787,6 +854,20 @@ static inline abi_long copy_from_user_fdset(fd_set *fds, return 0; } +static inline abi_ulong copy_from_user_fdset_ptr(fd_set *fds, fd_set **fds_ptr, + abi_ulong target_fds_addr, + int n) +{ + if (target_fds_addr) { + if (copy_from_user_fdset(fds, target_fds_addr, n)) + return -TARGET_EFAULT; + *fds_ptr = fds; + } else { + *fds_ptr = NULL; + } + return 0; +} + static inline abi_long copy_to_user_fdset(abi_ulong target_fds_addr, const fd_set *fds, int n) @@ -864,18 +945,68 @@ static inline abi_long host_to_target_rusage(abi_ulong target_addr, static inline rlim_t target_to_host_rlim(target_ulong target_rlim) { - if (target_rlim == TARGET_RLIM_INFINITY) - return RLIM_INFINITY; + target_ulong target_rlim_swap; + rlim_t result; + + target_rlim_swap = tswapl(target_rlim); + if (target_rlim_swap == TARGET_RLIM_INFINITY || target_rlim_swap != (rlim_t)target_rlim_swap) + result = RLIM_INFINITY; else - return tswapl(target_rlim); + result = target_rlim_swap; + + return result; } static inline target_ulong host_to_target_rlim(rlim_t rlim) { + target_ulong target_rlim_swap; + target_ulong result; + if (rlim == RLIM_INFINITY || rlim != (target_long)rlim) - return TARGET_RLIM_INFINITY; + target_rlim_swap = TARGET_RLIM_INFINITY; else - return tswapl(rlim); + target_rlim_swap = rlim; + result = tswapl(target_rlim_swap); + + return result; +} + +static inline int target_to_host_resource(int code) +{ + switch (code) { + case TARGET_RLIMIT_AS: + return RLIMIT_AS; + case TARGET_RLIMIT_CORE: + return RLIMIT_CORE; + case TARGET_RLIMIT_CPU: + return RLIMIT_CPU; + case TARGET_RLIMIT_DATA: + return RLIMIT_DATA; + case TARGET_RLIMIT_FSIZE: + return RLIMIT_FSIZE; + case TARGET_RLIMIT_LOCKS: + return RLIMIT_LOCKS; + case TARGET_RLIMIT_MEMLOCK: + return RLIMIT_MEMLOCK; + case TARGET_RLIMIT_MSGQUEUE: + return RLIMIT_MSGQUEUE; + case TARGET_RLIMIT_NICE: + return RLIMIT_NICE; + case TARGET_RLIMIT_NOFILE: + return RLIMIT_NOFILE; + case TARGET_RLIMIT_NPROC: + return RLIMIT_NPROC; + case TARGET_RLIMIT_RSS: + return RLIMIT_RSS; + case TARGET_RLIMIT_RTPRIO: + return RLIMIT_RTPRIO; + case TARGET_RLIMIT_SIGPENDING: + return RLIMIT_SIGPENDING; + case TARGET_RLIMIT_STACK: + return RLIMIT_STACK; + default: + return code; + } } static inline abi_long copy_from_user_timeval(struct timeval *tv, @@ -952,6 +1083,7 @@ static inline abi_long copy_to_user_mq_attr(abi_ulong target_mq_attr_addr, } #endif +#if defined(TARGET_NR_select) || defined(TARGET_NR__newselect) /* do_select() must return target values and target errnos. */ static abi_long do_select(int n, abi_ulong rfd_addr, abi_ulong wfd_addr, @@ -962,26 +1094,17 @@ static abi_long do_select(int n, struct timeval tv, *tv_ptr; abi_long ret; - if (rfd_addr) { - if (copy_from_user_fdset(&rfds, rfd_addr, n)) - return -TARGET_EFAULT; - rfds_ptr = &rfds; - } else { - rfds_ptr = NULL; + ret = copy_from_user_fdset_ptr(&rfds, &rfds_ptr, rfd_addr, n); + if (ret) { + return ret; } - if (wfd_addr) { - if (copy_from_user_fdset(&wfds, wfd_addr, n)) - return -TARGET_EFAULT; - wfds_ptr = &wfds; - } else { - wfds_ptr = NULL; + ret = copy_from_user_fdset_ptr(&wfds, &wfds_ptr, wfd_addr, n); + if (ret) { + return ret; } - if (efd_addr) { - if (copy_from_user_fdset(&efds, efd_addr, n)) - return -TARGET_EFAULT; - efds_ptr = &efds; - } else { - efds_ptr = NULL; + ret = copy_from_user_fdset_ptr(&efds, &efds_ptr, efd_addr, n); + if (ret) { + return ret; } if (target_tv_addr) { @@ -1008,6 +1131,7 @@ static abi_long do_select(int n, return ret; } +#endif static abi_long do_pipe2(int host_pipe[], int flags) { @@ -3751,10 +3875,10 @@ static abi_long do_get_thread_area(CPUX86State *env, abi_ulong ptr) #ifndef TARGET_ABI32 static abi_long do_arch_prctl(CPUX86State *env, int code, abi_ulong addr) { - abi_long ret; + abi_long ret = 0; abi_ulong val; int idx; - + switch(code) { case TARGET_ARCH_SET_GS: case TARGET_ARCH_SET_FS: @@ -3773,13 +3897,13 @@ static abi_long do_arch_prctl(CPUX86State *env, int code, abi_ulong addr) idx = R_FS; val = env->segs[idx].base; if (put_user(val, addr, abi_ulong)) - return -TARGET_EFAULT; + ret = -TARGET_EFAULT; break; default: ret = -TARGET_EINVAL; break; } - return 0; + return ret; } #endif @@ -4262,13 +4386,10 @@ static inline abi_long target_truncate64(void *cpu_env, const char *arg1, abi_long arg3, abi_long arg4) { -#ifdef TARGET_ARM - if (((CPUARMState *)cpu_env)->eabi) - { + if (regpairs_aligned(cpu_env)) { arg2 = arg3; arg3 = arg4; - } -#endif + } return get_errno(truncate64(arg1, target_offset64(arg2, arg3))); } #endif @@ -4279,13 +4400,10 @@ static inline abi_long target_ftruncate64(void *cpu_env, abi_long arg1, abi_long arg3, abi_long arg4) { -#ifdef TARGET_ARM - if (((CPUARMState *)cpu_env)->eabi) - { + if (regpairs_aligned(cpu_env)) { arg2 = arg3; arg3 = arg4; - } -#endif + } return get_errno(ftruncate64(arg1, target_offset64(arg2, arg3))); } #endif @@ -4484,7 +4602,8 @@ int get_osversion(void) All errnos that do_syscall() returns must be -TARGET_<errcode>. */ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, abi_long arg2, abi_long arg3, abi_long arg4, - abi_long arg5, abi_long arg6) + abi_long arg5, abi_long arg6, abi_long arg7, + abi_long arg8) { abi_long ret; struct stat st; @@ -5494,7 +5613,7 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, break; case TARGET_NR_setrlimit: { - int resource = arg1; + int resource = target_to_host_resource(arg1); struct target_rlimit *target_rlim; struct rlimit rlim; if (!lock_user_struct(VERIFY_READ, target_rlim, arg2, 1)) @@ -5507,7 +5626,7 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, break; case TARGET_NR_getrlimit: { - int resource = arg1; + int resource = target_to_host_resource(arg1); struct target_rlimit *target_rlim; struct rlimit rlim; @@ -5569,7 +5688,107 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, #endif #ifdef TARGET_NR_pselect6 case TARGET_NR_pselect6: - goto unimplemented_nowarn; + { + abi_long rfd_addr, wfd_addr, efd_addr, n, ts_addr; + fd_set rfds, wfds, efds; + fd_set *rfds_ptr, *wfds_ptr, *efds_ptr; + struct timespec ts, *ts_ptr; + + /* + * The 6th arg is actually two args smashed together, + * so we cannot use the C library. + */ + sigset_t set; + struct { + sigset_t *set; + size_t size; + } sig, *sig_ptr; + + abi_ulong arg_sigset, arg_sigsize, *arg7; + target_sigset_t *target_sigset; + + n = arg1; + rfd_addr = arg2; + wfd_addr = arg3; + efd_addr = arg4; + ts_addr = arg5; + + ret = copy_from_user_fdset_ptr(&rfds, &rfds_ptr, rfd_addr, n); + if (ret) { + goto fail; + } + ret = copy_from_user_fdset_ptr(&wfds, &wfds_ptr, wfd_addr, n); + if (ret) { + goto fail; + } + ret = copy_from_user_fdset_ptr(&efds, &efds_ptr, efd_addr, n); + if (ret) { + goto fail; + } + + /* + * This takes a timespec, and not a timeval, so we cannot + * use the do_select() helper ... + */ + if (ts_addr) { + if (target_to_host_timespec(&ts, ts_addr)) { + goto efault; + } + ts_ptr = &ts; + } else { + ts_ptr = NULL; + } + + /* Extract the two packed args for the sigset */ + if (arg6) { + sig_ptr = &sig; + sig.size = _NSIG / 8; + + arg7 = lock_user(VERIFY_READ, arg6, sizeof(*arg7) * 2, 1); + if (!arg7) { + goto efault; + } + arg_sigset = tswapl(arg7[0]); + arg_sigsize = tswapl(arg7[1]); + unlock_user(arg7, arg6, 0); + + if (arg_sigset) { + sig.set = &set; + if (arg_sigsize != sizeof(*target_sigset)) { + /* Like the kernel, we enforce correct size sigsets */ + ret = -TARGET_EINVAL; + goto fail; + } + target_sigset = lock_user(VERIFY_READ, arg_sigset, + sizeof(*target_sigset), 1); + if (!target_sigset) { + goto efault; + } + target_to_host_sigset(&set, target_sigset); + unlock_user(target_sigset, arg_sigset, 0); + } else { + sig.set = NULL; + } + } else { + sig_ptr = NULL; + } + + ret = get_errno(sys_pselect6(n, rfds_ptr, wfds_ptr, efds_ptr, + ts_ptr, sig_ptr)); + + if (!is_error(ret)) { + if (rfd_addr && copy_to_user_fdset(rfd_addr, &rfds, n)) + goto efault; + if (wfd_addr && copy_to_user_fdset(wfd_addr, &wfds, n)) + goto efault; + if (efd_addr && copy_to_user_fdset(efd_addr, &efds, n)) + goto efault; + + if (ts_addr && host_to_target_timespec(ts_addr, &ts)) + goto efault; + } + } + break; #endif case TARGET_NR_symlink: { @@ -6029,8 +6248,9 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, #endif #ifdef TARGET_NR_syscall case TARGET_NR_syscall: - ret = do_syscall(cpu_env,arg1 & 0xffff,arg2,arg3,arg4,arg5,arg6,0); - break; + ret = do_syscall(cpu_env, arg1 & 0xffff, arg2, arg3, arg4, arg5, + arg6, arg7, arg8, 0); + break; #endif case TARGET_NR_wait4: { @@ -6642,20 +6862,16 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, #endif #ifdef TARGET_NR_pread case TARGET_NR_pread: -#ifdef TARGET_ARM - if (((CPUARMState *)cpu_env)->eabi) + if (regpairs_aligned(cpu_env)) arg4 = arg5; -#endif if (!(p = lock_user(VERIFY_WRITE, arg2, arg3, 0))) goto efault; ret = get_errno(pread(arg1, p, arg3, arg4)); unlock_user(p, arg2, ret); break; case TARGET_NR_pwrite: -#ifdef TARGET_ARM - if (((CPUARMState *)cpu_env)->eabi) + if (regpairs_aligned(cpu_env)) arg4 = arg5; -#endif if (!(p = lock_user(VERIFY_READ, arg2, arg3, 1))) goto efault; ret = get_errno(pwrite(arg1, p, arg3, arg4)); @@ -6715,7 +6931,8 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, case TARGET_NR_ugetrlimit: { struct rlimit rlim; - ret = get_errno(getrlimit(arg1, &rlim)); + int resource = target_to_host_resource(arg1); + ret = get_errno(getrlimit(resource, &rlim)); if (!is_error(ret)) { struct target_rlimit *target_rlim; if (!lock_user_struct(VERIFY_WRITE, target_rlim, arg2, 0)) @@ -7058,7 +7275,7 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, case TARGET_NR_osf_sigprocmask: { abi_ulong mask; - int how = arg1; + int how; sigset_t set, oldset; switch(arg1) { @@ -7077,7 +7294,7 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, } mask = arg2; target_to_host_old_sigset(&set, &mask); - sigprocmask(arg1, &set, &oldset); + sigprocmask(how, &set, &oldset); host_to_target_old_sigset(&mask, &oldset); ret = mask; } @@ -7405,14 +7622,11 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, #ifdef TARGET_NR_readahead case TARGET_NR_readahead: #if TARGET_ABI_BITS == 32 -#ifdef TARGET_ARM - if (((CPUARMState *)cpu_env)->eabi) - { + if (regpairs_aligned(cpu_env)) { arg2 = arg3; arg3 = arg4; arg4 = arg5; } -#endif ret = get_errno(readahead(arg1, ((off64_t)arg3 << 32) | arg2, arg4)); #else ret = get_errno(readahead(arg1, arg2, arg3)); @@ -7717,8 +7931,13 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, #if defined(TARGET_NR_sync_file_range) case TARGET_NR_sync_file_range: #if TARGET_ABI_BITS == 32 +#if defined(TARGET_MIPS) + ret = get_errno(sync_file_range(arg1, target_offset64(arg3, arg4), + target_offset64(arg5, arg6), arg7)); +#else ret = get_errno(sync_file_range(arg1, target_offset64(arg2, arg3), target_offset64(arg4, arg5), arg6)); +#endif /* !TARGET_MIPS */ #else ret = get_errno(sync_file_range(arg1, arg2, arg3, arg4)); #endif @@ -7840,6 +8059,34 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, } #endif #endif +#ifdef TARGET_NR_prlimit64 + case TARGET_NR_prlimit64: + { + /* args: pid, resource number, ptr to new rlimit, ptr to old rlimit */ + struct target_rlimit64 *target_rnew, *target_rold; + struct host_rlimit64 rnew, rold, *rnewp = 0; + if (arg3) { + if (!lock_user_struct(VERIFY_READ, target_rnew, arg3, 1)) { + goto efault; + } + rnew.rlim_cur = tswap64(target_rnew->rlim_cur); + rnew.rlim_max = tswap64(target_rnew->rlim_max); + unlock_user_struct(target_rnew, arg3, 0); + rnewp = &rnew; + } + + ret = get_errno(sys_prlimit64(arg1, arg2, rnewp, arg4 ? &rold : 0)); + if (!is_error(ret) && arg4) { + if (!lock_user_struct(VERIFY_WRITE, target_rold, arg4, 1)) { + goto efault; + } + target_rold->rlim_cur = tswap64(rold.rlim_cur); + target_rold->rlim_max = tswap64(rold.rlim_max); + unlock_user_struct(target_rold, arg4, 1); + } + break; + } +#endif default: unimplemented: gemu_log("qemu: Unsupported syscall: %d\n", num); diff --git a/linux-user/syscall_defs.h b/linux-user/syscall_defs.h index 04c268de7c..a117407d84 100644 --- a/linux-user/syscall_defs.h +++ b/linux-user/syscall_defs.h @@ -693,6 +693,40 @@ struct target_rlimit { #define TARGET_RLIM_INFINITY ((target_ulong)~0UL) #endif +#if defined(TARGET_MIPS) +#define TARGET_RLIMIT_CPU 0 +#define TARGET_RLIMIT_FSIZE 1 +#define TARGET_RLIMIT_DATA 2 +#define TARGET_RLIMIT_STACK 3 +#define TARGET_RLIMIT_CORE 4 +#define TARGET_RLIMIT_RSS 7 +#define TARGET_RLIMIT_NPROC 8 +#define TARGET_RLIMIT_NOFILE 5 +#define TARGET_RLIMIT_MEMLOCK 9 +#define TARGET_RLIMIT_AS 6 +#define TARGET_RLIMIT_LOCKS 10 +#define TARGET_RLIMIT_SIGPENDING 11 +#define TARGET_RLIMIT_MSGQUEUE 12 +#define TARGET_RLIMIT_NICE 13 +#define TARGET_RLIMIT_RTPRIO 14 +#else +#define TARGET_RLIMIT_CPU 0 +#define TARGET_RLIMIT_FSIZE 1 +#define TARGET_RLIMIT_DATA 2 +#define TARGET_RLIMIT_STACK 3 +#define TARGET_RLIMIT_CORE 4 +#define TARGET_RLIMIT_RSS 5 +#define TARGET_RLIMIT_NPROC 6 +#define TARGET_RLIMIT_NOFILE 7 +#define TARGET_RLIMIT_MEMLOCK 8 +#define TARGET_RLIMIT_AS 9 +#define TARGET_RLIMIT_LOCKS 10 +#define TARGET_RLIMIT_SIGPENDING 11 +#define TARGET_RLIMIT_MSGQUEUE 12 +#define TARGET_RLIMIT_NICE 13 +#define TARGET_RLIMIT_RTPRIO 14 +#endif + struct target_pollfd { int fd; /* file descriptor */ short events; /* requested events */ @@ -708,6 +742,10 @@ struct target_pollfd { #define TARGET_KDSKBMODE 0x4b45 #define TARGET_KDGKBENT 0x4B46 /* gets one entry in translation table */ #define TARGET_KDGKBSENT 0x4B48 /* gets one function key string entry */ +#define TARGET_KDGKBLED 0x4B64 /* get led flags (not lights) */ +#define TARGET_KDSKBLED 0x4B65 /* set led flags (not lights) */ +#define TARGET_KDGETLED 0x4B31 /* return current led state */ +#define TARGET_KDSETLED 0x4B32 /* set led state [lights, not flags] */ #define TARGET_SIOCATMARK 0x8905 @@ -928,6 +966,11 @@ struct target_pollfd { #define TARGET_FBIOGET_VSCREENINFO 0x4600 #define TARGET_FBIOPUT_VSCREENINFO 0x4601 #define TARGET_FBIOGET_FSCREENINFO 0x4602 +#define TARGET_FBIOGETCMAP 0x4604 +#define TARGET_FBIOPUTCMAP 0x4605 +#define TARGET_FBIOPAN_DISPLAY 0x4606 +#define TARGET_FBIOGET_CON2FBMAP 0x460F +#define TARGET_FBIOPUT_CON2FBMAP 0x4610 /* vt ioctls */ #define TARGET_VT_OPENQRY 0x5600 @@ -936,6 +979,10 @@ struct target_pollfd { #define TARGET_VT_WAITACTIVE 0x5607 #define TARGET_VT_LOCKSWITCH 0x560b #define TARGET_VT_UNLOCKSWITCH 0x560c +#define TARGET_VT_GETMODE 0x5601 +#define TARGET_VT_SETMODE 0x5602 +#define TARGET_VT_RELDISP 0x5605 +#define TARGET_VT_DISALLOCATE 0x5608 /* from asm/termbits.h */ @@ -2280,3 +2327,7 @@ struct target_epoll_event { target_epoll_data_t data; }; #endif +struct target_rlimit64 { + uint64_t rlim_cur; + uint64_t rlim_max; +}; diff --git a/linux-user/syscall_types.h b/linux-user/syscall_types.h index 0e67cd8f30..c370125170 100644 --- a/linux-user/syscall_types.h +++ b/linux-user/syscall_types.h @@ -161,11 +161,31 @@ STRUCT(fb_var_screeninfo, TYPE_INT, /* rotate */ MK_ARRAY(TYPE_INT, 5)) /* reserved */ +STRUCT(fb_cmap, + TYPE_INT, /* start */ + TYPE_INT, /* len */ + TYPE_PTRVOID, /* red */ + TYPE_PTRVOID, /* green */ + TYPE_PTRVOID, /* blue */ + TYPE_PTRVOID) /* transp */ + +STRUCT(fb_con2fbmap, + TYPE_INT, /* console */ + TYPE_INT) /* framebuffer */ + + STRUCT(vt_stat, TYPE_SHORT, /* v_active */ TYPE_SHORT, /* v_signal */ TYPE_SHORT) /* v_state */ +STRUCT(vt_mode, + TYPE_CHAR, /* mode */ + TYPE_CHAR, /* waitv */ + TYPE_SHORT, /* relsig */ + TYPE_SHORT, /* acqsig */ + TYPE_SHORT) /* frsig */ + STRUCT(fiemap_extent, TYPE_ULONGLONG, /* fe_logical */ TYPE_ULONGLONG, /* fe_physical */ diff --git a/linux-user/x86_64/syscall_nr.h b/linux-user/x86_64/syscall_nr.h index 568a901d71..947e961ce4 100644 --- a/linux-user/x86_64/syscall_nr.h +++ b/linux-user/x86_64/syscall_nr.h @@ -293,3 +293,15 @@ #define TARGET_NR_dup3 292 #define TARGET_NR_pipe2 293 #define TARGET_NR_inotify_init1 294 +#define TARGET_NR_preadv 295 +#define TARGET_NR_pwritev 296 +#define TARGET_NR_rt_tgsigqueueinfo 297 +#define TARGET_NR_perf_event_open 298 +#define TARGET_NR_recvmmsg 299 +#define TARGET_NR_fanotify_init 300 +#define TARGET_NR_fanotify_mark 301 +#define TARGET_NR_prlimit64 302 +#define TARGET_NR_name_to_handle_at 303 +#define TARGET_NR_open_by_handle_at 304 +#define TARGET_NR_clock_adjtime 305 +#define TARGET_NR_syncfs 306 diff --git a/m68k-semi.c b/m68k-semi.c index 0371089b98..7fde10e8f3 100644 --- a/m68k-semi.c +++ b/m68k-semi.c @@ -370,7 +370,7 @@ void do_m68k_semihosting(CPUM68KState *env, int nr) TaskState *ts = env->opaque; /* Allocate the heap using sbrk. */ if (!ts->heap_limit) { - long ret; + abi_ulong ret; uint32_t size; uint32_t base; @@ -379,8 +379,9 @@ void do_m68k_semihosting(CPUM68KState *env, int nr) /* Try a big heap, and reduce the size if that fails. */ for (;;) { ret = do_brk(base + size); - if (ret != -1) + if (ret >= (base + size)) { break; + } size >>= 1; } ts->heap_limit = base + size; @@ -56,7 +56,7 @@ #include "json-streamer.h" #include "json-parser.h" #include "osdep.h" -#include "exec-all.h" +#include "cpu.h" #ifdef CONFIG_SIMPLE_TRACE #include "trace.h" #endif @@ -710,7 +710,7 @@ int qemu_find_nic_model(NICInfo *nd, const char * const *models, return i; } - error_report("qemu: Unsupported NIC model: %s", nd->model); + error_report("Unsupported NIC model: %s", nd->model); return -1; } diff --git a/net/socket.c b/net/socket.c index 7337f4fa10..bc1bf58894 100644 --- a/net/socket.c +++ b/net/socket.c @@ -530,7 +530,7 @@ int net_init_socket(QemuOpts *opts, qemu_opt_get(opts, "connect") || qemu_opt_get(opts, "mcast") || qemu_opt_get(opts, "localaddr")) { - error_report("listen=, connect=, mcast= and localaddr= is invalid with fd=\n"); + error_report("listen=, connect=, mcast= and localaddr= is invalid with fd="); return -1; } @@ -550,7 +550,7 @@ int net_init_socket(QemuOpts *opts, qemu_opt_get(opts, "connect") || qemu_opt_get(opts, "mcast") || qemu_opt_get(opts, "localaddr")) { - error_report("fd=, connect=, mcast= and localaddr= is invalid with listen=\n"); + error_report("fd=, connect=, mcast= and localaddr= is invalid with listen="); return -1; } @@ -566,7 +566,7 @@ int net_init_socket(QemuOpts *opts, qemu_opt_get(opts, "listen") || qemu_opt_get(opts, "mcast") || qemu_opt_get(opts, "localaddr")) { - error_report("fd=, listen=, mcast= and localaddr= is invalid with connect=\n"); + error_report("fd=, listen=, mcast= and localaddr= is invalid with connect="); return -1; } diff --git a/os-posix.c b/os-posix.c index 7dfb27836b..6f8d4886ea 100644 --- a/os-posix.c +++ b/os-posix.c @@ -31,6 +31,7 @@ /*needed for MAP_POPULATE before including qemu-options.h */ #include <sys/mman.h> #include <pwd.h> +#include <grp.h> #include <libgen.h> /* Needed early for CONFIG_BSD etc. */ @@ -199,6 +200,11 @@ static void change_process_uid(void) fprintf(stderr, "Failed to setgid(%d)\n", user_pwd->pw_gid); exit(1); } + if (initgroups(user_pwd->pw_name, user_pwd->pw_gid) < 0) { + fprintf(stderr, "Failed to initgroups(\"%s\", %d)\n", + user_pwd->pw_name, user_pwd->pw_gid); + exit(1); + } if (setuid(user_pwd->pw_uid) < 0) { fprintf(stderr, "Failed to setuid(%d)\n", user_pwd->pw_uid); exit(1); diff --git a/pc-bios/README b/pc-bios/README index fe221a940f..40568f82aa 100644 --- a/pc-bios/README +++ b/pc-bios/README @@ -10,8 +10,10 @@ - OpenBIOS (http://www.openbios.org/) is a free (GPL v2) portable firmware implementation. The goal is to implement a 100% IEEE 1275-1994 (referred to as Open Firmware) compliant firmware. - The included image for PowerPC (for 32 and 64 bit PPC CPUs), Sparc32 - and Sparc64 are built from OpenBIOS SVN revision 1018. + The included image for PowerPC (for 32 and 64 bit PPC CPUs), + + PowerPC is built from OpenBIOS SVN revision 1044 + Sparc32 and Sparc64 are built from OpenBIOS SVN revision 1018. - SLOF (Slimline Open Firmware) is a free IEEE 1275 Open Firmware implementation for certain IBM POWER hardware. The sources are at diff --git a/pc-bios/mpc8544ds.dtb b/pc-bios/mpc8544ds.dtb Binary files differindex 3299546696..ae318b1fe8 100644 --- a/pc-bios/mpc8544ds.dtb +++ b/pc-bios/mpc8544ds.dtb diff --git a/pc-bios/mpc8544ds.dts b/pc-bios/mpc8544ds.dts index 872152df93..a88b47c11b 100644 --- a/pc-bios/mpc8544ds.dts +++ b/pc-bios/mpc8544ds.dts @@ -82,6 +82,12 @@ compatible = "chrp,open-pic"; device_type = "open-pic"; }; + + global-utilities@e0000 { //global utilities block + compatible = "fsl,mpc8544-guts"; + reg = <0xe0000 0x1000>; + fsl,has-rstcr; + }; }; pci0: pci@e0008000 { @@ -119,4 +125,7 @@ chosen { linux,stdout-path = "/soc8544@e0000000/serial@4500"; }; + + hypervisor { + }; }; diff --git a/pc-bios/openbios-ppc b/pc-bios/openbios-ppc Binary files differindex ee6f5ae3b9..6525a9199a 100644 --- a/pc-bios/openbios-ppc +++ b/pc-bios/openbios-ppc diff --git a/qemu-common.h b/qemu-common.h index 109498dd4d..c2b79bd60e 100644 --- a/qemu-common.h +++ b/qemu-common.h @@ -112,17 +112,11 @@ static inline char *realpath(const char *path, char *resolved_path) _fullpath(resolved_path, path, _MAX_PATH); return resolved_path; } - -#define PRId64 "I64d" -#define PRIx64 "I64x" -#define PRIu64 "I64u" -#define PRIo64 "I64o" #endif /* FIXME: Remove NEED_CPU_H. */ #ifndef NEED_CPU_H -#include <setjmp.h> #include "osdep.h" #include "bswap.h" diff --git a/qemu-error.c b/qemu-error.c index 41c191d528..4b20d283a2 100644 --- a/qemu-error.c +++ b/qemu-error.c @@ -193,6 +193,8 @@ void error_print_loc(void) /* * Print an error message to current monitor if we have one, else to stderr. + * Format arguments like sprintf(). The result should not contain + * newlines. * Prepend the current location and append a newline. * It's wrong to call this in a QMP monitor. Use qerror_report() there. */ diff --git a/qemu-img-cmds.hx b/qemu-img-cmds.hx index 3072d383cf..2b70618c70 100644 --- a/qemu-img-cmds.hx +++ b/qemu-img-cmds.hx @@ -22,13 +22,13 @@ STEXI ETEXI DEF("commit", img_commit, - "commit [-f fmt] filename") + "commit [-f fmt] [-t cache] filename") STEXI @item commit [-f @var{fmt}] @var{filename} ETEXI DEF("convert", img_convert, - "convert [-c] [-p] [-f fmt] [-O output_fmt] [-o options] [-s snapshot_name] filename [filename2 [...]] output_filename") + "convert [-c] [-p] [-f fmt] [-t cache] [-O output_fmt] [-o options] [-s snapshot_name] filename [filename2 [...]] output_filename") STEXI @item convert [-c] [-f @var{fmt}] [-O @var{output_fmt}] [-o @var{options}] [-s @var{snapshot_name}] @var{filename} [@var{filename2} [...]] @var{output_filename} ETEXI @@ -46,7 +46,7 @@ STEXI ETEXI DEF("rebase", img_rebase, - "rebase [-f fmt] [-p] [-u] -b backing_file [-F backing_fmt] filename") + "rebase [-f fmt] [-t cache] [-p] [-u] -b backing_file [-F backing_fmt] filename") STEXI @item rebase [-f @var{fmt}] [-u] -b @var{backing_file} [-F @var{backing_fmt}] @var{filename} ETEXI diff --git a/qemu-img.c b/qemu-img.c index 4f162d1abe..54137a4e92 100644 --- a/qemu-img.c +++ b/qemu-img.c @@ -40,6 +40,7 @@ typedef struct img_cmd_t { /* Default to cache=writeback as data integrity is not important for qemu-tcg. */ #define BDRV_O_FLAGS BDRV_O_CACHE_WB +#define BDRV_DEFAULT_CACHE "writeback" static void format_print(void *opaque, const char *name) { @@ -64,6 +65,8 @@ static void help(void) "Command parameters:\n" " 'filename' is a disk image filename\n" " 'fmt' is the disk image format. It is guessed automatically in most cases\n" + " 'cache' is the cache mode used to write the output disk image, the valid\n" + " options are: 'none', 'writeback' (default), 'writethrough' and 'unsafe'\n" " 'size' is the disk image size in bytes. Optional suffixes\n" " 'k' or 'K' (kilobyte, 1024), 'M' (megabyte, 1024k), 'G' (gigabyte, 1024M)\n" " and T (terabyte, 1024G) are supported. 'b' is ignored.\n" @@ -180,6 +183,27 @@ static int read_password(char *buf, int buf_size) } #endif +static int set_cache_flag(const char *mode, int *flags) +{ + *flags &= ~BDRV_O_CACHE_MASK; + + if (!strcmp(mode, "none") || !strcmp(mode, "off")) { + *flags |= BDRV_O_CACHE_WB; + *flags |= BDRV_O_NOCACHE; + } else if (!strcmp(mode, "writeback")) { + *flags |= BDRV_O_CACHE_WB; + } else if (!strcmp(mode, "unsafe")) { + *flags |= BDRV_O_CACHE_WB; + *flags |= BDRV_O_NO_FLUSH; + } else if (!strcmp(mode, "writethrough")) { + /* this is the default */ + } else { + return -1; + } + + return 0; +} + static int print_block_option_help(const char *filename, const char *fmt) { BlockDriver *drv, *proto_drv; @@ -304,11 +328,11 @@ static int img_create(int argc, char **argv) fmt = optarg; break; case 'e': - error_report("qemu-img: option -e is deprecated, please use \'-o " + error_report("option -e is deprecated, please use \'-o " "encryption\' instead!"); return 1; case '6': - error_report("qemu-img: option -6 is deprecated, please use \'-o " + error_report("option -6 is deprecated, please use \'-o " "compat6\' instead!"); return 1; case 'o': @@ -441,13 +465,14 @@ static int img_check(int argc, char **argv) static int img_commit(int argc, char **argv) { - int c, ret; - const char *filename, *fmt; + int c, ret, flags; + const char *filename, *fmt, *cache; BlockDriverState *bs; fmt = NULL; + cache = BDRV_DEFAULT_CACHE; for(;;) { - c = getopt(argc, argv, "f:h"); + c = getopt(argc, argv, "f:ht:"); if (c == -1) { break; } @@ -459,6 +484,9 @@ static int img_commit(int argc, char **argv) case 'f': fmt = optarg; break; + case 't': + cache = optarg; + break; } } if (optind >= argc) { @@ -466,7 +494,14 @@ static int img_commit(int argc, char **argv) } filename = argv[optind++]; - bs = bdrv_new_open(filename, fmt, BDRV_O_FLAGS | BDRV_O_RDWR); + flags = BDRV_O_RDWR; + ret = set_cache_flag(cache, &flags); + if (ret < 0) { + error_report("Invalid cache option: %s", cache); + return -1; + } + + bs = bdrv_new_open(filename, fmt, flags); if (!bs) { return 1; } @@ -591,8 +626,8 @@ static int compare_sectors(const uint8_t *buf1, const uint8_t *buf2, int n, static int img_convert(int argc, char **argv) { int c, ret = 0, n, n1, bs_n, bs_i, compress, cluster_size, cluster_sectors; - int progress = 0; - const char *fmt, *out_fmt, *out_baseimg, *out_filename; + int progress = 0, flags; + const char *fmt, *out_fmt, *cache, *out_baseimg, *out_filename; BlockDriver *drv, *proto_drv; BlockDriverState **bs = NULL, *out_bs = NULL; int64_t total_sectors, nb_sectors, sector_num, bs_offset; @@ -608,10 +643,11 @@ static int img_convert(int argc, char **argv) fmt = NULL; out_fmt = "raw"; + cache = "unsafe"; out_baseimg = NULL; compress = 0; for(;;) { - c = getopt(argc, argv, "f:O:B:s:hce6o:p"); + c = getopt(argc, argv, "f:O:B:s:hce6o:pt:"); if (c == -1) { break; } @@ -633,11 +669,11 @@ static int img_convert(int argc, char **argv) compress = 1; break; case 'e': - error_report("qemu-img: option -e is deprecated, please use \'-o " + error_report("option -e is deprecated, please use \'-o " "encryption\' instead!"); return 1; case '6': - error_report("qemu-img: option -6 is deprecated, please use \'-o " + error_report("option -6 is deprecated, please use \'-o " "compat6\' instead!"); return 1; case 'o': @@ -649,6 +685,9 @@ static int img_convert(int argc, char **argv) case 'p': progress = 1; break; + case 't': + cache = optarg; + break; } } @@ -690,12 +729,12 @@ static int img_convert(int argc, char **argv) if (snapshot_name != NULL) { if (bs_n > 1) { - error_report("No support for concatenating multiple snapshot\n"); + error_report("No support for concatenating multiple snapshot"); ret = -1; goto out; } if (bdrv_snapshot_load_tmp(bs[0], snapshot_name) < 0) { - error_report("Failed to load snapshot\n"); + error_report("Failed to load snapshot"); ret = -1; goto out; } @@ -779,8 +818,14 @@ static int img_convert(int argc, char **argv) goto out; } - out_bs = bdrv_new_open(out_filename, out_fmt, - BDRV_O_FLAGS | BDRV_O_RDWR | BDRV_O_NO_FLUSH); + flags = BDRV_O_RDWR; + ret = set_cache_flag(cache, &flags); + if (ret < 0) { + error_report("Invalid cache option: %s", cache); + return -1; + } + + out_bs = bdrv_new_open(out_filename, out_fmt, flags); if (!out_bs) { ret = -1; goto out; @@ -1225,18 +1270,18 @@ static int img_rebase(int argc, char **argv) BlockDriverState *bs, *bs_old_backing = NULL, *bs_new_backing = NULL; BlockDriver *old_backing_drv, *new_backing_drv; char *filename; - const char *fmt, *out_basefmt, *out_baseimg; + const char *fmt, *cache, *out_basefmt, *out_baseimg; int c, flags, ret; int unsafe = 0; int progress = 0; /* Parse commandline parameters */ fmt = NULL; + cache = BDRV_DEFAULT_CACHE; out_baseimg = NULL; out_basefmt = NULL; - for(;;) { - c = getopt(argc, argv, "uhf:F:b:p"); + c = getopt(argc, argv, "uhf:F:b:pt:"); if (c == -1) { break; } @@ -1260,6 +1305,9 @@ static int img_rebase(int argc, char **argv) case 'p': progress = 1; break; + case 't': + cache = optarg; + break; } } @@ -1271,13 +1319,19 @@ static int img_rebase(int argc, char **argv) qemu_progress_init(progress, 2.0); qemu_progress_print(0, 100); + flags = BDRV_O_RDWR | (unsafe ? BDRV_O_NO_BACKING : 0); + ret = set_cache_flag(cache, &flags); + if (ret < 0) { + error_report("Invalid cache option: %s", cache); + return -1; + } + /* * Open the images. * * Ignore the old backing file for unsafe rebase in case we want to correct * the reference to a renamed or moved backing file. */ - flags = BDRV_O_FLAGS | BDRV_O_RDWR | (unsafe ? BDRV_O_NO_BACKING : 0); bs = bdrv_new_open(filename, fmt, flags); if (!bs) { return 1; diff --git a/qemu-img.texi b/qemu-img.texi index ced64a40ed..526474c112 100644 --- a/qemu-img.texi +++ b/qemu-img.texi @@ -173,12 +173,6 @@ Linux or NTFS on Windows), then only the written sectors will reserve space. Use @code{qemu-img info} to know the real size used by the image or @code{ls -ls} on Unix/Linux. -@item host_device - -Host device format. This format should be used instead of raw when -converting to block devices or other devices where "holes" are not -supported. - @item qcow2 QEMU image format, the most versatile format. Use it to have smaller images (useful if your filesystem does not supports holes, for example diff --git a/qemu-options.hx b/qemu-options.hx index 37e54ee27a..e6d7adc3af 100644 --- a/qemu-options.hx +++ b/qemu-options.hx @@ -787,6 +787,15 @@ STEXI Rotate graphical output 90 deg left (only PXA LCD). ETEXI +DEF("rotate", HAS_ARG, QEMU_OPTION_rotate, + "-rotate <deg> rotate graphical output some deg left (only PXA LCD)\n", + QEMU_ARCH_ALL) +STEXI +@item -rotate +@findex -rotate +Rotate graphical output some deg left (only PXA LCD). +ETEXI + DEF("vga", HAS_ARG, QEMU_OPTION_vga, "-vga [std|cirrus|vmware|qxl|xenfb|none]\n" " select video card type\n", QEMU_ARCH_ALL) diff --git a/scripts/checkpatch.pl b/scripts/checkpatch.pl index 075b6149a3..70a2111d19 100755 --- a/scripts/checkpatch.pl +++ b/scripts/checkpatch.pl @@ -2068,8 +2068,10 @@ sub process { } # , must have a space on the right. + # not required when having a single },{ on one line } elsif ($op eq ',') { - if ($ctx !~ /.x[WEC]/ && $cc !~ /^}/) { + if ($ctx !~ /.x[WEC]/ && $cc !~ /^}/ && + ($elements[$n] . $elements[$n + 2]) !~ " *}{") { ERROR("space required after that '$op' $at\n" . $hereptr); } diff --git a/target-alpha/cpu.h b/target-alpha/cpu.h index e98b32513c..78caa796b6 100644 --- a/target-alpha/cpu.h +++ b/target-alpha/cpu.h @@ -28,8 +28,6 @@ #include "cpu-defs.h" -#include <setjmp.h> - #include "softfloat.h" #define TARGET_HAS_ICE 1 @@ -492,4 +490,26 @@ static inline void cpu_set_tls(CPUState *env, target_ulong newtls) } #endif +static inline bool cpu_has_work(CPUState *env) +{ + /* Here we are checking to see if the CPU should wake up from HALT. + We will have gotten into this state only for WTINT from PALmode. */ + /* ??? I'm not sure how the IPL state works with WTINT to keep a CPU + asleep even if (some) interrupts have been asserted. For now, + assume that if a CPU really wants to stay asleep, it will mask + interrupts at the chipset level, which will prevent these bits + from being set in the first place. */ + return env->interrupt_request & (CPU_INTERRUPT_HARD + | CPU_INTERRUPT_TIMER + | CPU_INTERRUPT_SMP + | CPU_INTERRUPT_MCHK); +} + +#include "exec-all.h" + +static inline void cpu_pc_from_tb(CPUState *env, TranslationBlock *tb) +{ + env->pc = tb->pc; +} + #endif /* !defined (__CPU_ALPHA_H__) */ diff --git a/target-alpha/exec.h b/target-alpha/exec.h index 7a325e7a75..afb01d3727 100644 --- a/target-alpha/exec.h +++ b/target-alpha/exec.h @@ -31,30 +31,9 @@ register struct CPUAlphaState *env asm(AREG0); #define FP_STATUS (env->fp_status) #include "cpu.h" -#include "exec-all.h" #if !defined(CONFIG_USER_ONLY) #include "softmmu_exec.h" #endif /* !defined(CONFIG_USER_ONLY) */ -static inline int cpu_has_work(CPUState *env) -{ - /* Here we are checking to see if the CPU should wake up from HALT. - We will have gotten into this state only for WTINT from PALmode. */ - /* ??? I'm not sure how the IPL state works with WTINT to keep a CPU - asleep even if (some) interrupts have been asserted. For now, - assume that if a CPU really wants to stay asleep, it will mask - interrupts at the chipset level, which will prevent these bits - from being set in the first place. */ - return env->interrupt_request & (CPU_INTERRUPT_HARD - | CPU_INTERRUPT_TIMER - | CPU_INTERRUPT_SMP - | CPU_INTERRUPT_MCHK); -} - -static inline void cpu_pc_from_tb(CPUState *env, TranslationBlock *tb) -{ - env->pc = tb->pc; -} - #endif /* !defined (__ALPHA_EXEC_H__) */ diff --git a/target-alpha/helper.c b/target-alpha/helper.c index 32c2cf9db3..7049c80d5c 100644 --- a/target-alpha/helper.c +++ b/target-alpha/helper.c @@ -22,7 +22,6 @@ #include <stdio.h> #include "cpu.h" -#include "exec-all.h" #include "softfloat.h" uint64_t cpu_alpha_load_fpcr (CPUState *env) diff --git a/target-alpha/op_helper.c b/target-alpha/op_helper.c index d33271958f..51d1bd7099 100644 --- a/target-alpha/op_helper.c +++ b/target-alpha/op_helper.c @@ -32,7 +32,7 @@ void QEMU_NORETURN helper_excp(int excp, int error) { env->exception_index = excp; env->error_code = error; - cpu_loop_exit(); + cpu_loop_exit(env); } static void do_restore_state(void *retaddr) @@ -53,7 +53,7 @@ static void QEMU_NORETURN dynamic_excp(int excp, int error) env->exception_index = excp; env->error_code = error; do_restore_state(GETPC()); - cpu_loop_exit(); + cpu_loop_exit(env); } static void QEMU_NORETURN arith_excp(int exc, uint64_t mask) @@ -1341,7 +1341,7 @@ void tlb_fill (target_ulong addr, int is_write, int mmu_idx, void *retaddr) if (unlikely(ret != 0)) { do_restore_state(retaddr); /* Exception index and error code are already set */ - cpu_loop_exit(); + cpu_loop_exit(env); } env = saved_env; } diff --git a/target-alpha/translate.c b/target-alpha/translate.c index 936760c5ad..c61906a8b3 100644 --- a/target-alpha/translate.c +++ b/target-alpha/translate.c @@ -22,7 +22,6 @@ #include <stdio.h> #include "cpu.h" -#include "exec-all.h" #include "disas.h" #include "host-utils.h" #include "tcg-op.h" diff --git a/target-arm/cpu.h b/target-arm/cpu.h index 1276e6985a..adef42785c 100644 --- a/target-arm/cpu.h +++ b/target-arm/cpu.h @@ -227,7 +227,7 @@ typedef struct CPUARMState { void *opaque; } cp[15]; void *nvic; - struct arm_boot_info *boot_info; + const struct arm_boot_info *boot_info; } CPUARMState; CPUARMState *cpu_arm_init(const char *cpu_model); @@ -518,4 +518,17 @@ static inline void cpu_get_tb_cpu_state(CPUState *env, target_ulong *pc, } } +static inline bool cpu_has_work(CPUState *env) +{ + return env->interrupt_request & + (CPU_INTERRUPT_FIQ | CPU_INTERRUPT_HARD | CPU_INTERRUPT_EXITTB); +} + +#include "exec-all.h" + +static inline void cpu_pc_from_tb(CPUState *env, TranslationBlock *tb) +{ + env->regs[15] = tb->pc; +} + #endif diff --git a/target-arm/exec.h b/target-arm/exec.h index db6608ec8b..6793288d43 100644 --- a/target-arm/exec.h +++ b/target-arm/exec.h @@ -22,22 +22,9 @@ register struct CPUARMState *env asm(AREG0); #include "cpu.h" -#include "exec-all.h" - -static inline int cpu_has_work(CPUState *env) -{ - return (env->interrupt_request & - (CPU_INTERRUPT_FIQ | CPU_INTERRUPT_HARD | CPU_INTERRUPT_EXITTB)); -} #if !defined(CONFIG_USER_ONLY) #include "softmmu_exec.h" #endif void raise_exception(int); - -static inline void cpu_pc_from_tb(CPUState *env, TranslationBlock *tb) -{ - env->regs[15] = tb->pc; -} - diff --git a/target-arm/helper.c b/target-arm/helper.c index a0f2314799..ae4f334e40 100644 --- a/target-arm/helper.c +++ b/target-arm/helper.c @@ -3,7 +3,6 @@ #include <string.h> #include "cpu.h" -#include "exec-all.h" #include "gdbstub.h" #include "helper.h" #include "qemu-common.h" diff --git a/target-arm/op_helper.c b/target-arm/op_helper.c index 8334fbcf6d..46358844c5 100644 --- a/target-arm/op_helper.c +++ b/target-arm/op_helper.c @@ -25,7 +25,7 @@ void raise_exception(int tt) { env->exception_index = tt; - cpu_loop_exit(); + cpu_loop_exit(env); } uint32_t HELPER(neon_tbl)(uint32_t ireg, uint32_t def, @@ -234,13 +234,13 @@ void HELPER(wfi)(void) { env->exception_index = EXCP_HLT; env->halted = 1; - cpu_loop_exit(); + cpu_loop_exit(env); } void HELPER(exception)(uint32_t excp) { env->exception_index = excp; - cpu_loop_exit(); + cpu_loop_exit(env); } uint32_t HELPER(cpsr_read)(void) diff --git a/target-arm/translate.c b/target-arm/translate.c index 3e431e15cb..34d5e6ef1a 100644 --- a/target-arm/translate.c +++ b/target-arm/translate.c @@ -25,7 +25,6 @@ #include <inttypes.h> #include "cpu.h" -#include "exec-all.h" #include "disas.h" #include "tcg-op.h" #include "qemu-log.h" diff --git a/target-cris/cpu.h b/target-cris/cpu.h index 2bc35e4975..ecb0df1d33 100644 --- a/target-cris/cpu.h +++ b/target-cris/cpu.h @@ -268,4 +268,15 @@ static inline void cpu_get_tb_cpu_state(CPUState *env, target_ulong *pc, #define cpu_list cris_cpu_list void cris_cpu_list(FILE *f, fprintf_function cpu_fprintf); +static inline bool cpu_has_work(CPUState *env) +{ + return env->interrupt_request & (CPU_INTERRUPT_HARD | CPU_INTERRUPT_NMI); +} + +#include "exec-all.h" + +static inline void cpu_pc_from_tb(CPUState *env, TranslationBlock *tb) +{ + env->pc = tb->pc; +} #endif diff --git a/target-cris/exec.h b/target-cris/exec.h index 2d5d297e1b..3294abe393 100644 --- a/target-cris/exec.h +++ b/target-cris/exec.h @@ -22,19 +22,7 @@ register struct CPUCRISState *env asm(AREG0); #include "cpu.h" -#include "exec-all.h" #if !defined(CONFIG_USER_ONLY) #include "softmmu_exec.h" #endif - -static inline int cpu_has_work(CPUState *env) -{ - return (env->interrupt_request & (CPU_INTERRUPT_HARD | CPU_INTERRUPT_NMI)); -} - -static inline void cpu_pc_from_tb(CPUState *env, TranslationBlock *tb) -{ - env->pc = tb->pc; -} - diff --git a/target-cris/helper.c b/target-cris/helper.c index 2a4403b847..962d214177 100644 --- a/target-cris/helper.c +++ b/target-cris/helper.c @@ -24,7 +24,6 @@ #include "config.h" #include "cpu.h" #include "mmu.h" -#include "exec-all.h" #include "host-utils.h" diff --git a/target-cris/mmu.c b/target-cris/mmu.c index 1243745598..d481e39352 100644 --- a/target-cris/mmu.c +++ b/target-cris/mmu.c @@ -27,7 +27,6 @@ #include "config.h" #include "cpu.h" #include "mmu.h" -#include "exec-all.h" #ifdef DEBUG #define D(x) x diff --git a/target-cris/op_helper.c b/target-cris/op_helper.c index 34329e2a60..b3ddd33e02 100644 --- a/target-cris/op_helper.c +++ b/target-cris/op_helper.c @@ -83,7 +83,7 @@ void tlb_fill (target_ulong addr, int is_write, int mmu_idx, void *retaddr) helper_top_evaluate_flags(); } } - cpu_loop_exit(); + cpu_loop_exit(env); } env = saved_env; } @@ -93,7 +93,7 @@ void tlb_fill (target_ulong addr, int is_write, int mmu_idx, void *retaddr) void helper_raise_exception(uint32_t index) { env->exception_index = index; - cpu_loop_exit(); + cpu_loop_exit(env); } void helper_tlb_flush_pid(uint32_t pid) diff --git a/target-cris/translate.c b/target-cris/translate.c index e2607d64c0..dd85859c0b 100644 --- a/target-cris/translate.c +++ b/target-cris/translate.c @@ -30,7 +30,6 @@ #include <inttypes.h> #include "cpu.h" -#include "exec-all.h" #include "disas.h" #include "tcg-op.h" #include "helper.h" diff --git a/target-cris/translate_v10.c b/target-cris/translate_v10.c index 5b14157d1a..637ac2084a 100644 --- a/target-cris/translate_v10.c +++ b/target-cris/translate_v10.c @@ -262,9 +262,6 @@ static unsigned int dec10_quick_imm(DisasContext *dc) break; case CRISV10_QIMM_BCC_R0: - if (!dc->ir) { - cpu_abort(dc->env, "opcode zero\n"); - } case CRISV10_QIMM_BCC_R1: case CRISV10_QIMM_BCC_R2: case CRISV10_QIMM_BCC_R3: diff --git a/target-i386/cpu.h b/target-i386/cpu.h index cdf68ffd99..9819b5fdb9 100644 --- a/target-i386/cpu.h +++ b/target-i386/cpu.h @@ -957,6 +957,36 @@ static inline int cpu_mmu_index (CPUState *env) return (env->hflags & HF_CPL_MASK) == 3 ? 1 : 0; } +#undef EAX +#define EAX (env->regs[R_EAX]) +#undef ECX +#define ECX (env->regs[R_ECX]) +#undef EDX +#define EDX (env->regs[R_EDX]) +#undef EBX +#define EBX (env->regs[R_EBX]) +#undef ESP +#define ESP (env->regs[R_ESP]) +#undef EBP +#define EBP (env->regs[R_EBP]) +#undef ESI +#define ESI (env->regs[R_ESI]) +#undef EDI +#define EDI (env->regs[R_EDI]) +#undef EIP +#define EIP (env->eip) +#define DF (env->df) + +#define CC_SRC (env->cc_src) +#define CC_DST (env->cc_dst) +#define CC_OP (env->cc_op) + +/* float macros */ +#define FT0 (env->ft0) +#define ST0 (env->fpregs[env->fpstt].d) +#define ST(n) (env->fpregs[(env->fpstt + (n)) & 7].d) +#define ST1 ST(1) + /* translate.c */ void optimize_flags_init(void); @@ -981,6 +1011,23 @@ static inline void cpu_clone_regs(CPUState *env, target_ulong newsp) #include "hw/apic.h" #endif +static inline bool cpu_has_work(CPUState *env) +{ + return ((env->interrupt_request & CPU_INTERRUPT_HARD) && + (env->eflags & IF_MASK)) || + (env->interrupt_request & (CPU_INTERRUPT_NMI | + CPU_INTERRUPT_INIT | + CPU_INTERRUPT_SIPI | + CPU_INTERRUPT_MCE)); +} + +#include "exec-all.h" + +static inline void cpu_pc_from_tb(CPUState *env, TranslationBlock *tb) +{ + env->eip = tb->pc - tb->cs_base; +} + static inline void cpu_get_tb_cpu_state(CPUState *env, target_ulong *pc, target_ulong *cs_base, int *flags) { @@ -1000,4 +1047,14 @@ void cpu_x86_inject_mce(Monitor *mon, CPUState *cenv, int bank, uint64_t status, uint64_t mcg_status, uint64_t addr, uint64_t misc, int flags); +/* op_helper.c */ +void do_interrupt(CPUState *env); +void do_interrupt_x86_hardirq(CPUState *env, int intno, int is_hw); + +void do_smm_enter(CPUState *env1); + +void svm_check_intercept(CPUState *env1, uint32_t type); + +uint32_t cpu_cc_compute_all(CPUState *env1, int op); + #endif /* CPU_I386_H */ diff --git a/target-i386/exec.h b/target-i386/exec.h index 9bd080e3a8..dd9bce4eed 100644 --- a/target-i386/exec.h +++ b/target-i386/exec.h @@ -33,48 +33,12 @@ register struct CPUX86State *env asm(AREG0); #include "qemu-common.h" #include "qemu-log.h" -#undef EAX -#define EAX (env->regs[R_EAX]) -#undef ECX -#define ECX (env->regs[R_ECX]) -#undef EDX -#define EDX (env->regs[R_EDX]) -#undef EBX -#define EBX (env->regs[R_EBX]) -#undef ESP -#define ESP (env->regs[R_ESP]) -#undef EBP -#define EBP (env->regs[R_EBP]) -#undef ESI -#define ESI (env->regs[R_ESI]) -#undef EDI -#define EDI (env->regs[R_EDI]) -#undef EIP -#define EIP (env->eip) -#define DF (env->df) - -#define CC_SRC (env->cc_src) -#define CC_DST (env->cc_dst) -#define CC_OP (env->cc_op) - -/* float macros */ -#define FT0 (env->ft0) -#define ST0 (env->fpregs[env->fpstt].d) -#define ST(n) (env->fpregs[(env->fpstt + (n)) & 7].d) -#define ST1 ST(1) - #include "cpu.h" -#include "exec-all.h" /* op_helper.c */ -void do_interrupt(int intno, int is_int, int error_code, - target_ulong next_eip, int is_hw); -void do_interrupt_user(int intno, int is_int, int error_code, - target_ulong next_eip); void QEMU_NORETURN raise_exception_err(int exception_index, int error_code); void QEMU_NORETURN raise_exception(int exception_index); void QEMU_NORETURN raise_exception_env(int exception_index, CPUState *nenv); -void do_smm_enter(void); /* n must be a constant to be efficient */ static inline target_long lshift(target_long x, int n) @@ -87,11 +51,6 @@ static inline target_long lshift(target_long x, int n) #include "helper.h" -static inline void svm_check_intercept(uint32_t type) -{ - helper_svm_check_intercept_param(type, 0); -} - #if !defined(CONFIG_USER_ONLY) #include "softmmu_exec.h" @@ -170,16 +129,6 @@ static inline void load_eflags(int eflags, int update_mask) (eflags & update_mask) | 0x2; } -static inline int cpu_has_work(CPUState *env) -{ - return ((env->interrupt_request & CPU_INTERRUPT_HARD) && - (env->eflags & IF_MASK)) || - (env->interrupt_request & (CPU_INTERRUPT_NMI | - CPU_INTERRUPT_INIT | - CPU_INTERRUPT_SIPI | - CPU_INTERRUPT_MCE)); -} - /* load efer and update the corresponding hflags. XXX: do consistency checks with cpuid bits ? */ static inline void cpu_load_efer(CPUState *env, uint64_t val) @@ -191,9 +140,3 @@ static inline void cpu_load_efer(CPUState *env, uint64_t val) if (env->efer & MSR_EFER_SVME) env->hflags |= HF_SVME_MASK; } - -static inline void cpu_pc_from_tb(CPUState *env, TranslationBlock *tb) -{ - env->eip = tb->pc - tb->cs_base; -} - diff --git a/target-i386/helper.c b/target-i386/helper.c index 509d68ca0f..e9be104293 100644 --- a/target-i386/helper.c +++ b/target-i386/helper.c @@ -23,7 +23,6 @@ #include <inttypes.h> #include "cpu.h" -#include "exec-all.h" #include "qemu-common.h" #include "kvm.h" #ifndef CONFIG_USER_ONLY diff --git a/target-i386/machine.c b/target-i386/machine.c index 7662aa20b7..9aca8e0523 100644 --- a/target-i386/machine.c +++ b/target-i386/machine.c @@ -3,7 +3,7 @@ #include "hw/pc.h" #include "hw/isa.h" -#include "exec-all.h" +#include "cpu.h" #include "kvm.h" static const VMStateDescription vmstate_segment = { diff --git a/target-i386/op_helper.c b/target-i386/op_helper.c index cec0c7686f..315e18b9a4 100644 --- a/target-i386/op_helper.c +++ b/target-i386/op_helper.c @@ -19,7 +19,6 @@ #include <math.h> #include "exec.h" -#include "exec-all.h" #include "host-utils.h" #include "ioport.h" @@ -1000,7 +999,7 @@ void helper_syscall(int next_eip_addend) { env->exception_index = EXCP_SYSCALL; env->exception_next_eip = env->eip + next_eip_addend; - cpu_loop_exit(); + cpu_loop_exit(env); } #else void helper_syscall(int next_eip_addend) @@ -1150,9 +1149,10 @@ static void do_interrupt_real(int intno, int is_int, int error_code, env->eflags &= ~(IF_MASK | TF_MASK | AC_MASK | RF_MASK); } +#if defined(CONFIG_USER_ONLY) /* fake user mode interrupt */ -void do_interrupt_user(int intno, int is_int, int error_code, - target_ulong next_eip) +static void do_interrupt_user(int intno, int is_int, int error_code, + target_ulong next_eip) { SegmentCache *dt; target_ulong ptr; @@ -1181,7 +1181,8 @@ void do_interrupt_user(int intno, int is_int, int error_code, EIP = next_eip; } -#if !defined(CONFIG_USER_ONLY) +#else + static void handle_even_inj(int intno, int is_int, int error_code, int is_hw, int rm) { @@ -1207,8 +1208,8 @@ static void handle_even_inj(int intno, int is_int, int error_code, * the int instruction. next_eip is the EIP value AFTER the interrupt * instruction. It is only relevant if is_int is TRUE. */ -void do_interrupt(int intno, int is_int, int error_code, - target_ulong next_eip, int is_hw) +static void do_interrupt_all(int intno, int is_int, int error_code, + target_ulong next_eip, int is_hw) { if (qemu_loglevel_mask(CPU_LOG_INT)) { if ((env->cr[0] & CR0_PE_MASK)) { @@ -1270,6 +1271,46 @@ void do_interrupt(int intno, int is_int, int error_code, #endif } +void do_interrupt(CPUState *env1) +{ + CPUState *saved_env; + + saved_env = env; + env = env1; +#if defined(CONFIG_USER_ONLY) + /* if user mode only, we simulate a fake exception + which will be handled outside the cpu execution + loop */ + do_interrupt_user(env->exception_index, + env->exception_is_int, + env->error_code, + env->exception_next_eip); + /* successfully delivered */ + env->old_exception = -1; +#else + /* simulate a real cpu exception. On i386, it can + trigger new exceptions, but we do not handle + double or triple faults yet. */ + do_interrupt_all(env->exception_index, + env->exception_is_int, + env->error_code, + env->exception_next_eip, 0); + /* successfully delivered */ + env->old_exception = -1; +#endif + env = saved_env; +} + +void do_interrupt_x86_hardirq(CPUState *env1, int intno, int is_hw) +{ + CPUState *saved_env; + + saved_env = env; + env = env1; + do_interrupt_all(intno, 0, 0, 0, is_hw); + env = saved_env; +} + /* This should come from sysemu.h - if we could include it here... */ void qemu_system_reset_request(void); @@ -1335,7 +1376,7 @@ static void QEMU_NORETURN raise_interrupt(int intno, int is_int, int error_code, env->error_code = error_code; env->exception_is_int = is_int; env->exception_next_eip = env->eip + next_eip_addend; - cpu_loop_exit(); + cpu_loop_exit(env); } /* shortcuts to generate exceptions */ @@ -1359,7 +1400,7 @@ void raise_exception_env(int exception_index, CPUState *nenv) #if defined(CONFIG_USER_ONLY) -void do_smm_enter(void) +void do_smm_enter(CPUState *env1) { } @@ -1375,11 +1416,15 @@ void helper_rsm(void) #define SMM_REVISION_ID 0x00020000 #endif -void do_smm_enter(void) +void do_smm_enter(CPUState *env1) { target_ulong sm_state; SegmentCache *dt; int i, offset; + CPUState *saved_env; + + saved_env = env; + env = env1; qemu_log_mask(CPU_LOG_INT, "SMM: enter\n"); log_cpu_state_mask(CPU_LOG_INT, env, X86_DUMP_CCOP); @@ -1506,6 +1551,7 @@ void do_smm_enter(void) cpu_x86_update_cr4(env, 0); env->dr[7] = 0x00000400; CC_OP = CC_OP_EFLAGS; + env = saved_env; } void helper_rsm(void) @@ -4658,7 +4704,7 @@ static void do_hlt(void) env->hflags &= ~HF_INHIBIT_IRQ_MASK; /* needed if sti is just before */ env->halted = 1; env->exception_index = EXCP_HLT; - cpu_loop_exit(); + cpu_loop_exit(env); } void helper_hlt(int next_eip_addend) @@ -4696,7 +4742,7 @@ void helper_mwait(int next_eip_addend) void helper_debug(void) { env->exception_index = EXCP_DEBUG; - cpu_loop_exit(); + cpu_loop_exit(env); } void helper_reset_rf(void) @@ -4859,6 +4905,10 @@ void helper_svm_check_intercept_param(uint32_t type, uint64_t param) { } +void svm_check_intercept(CPUState *env1, uint32_t type) +{ +} + void helper_svm_check_io(uint32_t port, uint32_t param, uint32_t next_eip_addend) { @@ -5040,7 +5090,7 @@ void helper_vmrun(int aflag, int next_eip_addend) env->exception_next_eip = -1; qemu_log_mask(CPU_LOG_TB_IN_ASM, "INTR"); /* XXX: is it always correct ? */ - do_interrupt(vector, 0, 0, 0, 1); + do_interrupt_all(vector, 0, 0, 0, 1); break; case SVM_EVTINJ_TYPE_NMI: env->exception_index = EXCP02_NMI; @@ -5048,7 +5098,7 @@ void helper_vmrun(int aflag, int next_eip_addend) env->exception_is_int = 0; env->exception_next_eip = EIP; qemu_log_mask(CPU_LOG_TB_IN_ASM, "NMI"); - cpu_loop_exit(); + cpu_loop_exit(env); break; case SVM_EVTINJ_TYPE_EXEPT: env->exception_index = vector; @@ -5056,7 +5106,7 @@ void helper_vmrun(int aflag, int next_eip_addend) env->exception_is_int = 0; env->exception_next_eip = -1; qemu_log_mask(CPU_LOG_TB_IN_ASM, "EXEPT"); - cpu_loop_exit(); + cpu_loop_exit(env); break; case SVM_EVTINJ_TYPE_SOFT: env->exception_index = vector; @@ -5064,7 +5114,7 @@ void helper_vmrun(int aflag, int next_eip_addend) env->exception_is_int = 1; env->exception_next_eip = EIP; qemu_log_mask(CPU_LOG_TB_IN_ASM, "SOFT"); - cpu_loop_exit(); + cpu_loop_exit(env); break; } qemu_log_mask(CPU_LOG_TB_IN_ASM, " %#x %#x\n", env->exception_index, env->error_code); @@ -5249,6 +5299,16 @@ void helper_svm_check_intercept_param(uint32_t type, uint64_t param) } } +void svm_check_intercept(CPUState *env1, uint32_t type) +{ + CPUState *saved_env; + + saved_env = env; + env = env1; + helper_svm_check_intercept_param(type, 0); + env = saved_env; +} + void helper_svm_check_io(uint32_t port, uint32_t param, uint32_t next_eip_addend) { @@ -5400,7 +5460,7 @@ void helper_vmexit(uint32_t exit_code, uint64_t exit_info_1) env->error_code = 0; env->old_exception = -1; - cpu_loop_exit(); + cpu_loop_exit(env); } #endif @@ -5575,6 +5635,18 @@ uint32_t helper_cc_compute_all(int op) } } +uint32_t cpu_cc_compute_all(CPUState *env1, int op) +{ + CPUState *saved_env; + uint32_t ret; + + saved_env = env; + env = env1; + ret = helper_cc_compute_all(op); + env = saved_env; + return ret; +} + uint32_t helper_cc_compute_c(int op) { switch (op) { diff --git a/target-i386/translate.c b/target-i386/translate.c index 10bd72a0e2..ccef381be8 100644 --- a/target-i386/translate.c +++ b/target-i386/translate.c @@ -24,7 +24,6 @@ #include <signal.h> #include "cpu.h" -#include "exec-all.h" #include "disas.h" #include "tcg-op.h" diff --git a/target-lm32/cpu.h b/target-lm32/cpu.h index 8e2d26b995..876b5be2bd 100644 --- a/target-lm32/cpu.h +++ b/target-lm32/cpu.h @@ -241,4 +241,17 @@ static inline void cpu_get_tb_cpu_state(CPUState *env, target_ulong *pc, *cs_base = 0; *flags = 0; } + +static inline bool cpu_has_work(CPUState *env) +{ + return env->interrupt_request & CPU_INTERRUPT_HARD; +} + +#include "exec-all.h" + +static inline void cpu_pc_from_tb(CPUState *env, TranslationBlock *tb) +{ + env->pc = tb->pc; +} + #endif diff --git a/target-lm32/exec.h b/target-lm32/exec.h index 348b723f29..2a227b2953 100644 --- a/target-lm32/exec.h +++ b/target-lm32/exec.h @@ -22,12 +22,6 @@ register struct CPULM32State *env asm(AREG0); #include "cpu.h" -#include "exec-all.h" - -static inline int cpu_has_work(CPUState *env) -{ - return env->interrupt_request & CPU_INTERRUPT_HARD; -} static inline int cpu_halted(CPUState *env) { @@ -42,9 +36,3 @@ static inline int cpu_halted(CPUState *env) } return EXCP_HALTED; } - -static inline void cpu_pc_from_tb(CPUState *env, TranslationBlock *tb) -{ - env->pc = tb->pc; -} - diff --git a/target-lm32/helper.c b/target-lm32/helper.c index 4f3e7e0fcb..e79428d8e0 100644 --- a/target-lm32/helper.c +++ b/target-lm32/helper.c @@ -23,7 +23,6 @@ #include "config.h" #include "cpu.h" -#include "exec-all.h" #include "host-utils.h" int cpu_lm32_handle_mmu_fault(CPUState *env, target_ulong address, int rw, diff --git a/target-lm32/op_helper.c b/target-lm32/op_helper.c index c72b1df47b..a34cecd295 100644 --- a/target-lm32/op_helper.c +++ b/target-lm32/op_helper.c @@ -20,14 +20,14 @@ void helper_raise_exception(uint32_t index) { env->exception_index = index; - cpu_loop_exit(); + cpu_loop_exit(env); } void helper_hlt(void) { env->halted = 1; env->exception_index = EXCP_HLT; - cpu_loop_exit(); + cpu_loop_exit(env); } void helper_wcsr_im(uint32_t im) @@ -98,7 +98,7 @@ void tlb_fill(target_ulong addr, int is_write, int mmu_idx, void *retaddr) cpu_restore_state(tb, env, pc); } } - cpu_loop_exit(); + cpu_loop_exit(env); } env = saved_env; } diff --git a/target-lm32/translate.c b/target-lm32/translate.c index 5e197258eb..0be105d018 100644 --- a/target-lm32/translate.c +++ b/target-lm32/translate.c @@ -25,7 +25,6 @@ #include <assert.h> #include "cpu.h" -#include "exec-all.h" #include "disas.h" #include "helper.h" #include "tcg-op.h" diff --git a/target-m68k/cpu.h b/target-m68k/cpu.h index b025b6689d..e0f9b32014 100644 --- a/target-m68k/cpu.h +++ b/target-m68k/cpu.h @@ -119,7 +119,8 @@ void m68k_tcg_init(void); CPUM68KState *cpu_m68k_init(const char *cpu_model); int cpu_m68k_exec(CPUM68KState *s); void cpu_m68k_close(CPUM68KState *s); -void do_interrupt(int is_hw); +void do_interrupt(CPUState *env1); +void do_interrupt_m68k_hardirq(CPUState *env1); /* you can call this signal handler from your SIGBUS and SIGSEGV signal handlers to inform the virtual CPU of exceptions. non zero is returned if the signal was handled by the virtual CPU. */ @@ -254,4 +255,16 @@ static inline void cpu_get_tb_cpu_state(CPUState *env, target_ulong *pc, | ((env->macsr >> 4) & 0xf); /* Bits 0-3 */ } +static inline bool cpu_has_work(CPUState *env) +{ + return env->interrupt_request & CPU_INTERRUPT_HARD; +} + +#include "exec-all.h" + +static inline void cpu_pc_from_tb(CPUState *env, TranslationBlock *tb) +{ + env->pc = tb->pc; +} + #endif diff --git a/target-m68k/exec.h b/target-m68k/exec.h index 91daa6bac4..93e7912148 100644 --- a/target-m68k/exec.h +++ b/target-m68k/exec.h @@ -22,19 +22,7 @@ register struct CPUM68KState *env asm(AREG0); #include "cpu.h" -#include "exec-all.h" #if !defined(CONFIG_USER_ONLY) #include "softmmu_exec.h" #endif - -static inline int cpu_has_work(CPUState *env) -{ - return (env->interrupt_request & (CPU_INTERRUPT_HARD)); -} - -static inline void cpu_pc_from_tb(CPUState *env, TranslationBlock *tb) -{ - env->pc = tb->pc; -} - diff --git a/target-m68k/helper.c b/target-m68k/helper.c index faa8c42ae8..a936fe7b76 100644 --- a/target-m68k/helper.c +++ b/target-m68k/helper.c @@ -23,7 +23,6 @@ #include "config.h" #include "cpu.h" -#include "exec-all.h" #include "qemu-common.h" #include "gdbstub.h" diff --git a/target-m68k/op_helper.c b/target-m68k/op_helper.c index 9b13bdbcc2..237fc4cb54 100644 --- a/target-m68k/op_helper.c +++ b/target-m68k/op_helper.c @@ -21,9 +21,13 @@ #if defined(CONFIG_USER_ONLY) -void do_interrupt(int is_hw) +void do_interrupt(CPUState *env1) +{ + env1->exception_index = -1; +} + +void do_interrupt_m68k_hardirq(CPUState *env1) { - env->exception_index = -1; } #else @@ -71,7 +75,7 @@ void tlb_fill (target_ulong addr, int is_write, int mmu_idx, void *retaddr) cpu_restore_state(tb, env, pc); } } - cpu_loop_exit(); + cpu_loop_exit(env); } env = saved_env; } @@ -90,7 +94,7 @@ static void do_rte(void) env->aregs[7] = sp + 8; } -void do_interrupt(int is_hw) +static void do_interrupt_all(int is_hw) { uint32_t sp; uint32_t fmt; @@ -118,7 +122,7 @@ void do_interrupt(int is_hw) } env->halted = 1; env->exception_index = EXCP_HLT; - cpu_loop_exit(); + cpu_loop_exit(env); return; } if (env->exception_index >= EXCP_TRAP0 @@ -155,12 +159,31 @@ void do_interrupt(int is_hw) env->pc = ldl_kernel(env->vbr + vector); } +void do_interrupt(CPUState *env1) +{ + CPUState *saved_env; + + saved_env = env; + env = env1; + do_interrupt_all(0); + env = saved_env; +} + +void do_interrupt_m68k_hardirq(CPUState *env1) +{ + CPUState *saved_env; + + saved_env = env; + env = env1; + do_interrupt_all(1); + env = saved_env; +} #endif static void raise_exception(int tt) { env->exception_index = tt; - cpu_loop_exit(); + cpu_loop_exit(env); } void HELPER(raise_exception)(uint32_t tt) diff --git a/target-m68k/translate.c b/target-m68k/translate.c index 26f0ee42e9..0e7f1fe2c7 100644 --- a/target-m68k/translate.c +++ b/target-m68k/translate.c @@ -25,7 +25,6 @@ #include "config.h" #include "cpu.h" -#include "exec-all.h" #include "disas.h" #include "tcg-op.h" #include "qemu-log.h" diff --git a/target-microblaze/cpu.h b/target-microblaze/cpu.h index 78fe14ff35..51a13e38d1 100644 --- a/target-microblaze/cpu.h +++ b/target-microblaze/cpu.h @@ -350,4 +350,17 @@ static inline void cpu_get_tb_cpu_state(CPUState *env, target_ulong *pc, void do_unassigned_access(target_phys_addr_t addr, int is_write, int is_exec, int is_asi, int size); #endif + +static inline bool cpu_has_work(CPUState *env) +{ + return env->interrupt_request & (CPU_INTERRUPT_HARD | CPU_INTERRUPT_NMI); +} + +#include "exec-all.h" + +static inline void cpu_pc_from_tb(CPUState *env, TranslationBlock *tb) +{ + env->sregs[SR_PC] = tb->pc; +} + #endif diff --git a/target-microblaze/exec.h b/target-microblaze/exec.h index 1efff30620..71b4d397ed 100644 --- a/target-microblaze/exec.h +++ b/target-microblaze/exec.h @@ -21,19 +21,7 @@ register struct CPUMBState *env asm(AREG0); #include "cpu.h" -#include "exec-all.h" #if !defined(CONFIG_USER_ONLY) #include "softmmu_exec.h" #endif - -static inline int cpu_has_work(CPUState *env) -{ - return (env->interrupt_request & (CPU_INTERRUPT_HARD | CPU_INTERRUPT_NMI)); -} - -static inline void cpu_pc_from_tb(CPUState *env, TranslationBlock *tb) -{ - env->sregs[SR_PC] = tb->pc; -} - diff --git a/target-microblaze/helper.c b/target-microblaze/helper.c index a623c7b04a..299259c3f0 100644 --- a/target-microblaze/helper.c +++ b/target-microblaze/helper.c @@ -23,7 +23,6 @@ #include "config.h" #include "cpu.h" -#include "exec-all.h" #include "host-utils.h" #define D(x) diff --git a/target-microblaze/mmu.c b/target-microblaze/mmu.c index b38f7d98b7..281fc8d8c4 100644 --- a/target-microblaze/mmu.c +++ b/target-microblaze/mmu.c @@ -22,7 +22,6 @@ #include "config.h" #include "cpu.h" -#include "exec-all.h" #define D(x) diff --git a/target-microblaze/op_helper.c b/target-microblaze/op_helper.c index c7b2f97d96..1a0a476a62 100644 --- a/target-microblaze/op_helper.c +++ b/target-microblaze/op_helper.c @@ -63,7 +63,7 @@ void tlb_fill (target_ulong addr, int is_write, int mmu_idx, void *retaddr) cpu_restore_state(tb, env, pc); } } - cpu_loop_exit(); + cpu_loop_exit(env); } env = saved_env; } @@ -107,7 +107,7 @@ uint32_t helper_get(uint32_t id, uint32_t ctrl) void helper_raise_exception(uint32_t index) { env->exception_index = index; - cpu_loop_exit(); + cpu_loop_exit(env); } void helper_debug(void) diff --git a/target-microblaze/translate.c b/target-microblaze/translate.c index b47b92e909..31e8306ef3 100644 --- a/target-microblaze/translate.c +++ b/target-microblaze/translate.c @@ -25,7 +25,6 @@ #include <assert.h> #include "cpu.h" -#include "exec-all.h" #include "disas.h" #include "tcg-op.h" #include "helper.h" diff --git a/target-mips/cpu.h b/target-mips/cpu.h index 0b98d10266..b0ac4da5a7 100644 --- a/target-mips/cpu.h +++ b/target-mips/cpu.h @@ -656,4 +656,28 @@ static inline void cpu_set_tls(CPUState *env, target_ulong newtls) env->tls_value = newtls; } +static inline int cpu_has_work(CPUState *env) +{ + int has_work = 0; + + /* It is implementation dependent if non-enabled interrupts + wake-up the CPU, however most of the implementations only + check for interrupts that can be taken. */ + if ((env->interrupt_request & CPU_INTERRUPT_HARD) && + cpu_mips_hw_interrupts_pending(env)) { + has_work = 1; + } + + return has_work; +} + +#include "exec-all.h" + +static inline void cpu_pc_from_tb(CPUState *env, TranslationBlock *tb) +{ + env->active_tc.PC = tb->pc; + env->hflags &= ~MIPS_HFLAG_BMASK; + env->hflags |= tb->flags & MIPS_HFLAG_BMASK; +} + #endif /* !defined (__MIPS_CPU_H__) */ diff --git a/target-mips/exec.h b/target-mips/exec.h index 607edf12ca..e787e9a8ba 100644 --- a/target-mips/exec.h +++ b/target-mips/exec.h @@ -11,27 +11,11 @@ register struct CPUMIPSState *env asm(AREG0); #include "cpu.h" -#include "exec-all.h" #if !defined(CONFIG_USER_ONLY) #include "softmmu_exec.h" #endif /* !defined(CONFIG_USER_ONLY) */ -static inline int cpu_has_work(CPUState *env) -{ - int has_work = 0; - - /* It is implementation dependent if non-enabled interrupts - wake-up the CPU, however most of the implementations only - check for interrupts that can be taken. */ - if ((env->interrupt_request & CPU_INTERRUPT_HARD) && - cpu_mips_hw_interrupts_pending(env)) { - has_work = 1; - } - - return has_work; -} - static inline void compute_hflags(CPUState *env) { env->hflags &= ~(MIPS_HFLAG_COP1X | MIPS_HFLAG_64 | MIPS_HFLAG_CP0 | @@ -73,11 +57,4 @@ static inline void compute_hflags(CPUState *env) } } -static inline void cpu_pc_from_tb(CPUState *env, TranslationBlock *tb) -{ - env->active_tc.PC = tb->pc; - env->hflags &= ~MIPS_HFLAG_BMASK; - env->hflags |= tb->flags & MIPS_HFLAG_BMASK; -} - #endif /* !defined(__QEMU_MIPS_EXEC_H__) */ diff --git a/target-mips/helper.c b/target-mips/helper.c index 0f057c2171..ecf6182f56 100644 --- a/target-mips/helper.c +++ b/target-mips/helper.c @@ -24,7 +24,6 @@ #include <signal.h> #include "cpu.h" -#include "exec-all.h" enum { TLBRET_DIRTY = -4, diff --git a/target-mips/machine.c b/target-mips/machine.c index 9ffac711ce..be72b36de6 100644 --- a/target-mips/machine.c +++ b/target-mips/machine.c @@ -1,7 +1,7 @@ #include "hw/hw.h" #include "hw/boards.h" -#include "exec-all.h" +#include "cpu.h" static void save_tc(QEMUFile *f, TCState *tc) { diff --git a/target-mips/op_helper.c b/target-mips/op_helper.c index b8e4991f32..6b966b1849 100644 --- a/target-mips/op_helper.c +++ b/target-mips/op_helper.c @@ -38,7 +38,7 @@ void helper_raise_exception_err (uint32_t exception, int error_code) #endif env->exception_index = exception; env->error_code = error_code; - cpu_loop_exit(); + cpu_loop_exit(env); } void helper_raise_exception (uint32_t exception) @@ -277,7 +277,7 @@ static inline target_phys_addr_t do_translate_address(target_ulong address, int lladdr = cpu_mips_translate_address(env, address, rw); if (lladdr == -1LL) { - cpu_loop_exit(); + cpu_loop_exit(env); } else { return lladdr; } diff --git a/target-mips/translate.c b/target-mips/translate.c index 4eaa8261c3..2848c6a692 100644 --- a/target-mips/translate.c +++ b/target-mips/translate.c @@ -27,7 +27,6 @@ #include <inttypes.h> #include "cpu.h" -#include "exec-all.h" #include "disas.h" #include "tcg-op.h" #include "qemu-common.h" diff --git a/target-ppc/cpu.h b/target-ppc/cpu.h index 8e4582f6ab..d90336634d 100644 --- a/target-ppc/cpu.h +++ b/target-ppc/cpu.h @@ -75,8 +75,6 @@ #include "cpu-defs.h" -#include <setjmp.h> - #include "softfloat.h" #define TARGET_HAS_ICE 1 @@ -360,10 +358,24 @@ struct ppcemb_tlb_t { uint32_t attr; /* Storage attributes */ }; +typedef struct ppcmas_tlb_t { + uint32_t mas8; + uint32_t mas1; + uint64_t mas2; + uint64_t mas7_3; +} ppcmas_tlb_t; + union ppc_tlb_t { - ppc6xx_tlb_t tlb6; - ppcemb_tlb_t tlbe; + ppc6xx_tlb_t *tlb6; + ppcemb_tlb_t *tlbe; + ppcmas_tlb_t *tlbm; }; + +/* possible TLB variants */ +#define TLB_NONE 0 +#define TLB_6XX 1 +#define TLB_EMB 2 +#define TLB_MAS 3 #endif #define SDR_32_HTABORG 0xFFFF0000UL @@ -903,7 +915,8 @@ struct CPUPPCState { int last_way; /* Last used way used to allocate TLB in a LRU way */ int id_tlbs; /* If 1, MMU has separated TLBs for instructions & data */ int nb_pids; /* Number of available PID registers */ - ppc_tlb_t *tlb; /* TLB is optional. Allocate them only if needed */ + int tlb_type; /* Type of TLB we're dealing with */ + ppc_tlb_t tlb; /* TLB is optional. Allocate them only if needed */ /* 403 dedicated access protection registers */ target_ulong pb[4]; #endif @@ -1075,9 +1088,13 @@ void store_40x_sler (CPUPPCState *env, uint32_t val); void store_booke_tcr (CPUPPCState *env, target_ulong val); void store_booke_tsr (CPUPPCState *env, target_ulong val); void booke206_flush_tlb(CPUState *env, int flags, const int check_iprot); +target_phys_addr_t booke206_tlb_to_page_size(CPUState *env, ppcmas_tlb_t *tlb); int ppcemb_tlb_check(CPUState *env, ppcemb_tlb_t *tlb, target_phys_addr_t *raddrp, target_ulong address, uint32_t pid, int ext, int i); +int ppcmas_tlb_check(CPUState *env, ppcmas_tlb_t *tlb, + target_phys_addr_t *raddrp, target_ulong address, + uint32_t pid); void ppc_tlb_invalidate_all (CPUPPCState *env); void ppc_tlb_invalidate_one (CPUPPCState *env, target_ulong addr); #if defined(TARGET_PPC64) @@ -1927,12 +1944,12 @@ static inline void cpu_set_tls(CPUState *env, target_ulong newtls) } #if !defined(CONFIG_USER_ONLY) -static inline int booke206_tlbe_id(CPUState *env, ppcemb_tlb_t *tlbe) +static inline int booke206_tlbm_id(CPUState *env, ppcmas_tlb_t *tlbm) { - uintptr_t tlbel = (uintptr_t)tlbe; - uintptr_t tlbl = (uintptr_t)env->tlb; + uintptr_t tlbml = (uintptr_t)tlbm; + uintptr_t tlbl = (uintptr_t)env->tlb.tlbm; - return (tlbel - tlbl) / sizeof(env->tlb[0]); + return (tlbml - tlbl) / sizeof(env->tlb.tlbm[0]); } static inline int booke206_tlb_size(CPUState *env, int tlbn) @@ -1949,9 +1966,9 @@ static inline int booke206_tlb_ways(CPUState *env, int tlbn) return r; } -static inline int booke206_tlbe_to_tlbn(CPUState *env, ppcemb_tlb_t *tlbe) +static inline int booke206_tlbm_to_tlbn(CPUState *env, ppcmas_tlb_t *tlbm) { - int id = booke206_tlbe_id(env, tlbe); + int id = booke206_tlbm_id(env, tlbm); int end = 0; int i; @@ -1966,14 +1983,14 @@ static inline int booke206_tlbe_to_tlbn(CPUState *env, ppcemb_tlb_t *tlbe) return 0; } -static inline int booke206_tlbe_to_way(CPUState *env, ppcemb_tlb_t *tlb) +static inline int booke206_tlbm_to_way(CPUState *env, ppcmas_tlb_t *tlb) { - int tlbn = booke206_tlbe_to_tlbn(env, tlb); - int tlbid = booke206_tlbe_id(env, tlb); + int tlbn = booke206_tlbm_to_tlbn(env, tlb); + int tlbid = booke206_tlbm_id(env, tlb); return tlbid & (booke206_tlb_ways(env, tlbn) - 1); } -static inline ppcemb_tlb_t *booke206_get_tlbe(CPUState *env, const int tlbn, +static inline ppcmas_tlb_t *booke206_get_tlbm(CPUState *env, const int tlbn, target_ulong ea, int way) { int r; @@ -1992,11 +2009,23 @@ static inline ppcemb_tlb_t *booke206_get_tlbe(CPUState *env, const int tlbn, r += booke206_tlb_size(env, i); } - return &env->tlb[r].tlbe; + return &env->tlb.tlbm[r]; } #endif extern void (*cpu_ppc_hypercall)(CPUState *); +static inline bool cpu_has_work(CPUState *env) +{ + return msr_ee && (env->interrupt_request & CPU_INTERRUPT_HARD); +} + +#include "exec-all.h" + +static inline void cpu_pc_from_tb(CPUState *env, TranslationBlock *tb) +{ + env->nip = tb->pc; +} + #endif /* !defined (__CPU_PPC_H__) */ diff --git a/target-ppc/exec.h b/target-ppc/exec.h index f87847acb1..f4453e4965 100644 --- a/target-ppc/exec.h +++ b/target-ppc/exec.h @@ -24,7 +24,6 @@ #include "dyngen-exec.h" #include "cpu.h" -#include "exec-all.h" register struct CPUPPCState *env asm(AREG0); @@ -32,15 +31,4 @@ register struct CPUPPCState *env asm(AREG0); #include "softmmu_exec.h" #endif /* !defined(CONFIG_USER_ONLY) */ -static inline int cpu_has_work(CPUState *env) -{ - return (msr_ee && (env->interrupt_request & CPU_INTERRUPT_HARD)); -} - - -static inline void cpu_pc_from_tb(CPUState *env, TranslationBlock *tb) -{ - env->nip = tb->pc; -} - #endif /* !defined (__PPC_H__) */ diff --git a/target-ppc/helper.c b/target-ppc/helper.c index cf2a368b57..176128a3e2 100644 --- a/target-ppc/helper.c +++ b/target-ppc/helper.c @@ -23,7 +23,6 @@ #include <inttypes.h> #include "cpu.h" -#include "exec-all.h" #include "helper_regs.h" #include "qemu-common.h" #include "kvm.h" @@ -323,7 +322,7 @@ static inline void ppc6xx_tlb_invalidate_all(CPUState *env) if (env->id_tlbs == 1) max *= 2; for (nr = 0; nr < max; nr++) { - tlb = &env->tlb[nr].tlb6; + tlb = &env->tlb.tlb6[nr]; pte_invalidate(&tlb->pte0); } tlb_flush(env, 1); @@ -340,7 +339,7 @@ static inline void __ppc6xx_tlb_invalidate_virt(CPUState *env, /* Invalidate ITLB + DTLB, all ways */ for (way = 0; way < env->nb_ways; way++) { nr = ppc6xx_tlb_getnum(env, eaddr, way, is_code); - tlb = &env->tlb[nr].tlb6; + tlb = &env->tlb.tlb6[nr]; if (pte_is_valid(tlb->pte0) && (match_epn == 0 || eaddr == tlb->EPN)) { LOG_SWTLB("TLB invalidate %d/%d " TARGET_FMT_lx "\n", nr, env->nb_tlb, eaddr); @@ -367,7 +366,7 @@ void ppc6xx_tlb_store (CPUState *env, target_ulong EPN, int way, int is_code, int nr; nr = ppc6xx_tlb_getnum(env, EPN, way, is_code); - tlb = &env->tlb[nr].tlb6; + tlb = &env->tlb.tlb6[nr]; LOG_SWTLB("Set TLB %d/%d EPN " TARGET_FMT_lx " PTE0 " TARGET_FMT_lx " PTE1 " TARGET_FMT_lx "\n", nr, env->nb_tlb, EPN, pte0, pte1); /* Invalidate any pending reference in Qemu for this virtual address */ @@ -391,7 +390,7 @@ static inline int ppc6xx_tlb_check(CPUState *env, mmu_ctx_t *ctx, for (way = 0; way < env->nb_ways; way++) { nr = ppc6xx_tlb_getnum(env, eaddr, way, access_type == ACCESS_CODE ? 1 : 0); - tlb = &env->tlb[nr].tlb6; + tlb = &env->tlb.tlb6[nr]; /* This test "emulates" the PTE index match for hardware TLBs */ if ((eaddr & TARGET_PAGE_MASK) != tlb->EPN) { LOG_SWTLB("TLB %d/%d %s [" TARGET_FMT_lx " " TARGET_FMT_lx @@ -434,7 +433,7 @@ static inline int ppc6xx_tlb_check(CPUState *env, mmu_ctx_t *ctx, LOG_SWTLB("found TLB at addr " TARGET_FMT_plx " prot=%01x ret=%d\n", ctx->raddr & TARGET_PAGE_MASK, ctx->prot, ret); /* Update page flags */ - pte_update_flags(ctx, &env->tlb[best].tlb6.pte1, ret, rw); + pte_update_flags(ctx, &env->tlb.tlb6[best].pte1, ret, rw); } return ret; @@ -949,8 +948,24 @@ static inline int get_segment(CPUState *env, mmu_ctx_t *ctx, ret = -3; } } else { + target_ulong sr; LOG_MMU("direct store...\n"); /* Direct-store segment : absolutely *BUGGY* for now */ + + /* Direct-store implies a 32-bit MMU. + * Check the Segment Register's bus unit ID (BUID). + */ + sr = env->sr[eaddr >> 28]; + if ((sr & 0x1FF00000) >> 20 == 0x07f) { + /* Memory-forced I/O controller interface access */ + /* If T=1 and BUID=x'07F', the 601 performs a memory access + * to SR[28-31] LA[4-31], bypassing all protection mechanisms. + */ + ctx->raddr = ((sr & 0xF) << 28) | (eaddr & 0x0FFFFFFF); + ctx->prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC; + return 0; + } + switch (type) { case ACCESS_INT: /* Integer load/store : only access allowed */ @@ -1033,7 +1048,7 @@ int ppcemb_tlb_search (CPUPPCState *env, target_ulong address, uint32_t pid) /* Default return value is no match */ ret = -1; for (i = 0; i < env->nb_tlb; i++) { - tlb = &env->tlb[i].tlbe; + tlb = &env->tlb.tlbe[i]; if (ppcemb_tlb_check(env, tlb, &raddr, address, pid, 0, i) == 0) { ret = i; break; @@ -1050,7 +1065,7 @@ static inline void ppc4xx_tlb_invalidate_all(CPUState *env) int i; for (i = 0; i < env->nb_tlb; i++) { - tlb = &env->tlb[i].tlbe; + tlb = &env->tlb.tlbe[i]; tlb->prot &= ~PAGE_VALID; } tlb_flush(env, 1); @@ -1066,7 +1081,7 @@ static inline void ppc4xx_tlb_invalidate_virt(CPUState *env, int i; for (i = 0; i < env->nb_tlb; i++) { - tlb = &env->tlb[i].tlbe; + tlb = &env->tlb.tlbe[i]; if (ppcemb_tlb_check(env, tlb, &raddr, eaddr, pid, 0, i) == 0) { end = tlb->EPN + tlb->size; for (page = tlb->EPN; page < end; page += TARGET_PAGE_SIZE) @@ -1091,7 +1106,7 @@ static int mmu40x_get_physical_address (CPUState *env, mmu_ctx_t *ctx, raddr = (target_phys_addr_t)-1ULL; pr = msr_pr; for (i = 0; i < env->nb_tlb; i++) { - tlb = &env->tlb[i].tlbe; + tlb = &env->tlb.tlbe[i]; if (ppcemb_tlb_check(env, tlb, &raddr, address, env->spr[SPR_40x_PID], 0, i) < 0) continue; @@ -1232,7 +1247,7 @@ static int mmubooke_get_physical_address (CPUState *env, mmu_ctx_t *ctx, ret = -1; raddr = (target_phys_addr_t)-1ULL; for (i = 0; i < env->nb_tlb; i++) { - tlb = &env->tlb[i].tlbe; + tlb = &env->tlb.tlbe[i]; ret = mmubooke_check_tlb(env, tlb, &raddr, &ctx->prot, address, rw, access_type, i); if (!ret) { @@ -1257,14 +1272,14 @@ void booke206_flush_tlb(CPUState *env, int flags, const int check_iprot) { int tlb_size; int i, j; - ppc_tlb_t *tlb = env->tlb; + ppcmas_tlb_t *tlb = env->tlb.tlbm; for (i = 0; i < BOOKE206_MAX_TLBN; i++) { if (flags & (1 << i)) { tlb_size = booke206_tlb_size(env, i); for (j = 0; j < tlb_size; j++) { - if (!check_iprot || !(tlb[j].tlbe.attr & MAS1_IPROT)) { - tlb[j].tlbe.prot = 0; + if (!check_iprot || !(tlb[j].mas1 & MAS1_IPROT)) { + tlb[j].mas1 &= ~MAS1_VALID; } } } @@ -1274,11 +1289,148 @@ void booke206_flush_tlb(CPUState *env, int flags, const int check_iprot) tlb_flush(env, 1); } +target_phys_addr_t booke206_tlb_to_page_size(CPUState *env, ppcmas_tlb_t *tlb) +{ + uint32_t tlbncfg; + int tlbn = booke206_tlbm_to_tlbn(env, tlb); + target_phys_addr_t tlbm_size; + + tlbncfg = env->spr[SPR_BOOKE_TLB0CFG + tlbn]; + + if (tlbncfg & TLBnCFG_AVAIL) { + tlbm_size = (tlb->mas1 & MAS1_TSIZE_MASK) >> MAS1_TSIZE_SHIFT; + } else { + tlbm_size = (tlbncfg & TLBnCFG_MINSIZE) >> TLBnCFG_MINSIZE_SHIFT; + } + + return (1 << (tlbm_size << 1)) << 10; +} + +/* TLB check function for MAS based SoftTLBs */ +int ppcmas_tlb_check(CPUState *env, ppcmas_tlb_t *tlb, + target_phys_addr_t *raddrp, + target_ulong address, uint32_t pid) +{ + target_ulong mask; + uint32_t tlb_pid; + + /* Check valid flag */ + if (!(tlb->mas1 & MAS1_VALID)) { + return -1; + } + + mask = ~(booke206_tlb_to_page_size(env, tlb) - 1); + LOG_SWTLB("%s: TLB ADDR=0x" TARGET_FMT_lx " PID=0x%x MAS1=0x%x MAS2=0x%" + PRIx64 " mask=0x" TARGET_FMT_lx " MAS7_3=0x%" PRIx64 " MAS8=%x\n", + __func__, address, pid, tlb->mas1, tlb->mas2, mask, tlb->mas7_3, + tlb->mas8); + + /* Check PID */ + tlb_pid = (tlb->mas1 & MAS1_TID_MASK) >> MAS1_TID_SHIFT; + if (tlb_pid != 0 && tlb_pid != pid) { + return -1; + } + + /* Check effective address */ + if ((address & mask) != (tlb->mas2 & MAS2_EPN_MASK)) { + return -1; + } + *raddrp = (tlb->mas7_3 & mask) | (address & ~mask); + + return 0; +} + +static int mmubooke206_check_tlb(CPUState *env, ppcmas_tlb_t *tlb, + target_phys_addr_t *raddr, int *prot, + target_ulong address, int rw, + int access_type) +{ + int ret; + int _prot = 0; + + if (ppcmas_tlb_check(env, tlb, raddr, address, + env->spr[SPR_BOOKE_PID]) >= 0) { + goto found_tlb; + } + + if (env->spr[SPR_BOOKE_PID1] && + ppcmas_tlb_check(env, tlb, raddr, address, + env->spr[SPR_BOOKE_PID1]) >= 0) { + goto found_tlb; + } + + if (env->spr[SPR_BOOKE_PID2] && + ppcmas_tlb_check(env, tlb, raddr, address, + env->spr[SPR_BOOKE_PID2]) >= 0) { + goto found_tlb; + } + + LOG_SWTLB("%s: TLB entry not found\n", __func__); + return -1; + +found_tlb: + + if (msr_pr != 0) { + if (tlb->mas7_3 & MAS3_UR) { + _prot |= PAGE_READ; + } + if (tlb->mas7_3 & MAS3_UW) { + _prot |= PAGE_WRITE; + } + if (tlb->mas7_3 & MAS3_UX) { + _prot |= PAGE_EXEC; + } + } else { + if (tlb->mas7_3 & MAS3_SR) { + _prot |= PAGE_READ; + } + if (tlb->mas7_3 & MAS3_SW) { + _prot |= PAGE_WRITE; + } + if (tlb->mas7_3 & MAS3_SX) { + _prot |= PAGE_EXEC; + } + } + + /* Check the address space and permissions */ + if (access_type == ACCESS_CODE) { + if (msr_ir != ((tlb->mas1 & MAS1_TS) >> MAS1_TS_SHIFT)) { + LOG_SWTLB("%s: AS doesn't match\n", __func__); + return -1; + } + + *prot = _prot; + if (_prot & PAGE_EXEC) { + LOG_SWTLB("%s: good TLB!\n", __func__); + return 0; + } + + LOG_SWTLB("%s: no PAGE_EXEC: %x\n", __func__, _prot); + ret = -3; + } else { + if (msr_dr != ((tlb->mas1 & MAS1_TS) >> MAS1_TS_SHIFT)) { + LOG_SWTLB("%s: AS doesn't match\n", __func__); + return -1; + } + + *prot = _prot; + if ((!rw && _prot & PAGE_READ) || (rw && (_prot & PAGE_WRITE))) { + LOG_SWTLB("%s: found TLB!\n", __func__); + return 0; + } + + LOG_SWTLB("%s: PAGE_READ/WRITE doesn't match: %x\n", __func__, _prot); + ret = -2; + } + + return ret; +} + static int mmubooke206_get_physical_address(CPUState *env, mmu_ctx_t *ctx, - target_ulong address, int rw, - int access_type) + target_ulong address, int rw, + int access_type) { - ppcemb_tlb_t *tlb; + ppcmas_tlb_t *tlb; target_phys_addr_t raddr; int i, j, ret; @@ -1289,9 +1441,9 @@ static int mmubooke206_get_physical_address(CPUState *env, mmu_ctx_t *ctx, int ways = booke206_tlb_ways(env, i); for (j = 0; j < ways; j++) { - tlb = booke206_get_tlbe(env, i, address, j); - ret = mmubooke_check_tlb(env, tlb, &raddr, &ctx->prot, address, rw, - access_type, j); + tlb = booke206_get_tlbm(env, i, address, j); + ret = mmubooke206_check_tlb(env, tlb, &raddr, &ctx->prot, address, + rw, access_type); if (ret != -1) { goto found_tlb; } @@ -1396,7 +1548,7 @@ int get_physical_address (CPUState *env, mmu_ctx_t *ctx, target_ulong eaddr, rw, access_type); } else if (env->mmu_model == POWERPC_MMU_BOOKE206) { ret = mmubooke206_get_physical_address(env, ctx, eaddr, rw, - access_type); + access_type); } else { /* No address translation. */ ret = check_physical(env, ctx, eaddr, rw); diff --git a/target-ppc/machine.c b/target-ppc/machine.c index 0c1986e528..1c40d4358a 100644 --- a/target-ppc/machine.c +++ b/target-ppc/machine.c @@ -52,12 +52,12 @@ void cpu_save(QEMUFile *f, void *opaque) qemu_put_sbe32s(f, &env->last_way); qemu_put_sbe32s(f, &env->id_tlbs); qemu_put_sbe32s(f, &env->nb_pids); - if (env->tlb) { + if (env->tlb.tlb6) { // XXX assumes 6xx for (i = 0; i < env->nb_tlb; i++) { - qemu_put_betls(f, &env->tlb[i].tlb6.pte0); - qemu_put_betls(f, &env->tlb[i].tlb6.pte1); - qemu_put_betls(f, &env->tlb[i].tlb6.EPN); + qemu_put_betls(f, &env->tlb.tlb6[i].pte0); + qemu_put_betls(f, &env->tlb.tlb6[i].pte1); + qemu_put_betls(f, &env->tlb.tlb6[i].EPN); } } for (i = 0; i < 4; i++) @@ -140,12 +140,12 @@ int cpu_load(QEMUFile *f, void *opaque, int version_id) qemu_get_sbe32s(f, &env->last_way); qemu_get_sbe32s(f, &env->id_tlbs); qemu_get_sbe32s(f, &env->nb_pids); - if (env->tlb) { + if (env->tlb.tlb6) { // XXX assumes 6xx for (i = 0; i < env->nb_tlb; i++) { - qemu_get_betls(f, &env->tlb[i].tlb6.pte0); - qemu_get_betls(f, &env->tlb[i].tlb6.pte1); - qemu_get_betls(f, &env->tlb[i].tlb6.EPN); + qemu_get_betls(f, &env->tlb.tlb6[i].pte0); + qemu_get_betls(f, &env->tlb.tlb6[i].pte1); + qemu_get_betls(f, &env->tlb.tlb6[i].EPN); } } for (i = 0; i < 4; i++) diff --git a/target-ppc/op_helper.c b/target-ppc/op_helper.c index 15d9222c72..dde7595fda 100644 --- a/target-ppc/op_helper.c +++ b/target-ppc/op_helper.c @@ -44,7 +44,7 @@ void helper_raise_exception_err (uint32_t exception, uint32_t error_code) #endif env->exception_index = exception; env->error_code = error_code; - cpu_loop_exit(); + cpu_loop_exit(env); } void helper_raise_exception (uint32_t exception) @@ -3959,7 +3959,7 @@ target_ulong helper_4xx_tlbre_hi (target_ulong entry) int size; entry &= PPC4XX_TLB_ENTRY_MASK; - tlb = &env->tlb[entry].tlbe; + tlb = &env->tlb.tlbe[entry]; ret = tlb->EPN; if (tlb->prot & PAGE_VALID) { ret |= PPC4XX_TLBHI_V; @@ -3979,7 +3979,7 @@ target_ulong helper_4xx_tlbre_lo (target_ulong entry) target_ulong ret; entry &= PPC4XX_TLB_ENTRY_MASK; - tlb = &env->tlb[entry].tlbe; + tlb = &env->tlb.tlbe[entry]; ret = tlb->RPN; if (tlb->prot & PAGE_EXEC) { ret |= PPC4XX_TLBLO_EX; @@ -3998,7 +3998,7 @@ void helper_4xx_tlbwe_hi (target_ulong entry, target_ulong val) LOG_SWTLB("%s entry %d val " TARGET_FMT_lx "\n", __func__, (int)entry, val); entry &= PPC4XX_TLB_ENTRY_MASK; - tlb = &env->tlb[entry].tlbe; + tlb = &env->tlb.tlbe[entry]; /* Invalidate previous TLB (if it's valid) */ if (tlb->prot & PAGE_VALID) { end = tlb->EPN + tlb->size; @@ -4056,7 +4056,7 @@ void helper_4xx_tlbwe_lo (target_ulong entry, target_ulong val) LOG_SWTLB("%s entry %i val " TARGET_FMT_lx "\n", __func__, (int)entry, val); entry &= PPC4XX_TLB_ENTRY_MASK; - tlb = &env->tlb[entry].tlbe; + tlb = &env->tlb.tlbe[entry]; tlb->attr = val & PPC4XX_TLBLO_ATTR_MASK; tlb->RPN = val & PPC4XX_TLBLO_RPN_MASK; tlb->prot = PAGE_READ; @@ -4091,7 +4091,7 @@ void helper_440_tlbwe (uint32_t word, target_ulong entry, target_ulong value) __func__, word, (int)entry, value); do_flush_tlbs = 0; entry &= 0x3F; - tlb = &env->tlb[entry].tlbe; + tlb = &env->tlb.tlbe[entry]; switch (word) { default: /* Just here to please gcc */ @@ -4150,7 +4150,7 @@ target_ulong helper_440_tlbre (uint32_t word, target_ulong entry) int size; entry &= 0x3F; - tlb = &env->tlb[entry].tlbe; + tlb = &env->tlb.tlbe[entry]; switch (word) { default: /* Just here to please gcc */ @@ -4196,7 +4196,7 @@ target_ulong helper_440_tlbsx (target_ulong address) /* PowerPC BookE 2.06 TLB management */ -static ppcemb_tlb_t *booke206_cur_tlb(CPUState *env) +static ppcmas_tlb_t *booke206_cur_tlb(CPUState *env) { uint32_t tlbncfg = 0; int esel = (env->spr[SPR_BOOKE_MAS0] & MAS0_ESEL_MASK) >> MAS0_ESEL_SHIFT; @@ -4210,17 +4210,7 @@ static ppcemb_tlb_t *booke206_cur_tlb(CPUState *env) cpu_abort(env, "we don't support HES yet\n"); } - return booke206_get_tlbe(env, tlb, ea, esel); -} - -static inline target_phys_addr_t booke206_tlb_to_page_size(int size) -{ - return (1 << (size << 1)) << 10; -} - -static inline target_phys_addr_t booke206_page_size_to_tlb(uint64_t size) -{ - return (ffs(size >> 10) - 1) >> 1; + return booke206_get_tlbm(env, tlb, ea, esel); } void helper_booke_setpid(uint32_t pidn, target_ulong pid) @@ -4233,9 +4223,7 @@ void helper_booke_setpid(uint32_t pidn, target_ulong pid) void helper_booke206_tlbwe(void) { uint32_t tlbncfg, tlbn; - ppcemb_tlb_t *tlb; - target_phys_addr_t rpn; - int tlbe_size; + ppcmas_tlb_t *tlb; switch (env->spr[SPR_BOOKE_MAS0] & MAS0_WQ_MASK) { case MAS0_WQ_ALWAYS: @@ -4269,116 +4257,43 @@ void helper_booke206_tlbwe(void) if (msr_gs) { cpu_abort(env, "missing HV implementation\n"); - } else { - rpn = ((uint64_t)env->spr[SPR_BOOKE_MAS7] << 32) | - (env->spr[SPR_BOOKE_MAS3] & 0xfffff000); - } - tlb->RPN = rpn; - - tlb->PID = (env->spr[SPR_BOOKE_MAS1] & MAS1_TID_MASK) >> MAS1_TID_SHIFT; - if (tlbncfg & TLBnCFG_AVAIL) { - tlbe_size = (env->spr[SPR_BOOKE_MAS1] & MAS1_TSIZE_MASK) - >> MAS1_TSIZE_SHIFT; - } else { - tlbe_size = (tlbncfg & TLBnCFG_MINSIZE) >> TLBnCFG_MINSIZE_SHIFT; } + tlb->mas7_3 = ((uint64_t)env->spr[SPR_BOOKE_MAS7] << 32) | + env->spr[SPR_BOOKE_MAS3]; + tlb->mas1 = env->spr[SPR_BOOKE_MAS1]; + /* XXX needs to change when supporting 64-bit e500 */ + tlb->mas2 = env->spr[SPR_BOOKE_MAS2] & 0xffffffff; - tlb->size = booke206_tlb_to_page_size(tlbe_size); - tlb->EPN = (uint32_t)(env->spr[SPR_BOOKE_MAS2] & MAS2_EPN_MASK); - tlb->attr = env->spr[SPR_BOOKE_MAS2] & (MAS2_ACM | MAS2_VLE | MAS2_W | - MAS2_I | MAS2_M | MAS2_G | MAS2_E) - << 1; - - if (tlbncfg & TLBnCFG_IPROT) { - tlb->attr |= env->spr[SPR_BOOKE_MAS1] & MAS1_IPROT; - } - tlb->attr |= (env->spr[SPR_BOOKE_MAS3] & - ((MAS3_U0 | MAS3_U1 | MAS3_U2 | MAS3_U3)) << 8); - if (env->spr[SPR_BOOKE_MAS1] & MAS1_TS) { - tlb->attr |= 1; - } - - tlb->prot = 0; - - if (env->spr[SPR_BOOKE_MAS1] & MAS1_VALID) { - tlb->prot |= PAGE_VALID; - } - if (env->spr[SPR_BOOKE_MAS3] & MAS3_UX) { - tlb->prot |= PAGE_EXEC; - } - if (env->spr[SPR_BOOKE_MAS3] & MAS3_SX) { - tlb->prot |= PAGE_EXEC << 4; - } - if (env->spr[SPR_BOOKE_MAS3] & MAS3_UW) { - tlb->prot |= PAGE_WRITE; - } - if (env->spr[SPR_BOOKE_MAS3] & MAS3_SW) { - tlb->prot |= PAGE_WRITE << 4; - } - if (env->spr[SPR_BOOKE_MAS3] & MAS3_UR) { - tlb->prot |= PAGE_READ; - } - if (env->spr[SPR_BOOKE_MAS3] & MAS3_SR) { - tlb->prot |= PAGE_READ << 4; + if (!(tlbncfg & TLBnCFG_IPROT)) { + /* no IPROT supported by TLB */ + tlb->mas1 &= ~MAS1_IPROT; } - if (tlb->size == TARGET_PAGE_SIZE) { - tlb_flush_page(env, tlb->EPN); + if (booke206_tlb_to_page_size(env, tlb) == TARGET_PAGE_SIZE) { + tlb_flush_page(env, tlb->mas2 & MAS2_EPN_MASK); } else { tlb_flush(env, 1); } } -static inline void booke206_tlb_to_mas(CPUState *env, ppcemb_tlb_t *tlb) +static inline void booke206_tlb_to_mas(CPUState *env, ppcmas_tlb_t *tlb) { - int tlbn = booke206_tlbe_to_tlbn(env, tlb); - int way = booke206_tlbe_to_way(env, tlb); + int tlbn = booke206_tlbm_to_tlbn(env, tlb); + int way = booke206_tlbm_to_way(env, tlb); env->spr[SPR_BOOKE_MAS0] = tlbn << MAS0_TLBSEL_SHIFT; env->spr[SPR_BOOKE_MAS0] |= way << MAS0_ESEL_SHIFT; - - env->spr[SPR_BOOKE_MAS1] = MAS1_VALID; - env->spr[SPR_BOOKE_MAS2] = 0; - - env->spr[SPR_BOOKE_MAS7] = (uint64_t)tlb->RPN >> 32; - env->spr[SPR_BOOKE_MAS3] = tlb->RPN; - env->spr[SPR_BOOKE_MAS1] |= tlb->PID << MAS1_TID_SHIFT; - env->spr[SPR_BOOKE_MAS1] |= booke206_page_size_to_tlb(tlb->size) - << MAS1_TSIZE_SHIFT; - env->spr[SPR_BOOKE_MAS1] |= tlb->attr & MAS1_IPROT; - if (tlb->attr & 1) { - env->spr[SPR_BOOKE_MAS1] |= MAS1_TS; - } - - env->spr[SPR_BOOKE_MAS2] = tlb->EPN; - env->spr[SPR_BOOKE_MAS2] |= (tlb->attr >> 1) & - (MAS2_ACM | MAS2_VLE | MAS2_W | MAS2_I | MAS2_M | MAS2_G | MAS2_E); - - if (tlb->prot & PAGE_EXEC) { - env->spr[SPR_BOOKE_MAS3] |= MAS3_UX; - } - if (tlb->prot & (PAGE_EXEC << 4)) { - env->spr[SPR_BOOKE_MAS3] |= MAS3_SX; - } - if (tlb->prot & PAGE_WRITE) { - env->spr[SPR_BOOKE_MAS3] |= MAS3_UW; - } - if (tlb->prot & (PAGE_WRITE << 4)) { - env->spr[SPR_BOOKE_MAS3] |= MAS3_SW; - } - if (tlb->prot & PAGE_READ) { - env->spr[SPR_BOOKE_MAS3] |= MAS3_UR; - } - if (tlb->prot & (PAGE_READ << 4)) { - env->spr[SPR_BOOKE_MAS3] |= MAS3_SR; - } - env->spr[SPR_BOOKE_MAS0] |= env->last_way << MAS0_NV_SHIFT; + + env->spr[SPR_BOOKE_MAS1] = tlb->mas1; + env->spr[SPR_BOOKE_MAS2] = tlb->mas2; + env->spr[SPR_BOOKE_MAS3] = tlb->mas7_3; + env->spr[SPR_BOOKE_MAS7] = tlb->mas7_3 >> 32; } void helper_booke206_tlbre(void) { - ppcemb_tlb_t *tlb = NULL; + ppcmas_tlb_t *tlb = NULL; tlb = booke206_cur_tlb(env); booke206_tlb_to_mas(env, tlb); @@ -4386,7 +4301,7 @@ void helper_booke206_tlbre(void) void helper_booke206_tlbsx(target_ulong address) { - ppcemb_tlb_t *tlb = NULL; + ppcmas_tlb_t *tlb = NULL; int i, j; target_phys_addr_t raddr; uint32_t spid, sas; @@ -4398,13 +4313,13 @@ void helper_booke206_tlbsx(target_ulong address) int ways = booke206_tlb_ways(env, i); for (j = 0; j < ways; j++) { - tlb = booke206_get_tlbe(env, i, address, j); + tlb = booke206_get_tlbm(env, i, address, j); - if (ppcemb_tlb_check(env, tlb, &raddr, address, spid, 0, j)) { + if (ppcmas_tlb_check(env, tlb, &raddr, address, spid)) { continue; } - if (sas != (tlb->attr & MAS6_SAS)) { + if (sas != ((tlb->mas1 & MAS1_TS) >> MAS1_TS_SHIFT)) { continue; } @@ -4439,13 +4354,14 @@ static inline void booke206_invalidate_ea_tlb(CPUState *env, int tlbn, { int i; int ways = booke206_tlb_ways(env, tlbn); + target_ulong mask; for (i = 0; i < ways; i++) { - ppcemb_tlb_t *tlb = booke206_get_tlbe(env, tlbn, ea, i); - target_phys_addr_t masked_ea = ea & ~(tlb->size - 1); - if ((tlb->EPN == (masked_ea >> MAS2_EPN_SHIFT)) && - !(tlb->attr & MAS1_IPROT)) { - tlb->prot = 0; + ppcmas_tlb_t *tlb = booke206_get_tlbm(env, tlbn, ea, i); + mask = ~(booke206_tlb_to_page_size(env, tlb) - 1); + if (((tlb->mas2 & MAS2_EPN_MASK) == (ea & mask)) && + !(tlb->mas1 & MAS1_IPROT)) { + tlb->mas1 &= ~MAS1_VALID; } } } diff --git a/target-ppc/translate.c b/target-ppc/translate.c index 59aef855d4..fd7c2087d7 100644 --- a/target-ppc/translate.c +++ b/target-ppc/translate.c @@ -24,7 +24,6 @@ #include <inttypes.h> #include "cpu.h" -#include "exec-all.h" #include "disas.h" #include "tcg-op.h" #include "qemu-common.h" @@ -3878,24 +3877,19 @@ static void gen_mtmsr(DisasContext *ctx) tcg_gen_or_tl(cpu_msr, cpu_msr, t0); tcg_temp_free(t0); } else { + TCGv msr = tcg_temp_new(); + /* XXX: we need to update nip before the store * if we enter power saving mode, we will exit the loop * directly from ppc_store_msr */ gen_update_nip(ctx, ctx->nip); #if defined(TARGET_PPC64) - if (!ctx->sf_mode) { - TCGv t0 = tcg_temp_new(); - TCGv t1 = tcg_temp_new(); - tcg_gen_andi_tl(t0, cpu_msr, 0xFFFFFFFF00000000ULL); - tcg_gen_ext32u_tl(t1, cpu_gpr[rS(ctx->opcode)]); - tcg_gen_or_tl(t0, t0, t1); - tcg_temp_free(t1); - gen_helper_store_msr(t0); - tcg_temp_free(t0); - } else + tcg_gen_deposit_tl(msr, cpu_msr, cpu_gpr[rS(ctx->opcode)], 0, 32); +#else + tcg_gen_mov_tl(msr, cpu_gpr[rS(ctx->opcode)]); #endif - gen_helper_store_msr(cpu_gpr[rS(ctx->opcode)]); + gen_helper_store_msr(msr); /* Must stop the translation as machine state (may have) changed */ /* Note that mtmsr is not always defined as context-synchronizing */ gen_stop_exception(ctx); diff --git a/target-ppc/translate_init.c b/target-ppc/translate_init.c index fc50ae3cd2..f542b8e4f3 100644 --- a/target-ppc/translate_init.c +++ b/target-ppc/translate_init.c @@ -844,6 +844,7 @@ static void gen_6xx_7xx_soft_tlb (CPUPPCState *env, int nb_tlbs, int nb_ways) env->nb_tlb = nb_tlbs; env->nb_ways = nb_ways; env->id_tlbs = 1; + env->tlb_type = TLB_6XX; spr_register(env, SPR_DMISS, "DMISS", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, SPR_NOACCESS, @@ -1337,6 +1338,7 @@ static void gen_74xx_soft_tlb (CPUPPCState *env, int nb_tlbs, int nb_ways) env->nb_tlb = nb_tlbs; env->nb_ways = nb_ways; env->id_tlbs = 1; + env->tlb_type = TLB_6XX; /* XXX : not implemented */ spr_register(env, SPR_PTEHI, "PTEHI", SPR_NOACCESS, SPR_NOACCESS, @@ -3282,6 +3284,7 @@ static void init_proc_401x2 (CPUPPCState *env) env->nb_tlb = 64; env->nb_ways = 1; env->id_tlbs = 0; + env->tlb_type = TLB_EMB; #endif init_excp_4xx_softmmu(env); env->dcache_line_size = 32; @@ -3352,6 +3355,7 @@ static void init_proc_IOP480 (CPUPPCState *env) env->nb_tlb = 64; env->nb_ways = 1; env->id_tlbs = 0; + env->tlb_type = TLB_EMB; #endif init_excp_4xx_softmmu(env); env->dcache_line_size = 32; @@ -3431,6 +3435,7 @@ static void init_proc_403GCX (CPUPPCState *env) env->nb_tlb = 64; env->nb_ways = 1; env->id_tlbs = 0; + env->tlb_type = TLB_EMB; #endif init_excp_4xx_softmmu(env); env->dcache_line_size = 32; @@ -3479,6 +3484,7 @@ static void init_proc_405 (CPUPPCState *env) env->nb_tlb = 64; env->nb_ways = 1; env->id_tlbs = 0; + env->tlb_type = TLB_EMB; #endif init_excp_4xx_softmmu(env); env->dcache_line_size = 32; @@ -3561,6 +3567,7 @@ static void init_proc_440EP (CPUPPCState *env) env->nb_tlb = 64; env->nb_ways = 1; env->id_tlbs = 0; + env->tlb_type = TLB_EMB; #endif init_excp_BookE(env); env->dcache_line_size = 32; @@ -3624,6 +3631,7 @@ static void init_proc_440GP (CPUPPCState *env) env->nb_tlb = 64; env->nb_ways = 1; env->id_tlbs = 0; + env->tlb_type = TLB_EMB; #endif init_excp_BookE(env); env->dcache_line_size = 32; @@ -3687,6 +3695,7 @@ static void init_proc_440x4 (CPUPPCState *env) env->nb_tlb = 64; env->nb_ways = 1; env->id_tlbs = 0; + env->tlb_type = TLB_EMB; #endif init_excp_BookE(env); env->dcache_line_size = 32; @@ -3767,6 +3776,7 @@ static void init_proc_440x5 (CPUPPCState *env) env->nb_tlb = 64; env->nb_ways = 1; env->id_tlbs = 0; + env->tlb_type = TLB_EMB; #endif init_excp_BookE(env); env->dcache_line_size = 32; @@ -3854,6 +3864,7 @@ static void init_proc_460 (CPUPPCState *env) env->nb_tlb = 64; env->nb_ways = 1; env->id_tlbs = 0; + env->tlb_type = TLB_EMB; #endif init_excp_BookE(env); env->dcache_line_size = 32; @@ -3944,6 +3955,7 @@ static void init_proc_460F (CPUPPCState *env) env->nb_tlb = 64; env->nb_ways = 1; env->id_tlbs = 0; + env->tlb_type = TLB_EMB; #endif init_excp_BookE(env); env->dcache_line_size = 32; @@ -4251,6 +4263,7 @@ static void init_proc_e200 (CPUPPCState *env) env->nb_tlb = 64; env->nb_ways = 1; env->id_tlbs = 0; + env->tlb_type = TLB_EMB; #endif init_excp_e200(env); env->dcache_line_size = 32; @@ -4464,6 +4477,7 @@ static void init_proc_e500 (CPUPPCState *env, int version) #if !defined(CONFIG_USER_ONLY) env->nb_tlb = 0; + env->tlb_type = TLB_MAS; for (i = 0; i < BOOKE206_MAX_TLBN; i++) { env->nb_tlb += booke206_tlb_size(env, i); } @@ -9186,6 +9200,7 @@ static void init_ppc_proc (CPUPPCState *env, const ppc_def_t *def) env->nb_BATs = 0; env->nb_tlb = 0; env->nb_ways = 0; + env->tlb_type = TLB_NONE; #endif /* Register SPR common to all PowerPC implementations */ gen_spr_generic(env); @@ -9310,7 +9325,17 @@ static void init_ppc_proc (CPUPPCState *env, const ppc_def_t *def) int nb_tlb = env->nb_tlb; if (env->id_tlbs != 0) nb_tlb *= 2; - env->tlb = qemu_mallocz(nb_tlb * sizeof(ppc_tlb_t)); + switch (env->tlb_type) { + case TLB_6XX: + env->tlb.tlb6 = qemu_mallocz(nb_tlb * sizeof(ppc6xx_tlb_t)); + break; + case TLB_EMB: + env->tlb.tlbe = qemu_mallocz(nb_tlb * sizeof(ppcemb_tlb_t)); + break; + case TLB_MAS: + env->tlb.tlbm = qemu_mallocz(nb_tlb * sizeof(ppcmas_tlb_t)); + break; + } /* Pre-compute some useful values */ env->tlb_per_way = env->nb_tlb / env->nb_ways; } diff --git a/target-s390x/cpu.h b/target-s390x/cpu.h index b5e587fbe6..d48a9b7a0c 100644 --- a/target-s390x/cpu.h +++ b/target-s390x/cpu.h @@ -962,4 +962,15 @@ static inline void cpu_inject_ext(CPUState *env, uint32_t code, uint32_t param, cpu_interrupt(env, CPU_INTERRUPT_HARD); } +static inline bool cpu_has_work(CPUState *env) +{ + return (env->interrupt_request & CPU_INTERRUPT_HARD) && + (env->psw.mask & PSW_MASK_EXT); +} + +static inline void cpu_pc_from_tb(CPUState *env, TranslationBlock* tb) +{ + env->psw.addr = tb->pc; +} + #endif diff --git a/target-s390x/exec.h b/target-s390x/exec.h index 7a87fffca6..fb73f31804 100644 --- a/target-s390x/exec.h +++ b/target-s390x/exec.h @@ -23,18 +23,11 @@ register struct CPUS390XState *env asm(AREG0); #include "config.h" #include "cpu.h" -#include "exec-all.h" #if !defined(CONFIG_USER_ONLY) #include "softmmu_exec.h" #endif /* !defined(CONFIG_USER_ONLY) */ -static inline int cpu_has_work(CPUState *env) -{ - return ((env->interrupt_request & CPU_INTERRUPT_HARD) && - (env->psw.mask & PSW_MASK_EXT)); -} - static inline void regs_to_env(void) { } @@ -42,9 +35,3 @@ static inline void regs_to_env(void) static inline void env_to_regs(void) { } - -static inline void cpu_pc_from_tb(CPUState *env, TranslationBlock* tb) -{ - env->psw.addr = tb->pc; -} - diff --git a/target-s390x/helper.c b/target-s390x/helper.c index 745d8c52bb..1ce7079af7 100644 --- a/target-s390x/helper.c +++ b/target-s390x/helper.c @@ -23,7 +23,6 @@ #include <string.h> #include "cpu.h" -#include "exec-all.h" #include "gdbstub.h" #include "qemu-common.h" #include "qemu-timer.h" diff --git a/target-s390x/op_helper.c b/target-s390x/op_helper.c index 9429698c2c..cd33f99d21 100644 --- a/target-s390x/op_helper.c +++ b/target-s390x/op_helper.c @@ -23,8 +23,10 @@ #include "helpers.h" #include <string.h> #include "kvm.h" -#include <linux/kvm.h> #include "qemu-timer.h" +#ifdef CONFIG_KVM +#include <linux/kvm.h> +#endif /*****************************************************************************/ /* Softmmu support */ @@ -71,7 +73,7 @@ void tlb_fill (target_ulong addr, int is_write, int mmu_idx, void *retaddr) cpu_restore_state(tb, env, pc); } } - cpu_loop_exit(); + cpu_loop_exit(env); } env = saved_env; } @@ -90,7 +92,7 @@ void HELPER(exception)(uint32_t excp) { HELPER_LOG("%s: exception %d\n", __FUNCTION__, excp); env->exception_index = excp; - cpu_loop_exit(); + cpu_loop_exit(env); } #ifndef CONFIG_USER_ONLY @@ -2324,7 +2326,7 @@ void HELPER(tr)(uint32_t len, uint64_t array, uint64_t trans) void HELPER(load_psw)(uint64_t mask, uint64_t addr) { load_psw(env, mask, addr); - cpu_loop_exit(); + cpu_loop_exit(env); } static void program_interrupt(CPUState *env, uint32_t code, int ilc) @@ -2332,12 +2334,14 @@ static void program_interrupt(CPUState *env, uint32_t code, int ilc) qemu_log("program interrupt at %#" PRIx64 "\n", env->psw.addr); if (kvm_enabled()) { +#ifdef CONFIG_KVM kvm_s390_interrupt(env, KVM_S390_PROGRAM_INT, code); +#endif } else { env->int_pgm_code = code; env->int_pgm_ilc = ilc; env->exception_index = EXCP_PGM; - cpu_loop_exit(); + cpu_loop_exit(env); } } @@ -2824,12 +2828,12 @@ static uint32_t mvc_asc(int64_t l, uint64_t a1, uint64_t mode1, uint64_t a2, } if (mmu_translate(env, a1 & TARGET_PAGE_MASK, 1, mode1, &dest, &flags)) { - cpu_loop_exit(); + cpu_loop_exit(env); } dest |= a1 & ~TARGET_PAGE_MASK; if (mmu_translate(env, a2 & TARGET_PAGE_MASK, 0, mode2, &src, &flags)) { - cpu_loop_exit(); + cpu_loop_exit(env); } src |= a2 & ~TARGET_PAGE_MASK; diff --git a/target-s390x/translate.c b/target-s390x/translate.c index eda4624d11..77fb4482aa 100644 --- a/target-s390x/translate.c +++ b/target-s390x/translate.c @@ -35,7 +35,6 @@ #endif #include "cpu.h" -#include "exec-all.h" #include "disas.h" #include "tcg-op.h" #include "qemu-log.h" diff --git a/target-sh4/cpu.h b/target-sh4/cpu.h index 74ff97a908..00e32f2b10 100644 --- a/target-sh4/cpu.h +++ b/target-sh4/cpu.h @@ -361,4 +361,17 @@ static inline void cpu_get_tb_cpu_state(CPUState *env, target_ulong *pc, | (env->movcal_backup ? TB_FLAG_PENDING_MOVCA : 0); /* Bit 4 */ } +static inline bool cpu_has_work(CPUState *env) +{ + return env->interrupt_request & CPU_INTERRUPT_HARD; +} + +#include "exec-all.h" + +static inline void cpu_pc_from_tb(CPUState *env, TranslationBlock *tb) +{ + env->pc = tb->pc; + env->flags = tb->flags; +} + #endif /* _CPU_SH4_H */ diff --git a/target-sh4/exec.h b/target-sh4/exec.h index 9f1c1f6a00..4a6ae58898 100644 --- a/target-sh4/exec.h +++ b/target-sh4/exec.h @@ -25,21 +25,9 @@ register struct CPUSH4State *env asm(AREG0); #include "cpu.h" -#include "exec-all.h" - -static inline int cpu_has_work(CPUState *env) -{ - return (env->interrupt_request & CPU_INTERRUPT_HARD); -} #ifndef CONFIG_USER_ONLY #include "softmmu_exec.h" #endif -static inline void cpu_pc_from_tb(CPUState *env, TranslationBlock *tb) -{ - env->pc = tb->pc; - env->flags = tb->flags; -} - #endif /* _EXEC_SH4_H */ diff --git a/target-sh4/helper.c b/target-sh4/helper.c index 8f36d313cd..20e9b134d6 100644 --- a/target-sh4/helper.c +++ b/target-sh4/helper.c @@ -24,7 +24,6 @@ #include <signal.h> #include "cpu.h" -#include "exec-all.h" #include "hw/sh_intc.h" #if defined(CONFIG_USER_ONLY) diff --git a/target-sh4/op_helper.c b/target-sh4/op_helper.c index b909d18bc4..a932225880 100644 --- a/target-sh4/op_helper.c +++ b/target-sh4/op_helper.c @@ -66,7 +66,7 @@ void tlb_fill(target_ulong addr, int is_write, int mmu_idx, void *retaddr) if (ret) { /* now we have a real cpu fault */ cpu_restore_state_from_retaddr(retaddr); - cpu_loop_exit(); + cpu_loop_exit(env); } env = saved_env; } @@ -87,7 +87,7 @@ static inline void raise_exception(int index, void *retaddr) { env->exception_index = index; cpu_restore_state_from_retaddr(retaddr); - cpu_loop_exit(); + cpu_loop_exit(env); } void helper_raise_illegal_instruction(void) @@ -113,7 +113,7 @@ void helper_raise_slot_fpu_disable(void) void helper_debug(void) { env->exception_index = EXCP_DEBUG; - cpu_loop_exit(); + cpu_loop_exit(env); } void helper_sleep(uint32_t next_pc) @@ -122,7 +122,7 @@ void helper_sleep(uint32_t next_pc) env->in_sleep = 1; env->exception_index = EXCP_HLT; env->pc = next_pc; - cpu_loop_exit(); + cpu_loop_exit(env); } void helper_trapa(uint32_t tra) @@ -482,7 +482,7 @@ static void update_fpscr(void *retaddr) if (cause & enable) { cpu_restore_state_from_retaddr(retaddr); env->exception_index = 0x120; - cpu_loop_exit(); + cpu_loop_exit(env); } } } diff --git a/target-sh4/translate.c b/target-sh4/translate.c index 93c863650d..569bc738cb 100644 --- a/target-sh4/translate.c +++ b/target-sh4/translate.c @@ -27,7 +27,6 @@ //#define SH4_SINGLE_STEP #include "cpu.h" -#include "exec-all.h" #include "disas.h" #include "tcg-op.h" #include "qemu-common.h" diff --git a/target-sparc/cpu.h b/target-sparc/cpu.h index 320530ec9f..22ee2743d7 100644 --- a/target-sparc/cpu.h +++ b/target-sparc/cpu.h @@ -403,6 +403,8 @@ typedef struct CPUSPARCState { uint32_t mmuregs[32]; uint64_t mxccdata[4]; uint64_t mxccregs[8]; + uint32_t mmubpctrv, mmubpctrc, mmubpctrs; + uint64_t mmubpaction; uint64_t mmubpregs[4]; uint64_t prom_addr; #endif @@ -474,6 +476,7 @@ target_ulong cpu_get_ccr(CPUState *env1); void cpu_put_ccr(CPUState *env1, target_ulong val); target_ulong cpu_get_cwp64(CPUState *env1); void cpu_put_cwp64(CPUState *env1, int cwp); +void cpu_change_pstate(CPUState *env1, uint32_t new_pstate); #endif int cpu_cwp_inc(CPUState *env1, int cwp); int cpu_cwp_dec(CPUState *env1, int cwp); @@ -521,7 +524,7 @@ int cpu_sparc_signal_handler(int host_signum, void *pinfo, void *puc); #define cpu_signal_handler cpu_sparc_signal_handler #define cpu_list sparc_cpu_list -#define CPU_SAVE_VERSION 6 +#define CPU_SAVE_VERSION 7 /* MMU modes definitions */ #if defined (TARGET_SPARC64) @@ -603,17 +606,6 @@ static inline int cpu_pil_allowed(CPUState *env1, int pil) #endif } -static inline int cpu_fpu_enabled(CPUState *env1) -{ -#if defined(CONFIG_USER_ONLY) - return 1; -#elif !defined(TARGET_SPARC64) - return env1->psref; -#else - return ((env1->pstate & PS_PEF) != 0) && ((env1->fprs & FPRS_FEF) != 0); -#endif -} - #if defined(CONFIG_USER_ONLY) static inline void cpu_clone_regs(CPUState *env, target_ulong newsp) { @@ -636,6 +628,9 @@ void cpu_tick_set_limit(CPUTimer *timer, uint64_t limit); trap_state* cpu_tsptr(CPUState* env); #endif +#define TB_FLAG_FPU_ENABLED (1 << 4) +#define TB_FLAG_AM_ENABLED (1 << 5) + static inline void cpu_get_tb_cpu_state(CPUState *env, target_ulong *pc, target_ulong *cs_base, int *flags) { @@ -643,17 +638,59 @@ static inline void cpu_get_tb_cpu_state(CPUState *env, target_ulong *pc, *cs_base = env->npc; #ifdef TARGET_SPARC64 // AM . Combined FPU enable bits . PRIV . DMMU enabled . IMMU enabled - *flags = ((env->pstate & PS_AM) << 2) /* 5 */ - | (((env->pstate & PS_PEF) >> 1) /* 3 */ - | ((env->fprs & FPRS_FEF) << 2)) /* 4 */ - | (env->pstate & PS_PRIV) /* 2 */ + *flags = (env->pstate & PS_PRIV) /* 2 */ | ((env->lsu & (DMMU_E | IMMU_E)) >> 2) /* 1, 0 */ | ((env->tl & 0xff) << 8) | (env->dmmu.mmu_primary_context << 16); /* 16... */ + if (env->pstate & PS_AM) { + *flags |= TB_FLAG_AM_ENABLED; + } + if ((env->def->features & CPU_FEATURE_FLOAT) && (env->pstate & PS_PEF) + && (env->fprs & FPRS_FEF)) { + *flags |= TB_FLAG_FPU_ENABLED; + } #else // FPU enable . Supervisor - *flags = (env->psref << 4) | env->psrs; + *flags = env->psrs; + if ((env->def->features & CPU_FEATURE_FLOAT) && env->psref) { + *flags |= TB_FLAG_FPU_ENABLED; + } +#endif +} + +static inline bool tb_fpu_enabled(int tb_flags) +{ +#if defined(CONFIG_USER_ONLY) + return true; +#else + return tb_flags & TB_FLAG_FPU_ENABLED; +#endif +} + +static inline bool tb_am_enabled(int tb_flags) +{ +#ifndef TARGET_SPARC64 + return false; +#else + return tb_flags & TB_FLAG_AM_ENABLED; #endif } +/* helper.c */ +void do_interrupt(CPUState *env); + +static inline bool cpu_has_work(CPUState *env1) +{ + return (env1->interrupt_request & CPU_INTERRUPT_HARD) && + cpu_interrupts_enabled(env1); +} + +#include "exec-all.h" + +static inline void cpu_pc_from_tb(CPUState *env, TranslationBlock *tb) +{ + env->pc = tb->pc; + env->npc = tb->cs_base; +} + #endif diff --git a/target-sparc/exec.h b/target-sparc/exec.h index f5c221e48c..2395b0092f 100644 --- a/target-sparc/exec.h +++ b/target-sparc/exec.h @@ -12,20 +12,4 @@ register struct CPUSPARCState *env asm(AREG0); #include "softmmu_exec.h" #endif /* !defined(CONFIG_USER_ONLY) */ -/* op_helper.c */ -void do_interrupt(CPUState *env); - -static inline int cpu_has_work(CPUState *env1) -{ - return (env1->interrupt_request & CPU_INTERRUPT_HARD) && - cpu_interrupts_enabled(env1); -} - - -static inline void cpu_pc_from_tb(CPUState *env, TranslationBlock *tb) -{ - env->pc = tb->pc; - env->npc = tb->cs_base; -} - #endif diff --git a/target-sparc/helper.c b/target-sparc/helper.c index e9b42d03a9..7eea1acbd5 100644 --- a/target-sparc/helper.c +++ b/target-sparc/helper.c @@ -23,7 +23,6 @@ #include <inttypes.h> #include "cpu.h" -#include "exec-all.h" #include "qemu-common.h" //#define DEBUG_MMU @@ -729,6 +728,248 @@ target_phys_addr_t cpu_get_phys_page_debug(CPUState *env, target_ulong addr) } #endif +#ifdef TARGET_SPARC64 +#ifdef DEBUG_PCALL +static const char * const excp_names[0x80] = { + [TT_TFAULT] = "Instruction Access Fault", + [TT_TMISS] = "Instruction Access MMU Miss", + [TT_CODE_ACCESS] = "Instruction Access Error", + [TT_ILL_INSN] = "Illegal Instruction", + [TT_PRIV_INSN] = "Privileged Instruction", + [TT_NFPU_INSN] = "FPU Disabled", + [TT_FP_EXCP] = "FPU Exception", + [TT_TOVF] = "Tag Overflow", + [TT_CLRWIN] = "Clean Windows", + [TT_DIV_ZERO] = "Division By Zero", + [TT_DFAULT] = "Data Access Fault", + [TT_DMISS] = "Data Access MMU Miss", + [TT_DATA_ACCESS] = "Data Access Error", + [TT_DPROT] = "Data Protection Error", + [TT_UNALIGNED] = "Unaligned Memory Access", + [TT_PRIV_ACT] = "Privileged Action", + [TT_EXTINT | 0x1] = "External Interrupt 1", + [TT_EXTINT | 0x2] = "External Interrupt 2", + [TT_EXTINT | 0x3] = "External Interrupt 3", + [TT_EXTINT | 0x4] = "External Interrupt 4", + [TT_EXTINT | 0x5] = "External Interrupt 5", + [TT_EXTINT | 0x6] = "External Interrupt 6", + [TT_EXTINT | 0x7] = "External Interrupt 7", + [TT_EXTINT | 0x8] = "External Interrupt 8", + [TT_EXTINT | 0x9] = "External Interrupt 9", + [TT_EXTINT | 0xa] = "External Interrupt 10", + [TT_EXTINT | 0xb] = "External Interrupt 11", + [TT_EXTINT | 0xc] = "External Interrupt 12", + [TT_EXTINT | 0xd] = "External Interrupt 13", + [TT_EXTINT | 0xe] = "External Interrupt 14", + [TT_EXTINT | 0xf] = "External Interrupt 15", +}; +#endif + +void do_interrupt(CPUState *env) +{ + int intno = env->exception_index; + trap_state *tsptr; + +#ifdef DEBUG_PCALL + if (qemu_loglevel_mask(CPU_LOG_INT)) { + static int count; + const char *name; + + if (intno < 0 || intno >= 0x180) { + name = "Unknown"; + } else if (intno >= 0x100) { + name = "Trap Instruction"; + } else if (intno >= 0xc0) { + name = "Window Fill"; + } else if (intno >= 0x80) { + name = "Window Spill"; + } else { + name = excp_names[intno]; + if (!name) { + name = "Unknown"; + } + } + + qemu_log("%6d: %s (v=%04x) pc=%016" PRIx64 " npc=%016" PRIx64 + " SP=%016" PRIx64 "\n", + count, name, intno, + env->pc, + env->npc, env->regwptr[6]); + log_cpu_state(env, 0); +#if 0 + { + int i; + uint8_t *ptr; + + qemu_log(" code="); + ptr = (uint8_t *)env->pc; + for (i = 0; i < 16; i++) { + qemu_log(" %02x", ldub(ptr + i)); + } + qemu_log("\n"); + } +#endif + count++; + } +#endif +#if !defined(CONFIG_USER_ONLY) + if (env->tl >= env->maxtl) { + cpu_abort(env, "Trap 0x%04x while trap level (%d) >= MAXTL (%d)," + " Error state", env->exception_index, env->tl, env->maxtl); + return; + } +#endif + if (env->tl < env->maxtl - 1) { + env->tl++; + } else { + env->pstate |= PS_RED; + if (env->tl < env->maxtl) { + env->tl++; + } + } + tsptr = cpu_tsptr(env); + + tsptr->tstate = (cpu_get_ccr(env) << 32) | + ((env->asi & 0xff) << 24) | ((env->pstate & 0xf3f) << 8) | + cpu_get_cwp64(env); + tsptr->tpc = env->pc; + tsptr->tnpc = env->npc; + tsptr->tt = intno; + + switch (intno) { + case TT_IVEC: + cpu_change_pstate(env, PS_PEF | PS_PRIV | PS_IG); + break; + case TT_TFAULT: + case TT_DFAULT: + case TT_TMISS ... TT_TMISS + 3: + case TT_DMISS ... TT_DMISS + 3: + case TT_DPROT ... TT_DPROT + 3: + cpu_change_pstate(env, PS_PEF | PS_PRIV | PS_MG); + break; + default: + cpu_change_pstate(env, PS_PEF | PS_PRIV | PS_AG); + break; + } + + if (intno == TT_CLRWIN) { + cpu_set_cwp(env, cpu_cwp_dec(env, env->cwp - 1)); + } else if ((intno & 0x1c0) == TT_SPILL) { + cpu_set_cwp(env, cpu_cwp_dec(env, env->cwp - env->cansave - 2)); + } else if ((intno & 0x1c0) == TT_FILL) { + cpu_set_cwp(env, cpu_cwp_inc(env, env->cwp + 1)); + } + env->tbr &= ~0x7fffULL; + env->tbr |= ((env->tl > 1) ? 1 << 14 : 0) | (intno << 5); + env->pc = env->tbr; + env->npc = env->pc + 4; + env->exception_index = -1; +} +#else +#ifdef DEBUG_PCALL +static const char * const excp_names[0x80] = { + [TT_TFAULT] = "Instruction Access Fault", + [TT_ILL_INSN] = "Illegal Instruction", + [TT_PRIV_INSN] = "Privileged Instruction", + [TT_NFPU_INSN] = "FPU Disabled", + [TT_WIN_OVF] = "Window Overflow", + [TT_WIN_UNF] = "Window Underflow", + [TT_UNALIGNED] = "Unaligned Memory Access", + [TT_FP_EXCP] = "FPU Exception", + [TT_DFAULT] = "Data Access Fault", + [TT_TOVF] = "Tag Overflow", + [TT_EXTINT | 0x1] = "External Interrupt 1", + [TT_EXTINT | 0x2] = "External Interrupt 2", + [TT_EXTINT | 0x3] = "External Interrupt 3", + [TT_EXTINT | 0x4] = "External Interrupt 4", + [TT_EXTINT | 0x5] = "External Interrupt 5", + [TT_EXTINT | 0x6] = "External Interrupt 6", + [TT_EXTINT | 0x7] = "External Interrupt 7", + [TT_EXTINT | 0x8] = "External Interrupt 8", + [TT_EXTINT | 0x9] = "External Interrupt 9", + [TT_EXTINT | 0xa] = "External Interrupt 10", + [TT_EXTINT | 0xb] = "External Interrupt 11", + [TT_EXTINT | 0xc] = "External Interrupt 12", + [TT_EXTINT | 0xd] = "External Interrupt 13", + [TT_EXTINT | 0xe] = "External Interrupt 14", + [TT_EXTINT | 0xf] = "External Interrupt 15", + [TT_TOVF] = "Tag Overflow", + [TT_CODE_ACCESS] = "Instruction Access Error", + [TT_DATA_ACCESS] = "Data Access Error", + [TT_DIV_ZERO] = "Division By Zero", + [TT_NCP_INSN] = "Coprocessor Disabled", +}; +#endif + +void do_interrupt(CPUState *env) +{ + int cwp, intno = env->exception_index; + +#ifdef DEBUG_PCALL + if (qemu_loglevel_mask(CPU_LOG_INT)) { + static int count; + const char *name; + + if (intno < 0 || intno >= 0x100) { + name = "Unknown"; + } else if (intno >= 0x80) { + name = "Trap Instruction"; + } else { + name = excp_names[intno]; + if (!name) { + name = "Unknown"; + } + } + + qemu_log("%6d: %s (v=%02x) pc=%08x npc=%08x SP=%08x\n", + count, name, intno, + env->pc, + env->npc, env->regwptr[6]); + log_cpu_state(env, 0); +#if 0 + { + int i; + uint8_t *ptr; + + qemu_log(" code="); + ptr = (uint8_t *)env->pc; + for (i = 0; i < 16; i++) { + qemu_log(" %02x", ldub(ptr + i)); + } + qemu_log("\n"); + } +#endif + count++; + } +#endif +#if !defined(CONFIG_USER_ONLY) + if (env->psret == 0) { + cpu_abort(env, "Trap 0x%02x while interrupts disabled, Error state", + env->exception_index); + return; + } +#endif + env->psret = 0; + cwp = cpu_cwp_dec(env, env->cwp - 1); + cpu_set_cwp(env, cwp); + env->regwptr[9] = env->pc; + env->regwptr[10] = env->npc; + env->psrps = env->psrs; + env->psrs = 1; + env->tbr = (env->tbr & TBR_BASE_MASK) | (intno << 4); + env->pc = env->tbr; + env->npc = env->pc + 4; + env->exception_index = -1; + +#if !defined(CONFIG_USER_ONLY) + /* IRQ acknowledgment */ + if ((intno & ~15) == TT_EXTINT && env->qemu_irq_ack != NULL) { + env->qemu_irq_ack(env->irq_manager, intno); + } +#endif +} +#endif + void cpu_reset(CPUSPARCState *env) { if (qemu_loglevel_mask(CPU_LOG_RESET)) { diff --git a/target-sparc/machine.c b/target-sparc/machine.c index 752e431778..56ae0412cd 100644 --- a/target-sparc/machine.c +++ b/target-sparc/machine.c @@ -2,7 +2,7 @@ #include "hw/boards.h" #include "qemu-timer.h" -#include "exec-all.h" +#include "cpu.h" void cpu_save(QEMUFile *f, void *opaque) { @@ -45,6 +45,19 @@ void cpu_save(QEMUFile *f, void *opaque) /* MMU */ for (i = 0; i < 32; i++) qemu_put_be32s(f, &env->mmuregs[i]); + for (i = 0; i < 4; i++) { + qemu_put_be64s(f, &env->mxccdata[i]); + } + for (i = 0; i < 8; i++) { + qemu_put_be64s(f, &env->mxccregs[i]); + } + qemu_put_be32s(f, &env->mmubpctrv); + qemu_put_be32s(f, &env->mmubpctrc); + qemu_put_be32s(f, &env->mmubpctrs); + qemu_put_be64s(f, &env->mmubpaction); + for (i = 0; i < 4; i++) { + qemu_put_be64s(f, &env->mmubpregs[i]); + } #else qemu_put_be64s(f, &env->lsu); for (i = 0; i < 16; i++) { @@ -141,6 +154,19 @@ int cpu_load(QEMUFile *f, void *opaque, int version_id) /* MMU */ for (i = 0; i < 32; i++) qemu_get_be32s(f, &env->mmuregs[i]); + for (i = 0; i < 4; i++) { + qemu_get_be64s(f, &env->mxccdata[i]); + } + for (i = 0; i < 8; i++) { + qemu_get_be64s(f, &env->mxccregs[i]); + } + qemu_get_be32s(f, &env->mmubpctrv); + qemu_get_be32s(f, &env->mmubpctrc); + qemu_get_be32s(f, &env->mmubpctrs); + qemu_get_be64s(f, &env->mmubpaction); + for (i = 0; i < 4; i++) { + qemu_get_be64s(f, &env->mmubpregs[i]); + } #else qemu_get_be64s(f, &env->lsu); for (i = 0; i < 16; i++) { diff --git a/target-sparc/op_helper.c b/target-sparc/op_helper.c index b38691e19d..15af27ba1f 100644 --- a/target-sparc/op_helper.c +++ b/target-sparc/op_helper.c @@ -316,7 +316,7 @@ static inline target_ulong asi_address_mask(CPUState *env1, static void raise_exception(int tt) { env->exception_index = tt; - cpu_loop_exit(); + cpu_loop_exit(env); } void HELPER(raise_exception)(int tt) @@ -1940,7 +1940,6 @@ uint64_t helper_ld_asi(target_ulong addr, int asi, int size, int sign) case 0x31: // Turbosparc RAM snoop case 0x32: // Turbosparc page table descriptor diagnostic case 0x39: /* data cache diagnostic register */ - case 0x4c: /* SuperSPARC MMU Breakpoint Action register */ ret = 0; break; case 0x38: /* SuperSPARC MMU Breakpoint Control Registers */ @@ -1966,6 +1965,18 @@ uint64_t helper_ld_asi(target_ulong addr, int asi, int size, int sign) ret); } break; + case 0x49: /* SuperSPARC MMU Counter Breakpoint Value */ + ret = env->mmubpctrv; + break; + case 0x4a: /* SuperSPARC MMU Counter Breakpoint Control */ + ret = env->mmubpctrc; + break; + case 0x4b: /* SuperSPARC MMU Counter Breakpoint Status */ + ret = env->mmubpctrs; + break; + case 0x4c: /* SuperSPARC MMU Breakpoint Action */ + ret = env->mmubpaction; + break; case 8: /* User code access, XXX */ default: do_unassigned_access(addr, 0, 0, asi, size); @@ -2304,7 +2315,6 @@ void helper_st_asi(target_ulong addr, uint64_t val, int asi, int size) // descriptor diagnostic case 0x36: /* I-cache flash clear */ case 0x37: /* D-cache flash clear */ - case 0x4c: /* breakpoint action */ break; case 0x38: /* SuperSPARC MMU Breakpoint Control Registers*/ { @@ -2328,6 +2338,18 @@ void helper_st_asi(target_ulong addr, uint64_t val, int asi, int size) env->mmuregs[reg]); } break; + case 0x49: /* SuperSPARC MMU Counter Breakpoint Value */ + env->mmubpctrv = val & 0xffffffff; + break; + case 0x4a: /* SuperSPARC MMU Counter Breakpoint Control */ + env->mmubpctrc = val & 0x3; + break; + case 0x4b: /* SuperSPARC MMU Counter Breakpoint Status */ + env->mmubpctrs = val & 0x3; + break; + case 0x4c: /* SuperSPARC MMU Breakpoint Action */ + env->mmubpaction = val & 0x1fff; + break; case 8: /* User code access, XXX */ case 9: /* Supervisor code access, XXX */ default: @@ -3309,16 +3331,16 @@ void helper_ldda_asi(target_ulong addr, int asi, int rd) void helper_ldf_asi(target_ulong addr, int asi, int size, int rd) { unsigned int i; - target_ulong val; + CPU_DoubleU u; helper_check_align(addr, 3); addr = asi_address_mask(env, asi, addr); switch (asi) { - case 0xf0: // Block load primary - case 0xf1: // Block load secondary - case 0xf8: // Block load primary LE - case 0xf9: // Block load secondary LE + case 0xf0: /* UA2007/JPS1 Block load primary */ + case 0xf1: /* UA2007/JPS1 Block load secondary */ + case 0xf8: /* UA2007/JPS1 Block load primary LE */ + case 0xf9: /* UA2007/JPS1 Block load secondary LE */ if (rd & 7) { raise_exception(TT_ILL_INSN); return; @@ -3331,15 +3353,21 @@ void helper_ldf_asi(target_ulong addr, int asi, int size, int rd) } return; - case 0x70: // Block load primary, user privilege - case 0x71: // Block load secondary, user privilege + case 0x16: /* UA2007 Block load primary, user privilege */ + case 0x17: /* UA2007 Block load secondary, user privilege */ + case 0x1e: /* UA2007 Block load primary LE, user privilege */ + case 0x1f: /* UA2007 Block load secondary LE, user privilege */ + case 0x70: /* JPS1 Block load primary, user privilege */ + case 0x71: /* JPS1 Block load secondary, user privilege */ + case 0x78: /* JPS1 Block load primary LE, user privilege */ + case 0x79: /* JPS1 Block load secondary LE, user privilege */ if (rd & 7) { raise_exception(TT_ILL_INSN); return; } helper_check_align(addr, 0x3f); for (i = 0; i < 16; i++) { - *(uint32_t *)&env->fpr[rd++] = helper_ld_asi(addr, asi & 0x1f, 4, + *(uint32_t *)&env->fpr[rd++] = helper_ld_asi(addr, asi & 0x19, 4, 0); addr += 4; } @@ -3349,17 +3377,23 @@ void helper_ldf_asi(target_ulong addr, int asi, int size, int rd) break; } - val = helper_ld_asi(addr, asi, size, 0); switch(size) { default: case 4: - *((uint32_t *)&env->fpr[rd]) = val; + *((uint32_t *)&env->fpr[rd]) = helper_ld_asi(addr, asi, size, 0); break; case 8: - *((int64_t *)&DT0) = val; + u.ll = helper_ld_asi(addr, asi, size, 0); + *((uint32_t *)&env->fpr[rd++]) = u.l.upper; + *((uint32_t *)&env->fpr[rd++]) = u.l.lower; break; case 16: - // XXX + u.ll = helper_ld_asi(addr, asi, 8, 0); + *((uint32_t *)&env->fpr[rd++]) = u.l.upper; + *((uint32_t *)&env->fpr[rd++]) = u.l.lower; + u.ll = helper_ld_asi(addr + 8, asi, 8, 0); + *((uint32_t *)&env->fpr[rd++]) = u.l.upper; + *((uint32_t *)&env->fpr[rd++]) = u.l.lower; break; } } @@ -3368,17 +3402,18 @@ void helper_stf_asi(target_ulong addr, int asi, int size, int rd) { unsigned int i; target_ulong val = 0; + CPU_DoubleU u; helper_check_align(addr, 3); addr = asi_address_mask(env, asi, addr); switch (asi) { - case 0xe0: // UA2007 Block commit store primary (cache flush) - case 0xe1: // UA2007 Block commit store secondary (cache flush) - case 0xf0: // Block store primary - case 0xf1: // Block store secondary - case 0xf8: // Block store primary LE - case 0xf9: // Block store secondary LE + case 0xe0: /* UA2007/JPS1 Block commit store primary (cache flush) */ + case 0xe1: /* UA2007/JPS1 Block commit store secondary (cache flush) */ + case 0xf0: /* UA2007/JPS1 Block store primary */ + case 0xf1: /* UA2007/JPS1 Block store secondary */ + case 0xf8: /* UA2007/JPS1 Block store primary LE */ + case 0xf9: /* UA2007/JPS1 Block store secondary LE */ if (rd & 7) { raise_exception(TT_ILL_INSN); return; @@ -3391,8 +3426,14 @@ void helper_stf_asi(target_ulong addr, int asi, int size, int rd) } return; - case 0x70: // Block store primary, user privilege - case 0x71: // Block store secondary, user privilege + case 0x16: /* UA2007 Block load primary, user privilege */ + case 0x17: /* UA2007 Block load secondary, user privilege */ + case 0x1e: /* UA2007 Block load primary LE, user privilege */ + case 0x1f: /* UA2007 Block load secondary LE, user privilege */ + case 0x70: /* JPS1 Block store primary, user privilege */ + case 0x71: /* JPS1 Block store secondary, user privilege */ + case 0x78: /* JPS1 Block load primary LE, user privilege */ + case 0x79: /* JPS1 Block load secondary LE, user privilege */ if (rd & 7) { raise_exception(TT_ILL_INSN); return; @@ -3400,7 +3441,7 @@ void helper_stf_asi(target_ulong addr, int asi, int size, int rd) helper_check_align(addr, 0x3f); for (i = 0; i < 16; i++) { val = *(uint32_t *)&env->fpr[rd++]; - helper_st_asi(addr, val, asi & 0x1f, 4); + helper_st_asi(addr, val, asi & 0x19, 4); addr += 4; } @@ -3412,16 +3453,22 @@ void helper_stf_asi(target_ulong addr, int asi, int size, int rd) switch(size) { default: case 4: - val = *((uint32_t *)&env->fpr[rd]); + helper_st_asi(addr, *(uint32_t *)&env->fpr[rd], asi, size); break; case 8: - val = *((int64_t *)&DT0); + u.l.upper = *(uint32_t *)&env->fpr[rd++]; + u.l.lower = *(uint32_t *)&env->fpr[rd++]; + helper_st_asi(addr, u.ll, asi, size); break; case 16: - // XXX + u.l.upper = *(uint32_t *)&env->fpr[rd++]; + u.l.lower = *(uint32_t *)&env->fpr[rd++]; + helper_st_asi(addr, u.ll, asi, 8); + u.l.upper = *(uint32_t *)&env->fpr[rd++]; + u.l.lower = *(uint32_t *)&env->fpr[rd++]; + helper_st_asi(addr + 8, u.ll, asi, 8); break; } - helper_st_asi(addr, val, asi, size); } target_ulong helper_cas_asi(target_ulong addr, target_ulong val1, @@ -3702,7 +3749,7 @@ void helper_ldxfsr(uint64_t new_fsr) void helper_debug(void) { env->exception_index = EXCP_DEBUG; - cpu_loop_exit(); + cpu_loop_exit(env); } #ifndef TARGET_SPARC64 @@ -4007,6 +4054,16 @@ void helper_wrpstate(target_ulong new_state) #endif } +void cpu_change_pstate(CPUState *env1, uint32_t new_pstate) +{ + CPUState *saved_env; + + saved_env = env; + env = env1; + change_pstate(new_pstate); + env = saved_env; +} + void helper_wrpil(target_ulong new_pil) { #if !defined(CONFIG_USER_ONLY) @@ -4093,247 +4150,10 @@ void helper_write_softint(uint64_t value) #endif #ifdef TARGET_SPARC64 -#ifdef DEBUG_PCALL -static const char * const excp_names[0x80] = { - [TT_TFAULT] = "Instruction Access Fault", - [TT_TMISS] = "Instruction Access MMU Miss", - [TT_CODE_ACCESS] = "Instruction Access Error", - [TT_ILL_INSN] = "Illegal Instruction", - [TT_PRIV_INSN] = "Privileged Instruction", - [TT_NFPU_INSN] = "FPU Disabled", - [TT_FP_EXCP] = "FPU Exception", - [TT_TOVF] = "Tag Overflow", - [TT_CLRWIN] = "Clean Windows", - [TT_DIV_ZERO] = "Division By Zero", - [TT_DFAULT] = "Data Access Fault", - [TT_DMISS] = "Data Access MMU Miss", - [TT_DATA_ACCESS] = "Data Access Error", - [TT_DPROT] = "Data Protection Error", - [TT_UNALIGNED] = "Unaligned Memory Access", - [TT_PRIV_ACT] = "Privileged Action", - [TT_EXTINT | 0x1] = "External Interrupt 1", - [TT_EXTINT | 0x2] = "External Interrupt 2", - [TT_EXTINT | 0x3] = "External Interrupt 3", - [TT_EXTINT | 0x4] = "External Interrupt 4", - [TT_EXTINT | 0x5] = "External Interrupt 5", - [TT_EXTINT | 0x6] = "External Interrupt 6", - [TT_EXTINT | 0x7] = "External Interrupt 7", - [TT_EXTINT | 0x8] = "External Interrupt 8", - [TT_EXTINT | 0x9] = "External Interrupt 9", - [TT_EXTINT | 0xa] = "External Interrupt 10", - [TT_EXTINT | 0xb] = "External Interrupt 11", - [TT_EXTINT | 0xc] = "External Interrupt 12", - [TT_EXTINT | 0xd] = "External Interrupt 13", - [TT_EXTINT | 0xe] = "External Interrupt 14", - [TT_EXTINT | 0xf] = "External Interrupt 15", -}; -#endif - trap_state* cpu_tsptr(CPUState* env) { return &env->ts[env->tl & MAXTL_MASK]; } - -void do_interrupt(CPUState *env) -{ - int intno = env->exception_index; - trap_state* tsptr; - -#ifdef DEBUG_PCALL - if (qemu_loglevel_mask(CPU_LOG_INT)) { - static int count; - const char *name; - - if (intno < 0 || intno >= 0x180) - name = "Unknown"; - else if (intno >= 0x100) - name = "Trap Instruction"; - else if (intno >= 0xc0) - name = "Window Fill"; - else if (intno >= 0x80) - name = "Window Spill"; - else { - name = excp_names[intno]; - if (!name) - name = "Unknown"; - } - - qemu_log("%6d: %s (v=%04x) pc=%016" PRIx64 " npc=%016" PRIx64 - " SP=%016" PRIx64 "\n", - count, name, intno, - env->pc, - env->npc, env->regwptr[6]); - log_cpu_state(env, 0); -#if 0 - { - int i; - uint8_t *ptr; - - qemu_log(" code="); - ptr = (uint8_t *)env->pc; - for(i = 0; i < 16; i++) { - qemu_log(" %02x", ldub(ptr + i)); - } - qemu_log("\n"); - } -#endif - count++; - } -#endif -#if !defined(CONFIG_USER_ONLY) - if (env->tl >= env->maxtl) { - cpu_abort(env, "Trap 0x%04x while trap level (%d) >= MAXTL (%d)," - " Error state", env->exception_index, env->tl, env->maxtl); - return; - } -#endif - if (env->tl < env->maxtl - 1) { - env->tl++; - } else { - env->pstate |= PS_RED; - if (env->tl < env->maxtl) - env->tl++; - } - tsptr = cpu_tsptr(env); - - tsptr->tstate = (get_ccr() << 32) | - ((env->asi & 0xff) << 24) | ((env->pstate & 0xf3f) << 8) | - get_cwp64(); - tsptr->tpc = env->pc; - tsptr->tnpc = env->npc; - tsptr->tt = intno; - - switch (intno) { - case TT_IVEC: - change_pstate(PS_PEF | PS_PRIV | PS_IG); - break; - case TT_TFAULT: - case TT_DFAULT: - case TT_TMISS ... TT_TMISS + 3: - case TT_DMISS ... TT_DMISS + 3: - case TT_DPROT ... TT_DPROT + 3: - change_pstate(PS_PEF | PS_PRIV | PS_MG); - break; - default: - change_pstate(PS_PEF | PS_PRIV | PS_AG); - break; - } - - if (intno == TT_CLRWIN) { - set_cwp(cwp_dec(env->cwp - 1)); - } else if ((intno & 0x1c0) == TT_SPILL) { - set_cwp(cwp_dec(env->cwp - env->cansave - 2)); - } else if ((intno & 0x1c0) == TT_FILL) { - set_cwp(cwp_inc(env->cwp + 1)); - } - env->tbr &= ~0x7fffULL; - env->tbr |= ((env->tl > 1) ? 1 << 14 : 0) | (intno << 5); - env->pc = env->tbr; - env->npc = env->pc + 4; - env->exception_index = -1; -} -#else -#ifdef DEBUG_PCALL -static const char * const excp_names[0x80] = { - [TT_TFAULT] = "Instruction Access Fault", - [TT_ILL_INSN] = "Illegal Instruction", - [TT_PRIV_INSN] = "Privileged Instruction", - [TT_NFPU_INSN] = "FPU Disabled", - [TT_WIN_OVF] = "Window Overflow", - [TT_WIN_UNF] = "Window Underflow", - [TT_UNALIGNED] = "Unaligned Memory Access", - [TT_FP_EXCP] = "FPU Exception", - [TT_DFAULT] = "Data Access Fault", - [TT_TOVF] = "Tag Overflow", - [TT_EXTINT | 0x1] = "External Interrupt 1", - [TT_EXTINT | 0x2] = "External Interrupt 2", - [TT_EXTINT | 0x3] = "External Interrupt 3", - [TT_EXTINT | 0x4] = "External Interrupt 4", - [TT_EXTINT | 0x5] = "External Interrupt 5", - [TT_EXTINT | 0x6] = "External Interrupt 6", - [TT_EXTINT | 0x7] = "External Interrupt 7", - [TT_EXTINT | 0x8] = "External Interrupt 8", - [TT_EXTINT | 0x9] = "External Interrupt 9", - [TT_EXTINT | 0xa] = "External Interrupt 10", - [TT_EXTINT | 0xb] = "External Interrupt 11", - [TT_EXTINT | 0xc] = "External Interrupt 12", - [TT_EXTINT | 0xd] = "External Interrupt 13", - [TT_EXTINT | 0xe] = "External Interrupt 14", - [TT_EXTINT | 0xf] = "External Interrupt 15", - [TT_TOVF] = "Tag Overflow", - [TT_CODE_ACCESS] = "Instruction Access Error", - [TT_DATA_ACCESS] = "Data Access Error", - [TT_DIV_ZERO] = "Division By Zero", - [TT_NCP_INSN] = "Coprocessor Disabled", -}; -#endif - -void do_interrupt(CPUState *env) -{ - int cwp, intno = env->exception_index; - -#ifdef DEBUG_PCALL - if (qemu_loglevel_mask(CPU_LOG_INT)) { - static int count; - const char *name; - - if (intno < 0 || intno >= 0x100) - name = "Unknown"; - else if (intno >= 0x80) - name = "Trap Instruction"; - else { - name = excp_names[intno]; - if (!name) - name = "Unknown"; - } - - qemu_log("%6d: %s (v=%02x) pc=%08x npc=%08x SP=%08x\n", - count, name, intno, - env->pc, - env->npc, env->regwptr[6]); - log_cpu_state(env, 0); -#if 0 - { - int i; - uint8_t *ptr; - - qemu_log(" code="); - ptr = (uint8_t *)env->pc; - for(i = 0; i < 16; i++) { - qemu_log(" %02x", ldub(ptr + i)); - } - qemu_log("\n"); - } -#endif - count++; - } -#endif -#if !defined(CONFIG_USER_ONLY) - if (env->psret == 0) { - cpu_abort(env, "Trap 0x%02x while interrupts disabled, Error state", - env->exception_index); - return; - } -#endif - env->psret = 0; - cwp = cwp_dec(env->cwp - 1); - set_cwp(cwp); - env->regwptr[9] = env->pc; - env->regwptr[10] = env->npc; - env->psrps = env->psrs; - env->psrs = 1; - env->tbr = (env->tbr & TBR_BASE_MASK) | (intno << 4); - env->pc = env->tbr; - env->npc = env->pc + 4; - env->exception_index = -1; - -#if !defined(CONFIG_USER_ONLY) - /* IRQ acknowledgment */ - if ((intno & ~15) == TT_EXTINT && env->qemu_irq_ack != NULL) { - env->qemu_irq_ack(env->irq_manager, intno); - } -#endif -} #endif #if !defined(CONFIG_USER_ONLY) @@ -4402,7 +4222,7 @@ void tlb_fill(target_ulong addr, int is_write, int mmu_idx, void *retaddr) ret = cpu_sparc_handle_mmu_fault(env, addr, is_write, mmu_idx, 1); if (ret) { cpu_restore_state2(retaddr); - cpu_loop_exit(); + cpu_loop_exit(env); } env = saved_env; } diff --git a/target-sparc/translate.c b/target-sparc/translate.c index 0cc47e9ff3..27c2cf98e8 100644 --- a/target-sparc/translate.c +++ b/target-sparc/translate.c @@ -25,7 +25,6 @@ #include <inttypes.h> #include "cpu.h" -#include "exec-all.h" #include "disas.h" #include "helper.h" #include "tcg-op.h" @@ -728,19 +727,24 @@ static inline void gen_trap_ifdivzero_tl(TCGv divisor) static inline void gen_op_sdivx(TCGv dst, TCGv src1, TCGv src2) { int l1, l2; + TCGv r_temp1, r_temp2; l1 = gen_new_label(); l2 = gen_new_label(); - tcg_gen_mov_tl(cpu_cc_src, src1); - tcg_gen_mov_tl(cpu_cc_src2, src2); - gen_trap_ifdivzero_tl(cpu_cc_src2); - tcg_gen_brcondi_tl(TCG_COND_NE, cpu_cc_src, INT64_MIN, l1); - tcg_gen_brcondi_tl(TCG_COND_NE, cpu_cc_src2, -1, l1); + r_temp1 = tcg_temp_local_new(); + r_temp2 = tcg_temp_local_new(); + tcg_gen_mov_tl(r_temp1, src1); + tcg_gen_mov_tl(r_temp2, src2); + gen_trap_ifdivzero_tl(r_temp2); + tcg_gen_brcondi_tl(TCG_COND_NE, r_temp1, INT64_MIN, l1); + tcg_gen_brcondi_tl(TCG_COND_NE, r_temp2, -1, l1); tcg_gen_movi_i64(dst, INT64_MIN); tcg_gen_br(l2); gen_set_label(l1); - tcg_gen_div_i64(dst, cpu_cc_src, cpu_cc_src2); + tcg_gen_div_i64(dst, r_temp1, r_temp2); gen_set_label(l2); + tcg_temp_free(r_temp1); + tcg_temp_free(r_temp2); } #endif @@ -3174,10 +3178,17 @@ static void disas_sparc_insn(DisasContext * dc) break; #ifdef TARGET_SPARC64 case 0xd: /* V9 udivx */ - tcg_gen_mov_tl(cpu_cc_src, cpu_src1); - tcg_gen_mov_tl(cpu_cc_src2, cpu_src2); - gen_trap_ifdivzero_tl(cpu_cc_src2); - tcg_gen_divu_i64(cpu_dst, cpu_cc_src, cpu_cc_src2); + { + TCGv r_temp1, r_temp2; + r_temp1 = tcg_temp_local_new(); + r_temp2 = tcg_temp_local_new(); + tcg_gen_mov_tl(r_temp1, cpu_src1); + tcg_gen_mov_tl(r_temp2, cpu_src2); + gen_trap_ifdivzero_tl(r_temp2); + tcg_gen_divu_i64(cpu_dst, r_temp1, r_temp2); + tcg_temp_free(r_temp1); + tcg_temp_free(r_temp2); + } break; #endif case 0xe: /* udiv */ @@ -4473,10 +4484,16 @@ static void disas_sparc_insn(DisasContext * dc) case 0x2d: /* V9 prefetch, no effect */ goto skip_move; case 0x30: /* V9 ldfa */ + if (gen_trap_ifnofpu(dc, cpu_cond)) { + goto jmp_insn; + } save_state(dc, cpu_cond); gen_ldf_asi(cpu_addr, insn, 4, rd); goto skip_move; case 0x33: /* V9 lddfa */ + if (gen_trap_ifnofpu(dc, cpu_cond)) { + goto jmp_insn; + } save_state(dc, cpu_cond); gen_ldf_asi(cpu_addr, insn, 8, DFPREG(rd)); goto skip_move; @@ -4484,6 +4501,9 @@ static void disas_sparc_insn(DisasContext * dc) goto skip_move; case 0x32: /* V9 ldqfa */ CHECK_FPU_FEATURE(dc, FLOAT128); + if (gen_trap_ifnofpu(dc, cpu_cond)) { + goto jmp_insn; + } save_state(dc, cpu_cond); gen_ldf_asi(cpu_addr, insn, 16, QFPREG(rd)); goto skip_move; @@ -4712,6 +4732,9 @@ static void disas_sparc_insn(DisasContext * dc) switch (xop) { #ifdef TARGET_SPARC64 case 0x34: /* V9 stfa */ + if (gen_trap_ifnofpu(dc, cpu_cond)) { + goto jmp_insn; + } gen_stf_asi(cpu_addr, insn, 4, rd); break; case 0x36: /* V9 stqfa */ @@ -4719,15 +4742,19 @@ static void disas_sparc_insn(DisasContext * dc) TCGv_i32 r_const; CHECK_FPU_FEATURE(dc, FLOAT128); + if (gen_trap_ifnofpu(dc, cpu_cond)) { + goto jmp_insn; + } r_const = tcg_const_i32(7); gen_helper_check_align(cpu_addr, r_const); tcg_temp_free_i32(r_const); - gen_op_load_fpr_QT0(QFPREG(rd)); gen_stf_asi(cpu_addr, insn, 16, QFPREG(rd)); } break; case 0x37: /* V9 stdfa */ - gen_op_load_fpr_DT0(DFPREG(rd)); + if (gen_trap_ifnofpu(dc, cpu_cond)) { + goto jmp_insn; + } gen_stf_asi(cpu_addr, insn, 8, DFPREG(rd)); break; case 0x3c: /* V9 casa */ @@ -4852,13 +4879,8 @@ static inline void gen_intermediate_code_internal(TranslationBlock * tb, dc->cc_op = CC_OP_DYNAMIC; dc->mem_idx = cpu_mmu_index(env); dc->def = env->def; - if ((dc->def->features & CPU_FEATURE_FLOAT)) - dc->fpu_enabled = cpu_fpu_enabled(env); - else - dc->fpu_enabled = 0; -#ifdef TARGET_SPARC64 - dc->address_mask_32bit = env->pstate & PS_AM; -#endif + dc->fpu_enabled = tb_fpu_enabled(tb->flags); + dc->address_mask_32bit = tb_am_enabled(tb->flags); dc->singlestep = (env->singlestep_enabled || singlestep); gen_opc_end = gen_opc_buf + OPC_MAX_SIZE; diff --git a/target-unicore32/cpu.h b/target-unicore32/cpu.h index 1e10049f89..981760734f 100644 --- a/target-unicore32/cpu.h +++ b/target-unicore32/cpu.h @@ -179,4 +179,10 @@ void uc32_translate_init(void); void do_interrupt(CPUState *); void switch_mode(CPUState_UniCore32 *, int); +static inline bool cpu_has_work(CPUState *env) +{ + return env->interrupt_request & + (CPU_INTERRUPT_HARD | CPU_INTERRUPT_EXITTB); +} + #endif /* __CPU_UC32_H__ */ diff --git a/target-unicore32/exec.h b/target-unicore32/exec.h index 4ab55f42cf..7912105e32 100644 --- a/target-unicore32/exec.h +++ b/target-unicore32/exec.h @@ -16,7 +16,6 @@ register struct CPUState_UniCore32 *env asm(AREG0); #include "cpu.h" -#include "exec-all.h" static inline void env_to_regs(void) { @@ -26,12 +25,6 @@ static inline void regs_to_env(void) { } -static inline int cpu_has_work(CPUState *env) -{ - return env->interrupt_request & - (CPU_INTERRUPT_HARD | CPU_INTERRUPT_EXITTB); -} - static inline int cpu_halted(CPUState *env) { if (!env->halted) { diff --git a/target-unicore32/helper.c b/target-unicore32/helper.c index 483aeaeb14..02707d5857 100644 --- a/target-unicore32/helper.c +++ b/target-unicore32/helper.c @@ -10,7 +10,6 @@ #include <string.h> #include "cpu.h" -#include "exec-all.h" #include "gdbstub.h" #include "helper.h" #include "qemu-common.h" diff --git a/target-unicore32/op_helper.c b/target-unicore32/op_helper.c index 31e4b11e43..541e6f099d 100644 --- a/target-unicore32/op_helper.c +++ b/target-unicore32/op_helper.c @@ -16,7 +16,7 @@ void HELPER(exception)(uint32_t excp) { env->exception_index = excp; - cpu_loop_exit(); + cpu_loop_exit(env); } static target_ulong asr_read(void) diff --git a/target-unicore32/translate.c b/target-unicore32/translate.c index 98eaeb3d43..a15e42d663 100644 --- a/target-unicore32/translate.c +++ b/target-unicore32/translate.c @@ -14,7 +14,6 @@ #include <inttypes.h> #include "cpu.h" -#include "exec-all.h" #include "disas.h" #include "tcg-op.h" #include "qemu-log.h" diff --git a/tcg/README b/tcg/README index 660012281f..cfdfd96d09 100644 --- a/tcg/README +++ b/tcg/README @@ -504,7 +504,15 @@ register. - Don't hesitate to use helpers for complicated or seldom used target instructions. There is little performance advantage in using TCG to implement target instructions taking more than about twenty TCG - instructions. + instructions. Note that this rule of thumb is more applicable to + helpers doing complex logic or arithmetic, where the C compiler has + scope to do a good job of optimisation; it is less relevant where + the instruction is mostly doing loads and stores, and in those cases + inline TCG may still be faster for longer sequences. + +- The hard limit on the number of TCG instructions you can generate + per target instruction is set by MAX_OP_PER_INSTR in exec-all.h -- + you cannot exceed this without risking a buffer overrun. - Use the 'discard' instruction if you know that TCG won't be able to prove that a given global is "dead" at a given program point. The diff --git a/tcg/arm/tcg-target.c b/tcg/arm/tcg-target.c index fb858d8634..93eb0f1a45 100644 --- a/tcg/arm/tcg-target.c +++ b/tcg/arm/tcg-target.c @@ -1804,6 +1804,8 @@ static void tcg_target_init(TCGContext *s) tcg_regset_set_reg(s->reserved_regs, TCG_REG_PC); tcg_add_target_add_op_defs(arm_op_defs); + tcg_set_frame(s, TCG_AREG0, offsetof(CPUState, temp_buf), + CPU_TEMP_BUF_NLONGS * sizeof(long)); } static inline void tcg_out_ld(TCGContext *s, TCGType type, int arg, @@ -1846,15 +1848,18 @@ static inline void tcg_out_movi(TCGContext *s, TCGType type, static void tcg_target_qemu_prologue(TCGContext *s) { - /* There is no need to save r7, it is used to store the address - of the env structure and is not modified by GCC. */ + /* Calling convention requires us to save r4-r11 and lr; + * save also r12 to maintain stack 8-alignment. + */ + + /* stmdb sp!, { r4 - r12, lr } */ + tcg_out32(s, (COND_AL << 28) | 0x092d5ff0); - /* stmdb sp!, { r4 - r6, r8 - r11, lr } */ - tcg_out32(s, (COND_AL << 28) | 0x092d4f70); + tcg_out_mov(s, TCG_TYPE_PTR, TCG_AREG0, tcg_target_call_iarg_regs[0]); - tcg_out_bx(s, COND_AL, TCG_REG_R0); + tcg_out_bx(s, COND_AL, tcg_target_call_iarg_regs[1]); tb_ret_addr = s->code_ptr; - /* ldmia sp!, { r4 - r6, r8 - r11, pc } */ - tcg_out32(s, (COND_AL << 28) | 0x08bd8f70); + /* ldmia sp!, { r4 - r12, pc } */ + tcg_out32(s, (COND_AL << 28) | 0x08bd9ff0); } diff --git a/tcg/hppa/tcg-target.c b/tcg/hppa/tcg-target.c index 7f4653e342..222f33eb6d 100644 --- a/tcg/hppa/tcg-target.c +++ b/tcg/hppa/tcg-target.c @@ -467,6 +467,14 @@ static inline void tcg_out_dep(TCGContext *s, int ret, int arg, | INSN_SHDEP_CP(31 - ofs) | INSN_DEP_LEN(len)); } +static inline void tcg_out_depi(TCGContext *s, int ret, int arg, + unsigned ofs, unsigned len) +{ + assert(ofs < 32 && len <= 32 - ofs); + tcg_out32(s, INSN_DEPI | INSN_R2(ret) | INSN_IM5(arg) + | INSN_SHDEP_CP(31 - ofs) | INSN_DEP_LEN(len)); +} + static inline void tcg_out_shd(TCGContext *s, int ret, int hi, int lo, unsigned count) { @@ -499,8 +507,7 @@ static void tcg_out_ori(TCGContext *s, int ret, int arg, tcg_target_ulong m) assert(bs1 == 32 || (1ul << bs1) > m); tcg_out_mov(s, TCG_TYPE_I32, ret, arg); - tcg_out32(s, INSN_DEPI | INSN_R2(ret) | INSN_IM5(-1) - | INSN_SHDEP_CP(31 - bs0) | INSN_DEP_LEN(bs1 - bs0)); + tcg_out_depi(s, ret, -1, bs0, bs1 - bs0); } static void tcg_out_andi(TCGContext *s, int ret, int arg, tcg_target_ulong m) @@ -529,8 +536,7 @@ static void tcg_out_andi(TCGContext *s, int ret, int arg, tcg_target_ulong m) tcg_out_extr(s, ret, arg, 0, ls0, 0); } else { tcg_out_mov(s, TCG_TYPE_I32, ret, arg); - tcg_out32(s, INSN_DEPI | INSN_R2(ret) | INSN_IM5(0) - | INSN_SHDEP_CP(31 - ls0) | INSN_DEP_LEN(ls1 - ls0)); + tcg_out_depi(s, ret, 0, ls0, ls1 - ls0); } } @@ -646,14 +652,14 @@ static void tcg_out_xmpyu(TCGContext *s, int retl, int reth, int arg1, int arg2) { /* Store both words into the stack for copy to the FPU. */ - tcg_out_ldst(s, arg1, TCG_REG_SP, STACK_TEMP_OFS, INSN_STW); - tcg_out_ldst(s, arg2, TCG_REG_SP, STACK_TEMP_OFS + 4, INSN_STW); + tcg_out_ldst(s, arg1, TCG_REG_CALL_STACK, STACK_TEMP_OFS, INSN_STW); + tcg_out_ldst(s, arg2, TCG_REG_CALL_STACK, STACK_TEMP_OFS + 4, INSN_STW); /* Load both words into the FPU at the same time. We get away with this because we can address the left and right half of the FPU registers individually once loaded. */ /* fldds stack_temp(sp),fr22 */ - tcg_out32(s, INSN_FLDDS | INSN_R2(TCG_REG_SP) + tcg_out32(s, INSN_FLDDS | INSN_R2(TCG_REG_CALL_STACK) | INSN_IM5(STACK_TEMP_OFS) | INSN_T(22)); /* xmpyu fr22r,fr22,fr22 */ @@ -661,15 +667,16 @@ static void tcg_out_xmpyu(TCGContext *s, int retl, int reth, /* Store the 64-bit result back into the stack. */ /* fstds stack_temp(sp),fr22 */ - tcg_out32(s, INSN_FSTDS | INSN_R2(TCG_REG_SP) + tcg_out32(s, INSN_FSTDS | INSN_R2(TCG_REG_CALL_STACK) | INSN_IM5(STACK_TEMP_OFS) | INSN_T(22)); /* Load the pieces of the result that the caller requested. */ if (reth) { - tcg_out_ldst(s, reth, TCG_REG_SP, STACK_TEMP_OFS, INSN_LDW); + tcg_out_ldst(s, reth, TCG_REG_CALL_STACK, STACK_TEMP_OFS, INSN_LDW); } if (retl) { - tcg_out_ldst(s, retl, TCG_REG_SP, STACK_TEMP_OFS + 4, INSN_LDW); + tcg_out_ldst(s, retl, TCG_REG_CALL_STACK, STACK_TEMP_OFS + 4, + INSN_LDW); } } @@ -1198,7 +1205,7 @@ static void tcg_out_qemu_st(TCGContext *s, const TCGArg *args, int opc) } tcg_out_mov(s, TCG_TYPE_I32, TCG_REG_R23, datahi_reg); tcg_out_mov(s, TCG_TYPE_I32, TCG_REG_R24, datalo_reg); - tcg_out_st(s, TCG_TYPE_I32, argreg, TCG_REG_SP, + tcg_out_st(s, TCG_TYPE_I32, argreg, TCG_REG_CALL_STACK, TCG_TARGET_CALL_STACK_OFFSET - 4); break; default: @@ -1458,6 +1465,14 @@ static inline void tcg_out_op(TCGContext *s, TCGOpcode opc, const TCGArg *args, args[4], args[5], const_args[2], const_args[4]); break; + case INDEX_op_deposit_i32: + if (const_args[2]) { + tcg_out_depi(s, args[0], args[2], args[3], args[4]); + } else { + tcg_out_dep(s, args[0], args[2], args[3], args[4]); + } + break; + case INDEX_op_qemu_ld8u: tcg_out_qemu_ld(s, args, 0); break; @@ -1551,6 +1566,8 @@ static const TCGTargetOpDef hppa_op_defs[] = { { INDEX_op_add2_i32, { "r", "r", "rZ", "rZ", "rI", "rZ" } }, { INDEX_op_sub2_i32, { "r", "r", "rI", "rZ", "rK", "rZ" } }, + { INDEX_op_deposit_i32, { "r", "0", "rJ" } }, + #if TARGET_LONG_BITS == 32 { INDEX_op_qemu_ld8u, { "r", "L" } }, { INDEX_op_qemu_ld8s, { "r", "L" } }, @@ -1596,7 +1613,7 @@ static int tcg_target_callee_save_regs[] = { TCG_REG_R14, TCG_REG_R15, TCG_REG_R16, - /* R17 is the global env, so no need to save. */ + TCG_REG_R17, /* R17 is the global env. */ TCG_REG_R18 }; @@ -1611,23 +1628,30 @@ static void tcg_target_qemu_prologue(TCGContext *s) /* Allocate space for the saved registers. */ frame_size += ARRAY_SIZE(tcg_target_callee_save_regs) * 4; + /* Allocate space for the TCG temps. */ + frame_size += CPU_TEMP_BUF_NLONGS * sizeof(long); + /* Align the allocated space. */ frame_size = ((frame_size + TCG_TARGET_STACK_ALIGN - 1) & -TCG_TARGET_STACK_ALIGN); /* The return address is stored in the caller's frame. */ - tcg_out_st(s, TCG_TYPE_PTR, TCG_REG_RP, TCG_REG_SP, -20); + tcg_out_st(s, TCG_TYPE_PTR, TCG_REG_RP, TCG_REG_CALL_STACK, -20); /* Allocate stack frame, saving the first register at the same time. */ tcg_out_ldst(s, tcg_target_callee_save_regs[0], - TCG_REG_SP, frame_size, INSN_STWM); + TCG_REG_CALL_STACK, frame_size, INSN_STWM); /* Save all callee saved registers. */ for (i = 1; i < ARRAY_SIZE(tcg_target_callee_save_regs); i++) { tcg_out_st(s, TCG_TYPE_PTR, tcg_target_callee_save_regs[i], - TCG_REG_SP, -frame_size + i * 4); + TCG_REG_CALL_STACK, -frame_size + i * 4); } + /* Record the location of the TCG temps. */ + tcg_set_frame(s, TCG_REG_CALL_STACK, -frame_size + i * 4, + TCG_TEMP_BUF_NLONGS * sizeof(long)); + #ifdef CONFIG_USE_GUEST_BASE if (GUEST_BASE != 0) { tcg_out_movi(s, TCG_TYPE_PTR, TCG_GUEST_BASE_REG, GUEST_BASE); @@ -1635,21 +1659,24 @@ static void tcg_target_qemu_prologue(TCGContext *s) } #endif + tcg_out_mov(s, TCG_TYPE_PTR, TCG_AREG0, tcg_target_call_iarg_regs[0]); + /* Jump to TB, and adjust R18 to be the return address. */ - tcg_out32(s, INSN_BLE_SR4 | INSN_R2(TCG_REG_R26)); + tcg_out32(s, INSN_BLE_SR4 | INSN_R2(tcg_target_call_iarg_regs[1])); tcg_out_mov(s, TCG_TYPE_I32, TCG_REG_R18, TCG_REG_R31); /* Restore callee saved registers. */ - tcg_out_ld(s, TCG_TYPE_PTR, TCG_REG_RP, TCG_REG_SP, -frame_size - 20); + tcg_out_ld(s, TCG_TYPE_PTR, TCG_REG_RP, TCG_REG_CALL_STACK, + -frame_size - 20); for (i = 1; i < ARRAY_SIZE(tcg_target_callee_save_regs); i++) { tcg_out_ld(s, TCG_TYPE_PTR, tcg_target_callee_save_regs[i], - TCG_REG_SP, -frame_size + i * 4); + TCG_REG_CALL_STACK, -frame_size + i * 4); } /* Deallocate stack frame and return. */ tcg_out32(s, INSN_BV | INSN_R2(TCG_REG_RP)); tcg_out_ldst(s, tcg_target_callee_save_regs[0], - TCG_REG_SP, -frame_size, INSN_LDWM); + TCG_REG_CALL_STACK, -frame_size, INSN_LDWM); } static void tcg_target_init(TCGContext *s) @@ -1676,7 +1703,7 @@ static void tcg_target_init(TCGContext *s) tcg_regset_set_reg(s->reserved_regs, TCG_REG_R19); /* clobbered w/o pic */ tcg_regset_set_reg(s->reserved_regs, TCG_REG_R20); /* reserved */ tcg_regset_set_reg(s->reserved_regs, TCG_REG_DP); /* data pointer */ - tcg_regset_set_reg(s->reserved_regs, TCG_REG_SP); /* stack pointer */ + tcg_regset_set_reg(s->reserved_regs, TCG_REG_CALL_STACK); /* stack pointer */ tcg_regset_set_reg(s->reserved_regs, TCG_REG_R31); /* ble link reg */ tcg_add_target_add_op_defs(hppa_op_defs); diff --git a/tcg/hppa/tcg-target.h b/tcg/hppa/tcg-target.h index a5cc440d49..f7919ceef7 100644 --- a/tcg/hppa/tcg-target.h +++ b/tcg/hppa/tcg-target.h @@ -94,6 +94,7 @@ enum { #define TCG_TARGET_HAS_not_i32 #define TCG_TARGET_HAS_andc_i32 // #define TCG_TARGET_HAS_orc_i32 +#define TCG_TARGET_HAS_deposit_i32 /* optional instructions automatically implemented */ #undef TCG_TARGET_HAS_neg_i32 /* sub rd, 0, rs */ diff --git a/tcg/i386/tcg-target.c b/tcg/i386/tcg-target.c index bb19a950bf..7529677fe2 100644 --- a/tcg/i386/tcg-target.c +++ b/tcg/i386/tcg-target.c @@ -1398,7 +1398,7 @@ static void tcg_out_qemu_st(TCGContext *s, const TCGArg *args, /* Pop and discard. This is 2 bytes smaller than the add. */ tcg_out_pop(s, TCG_REG_ECX); } else if (stack_adjust != 0) { - tcg_out_addi(s, TCG_REG_ESP, stack_adjust); + tcg_out_addi(s, TCG_REG_CALL_STACK, stack_adjust); } /* label2: */ @@ -1901,10 +1901,10 @@ static int tcg_target_callee_save_regs[] = { TCG_REG_RBX, TCG_REG_R12, TCG_REG_R13, - /* TCG_REG_R14, */ /* Currently used for the global env. */ + TCG_REG_R14, /* Currently used for the global env. */ TCG_REG_R15, #else - /* TCG_REG_EBP, */ /* Currently used for the global env. */ + TCG_REG_EBP, /* Currently used for the global env. */ TCG_REG_EBX, TCG_REG_ESI, TCG_REG_EDI, @@ -1918,28 +1918,34 @@ static void tcg_target_qemu_prologue(TCGContext *s) /* TB prologue */ - /* Save all callee saved registers. */ - for (i = 0; i < ARRAY_SIZE(tcg_target_callee_save_regs); i++) { - tcg_out_push(s, tcg_target_callee_save_regs[i]); - } - - /* Reserve some stack space. */ + /* Reserve some stack space, also for TCG temps. */ push_size = 1 + ARRAY_SIZE(tcg_target_callee_save_regs); push_size *= TCG_TARGET_REG_BITS / 8; - frame_size = push_size + TCG_STATIC_CALL_ARGS_SIZE; + frame_size = push_size + TCG_STATIC_CALL_ARGS_SIZE + + CPU_TEMP_BUF_NLONGS * sizeof(long); frame_size = (frame_size + TCG_TARGET_STACK_ALIGN - 1) & ~(TCG_TARGET_STACK_ALIGN - 1); stack_addend = frame_size - push_size; + tcg_set_frame(s, TCG_REG_CALL_STACK, TCG_STATIC_CALL_ARGS_SIZE, + CPU_TEMP_BUF_NLONGS * sizeof(long)); + + /* Save all callee saved registers. */ + for (i = 0; i < ARRAY_SIZE(tcg_target_callee_save_regs); i++) { + tcg_out_push(s, tcg_target_callee_save_regs[i]); + } + tcg_out_addi(s, TCG_REG_ESP, -stack_addend); + tcg_out_mov(s, TCG_TYPE_PTR, TCG_AREG0, tcg_target_call_iarg_regs[0]); + /* jmp *tb. */ - tcg_out_modrm(s, OPC_GRP5, EXT5_JMPN_Ev, tcg_target_call_iarg_regs[0]); + tcg_out_modrm(s, OPC_GRP5, EXT5_JMPN_Ev, tcg_target_call_iarg_regs[1]); /* TB epilogue */ tb_ret_addr = s->code_ptr; - tcg_out_addi(s, TCG_REG_ESP, stack_addend); + tcg_out_addi(s, TCG_REG_CALL_STACK, stack_addend); for (i = ARRAY_SIZE(tcg_target_callee_save_regs) - 1; i >= 0; i--) { tcg_out_pop(s, tcg_target_callee_save_regs[i]); @@ -1976,7 +1982,7 @@ static void tcg_target_init(TCGContext *s) } tcg_regset_clear(s->reserved_regs); - tcg_regset_set_reg(s->reserved_regs, TCG_REG_ESP); + tcg_regset_set_reg(s->reserved_regs, TCG_REG_CALL_STACK); tcg_add_target_add_op_defs(x86_op_defs); } diff --git a/tcg/ia64/tcg-target.c b/tcg/ia64/tcg-target.c index 8dac7f72fd..6386a5bf27 100644 --- a/tcg/ia64/tcg-target.c +++ b/tcg/ia64/tcg-target.c @@ -2292,7 +2292,7 @@ static void tcg_target_qemu_prologue(TCGContext *s) tcg_opc_m34(TCG_REG_P0, OPC_ALLOC_M34, TCG_REG_R33, 32, 24, 0), tcg_opc_i21(TCG_REG_P0, OPC_MOV_I21, - TCG_REG_B6, TCG_REG_R32, 0), + TCG_REG_B6, TCG_REG_R33, 0), tcg_opc_i22(TCG_REG_P0, OPC_MOV_I22, TCG_REG_R32, TCG_REG_B0)); @@ -2308,7 +2308,8 @@ static void tcg_target_qemu_prologue(TCGContext *s) } tcg_out_bundle(s, miB, - tcg_opc_m48(TCG_REG_P0, OPC_NOP_M48, 0), + tcg_opc_m48(TCG_REG_P0, OPC_MOV_I21, + TCG_REG_AREG0, TCG_REG_R32, 0), tcg_opc_a4 (TCG_REG_P0, OPC_ADDS_A4, TCG_REG_R12, -frame_size, TCG_REG_R12), tcg_opc_b4 (TCG_REG_P0, OPC_BR_SPTK_MANY_B4, TCG_REG_B6)); @@ -2387,4 +2388,6 @@ static void tcg_target_init(TCGContext *s) tcg_regset_set_reg(s->reserved_regs, TCG_REG_R6); tcg_add_target_add_op_defs(ia64_op_defs); + tcg_set_frame(s, TCG_AREG0, offsetof(CPUState, temp_buf), + CPU_TEMP_BUF_NLONGS * sizeof(long)); } diff --git a/tcg/mips/tcg-target.c b/tcg/mips/tcg-target.c index e04b0dc32f..12ff9d5259 100644 --- a/tcg/mips/tcg-target.c +++ b/tcg/mips/tcg-target.c @@ -1452,9 +1452,7 @@ static const TCGTargetOpDef mips_op_defs[] = { }; static int tcg_target_callee_save_regs[] = { -#if 0 /* used for the global env (TCG_AREG0), so no need to save */ - TCG_REG_S0, -#endif + TCG_REG_S0, /* used for the global env (TCG_AREG0) */ TCG_REG_S1, TCG_REG_S2, TCG_REG_S3, @@ -1486,8 +1484,8 @@ static void tcg_target_qemu_prologue(TCGContext *s) } /* Call generated code */ - tcg_out_opc_reg(s, OPC_JR, 0, TCG_REG_A0, 0); - tcg_out_nop(s); + tcg_out_opc_reg(s, OPC_JR, 0, tcg_target_call_iarg_regs[1]), 0); + tcg_out_mov(s, TCG_TYPE_PTR, TCG_AREG0, tcg_target_call_iarg_regs[0]); tb_ret_addr = s->code_ptr; /* TB epilogue */ @@ -1530,4 +1528,6 @@ static void tcg_target_init(TCGContext *s) tcg_regset_set_reg(s->reserved_regs, TCG_REG_SP); /* stack pointer */ tcg_add_target_add_op_defs(mips_op_defs); + tcg_set_frame(s, TCG_AREG0, offsetof(CPUState, temp_buf), + CPU_TEMP_BUF_NLONGS * sizeof(long)); } diff --git a/tcg/ppc/tcg-target.c b/tcg/ppc/tcg-target.c index 7970268e5a..58c8621709 100644 --- a/tcg/ppc/tcg-target.c +++ b/tcg/ppc/tcg-target.c @@ -160,8 +160,7 @@ static const int tcg_target_callee_save_regs[] = { TCG_REG_R24, TCG_REG_R25, TCG_REG_R26, - /* TCG_REG_R27, */ /* currently used for the global env, so no - need to save */ + TCG_REG_R27, /* currently used for the global env */ TCG_REG_R28, TCG_REG_R29, TCG_REG_R30, @@ -908,9 +907,14 @@ static void tcg_target_qemu_prologue (TCGContext *s) + LINKAGE_AREA_SIZE + TCG_STATIC_CALL_ARGS_SIZE + ARRAY_SIZE (tcg_target_callee_save_regs) * 4 + + CPU_TEMP_BUF_NLONGS * sizeof(long) ; frame_size = (frame_size + 15) & ~15; + tcg_set_frame(s, TCG_REG_CALL_STACK, frame_size + - CPU_TEMP_BUF_NLONGS * sizeof(long), + CPU_TEMP_BUF_NLONGS * sizeof(long)); + #ifdef _CALL_AIX { uint32_t addr; @@ -939,7 +943,8 @@ static void tcg_target_qemu_prologue (TCGContext *s) } #endif - tcg_out32 (s, MTSPR | RS (3) | CTR); + tcg_out_mov (s, TCG_TYPE_PTR, TCG_AREG0, tcg_target_call_iarg_regs[0]); + tcg_out32 (s, MTSPR | RS (tcg_target_call_iarg_regs[1]) | CTR); tcg_out32 (s, BCCTR | BO_ALWAYS); tb_ret_addr = s->code_ptr; @@ -982,11 +987,6 @@ static void ppc_addi (TCGContext *s, int rt, int ra, tcg_target_long si) } } -static void tcg_out_addi(TCGContext *s, int reg, tcg_target_long val) -{ - ppc_addi (s, reg, reg, val); -} - static void tcg_out_cmp (TCGContext *s, int cond, TCGArg arg1, TCGArg arg2, int const_arg2, int cr) { diff --git a/tcg/ppc64/tcg-target.c b/tcg/ppc64/tcg-target.c index ebbee343fd..02a6cb2411 100644 --- a/tcg/ppc64/tcg-target.c +++ b/tcg/ppc64/tcg-target.c @@ -151,8 +151,7 @@ static const int tcg_target_callee_save_regs[] = { TCG_REG_R24, TCG_REG_R25, TCG_REG_R26, - /* TCG_REG_R27, */ /* currently used for the global env, so no - need to save */ + TCG_REG_R27, /* currently used for the global env */ TCG_REG_R28, TCG_REG_R29, TCG_REG_R30, @@ -876,9 +875,14 @@ static void tcg_target_qemu_prologue (TCGContext *s) + 8 /* TOC save area */ + TCG_STATIC_CALL_ARGS_SIZE + ARRAY_SIZE (tcg_target_callee_save_regs) * 8 + + CPU_TEMP_BUF_NLONGS * sizeof(long) ; frame_size = (frame_size + 15) & ~15; + tcg_set_frame(s, TCG_REG_CALL_STACK, frame_size + - CPU_TEMP_BUF_NLONGS * sizeof(long), + CPU_TEMP_BUF_NLONGS * sizeof(long)); + #ifndef __APPLE__ /* First emit adhoc function descriptor */ addr = (uint64_t) s->code_ptr + 24; @@ -905,7 +909,8 @@ static void tcg_target_qemu_prologue (TCGContext *s) } #endif - tcg_out32 (s, MTSPR | RS (3) | CTR); + tcg_out_mov (s, TCG_TYPE_PTR, TCG_AREG0, tcg_target_call_iarg_regs[0]); + tcg_out32 (s, MTSPR | RS (tcg_target_call_iarg_regs[1]) | CTR); tcg_out32 (s, BCCTR | BO_ALWAYS); /* Epilogue */ @@ -968,11 +973,6 @@ static void ppc_addi64 (TCGContext *s, int rt, int ra, tcg_target_long si) } } -static void tcg_out_addi (TCGContext *s, int reg, tcg_target_long val) -{ - ppc_addi64 (s, reg, reg, val); -} - static void tcg_out_cmp (TCGContext *s, int cond, TCGArg arg1, TCGArg arg2, int const_arg2, int cr, int arch64) { diff --git a/tcg/s390/tcg-target.c b/tcg/s390/tcg-target.c index 450fcabd70..2fc5646400 100644 --- a/tcg/s390/tcg-target.c +++ b/tcg/s390/tcg-target.c @@ -2291,6 +2291,8 @@ static void tcg_target_init(TCGContext *s) tcg_regset_set_reg(s->reserved_regs, TCG_REG_CALL_STACK); tcg_add_target_add_op_defs(s390_op_defs); + tcg_set_frame(s, TCG_AREG0, offsetof(CPUState, temp_buf), + CPU_TEMP_BUF_NLONGS * sizeof(long)); } static void tcg_target_qemu_prologue(TCGContext *s) @@ -2306,8 +2308,9 @@ static void tcg_target_qemu_prologue(TCGContext *s) tcg_regset_set_reg(s->reserved_regs, TCG_GUEST_BASE_REG); } - /* br %r2 (go to TB) */ - tcg_out_insn(s, RR, BCR, S390_CC_ALWAYS, TCG_REG_R2); + tcg_out_mov(s, TCG_TYPE_PTR, TCG_AREG0, tcg_target_call_iarg_regs[0]); + /* br %r3 (go to TB) */ + tcg_out_insn(s, RR, BCR, S390_CC_ALWAYS, tcg_target_call_iarg_regs[1]); tb_ret_addr = s->code_ptr; diff --git a/tcg/sparc/tcg-target.c b/tcg/sparc/tcg-target.c index 5f1353adf8..ac76e1198d 100644 --- a/tcg/sparc/tcg-target.c +++ b/tcg/sparc/tcg-target.c @@ -693,11 +693,14 @@ static void tcg_out_setcond2_i32(TCGContext *s, TCGCond cond, TCGArg ret, /* Generate global QEMU prologue and epilogue code */ static void tcg_target_qemu_prologue(TCGContext *s) { + tcg_set_frame(s, TCG_REG_I6, TCG_TARGET_CALL_STACK_OFFSET, + CPU_TEMP_BUF_NLONGS * (int)sizeof(long)); tcg_out32(s, SAVE | INSN_RD(TCG_REG_O6) | INSN_RS1(TCG_REG_O6) | - INSN_IMM13(-TCG_TARGET_STACK_MINFRAME)); - tcg_out32(s, JMPL | INSN_RD(TCG_REG_G0) | INSN_RS1(TCG_REG_I0) | + INSN_IMM13(-(TCG_TARGET_STACK_MINFRAME + + CPU_TEMP_BUF_NLONGS * (int)sizeof(long)))); + tcg_out32(s, JMPL | INSN_RD(TCG_REG_G0) | INSN_RS1(TCG_REG_I1) | INSN_RS2(TCG_REG_G0)); - tcg_out_nop(s); + tcg_out_mov(s, TCG_TYPE_PTR, TCG_AREG0, TCG_REG_I0); } #if defined(CONFIG_SOFTMMU) @@ -54,7 +54,6 @@ instructions */ #define NO_CPU_IO_DEFS #include "cpu.h" -#include "exec-all.h" #include "tcg-op.h" #include "elf.h" @@ -1440,13 +1439,19 @@ static void temp_allocate_frame(TCGContext *s, int temp) { TCGTemp *ts; ts = &s->temps[temp]; - s->current_frame_offset = (s->current_frame_offset + sizeof(tcg_target_long) - 1) & ~(sizeof(tcg_target_long) - 1); - if (s->current_frame_offset + sizeof(tcg_target_long) > s->frame_end) +#ifndef __sparc_v9__ /* Sparc64 stack is accessed with offset of 2047 */ + s->current_frame_offset = (s->current_frame_offset + + (tcg_target_long)sizeof(tcg_target_long) - 1) & + ~(sizeof(tcg_target_long) - 1); +#endif + if (s->current_frame_offset + (tcg_target_long)sizeof(tcg_target_long) > + s->frame_end) { tcg_abort(); + } ts->mem_offset = s->current_frame_offset; ts->mem_reg = s->frame_reg; ts->mem_allocated = 1; - s->current_frame_offset += sizeof(tcg_target_long); + s->current_frame_offset += (tcg_target_long)sizeof(tcg_target_long); } /* free register 'reg' by spilling the corresponding temporary if necessary */ @@ -1842,13 +1847,14 @@ static int tcg_reg_alloc_call(TCGContext *s, const TCGOpDef *def, nb_regs = nb_params; /* assign stack slots first */ - /* XXX: preallocate call stack */ call_stack_size = (nb_params - nb_regs) * sizeof(tcg_target_long); call_stack_size = (call_stack_size + TCG_TARGET_STACK_ALIGN - 1) & ~(TCG_TARGET_STACK_ALIGN - 1); allocate_args = (call_stack_size > TCG_STATIC_CALL_ARGS_SIZE); if (allocate_args) { - tcg_out_addi(s, TCG_REG_CALL_STACK, -STACK_DIR(call_stack_size)); + /* XXX: if more than TCG_STATIC_CALL_ARGS_SIZE is needed, + preallocate call stack */ + tcg_abort(); } stack_offset = TCG_TARGET_CALL_STACK_OFFSET; @@ -1967,10 +1973,6 @@ static int tcg_reg_alloc_call(TCGContext *s, const TCGOpDef *def, } tcg_out_op(s, opc, &func_arg, &const_func_arg); - - if (allocate_args) { - tcg_out_addi(s, TCG_REG_CALL_STACK, STACK_DIR(call_stack_size)); - } /* assign output registers and emit moves if needed */ for(i = 0; i < nb_oargs; i++) { @@ -515,8 +515,9 @@ TCGv_i64 tcg_const_local_i64(int64_t val); extern uint8_t code_gen_prologue[]; #if defined(_ARCH_PPC) && !defined(_ARCH_PPC64) -#define tcg_qemu_tb_exec(tb_ptr) \ - ((long REGPARM __attribute__ ((longcall)) (*)(void *))code_gen_prologue)(tb_ptr) +#define tcg_qemu_tb_exec(env, tb_ptr) \ + ((long REGPARM __attribute__ ((longcall)) (*)(void *, void *))code_gen_prologue)(env, tb_ptr) #else -#define tcg_qemu_tb_exec(tb_ptr) ((long REGPARM (*)(void *))code_gen_prologue)(tb_ptr) +#define tcg_qemu_tb_exec(env, tb_ptr) \ + ((long REGPARM (*)(void *, void *))code_gen_prologue)(env, tb_ptr) #endif diff --git a/trace-events b/trace-events index bebf612fe9..ad11b09c0a 100644 --- a/trace-events +++ b/trace-events @@ -46,6 +46,17 @@ disable virtio_queue_notify(void *vdev, int n, void *vq) "vdev %p n %d vq %p" disable virtio_irq(void *vq) "vq %p" disable virtio_notify(void *vdev, void *vq) "vdev %p vq %p" +# hw/virtio-serial-bus.c +disable virtio_serial_send_control_event(unsigned int port, uint16_t event, uint16_t value) "port %u, event %u, value %u" +disable virtio_serial_throttle_port(unsigned int port, bool throttle) "port %u, throttle %d" +disable virtio_serial_handle_control_message(uint16_t event, uint16_t value) "event %u, value %u" +disable virtio_serial_handle_control_message_port(unsigned int port) "port %u" + +# hw/virtio-console.c +disable virtio_console_flush_buf(unsigned int port, size_t len, ssize_t ret) "port %u, in_len %zu, out_len %zd" +disable virtio_console_chr_read(unsigned int port, int size) "port %u, size %d" +disable virtio_console_chr_event(unsigned int port, int event) "port %u, event %d" + # block.c disable multiwrite_cb(void *mcb, int ret) "mcb %p ret %d" disable bdrv_aio_multiwrite(void *mcb, int num_callbacks, int num_reqs) "mcb %p num_callbacks %d num_reqs %d" @@ -399,9 +410,9 @@ disable xen_ram_alloc(unsigned long ram_addr, unsigned long size) "requested: %# disable xen_client_set_memory(uint64_t start_addr, unsigned long size, unsigned long phys_offset, bool log_dirty) "%#"PRIx64" size %#lx, offset %#lx, log_dirty %i" # xen-mapcache.c -disable qemu_map_cache(uint64_t phys_addr) "want %#"PRIx64"" -disable qemu_remap_bucket(uint64_t index) "index %#"PRIx64"" -disable qemu_map_cache_return(void* ptr) "%p" +disable xen_map_cache(uint64_t phys_addr) "want %#"PRIx64"" +disable xen_remap_bucket(uint64_t index) "index %#"PRIx64"" +disable xen_map_cache_return(void* ptr) "%p" disable xen_map_block(uint64_t phys_addr, uint64_t size) "%#"PRIx64", size %#"PRIx64"" disable xen_unmap_block(void* addr, unsigned long size) "%p, size %#lx" diff --git a/translate-all.c b/translate-all.c index 2ca190ca8f..041c108948 100644 --- a/translate-all.c +++ b/translate-all.c @@ -26,7 +26,6 @@ #define NO_CPU_IO_DEFS #include "cpu.h" -#include "exec-all.h" #include "disas.h" #include "tcg.h" #include "qemu-timer.h" @@ -44,8 +43,6 @@ uint8_t gen_opc_instr_start[OPC_BUF_SIZE]; void cpu_gen_init(void) { tcg_context_init(&tcg_ctx); - tcg_set_frame(&tcg_ctx, TCG_AREG0, offsetof(CPUState, temp_buf), - CPU_TEMP_BUF_NLONGS * sizeof(long)); } /* return non zero if the very first instruction is invalid so that diff --git a/ui/spice-core.c b/ui/spice-core.c index dd9905be36..e142452bb6 100644 --- a/ui/spice-core.c +++ b/ui/spice-core.c @@ -602,7 +602,10 @@ void qemu_spice_init(void) qemu_opt_foreach(opts, add_channel, NULL, 0); - spice_server_init(spice_server, &core_interface); + if (0 != spice_server_init(spice_server, &core_interface)) { + fprintf(stderr, "failed to initialize spice server"); + exit(1); + }; using_spice = 1; migration_state.notify = migration_state_notifier; diff --git a/ui/spice-display.c b/ui/spice-display.c index 15f0704eaf..feeee73dcc 100644 --- a/ui/spice-display.c +++ b/ui/spice-display.c @@ -70,6 +70,7 @@ static SimpleSpiceUpdate *qemu_spice_create_update(SimpleSpiceDisplay *ssd) QXLCommand *cmd; uint8_t *src, *dst; int by, bw, bh; + struct timespec time_space; if (qemu_spice_rect_is_empty(&ssd->dirty)) { return NULL; @@ -96,6 +97,10 @@ static SimpleSpiceUpdate *qemu_spice_create_update(SimpleSpiceDisplay *ssd) drawable->surfaces_dest[0] = -1; drawable->surfaces_dest[1] = -1; drawable->surfaces_dest[2] = -1; + clock_gettime(CLOCK_MONOTONIC, &time_space); + /* time in milliseconds from epoch. */ + drawable->mm_time = time_space.tv_sec * 1000 + + time_space.tv_nsec / 1000 / 1000; drawable->u.copy.rop_descriptor = SPICE_ROPD_OP_PUT; drawable->u.copy.src_bitmap = (intptr_t)image; diff --git a/ui/vnc-enc-tight.c b/ui/vnc-enc-tight.c index 87fdf35d3e..5c02803411 100644 --- a/ui/vnc-enc-tight.c +++ b/ui/vnc-enc-tight.c @@ -28,7 +28,15 @@ #include "config-host.h" +/* This needs to be before jpeglib.h line because of conflict with + INT32 definitions between jmorecfg.h (included by jpeglib.h) and + Win32 basetsd.h (included by windows.h). */ +#include "qemu-common.h" + #ifdef CONFIG_VNC_PNG +/* The following define is needed by pngconf.h. Otherwise it won't compile, + because setjmp.h was already included by qemu-common.h. */ +#define PNG_SKIP_SETJMP_CHECK #include <png.h> #endif #ifdef CONFIG_VNC_JPEG @@ -36,8 +44,6 @@ #include <jpeglib.h> #endif -#include "qemu-common.h" - #include "bswap.h" #include "qint.h" #include "vnc.h" @@ -367,8 +367,10 @@ USBDevice *usb_host_device_open(const char *devname) if (dev_info.udi_speed == 1) { dev->dev.speed = USB_SPEED_LOW - 1; + dev->dev.speedmask = USB_SPEED_MASK_LOW; } else { dev->dev.speed = USB_SPEED_FULL - 1; + dev->dev.speedmask = USB_SPEED_MASK_FULL; } if (strncmp(dev_info.udi_product, "product", 7) != 0) { diff --git a/usb-linux.c b/usb-linux.c index 5d2ec5c5c7..1a2deb35c9 100644 --- a/usb-linux.c +++ b/usb-linux.c @@ -85,7 +85,6 @@ static int usb_fs_type; /* endpoint association data */ #define ISO_FRAME_DESC_PER_URB 32 -#define ISO_URB_COUNT 3 #define INVALID_EP_TYPE 255 /* devio.c limits single requests to 16k */ @@ -101,6 +100,7 @@ struct endp_data { int iso_urb_idx; int iso_buffer_used; int max_packet_size; + int inflight; }; struct USBAutoFilter { @@ -120,6 +120,7 @@ typedef struct USBHostDevice { int configuration; int ninterfaces; int closing; + uint32_t iso_urb_count; Notifier exit; struct endp_data endp_table[MAX_ENDPOINTS]; @@ -142,74 +143,91 @@ static void usb_host_auto_check(void *unused); static int usb_host_read_file(char *line, size_t line_size, const char *device_file, const char *device_name); +static struct endp_data *get_endp(USBHostDevice *s, int ep) +{ + return s->endp_table + ep - 1; +} + static int is_isoc(USBHostDevice *s, int ep) { - return s->endp_table[ep - 1].type == USBDEVFS_URB_TYPE_ISO; + return get_endp(s, ep)->type == USBDEVFS_URB_TYPE_ISO; } static int is_valid(USBHostDevice *s, int ep) { - return s->endp_table[ep - 1].type != INVALID_EP_TYPE; + return get_endp(s, ep)->type != INVALID_EP_TYPE; } static int is_halted(USBHostDevice *s, int ep) { - return s->endp_table[ep - 1].halted; + return get_endp(s, ep)->halted; } static void clear_halt(USBHostDevice *s, int ep) { - s->endp_table[ep - 1].halted = 0; + get_endp(s, ep)->halted = 0; } static void set_halt(USBHostDevice *s, int ep) { - s->endp_table[ep - 1].halted = 1; + get_endp(s, ep)->halted = 1; } static int is_iso_started(USBHostDevice *s, int ep) { - return s->endp_table[ep - 1].iso_started; + return get_endp(s, ep)->iso_started; } static void clear_iso_started(USBHostDevice *s, int ep) { - s->endp_table[ep - 1].iso_started = 0; + get_endp(s, ep)->iso_started = 0; } static void set_iso_started(USBHostDevice *s, int ep) { - s->endp_table[ep - 1].iso_started = 1; + struct endp_data *e = get_endp(s, ep); + if (!e->iso_started) { + e->iso_started = 1; + e->inflight = 0; + } +} + +static int change_iso_inflight(USBHostDevice *s, int ep, int value) +{ + struct endp_data *e = get_endp(s, ep); + + e->inflight += value; + return e->inflight; } static void set_iso_urb(USBHostDevice *s, int ep, AsyncURB *iso_urb) { - s->endp_table[ep - 1].iso_urb = iso_urb; + get_endp(s, ep)->iso_urb = iso_urb; } static AsyncURB *get_iso_urb(USBHostDevice *s, int ep) { - return s->endp_table[ep - 1].iso_urb; + return get_endp(s, ep)->iso_urb; } static void set_iso_urb_idx(USBHostDevice *s, int ep, int i) { - s->endp_table[ep - 1].iso_urb_idx = i; + get_endp(s, ep)->iso_urb_idx = i; } static int get_iso_urb_idx(USBHostDevice *s, int ep) { - return s->endp_table[ep - 1].iso_urb_idx; + return get_endp(s, ep)->iso_urb_idx; } static void set_iso_buffer_used(USBHostDevice *s, int ep, int i) { - s->endp_table[ep - 1].iso_buffer_used = i; + get_endp(s, ep)->iso_buffer_used = i; } static int get_iso_buffer_used(USBHostDevice *s, int ep) { - return s->endp_table[ep - 1].iso_buffer_used; + return get_endp(s, ep)->iso_buffer_used; } static void set_max_packet_size(USBHostDevice *s, int ep, uint8_t *descriptor) @@ -223,14 +241,12 @@ static void set_max_packet_size(USBHostDevice *s, int ep, uint8_t *descriptor) case 2: microframes = 3; break; default: microframes = 1; break; } - DPRINTF("husb: max packet size: 0x%x -> %d x %d\n", - raw, microframes, size); - s->endp_table[ep - 1].max_packet_size = size * microframes; + get_endp(s, ep)->max_packet_size = size * microframes; } static int get_max_packet_size(USBHostDevice *s, int ep) { - return s->endp_table[ep - 1].max_packet_size; + return get_endp(s, ep)->max_packet_size; } /* @@ -279,6 +295,7 @@ static void async_complete(void *opaque) { USBHostDevice *s = opaque; AsyncURB *aurb; + int urbs = 0; while (1) { USBPacket *p; @@ -286,6 +303,9 @@ static void async_complete(void *opaque) int r = ioctl(s->fd, USBDEVFS_REAPURBNDELAY, &aurb); if (r < 0) { if (errno == EAGAIN) { + if (urbs > 2) { + fprintf(stderr, "husb: %d iso urbs finished at once\n", urbs); + } return; } if (errno == ENODEV && !s->closing) { @@ -303,10 +323,16 @@ static void async_complete(void *opaque) /* If this is a buffered iso urb mark it as complete and don't do anything else (it is handled further in usb_host_handle_iso_data) */ if (aurb->iso_frame_idx == -1) { + int inflight; if (aurb->urb.status == -EPIPE) { set_halt(s, aurb->urb.endpoint & 0xf); } aurb->iso_frame_idx = 0; + urbs++; + inflight = change_iso_inflight(s, aurb->urb.endpoint & 0xf, -1); + if (inflight == 0 && is_iso_started(s, aurb->urb.endpoint & 0xf)) { + fprintf(stderr, "husb: out of buffers for iso stream\n"); + } continue; } @@ -502,8 +528,8 @@ static AsyncURB *usb_host_alloc_iso(USBHostDevice *s, uint8_t ep, int in) AsyncURB *aurb; int i, j, len = get_max_packet_size(s, ep); - aurb = qemu_mallocz(ISO_URB_COUNT * sizeof(*aurb)); - for (i = 0; i < ISO_URB_COUNT; i++) { + aurb = qemu_mallocz(s->iso_urb_count * sizeof(*aurb)); + for (i = 0; i < s->iso_urb_count; i++) { aurb[i].urb.endpoint = ep; aurb[i].urb.buffer_length = ISO_FRAME_DESC_PER_URB * len; aurb[i].urb.buffer = qemu_malloc(aurb[i].urb.buffer_length); @@ -533,7 +559,7 @@ static void usb_host_stop_n_free_iso(USBHostDevice *s, uint8_t ep) return; } - for (i = 0; i < ISO_URB_COUNT; i++) { + for (i = 0; i < s->iso_urb_count; i++) { /* in flight? */ if (aurb[i].iso_frame_idx == -1) { ret = ioctl(s->fd, USBDEVFS_DISCARDURB, &aurb[i]); @@ -551,7 +577,7 @@ static void usb_host_stop_n_free_iso(USBHostDevice *s, uint8_t ep) async_complete(s); } - for (i = 0; i < ISO_URB_COUNT; i++) { + for (i = 0; i < s->iso_urb_count; i++) { qemu_free(aurb[i].urb.buffer); } @@ -636,7 +662,7 @@ static int usb_host_handle_iso_data(USBHostDevice *s, USBPacket *p, int in) } aurb[i].iso_frame_idx++; if (aurb[i].iso_frame_idx == ISO_FRAME_DESC_PER_URB) { - i = (i + 1) % ISO_URB_COUNT; + i = (i + 1) % s->iso_urb_count; set_iso_urb_idx(s, p->devep, i); } } else { @@ -649,7 +675,7 @@ static int usb_host_handle_iso_data(USBHostDevice *s, USBPacket *p, int in) if (is_iso_started(s, p->devep)) { /* (Re)-submit all fully consumed / filled urbs */ - for (i = 0; i < ISO_URB_COUNT; i++) { + for (i = 0; i < s->iso_urb_count; i++) { if (aurb[i].iso_frame_idx == ISO_FRAME_DESC_PER_URB) { ret = ioctl(s->fd, USBDEVFS_SUBMITURB, &aurb[i]); if (ret < 0) { @@ -667,6 +693,7 @@ static int usb_host_handle_iso_data(USBHostDevice *s, USBPacket *p, int in) break; } aurb[i].iso_frame_idx = -1; + change_iso_inflight(s, p->devep, +1); } } } @@ -1061,6 +1088,42 @@ static int usb_linux_update_endp_table(USBHostDevice *s) return 0; } +/* + * Check if we can safely redirect a usb2 device to a usb1 virtual controller, + * this function assumes this is safe, if: + * 1) There are no isoc endpoints + * 2) There are no interrupt endpoints with a max_packet_size > 64 + * Note bulk endpoints with a max_packet_size > 64 in theory also are not + * usb1 compatible, but in practice this seems to work fine. + */ +static int usb_linux_full_speed_compat(USBHostDevice *dev) +{ + int i, packet_size; + + /* + * usb_linux_update_endp_table only registers info about ep in the current + * interface altsettings, so we need to parse the descriptors again. + */ + for (i = 0; (i + 5) < dev->descr_len; i += dev->descr[i]) { + if (dev->descr[i + 1] == USB_DT_ENDPOINT) { + switch (dev->descr[i + 3] & 0x3) { + case 0x00: /* CONTROL */ + break; + case 0x01: /* ISO */ + return 0; + case 0x02: /* BULK */ + break; + case 0x03: /* INTERRUPT */ + packet_size = dev->descr[i + 4] + (dev->descr[i + 5] << 8); + if (packet_size > 64) + return 0; + break; + } + } + } + return 1; +} + static int usb_host_open(USBHostDevice *dev, int bus_num, int addr, char *port, const char *prod_name, int speed) { @@ -1140,6 +1203,10 @@ static int usb_host_open(USBHostDevice *dev, int bus_num, } } dev->dev.speed = speed; + dev->dev.speedmask = (1 << speed); + if (dev->dev.speed == USB_SPEED_HIGH && usb_linux_full_speed_compat(dev)) { + dev->dev.speedmask |= USB_SPEED_MASK_FULL; + } printf("husb: grabbed usb device %d.%d\n", bus_num, addr); @@ -1151,10 +1218,14 @@ static int usb_host_open(USBHostDevice *dev, int bus_num, prod_name); } + ret = usb_device_attach(&dev->dev); + if (ret) { + goto fail; + } + /* USB devio uses 'write' flag to check for async completions */ qemu_set_fd_handler(dev->fd, NULL, async_complete, dev); - usb_device_attach(&dev->dev); return 0; fail: @@ -1230,6 +1301,7 @@ static struct USBDeviceInfo usb_host_dev_info = { DEFINE_PROP_STRING("hostport", USBHostDevice, match.port), DEFINE_PROP_HEX32("vendorid", USBHostDevice, match.vendor_id, 0), DEFINE_PROP_HEX32("productid", USBHostDevice, match.product_id, 0), + DEFINE_PROP_UINT32("isobufs", USBHostDevice, iso_urb_count, 4), DEFINE_PROP_END_OF_LIST(), }, }; diff --git a/user-exec.c b/user-exec.c index d4a6abb8f5..02c2f8ba43 100644 --- a/user-exec.c +++ b/user-exec.c @@ -37,13 +37,14 @@ //#define DEBUG_SIGNAL +static void exception_action(CPUState *env1) +{ #if defined(TARGET_I386) -#define EXCEPTION_ACTION \ - raise_exception_err(env->exception_index, env->error_code) + raise_exception_err(env1->exception_index, env1->error_code); #else -#define EXCEPTION_ACTION \ - cpu_loop_exit() + cpu_loop_exit(env1); #endif +} /* exit the current TB from a signal handler. The host registers are restored in a state compatible with the CPU emulator @@ -118,7 +119,7 @@ static inline int handle_cpu_signal(unsigned long pc, unsigned long address, /* we restore the process signal mask as the sigreturn should do it (XXX: use sigsetjmp) */ sigprocmask(SIG_SETMASK, old_set, NULL); - EXCEPTION_ACTION; + exception_action(env); /* never comes here */ return 1; @@ -2300,7 +2300,16 @@ int main(int argc, char **argv, char **envp) #endif break; case QEMU_OPTION_portrait: - graphic_rotate = 1; + graphic_rotate = 90; + break; + case QEMU_OPTION_rotate: + graphic_rotate = strtol(optarg, (char **) &optarg, 10); + if (graphic_rotate != 0 && graphic_rotate != 90 && + graphic_rotate != 180 && graphic_rotate != 270) { + fprintf(stderr, + "qemu: only 90, 180, 270 deg rotation is available\n"); + exit(1); + } break; case QEMU_OPTION_kernel: kernel_filename = optarg; @@ -644,7 +644,7 @@ static void handle_ioreq(ioreq_t *req) case IOREQ_TYPE_TIMEOFFSET: break; case IOREQ_TYPE_INVALIDATE: - qemu_invalidate_map_cache(); + xen_invalidate_map_cache(); break; default: hw_error("Invalid ioreq type 0x%x\n", req->type); @@ -737,6 +737,66 @@ static void cpu_handle_ioreq(void *opaque) } } +static int store_dev_info(int domid, CharDriverState *cs, const char *string) +{ + struct xs_handle *xs = NULL; + char *path = NULL; + char *newpath = NULL; + char *pts = NULL; + int ret = -1; + + /* Only continue if we're talking to a pty. */ + if (strncmp(cs->filename, "pty:", 4)) { + return 0; + } + pts = cs->filename + 4; + + /* We now have everything we need to set the xenstore entry. */ + xs = xs_open(0); + if (xs == NULL) { + fprintf(stderr, "Could not contact XenStore\n"); + goto out; + } + + path = xs_get_domain_path(xs, domid); + if (path == NULL) { + fprintf(stderr, "xs_get_domain_path() error\n"); + goto out; + } + newpath = realloc(path, (strlen(path) + strlen(string) + + strlen("/tty") + 1)); + if (newpath == NULL) { + fprintf(stderr, "realloc error\n"); + goto out; + } + path = newpath; + + strcat(path, string); + strcat(path, "/tty"); + if (!xs_write(xs, XBT_NULL, path, pts, strlen(pts))) { + fprintf(stderr, "xs_write for '%s' fail", string); + goto out; + } + ret = 0; + +out: + free(path); + xs_close(xs); + + return ret; +} + +void xenstore_store_pv_console_info(int i, CharDriverState *chr) +{ + if (i == 0) { + store_dev_info(xen_domid, chr, "/console"); + } else { + char buf[32]; + snprintf(buf, sizeof(buf), "/device/console/%d", i); + store_dev_info(xen_domid, chr, buf); + } +} + static void xenstore_record_dm_state(XenIOState *s, const char *state) { char path[50]; @@ -852,7 +912,7 @@ int xen_hvm_init(void) } /* Init RAM management */ - qemu_map_cache_init(); + xen_map_cache_init(); xen_ram_init(ram_size); qemu_add_vm_change_state_handler(xen_vm_change_state_handler, state); @@ -862,6 +922,15 @@ int xen_hvm_init(void) cpu_register_phys_memory_client(&state->client); state->log_for_dirtybit = NULL; + /* Initialize backend core & drivers */ + if (xen_be_init() != 0) { + fprintf(stderr, "%s: xen backend core setup failed\n", __FUNCTION__); + exit(1); + } + xen_be_register("console", &xen_console_ops); + xen_be_register("vkbd", &xen_kbdmouse_ops); + xen_be_register("qdisk", &xen_blkdev_ops); + return 0; } diff --git a/xen-mapcache-stub.c b/xen-mapcache-stub.c deleted file mode 100644 index 8a2380a151..0000000000 --- a/xen-mapcache-stub.c +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Copyright (C) 2011 Citrix Ltd. - * - * This work is licensed under the terms of the GNU GPL, version 2. See - * the COPYING file in the top-level directory. - * - */ - -#include "config.h" - -#include "exec-all.h" -#include "qemu-common.h" -#include "cpu-common.h" -#include "xen-mapcache.h" - -void qemu_map_cache_init(void) -{ -} - -uint8_t *qemu_map_cache(target_phys_addr_t phys_addr, target_phys_addr_t size, uint8_t lock) -{ - return qemu_get_ram_ptr(phys_addr); -} - -ram_addr_t qemu_ram_addr_from_mapcache(void *ptr) -{ - return -1; -} - -void qemu_invalidate_map_cache(void) -{ -} - -void qemu_invalidate_entry(uint8_t *buffer) -{ -} diff --git a/xen-mapcache.c b/xen-mapcache.c index fac47cd9be..007136af26 100644 --- a/xen-mapcache.c +++ b/xen-mapcache.c @@ -40,6 +40,9 @@ #endif #define MCACHE_BUCKET_SIZE (1UL << MCACHE_BUCKET_SHIFT) +#define mapcache_lock() ((void)0) +#define mapcache_unlock() ((void)0) + typedef struct MapCacheEntry { target_phys_addr_t paddr_index; uint8_t *vaddr_base; @@ -79,7 +82,7 @@ static inline int test_bits(int nr, int size, const unsigned long *addr) return 0; } -void qemu_map_cache_init(void) +void xen_map_cache_init(void) { unsigned long size; struct rlimit rlimit_as; @@ -106,13 +109,14 @@ void qemu_map_cache_init(void) size = mapcache->nr_buckets * sizeof (MapCacheEntry); size = (size + XC_PAGE_SIZE - 1) & ~(XC_PAGE_SIZE - 1); - DPRINTF("qemu_map_cache_init, nr_buckets = %lx size %lu\n", mapcache->nr_buckets, size); + DPRINTF("%s, nr_buckets = %lx size %lu\n", __func__, + mapcache->nr_buckets, size); mapcache->entry = qemu_mallocz(size); } -static void qemu_remap_bucket(MapCacheEntry *entry, - target_phys_addr_t size, - target_phys_addr_t address_index) +static void xen_remap_bucket(MapCacheEntry *entry, + target_phys_addr_t size, + target_phys_addr_t address_index) { uint8_t *vaddr_base; xen_pfn_t *pfns; @@ -120,7 +124,7 @@ static void qemu_remap_bucket(MapCacheEntry *entry, unsigned int i; target_phys_addr_t nb_pfn = size >> XC_PAGE_SHIFT; - trace_qemu_remap_bucket(address_index); + trace_xen_remap_bucket(address_index); pfns = qemu_mallocz(nb_pfn * sizeof (xen_pfn_t)); err = qemu_mallocz(nb_pfn * sizeof (int)); @@ -164,17 +168,18 @@ static void qemu_remap_bucket(MapCacheEntry *entry, qemu_free(err); } -uint8_t *qemu_map_cache(target_phys_addr_t phys_addr, target_phys_addr_t size, uint8_t lock) +uint8_t *xen_map_cache(target_phys_addr_t phys_addr, target_phys_addr_t size, + uint8_t lock) { MapCacheEntry *entry, *pentry = NULL; target_phys_addr_t address_index = phys_addr >> MCACHE_BUCKET_SHIFT; target_phys_addr_t address_offset = phys_addr & (MCACHE_BUCKET_SIZE - 1); target_phys_addr_t __size = size; - trace_qemu_map_cache(phys_addr); + trace_xen_map_cache(phys_addr); if (address_index == mapcache->last_address_index && !lock && !__size) { - trace_qemu_map_cache_return(mapcache->last_address_vaddr + address_offset); + trace_xen_map_cache_return(mapcache->last_address_vaddr + address_offset); return mapcache->last_address_vaddr + address_offset; } @@ -198,20 +203,20 @@ uint8_t *qemu_map_cache(target_phys_addr_t phys_addr, target_phys_addr_t size, u if (!entry) { entry = qemu_mallocz(sizeof (MapCacheEntry)); pentry->next = entry; - qemu_remap_bucket(entry, __size, address_index); + xen_remap_bucket(entry, __size, address_index); } else if (!entry->lock) { if (!entry->vaddr_base || entry->paddr_index != address_index || entry->size != __size || !test_bits(address_offset >> XC_PAGE_SHIFT, size >> XC_PAGE_SHIFT, entry->valid_mapping)) { - qemu_remap_bucket(entry, __size, address_index); + xen_remap_bucket(entry, __size, address_index); } } if(!test_bits(address_offset >> XC_PAGE_SHIFT, size >> XC_PAGE_SHIFT, entry->valid_mapping)) { mapcache->last_address_index = -1; - trace_qemu_map_cache_return(NULL); + trace_xen_map_cache_return(NULL); return NULL; } @@ -226,11 +231,11 @@ uint8_t *qemu_map_cache(target_phys_addr_t phys_addr, target_phys_addr_t size, u QTAILQ_INSERT_HEAD(&mapcache->locked_entries, reventry, next); } - trace_qemu_map_cache_return(mapcache->last_address_vaddr + address_offset); + trace_xen_map_cache_return(mapcache->last_address_vaddr + address_offset); return mapcache->last_address_vaddr + address_offset; } -ram_addr_t qemu_ram_addr_from_mapcache(void *ptr) +ram_addr_t xen_ram_addr_from_mapcache(void *ptr) { MapCacheEntry *entry = NULL, *pentry = NULL; MapCacheRev *reventry; @@ -247,7 +252,7 @@ ram_addr_t qemu_ram_addr_from_mapcache(void *ptr) } } if (!found) { - fprintf(stderr, "qemu_ram_addr_from_mapcache, could not find %p\n", ptr); + fprintf(stderr, "%s, could not find %p\n", __func__, ptr); QTAILQ_FOREACH(reventry, &mapcache->locked_entries, next) { DPRINTF(" "TARGET_FMT_plx" -> %p is present\n", reventry->paddr_index, reventry->vaddr_req); @@ -269,7 +274,7 @@ ram_addr_t qemu_ram_addr_from_mapcache(void *ptr) ((unsigned long) ptr - (unsigned long) entry->vaddr_base); } -void qemu_invalidate_entry(uint8_t *buffer) +void xen_invalidate_map_cache_entry(uint8_t *buffer) { MapCacheEntry *entry = NULL, *pentry = NULL; MapCacheRev *reventry; @@ -290,7 +295,7 @@ void qemu_invalidate_entry(uint8_t *buffer) } } if (!found) { - DPRINTF("qemu_invalidate_entry, could not find %p\n", buffer); + DPRINTF("%s, could not find %p\n", __func__, buffer); QTAILQ_FOREACH(reventry, &mapcache->locked_entries, next) { DPRINTF(" "TARGET_FMT_plx" -> %p is present\n", reventry->paddr_index, reventry->vaddr_req); } @@ -322,7 +327,7 @@ void qemu_invalidate_entry(uint8_t *buffer) qemu_free(entry); } -void qemu_invalidate_map_cache(void) +void xen_invalidate_map_cache(void) { unsigned long i; MapCacheRev *reventry; diff --git a/xen-mapcache.h b/xen-mapcache.h index 6216cc3be7..606b8afc52 100644 --- a/xen-mapcache.h +++ b/xen-mapcache.h @@ -9,13 +9,11 @@ #ifndef XEN_MAPCACHE_H #define XEN_MAPCACHE_H -void qemu_map_cache_init(void); -uint8_t *qemu_map_cache(target_phys_addr_t phys_addr, target_phys_addr_t size, uint8_t lock); -ram_addr_t qemu_ram_addr_from_mapcache(void *ptr); -void qemu_invalidate_entry(uint8_t *buffer); -void qemu_invalidate_map_cache(void); - -#define mapcache_lock() ((void)0) -#define mapcache_unlock() ((void)0) +void xen_map_cache_init(void); +uint8_t *xen_map_cache(target_phys_addr_t phys_addr, target_phys_addr_t size, + uint8_t lock); +ram_addr_t xen_ram_addr_from_mapcache(void *ptr); +void xen_invalidate_map_cache_entry(uint8_t *buffer); +void xen_invalidate_map_cache(void); #endif /* !XEN_MAPCACHE_H */ diff --git a/xen-stub.c b/xen-stub.c index a4f35a19fb..efe2ab55f2 100644 --- a/xen-stub.c +++ b/xen-stub.c @@ -9,6 +9,10 @@ #include "qemu-common.h" #include "hw/xen.h" +void xenstore_store_pv_console_info(int i, CharDriverState *chr) +{ +} + int xen_pci_slot_get_pirq(PCIDevice *pci_dev, int irq_num) { return -1; |