diff options
88 files changed, 812 insertions, 462 deletions
diff --git a/accel/kvm/kvm-all.c b/accel/kvm/kvm-all.c index 0125c17edb..cace5ffe64 100644 --- a/accel/kvm/kvm-all.c +++ b/accel/kvm/kvm-all.c @@ -2469,7 +2469,7 @@ static int kvm_init(MachineState *ms) ret = kvm_vm_enable_cap(s, KVM_CAP_DIRTY_LOG_RING, 0, ring_bytes); if (ret) { error_report("Enabling of KVM dirty ring failed: %s. " - "Suggested mininum value is 1024.", strerror(-ret)); + "Suggested minimum value is 1024.", strerror(-ret)); goto err; } diff --git a/block/file-posix.c b/block/file-posix.c index 9f35e5631a..d81e15efa4 100644 --- a/block/file-posix.c +++ b/block/file-posix.c @@ -1705,7 +1705,7 @@ static int handle_aiocb_write_zeroes(void *opaque) */ warn_report_once("Your file system is misbehaving: " "fallocate(FALLOC_FL_PUNCH_HOLE) returned EINVAL. " - "Please report this bug to your file sytem " + "Please report this bug to your file system " "vendor."); } else if (ret != -ENOTSUP) { return ret; diff --git a/configure b/configure index da2501489f..1043ccce4f 100755 --- a/configure +++ b/configure @@ -5052,7 +5052,9 @@ for bios_file in \ $source_path/pc-bios/openbios-* \ $source_path/pc-bios/u-boot.* \ $source_path/pc-bios/edk2-*.fd.bz2 \ - $source_path/pc-bios/palcode-* + $source_path/pc-bios/palcode-* \ + $source_path/pc-bios/qemu_vga.ndrv + do LINKS="$LINKS pc-bios/$(basename $bios_file)" done diff --git a/gdbstub.c b/gdbstub.c index 5d8e6ae3cd..36b85aa50e 100644 --- a/gdbstub.c +++ b/gdbstub.c @@ -31,13 +31,13 @@ #include "qemu/cutils.h" #include "qemu/module.h" #include "trace/trace-root.h" +#include "exec/gdbstub.h" #ifdef CONFIG_USER_ONLY #include "qemu.h" #else #include "monitor/monitor.h" #include "chardev/char.h" #include "chardev/char-fe.h" -#include "exec/gdbstub.h" #include "hw/cpu/cluster.h" #include "hw/boards.h" #endif diff --git a/hw/display/qxl.c b/hw/display/qxl.c index 43482d4364..29c80b4289 100644 --- a/hw/display/qxl.c +++ b/hw/display/qxl.c @@ -2252,7 +2252,7 @@ static int qxl_pre_save(void *opaque) } else { d->last_release_offset = (uint8_t *)d->last_release - ram_start; } - if (d->last_release_offset < d->vga.vram_size) { + if (d->last_release_offset >= d->vga.vram_size) { return 1; } diff --git a/hw/display/virtio-gpu-udmabuf.c b/hw/display/virtio-gpu-udmabuf.c index 3c01a415e7..c6f7f58784 100644 --- a/hw/display/virtio-gpu-udmabuf.c +++ b/hw/display/virtio-gpu-udmabuf.c @@ -185,6 +185,7 @@ static VGPUDMABuf dmabuf->buf.stride = fb->stride; dmabuf->buf.fourcc = qemu_pixman_to_drm_format(fb->format); dmabuf->buf.fd = res->dmabuf_fd; + dmabuf->buf.allow_fences = true; dmabuf->scanout_id = scanout_id; QTAILQ_INSERT_HEAD(&g->dmabuf.bufs, dmabuf, next); diff --git a/hw/display/virtio-gpu.c b/hw/display/virtio-gpu.c index 72da5bf500..182e0868b0 100644 --- a/hw/display/virtio-gpu.c +++ b/hw/display/virtio-gpu.c @@ -985,8 +985,10 @@ void virtio_gpu_simple_process_cmd(VirtIOGPU *g, break; } if (!cmd->finished) { - virtio_gpu_ctrl_response_nodata(g, cmd, cmd->error ? cmd->error : - VIRTIO_GPU_RESP_OK_NODATA); + if (!g->parent_obj.renderer_blocked) { + virtio_gpu_ctrl_response_nodata(g, cmd, cmd->error ? cmd->error : + VIRTIO_GPU_RESP_OK_NODATA); + } } } @@ -1042,6 +1044,30 @@ void virtio_gpu_process_cmdq(VirtIOGPU *g) g->processing_cmdq = false; } +static void virtio_gpu_process_fenceq(VirtIOGPU *g) +{ + struct virtio_gpu_ctrl_command *cmd, *tmp; + + QTAILQ_FOREACH_SAFE(cmd, &g->fenceq, next, tmp) { + trace_virtio_gpu_fence_resp(cmd->cmd_hdr.fence_id); + virtio_gpu_ctrl_response_nodata(g, cmd, VIRTIO_GPU_RESP_OK_NODATA); + QTAILQ_REMOVE(&g->fenceq, cmd, next); + g_free(cmd); + g->inflight--; + if (virtio_gpu_stats_enabled(g->parent_obj.conf)) { + fprintf(stderr, "inflight: %3d (-)\r", g->inflight); + } + } +} + +static void virtio_gpu_handle_gl_flushed(VirtIOGPUBase *b) +{ + VirtIOGPU *g = container_of(b, VirtIOGPU, parent_obj); + + virtio_gpu_process_fenceq(g); + virtio_gpu_process_cmdq(g); +} + static void virtio_gpu_handle_ctrl(VirtIODevice *vdev, VirtQueue *vq) { VirtIOGPU *g = VIRTIO_GPU(vdev); @@ -1400,10 +1426,12 @@ static void virtio_gpu_class_init(ObjectClass *klass, void *data) DeviceClass *dc = DEVICE_CLASS(klass); VirtioDeviceClass *vdc = VIRTIO_DEVICE_CLASS(klass); VirtIOGPUClass *vgc = VIRTIO_GPU_CLASS(klass); + VirtIOGPUBaseClass *vgbc = &vgc->parent; vgc->handle_ctrl = virtio_gpu_handle_ctrl; vgc->process_cmd = virtio_gpu_simple_process_cmd; vgc->update_cursor_data = virtio_gpu_update_cursor_data; + vgbc->gl_flushed = virtio_gpu_handle_gl_flushed; vdc->realize = virtio_gpu_device_realize; vdc->reset = virtio_gpu_reset; diff --git a/hw/i386/acpi-build.c b/hw/i386/acpi-build.c index d1f5fa3b5a..dfaa47cdc2 100644 --- a/hw/i386/acpi-build.c +++ b/hw/i386/acpi-build.c @@ -1916,7 +1916,7 @@ build_srat(GArray *table_data, BIOSLinker *linker, MachineState *machine) PCMachineState *pcms = PC_MACHINE(machine); int nb_numa_nodes = machine->numa_state->num_nodes; NodeInfo *numa_info = machine->numa_state->nodes; - ram_addr_t hotplugabble_address_space_size = + ram_addr_t hotpluggable_address_space_size = object_property_get_int(OBJECT(pcms), PC_MACHINE_DEVMEM_REGION_SIZE, NULL); @@ -2022,10 +2022,10 @@ build_srat(GArray *table_data, BIOSLinker *linker, MachineState *machine) * Memory devices may override proximity set by this entry, * providing _PXM method if necessary. */ - if (hotplugabble_address_space_size) { + if (hotpluggable_address_space_size) { numamem = acpi_data_push(table_data, sizeof *numamem); build_srat_memory(numamem, machine->device_memory->base, - hotplugabble_address_space_size, nb_numa_nodes - 1, + hotpluggable_address_space_size, nb_numa_nodes - 1, MEM_AFFINITY_HOTPLUGGABLE | MEM_AFFINITY_ENABLED); } diff --git a/hw/i386/intel_iommu.c b/hw/i386/intel_iommu.c index 209b3f5553..75f075547f 100644 --- a/hw/i386/intel_iommu.c +++ b/hw/i386/intel_iommu.c @@ -679,7 +679,7 @@ static inline bool vtd_pe_type_check(X86IOMMUState *x86_iommu, } break; default: - /* Unknwon type */ + /* Unknown type */ return false; } return true; @@ -692,7 +692,7 @@ static inline bool vtd_pdire_present(VTDPASIDDirEntry *pdire) /** * Caller of this function should check present bit if wants - * to use pdir entry for futher usage except for fpd bit check. + * to use pdir entry for further usage except for fpd bit check. */ static int vtd_get_pdire_from_pdir_table(dma_addr_t pasid_dir_base, uint32_t pasid, @@ -746,7 +746,7 @@ static int vtd_get_pe_in_pasid_leaf_table(IntelIOMMUState *s, /** * Caller of this function should check present bit if wants - * to use pasid entry for futher usage except for fpd bit check. + * to use pasid entry for further usage except for fpd bit check. */ static int vtd_get_pe_from_pdire(IntelIOMMUState *s, uint32_t pasid, @@ -1507,7 +1507,7 @@ static int vtd_sync_shadow_page_table(VTDAddressSpace *vtd_as) } /* - * Check if specific device is configed to bypass address + * Check if specific device is configured to bypass address * translation for DMA requests. In Scalable Mode, bypass * 1st-level translation or 2nd-level translation, it depends * on PGTT setting. diff --git a/hw/vfio/igd.c b/hw/vfio/igd.c index 470205f487..d4685709a3 100644 --- a/hw/vfio/igd.c +++ b/hw/vfio/igd.c @@ -557,7 +557,7 @@ void vfio_probe_igd_bar4_quirk(VFIOPCIDevice *vdev, int nr) * must allocate a 1MB aligned reserved memory region below 4GB with * the requested size (in bytes) for use by the Intel PCI class VGA * device at VM address 00:02.0. The base address of this reserved - * memory region must be written to the device BDSM regsiter at PCI + * memory region must be written to the device BDSM register at PCI * config offset 0x5C. */ bdsm_size = g_malloc(sizeof(*bdsm_size)); diff --git a/hw/vfio/pci-quirks.c b/hw/vfio/pci-quirks.c index e21a6ede11..0cf69a8c6d 100644 --- a/hw/vfio/pci-quirks.c +++ b/hw/vfio/pci-quirks.c @@ -1356,7 +1356,7 @@ static bool vfio_radeon_smc_is_running(VFIOPCIDevice *vdev) /* * The scope of a config reset is controlled by a mode bit in the misc register * and a fuse, exposed as a bit in another register. The fuse is the default - * (0 = GFX, 1 = whole GPU), the misc bit is a toggle, with the forumula + * (0 = GFX, 1 = whole GPU), the misc bit is a toggle, with the formula * scope = !(misc ^ fuse), where the resulting scope is defined the same as * the fuse. A truth table therefore tells us that if misc == fuse, we need * to flip the value of the bit in the misc register. diff --git a/hw/vfio/pci.c b/hw/vfio/pci.c index e1ea1d8a23..4feaa1cb68 100644 --- a/hw/vfio/pci.c +++ b/hw/vfio/pci.c @@ -1364,7 +1364,7 @@ static void vfio_pci_relocate_msix(VFIOPCIDevice *vdev, Error **errp) * TODO: Lookup table for known devices. * * Logically we might use an algorithm here to select the BAR adding - * the least additional MMIO space, but we cannot programatically + * the least additional MMIO space, but we cannot programmatically * predict the driver dependency on BAR ordering or sizing, therefore * 'auto' becomes a lookup for combinations reported to work. */ @@ -2158,7 +2158,7 @@ static void vfio_pci_pre_reset(VFIOPCIDevice *vdev) } /* - * Stop any ongoing DMA by disconecting I/O, MMIO, and bus master. + * Stop any ongoing DMA by disconnecting I/O, MMIO, and bus master. * Also put INTx Disable in known state. */ cmd = vfio_pci_read_config(pdev, PCI_COMMAND, 2); @@ -2384,7 +2384,7 @@ out_single: } /* - * We want to differentiate hot reset of mulitple in-use devices vs hot reset + * We want to differentiate hot reset of multiple in-use devices vs hot reset * of a single in-use device. VFIO_DEVICE_RESET will already handle the case * of doing hot resets when there is only a single device per bus. The in-use * here refers to how many VFIODevices are affected. A hot reset that affects diff --git a/hw/vfio/platform.c b/hw/vfio/platform.c index cc3f66f7e4..f8f08a0f36 100644 --- a/hw/vfio/platform.c +++ b/hw/vfio/platform.c @@ -156,7 +156,7 @@ static void vfio_mmap_set_enabled(VFIOPlatformDevice *vdev, bool enabled) * if there is no more active IRQ * @opaque: actually points to the VFIO platform device * - * Called on mmap timer timout, this function checks whether the + * Called on mmap timer timeout, this function checks whether the * IRQ is still active and if not, restores the fast path. * by construction a single eventfd is handled at a time. * if the IRQ is still active, the timer is re-programmed. diff --git a/include/hw/qdev-core.h b/include/hw/qdev-core.h index 762f9584dd..34c8a7506a 100644 --- a/include/hw/qdev-core.h +++ b/include/hw/qdev-core.h @@ -598,6 +598,10 @@ void qdev_init_gpio_in(DeviceState *dev, qemu_irq_handler handler, int n); * * See qdev_connect_gpio_out() for how code that uses such a device * can connect to one of its output GPIO lines. + * + * There is no need to release the @pins allocated array because it + * will be automatically released when @dev calls its instance_finalize() + * handler. */ void qdev_init_gpio_out(DeviceState *dev, qemu_irq *pins, int n); /** diff --git a/include/ui/console.h b/include/ui/console.h index 3be21497a2..244664d727 100644 --- a/include/ui/console.h +++ b/include/ui/console.h @@ -168,6 +168,9 @@ typedef struct QemuDmaBuf { uint64_t modifier; uint32_t texture; bool y0_top; + void *sync; + int fence_fd; + bool allow_fences; } QemuDmaBuf; typedef struct DisplayState DisplayState; diff --git a/include/ui/egl-helpers.h b/include/ui/egl-helpers.h index f1bf8f97fc..2fb6e0dd6b 100644 --- a/include/ui/egl-helpers.h +++ b/include/ui/egl-helpers.h @@ -19,6 +19,7 @@ typedef struct egl_fb { GLuint texture; GLuint framebuffer; bool delete_texture; + QemuDmaBuf *dmabuf; } egl_fb; void egl_fb_destroy(egl_fb *fb); @@ -45,6 +46,8 @@ int egl_get_fd_for_texture(uint32_t tex_id, EGLint *stride, EGLint *fourcc, void egl_dmabuf_import_texture(QemuDmaBuf *dmabuf); void egl_dmabuf_release_texture(QemuDmaBuf *dmabuf); +void egl_dmabuf_create_sync(QemuDmaBuf *dmabuf); +void egl_dmabuf_create_fence(QemuDmaBuf *dmabuf); #endif diff --git a/include/ui/gtk.h b/include/ui/gtk.h index 7835ef1a71..7d22affd38 100644 --- a/include/ui/gtk.h +++ b/include/ui/gtk.h @@ -155,6 +155,7 @@ extern bool gtk_use_gl_area; /* ui/gtk.c */ void gd_update_windowsize(VirtualConsole *vc); int gd_monitor_update_interval(GtkWidget *widget); +void gd_hw_gl_flushed(void *vc); /* ui/gtk-egl.c */ void gd_egl_init(VirtualConsole *vc); @@ -181,8 +182,8 @@ void gd_egl_cursor_dmabuf(DisplayChangeListener *dcl, uint32_t hot_x, uint32_t hot_y); void gd_egl_cursor_position(DisplayChangeListener *dcl, uint32_t pos_x, uint32_t pos_y); -void gd_egl_release_dmabuf(DisplayChangeListener *dcl, - QemuDmaBuf *dmabuf); +void gd_egl_flush(DisplayChangeListener *dcl, + uint32_t x, uint32_t y, uint32_t w, uint32_t h); void gd_egl_scanout_flush(DisplayChangeListener *dcl, uint32_t x, uint32_t y, uint32_t w, uint32_t h); void gtk_egl_init(DisplayGLMode mode); diff --git a/linux-user/aarch64/cpu_loop.c b/linux-user/aarch64/cpu_loop.c index ee72a1c20f..5425b85659 100644 --- a/linux-user/aarch64/cpu_loop.c +++ b/linux-user/aarch64/cpu_loop.c @@ -20,7 +20,9 @@ #include "qemu/osdep.h" #include "qemu-common.h" #include "qemu.h" +#include "user-internals.h" #include "cpu_loop-common.h" +#include "signal-common.h" #include "qemu/guest-random.h" #include "semihosting/common-semi.h" #include "target/arm/syndrome.h" diff --git a/linux-user/aarch64/signal.c b/linux-user/aarch64/signal.c index 662bcd1c4e..49025648cb 100644 --- a/linux-user/aarch64/signal.c +++ b/linux-user/aarch64/signal.c @@ -18,6 +18,7 @@ */ #include "qemu/osdep.h" #include "qemu.h" +#include "user-internals.h" #include "signal-common.h" #include "linux-user/trace.h" diff --git a/linux-user/alpha/cpu_loop.c b/linux-user/alpha/cpu_loop.c index 7ce2461a02..1b00a81385 100644 --- a/linux-user/alpha/cpu_loop.c +++ b/linux-user/alpha/cpu_loop.c @@ -20,7 +20,9 @@ #include "qemu/osdep.h" #include "qemu-common.h" #include "qemu.h" +#include "user-internals.h" #include "cpu_loop-common.h" +#include "signal-common.h" void cpu_loop(CPUAlphaState *env) { diff --git a/linux-user/alpha/signal.c b/linux-user/alpha/signal.c index 1129ffeea1..3a820f616b 100644 --- a/linux-user/alpha/signal.c +++ b/linux-user/alpha/signal.c @@ -18,6 +18,7 @@ */ #include "qemu/osdep.h" #include "qemu.h" +#include "user-internals.h" #include "signal-common.h" #include "linux-user/trace.h" diff --git a/linux-user/arm/cpu_loop.c b/linux-user/arm/cpu_loop.c index 69632d15be..07032b3006 100644 --- a/linux-user/arm/cpu_loop.c +++ b/linux-user/arm/cpu_loop.c @@ -20,8 +20,10 @@ #include "qemu/osdep.h" #include "qemu-common.h" #include "qemu.h" +#include "user-internals.h" #include "elf.h" #include "cpu_loop-common.h" +#include "signal-common.h" #include "semihosting/common-semi.h" #define get_user_code_u32(x, gaddr, env) \ diff --git a/linux-user/arm/signal.c b/linux-user/arm/signal.c index 1dfcfd2d57..ed144f9455 100644 --- a/linux-user/arm/signal.c +++ b/linux-user/arm/signal.c @@ -18,6 +18,7 @@ */ #include "qemu/osdep.h" #include "qemu.h" +#include "user-internals.h" #include "signal-common.h" #include "linux-user/trace.h" diff --git a/linux-user/cris/cpu_loop.c b/linux-user/cris/cpu_loop.c index 334edddd1e..b9085619c4 100644 --- a/linux-user/cris/cpu_loop.c +++ b/linux-user/cris/cpu_loop.c @@ -20,7 +20,9 @@ #include "qemu/osdep.h" #include "qemu-common.h" #include "qemu.h" +#include "user-internals.h" #include "cpu_loop-common.h" +#include "signal-common.h" void cpu_loop(CPUCRISState *env) { diff --git a/linux-user/cris/signal.c b/linux-user/cris/signal.c index 1e02194377..2c39bdf727 100644 --- a/linux-user/cris/signal.c +++ b/linux-user/cris/signal.c @@ -18,6 +18,7 @@ */ #include "qemu/osdep.h" #include "qemu.h" +#include "user-internals.h" #include "signal-common.h" #include "linux-user/trace.h" diff --git a/linux-user/elfload.c b/linux-user/elfload.c index 01e9a833fb..5f9e2141ad 100644 --- a/linux-user/elfload.c +++ b/linux-user/elfload.c @@ -6,6 +6,9 @@ #include <sys/shm.h> #include "qemu.h" +#include "user-internals.h" +#include "loader.h" +#include "user-mmap.h" #include "disas/disas.h" #include "qemu/bitops.h" #include "qemu/path.h" diff --git a/linux-user/exit.c b/linux-user/exit.c index 527e29cbc1..fa6ef0b9b4 100644 --- a/linux-user/exit.c +++ b/linux-user/exit.c @@ -17,7 +17,9 @@ * along with this program; if not, see <http://www.gnu.org/licenses/>. */ #include "qemu/osdep.h" +#include "exec/gdbstub.h" #include "qemu.h" +#include "user-internals.h" #ifdef CONFIG_GPROF #include <sys/gmon.h> #endif diff --git a/linux-user/fd-trans.c b/linux-user/fd-trans.c index 86b6f484d3..6941089959 100644 --- a/linux-user/fd-trans.c +++ b/linux-user/fd-trans.c @@ -27,7 +27,9 @@ #include <linux/if_bridge.h> #endif #include "qemu.h" +#include "user-internals.h" #include "fd-trans.h" +#include "signal-common.h" enum { QEMU_IFLA_BR_UNSPEC, diff --git a/linux-user/flatload.c b/linux-user/flatload.c index 3e5594cf89..e4c2f89a22 100644 --- a/linux-user/flatload.c +++ b/linux-user/flatload.c @@ -36,6 +36,9 @@ #include "qemu/osdep.h" #include "qemu.h" +#include "user-internals.h" +#include "loader.h" +#include "user-mmap.h" #include "flat.h" #include "target_flat.h" diff --git a/linux-user/hexagon/cpu_loop.c b/linux-user/hexagon/cpu_loop.c index bc34f5d7c3..bee2a9e4ea 100644 --- a/linux-user/hexagon/cpu_loop.c +++ b/linux-user/hexagon/cpu_loop.c @@ -20,7 +20,9 @@ #include "qemu/osdep.h" #include "qemu.h" +#include "user-internals.h" #include "cpu_loop-common.h" +#include "signal-common.h" #include "internal.h" void cpu_loop(CPUHexagonState *env) diff --git a/linux-user/hexagon/signal.c b/linux-user/hexagon/signal.c index 85eab5e943..c7f0bf6b92 100644 --- a/linux-user/hexagon/signal.c +++ b/linux-user/hexagon/signal.c @@ -19,6 +19,7 @@ */ #include "qemu/osdep.h" #include "qemu.h" +#include "user-internals.h" #include "signal-common.h" #include "linux-user/trace.h" diff --git a/linux-user/hppa/cpu_loop.c b/linux-user/hppa/cpu_loop.c index 82d8183821..81607a9b27 100644 --- a/linux-user/hppa/cpu_loop.c +++ b/linux-user/hppa/cpu_loop.c @@ -19,7 +19,9 @@ #include "qemu/osdep.h" #include "qemu.h" +#include "user-internals.h" #include "cpu_loop-common.h" +#include "signal-common.h" static abi_ulong hppa_lws(CPUHPPAState *env) { diff --git a/linux-user/hppa/signal.c b/linux-user/hppa/signal.c index 0e266f472d..c2fbc26ebb 100644 --- a/linux-user/hppa/signal.c +++ b/linux-user/hppa/signal.c @@ -18,6 +18,7 @@ */ #include "qemu/osdep.h" #include "qemu.h" +#include "user-internals.h" #include "signal-common.h" #include "linux-user/trace.h" diff --git a/linux-user/i386/cpu_loop.c b/linux-user/i386/cpu_loop.c index f813e87294..f6a1cc632b 100644 --- a/linux-user/i386/cpu_loop.c +++ b/linux-user/i386/cpu_loop.c @@ -20,7 +20,10 @@ #include "qemu/osdep.h" #include "qemu-common.h" #include "qemu.h" +#include "user-internals.h" #include "cpu_loop-common.h" +#include "signal-common.h" +#include "user-mmap.h" /***********************************************************/ /* CPUX86 core interface */ diff --git a/linux-user/i386/signal.c b/linux-user/i386/signal.c index 841cd19651..3b4b55fc0a 100644 --- a/linux-user/i386/signal.c +++ b/linux-user/i386/signal.c @@ -18,6 +18,7 @@ */ #include "qemu/osdep.h" #include "qemu.h" +#include "user-internals.h" #include "signal-common.h" #include "linux-user/trace.h" diff --git a/linux-user/linuxload.c b/linux-user/linuxload.c index 9d4eb5e94b..2ed5fc45ed 100644 --- a/linux-user/linuxload.c +++ b/linux-user/linuxload.c @@ -2,6 +2,8 @@ #include "qemu/osdep.h" #include "qemu.h" +#include "user-internals.h" +#include "loader.h" #define NGROUPS 32 diff --git a/linux-user/loader.h b/linux-user/loader.h new file mode 100644 index 0000000000..f375ee0679 --- /dev/null +++ b/linux-user/loader.h @@ -0,0 +1,59 @@ +/* + * loader.h: prototypes for linux-user guest binary loader + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef LINUX_USER_LOADER_H +#define LINUX_USER_LOADER_H + +/* + * Read a good amount of data initially, to hopefully get all the + * program headers loaded. + */ +#define BPRM_BUF_SIZE 1024 + +/* + * This structure is used to hold the arguments that are + * used when loading binaries. + */ +struct linux_binprm { + char buf[BPRM_BUF_SIZE] __attribute__((aligned)); + abi_ulong p; + int fd; + int e_uid, e_gid; + int argc, envc; + char **argv; + char **envp; + char *filename; /* Name of binary */ + int (*core_dump)(int, const CPUArchState *); /* coredump routine */ +}; + +void do_init_thread(struct target_pt_regs *regs, struct image_info *infop); +abi_ulong loader_build_argptr(int envc, int argc, abi_ulong sp, + abi_ulong stringp, int push_ptr); +int loader_exec(int fdexec, const char *filename, char **argv, char **envp, + struct target_pt_regs *regs, struct image_info *infop, + struct linux_binprm *); + +uint32_t get_elf_eflags(int fd); +int load_elf_binary(struct linux_binprm *bprm, struct image_info *info); +int load_flt_binary(struct linux_binprm *bprm, struct image_info *info); + +abi_long memcpy_to_target(abi_ulong dest, const void *src, + unsigned long len); + +extern unsigned long guest_stack_size; + +#endif /* LINUX_USER_LOADER_H */ diff --git a/linux-user/m68k/cpu_loop.c b/linux-user/m68k/cpu_loop.c index c7a500b58c..ebf32be78f 100644 --- a/linux-user/m68k/cpu_loop.c +++ b/linux-user/m68k/cpu_loop.c @@ -20,7 +20,9 @@ #include "qemu/osdep.h" #include "qemu-common.h" #include "qemu.h" +#include "user-internals.h" #include "cpu_loop-common.h" +#include "signal-common.h" void cpu_loop(CPUM68KState *env) { diff --git a/linux-user/m68k/signal.c b/linux-user/m68k/signal.c index d06230655e..4f8eb6f727 100644 --- a/linux-user/m68k/signal.c +++ b/linux-user/m68k/signal.c @@ -18,6 +18,7 @@ */ #include "qemu/osdep.h" #include "qemu.h" +#include "user-internals.h" #include "signal-common.h" #include "linux-user/trace.h" diff --git a/linux-user/main.c b/linux-user/main.c index 45bde4598d..16def5215d 100644 --- a/linux-user/main.c +++ b/linux-user/main.c @@ -30,6 +30,7 @@ #include "qapi/error.h" #include "qemu.h" +#include "user-internals.h" #include "qemu/path.h" #include "qemu/queue.h" #include "qemu/config-file.h" @@ -39,6 +40,7 @@ #include "qemu/module.h" #include "qemu/plugin.h" #include "exec/exec-all.h" +#include "exec/gdbstub.h" #include "tcg/tcg.h" #include "qemu/timer.h" #include "qemu/envlist.h" @@ -49,6 +51,9 @@ #include "cpu_loop-common.h" #include "crypto/init.h" #include "fd-trans.h" +#include "signal-common.h" +#include "loader.h" +#include "user-mmap.h" #ifndef AT_FLAGS_PRESERVE_ARGV0 #define AT_FLAGS_PRESERVE_ARGV0_BIT 0 diff --git a/linux-user/microblaze/cpu_loop.c b/linux-user/microblaze/cpu_loop.c index c3396a6e09..52222eb93f 100644 --- a/linux-user/microblaze/cpu_loop.c +++ b/linux-user/microblaze/cpu_loop.c @@ -20,7 +20,9 @@ #include "qemu/osdep.h" #include "qemu-common.h" #include "qemu.h" +#include "user-internals.h" #include "cpu_loop-common.h" +#include "signal-common.h" void cpu_loop(CPUMBState *env) { diff --git a/linux-user/microblaze/signal.c b/linux-user/microblaze/signal.c index 4c483bd8c6..b822679d18 100644 --- a/linux-user/microblaze/signal.c +++ b/linux-user/microblaze/signal.c @@ -18,6 +18,7 @@ */ #include "qemu/osdep.h" #include "qemu.h" +#include "user-internals.h" #include "signal-common.h" #include "linux-user/trace.h" diff --git a/linux-user/mips/cpu_loop.c b/linux-user/mips/cpu_loop.c index 9d813ece4e..cb03fb066b 100644 --- a/linux-user/mips/cpu_loop.c +++ b/linux-user/mips/cpu_loop.c @@ -20,7 +20,9 @@ #include "qemu/osdep.h" #include "qemu-common.h" #include "qemu.h" +#include "user-internals.h" #include "cpu_loop-common.h" +#include "signal-common.h" #include "elf.h" #include "internal.h" #include "fpu_helper.h" diff --git a/linux-user/mips/signal.c b/linux-user/mips/signal.c index e6be807a81..d174b3453c 100644 --- a/linux-user/mips/signal.c +++ b/linux-user/mips/signal.c @@ -18,6 +18,7 @@ */ #include "qemu/osdep.h" #include "qemu.h" +#include "user-internals.h" #include "signal-common.h" #include "linux-user/trace.h" diff --git a/linux-user/mmap.c b/linux-user/mmap.c index 0e103859fe..c125031b90 100644 --- a/linux-user/mmap.c +++ b/linux-user/mmap.c @@ -20,6 +20,8 @@ #include "trace.h" #include "exec/log.h" #include "qemu.h" +#include "user-internals.h" +#include "user-mmap.h" static pthread_mutex_t mmap_mutex = PTHREAD_MUTEX_INITIALIZER; static __thread int mmap_lock_count; diff --git a/linux-user/nios2/cpu_loop.c b/linux-user/nios2/cpu_loop.c index 9869083fa1..34290fb3b5 100644 --- a/linux-user/nios2/cpu_loop.c +++ b/linux-user/nios2/cpu_loop.c @@ -19,7 +19,9 @@ #include "qemu/osdep.h" #include "qemu.h" +#include "user-internals.h" #include "cpu_loop-common.h" +#include "signal-common.h" void cpu_loop(CPUNios2State *env) { diff --git a/linux-user/nios2/signal.c b/linux-user/nios2/signal.c index cc3872f11d..a77e8a40f4 100644 --- a/linux-user/nios2/signal.c +++ b/linux-user/nios2/signal.c @@ -18,6 +18,7 @@ */ #include "qemu/osdep.h" #include "qemu.h" +#include "user-internals.h" #include "signal-common.h" #include "linux-user/trace.h" diff --git a/linux-user/openrisc/cpu_loop.c b/linux-user/openrisc/cpu_loop.c index b33fa77718..f6360db47c 100644 --- a/linux-user/openrisc/cpu_loop.c +++ b/linux-user/openrisc/cpu_loop.c @@ -20,7 +20,9 @@ #include "qemu/osdep.h" #include "qemu-common.h" #include "qemu.h" +#include "user-internals.h" #include "cpu_loop-common.h" +#include "signal-common.h" void cpu_loop(CPUOpenRISCState *env) { diff --git a/linux-user/openrisc/signal.c b/linux-user/openrisc/signal.c index 5c5640a284..ca2532bf50 100644 --- a/linux-user/openrisc/signal.c +++ b/linux-user/openrisc/signal.c @@ -18,6 +18,7 @@ */ #include "qemu/osdep.h" #include "qemu.h" +#include "user-internals.h" #include "signal-common.h" #include "linux-user/trace.h" diff --git a/linux-user/ppc/cpu_loop.c b/linux-user/ppc/cpu_loop.c index fa91ea0eed..840b23736b 100644 --- a/linux-user/ppc/cpu_loop.c +++ b/linux-user/ppc/cpu_loop.c @@ -20,7 +20,9 @@ #include "qemu/osdep.h" #include "qemu-common.h" #include "qemu.h" +#include "user-internals.h" #include "cpu_loop-common.h" +#include "signal-common.h" static inline uint64_t cpu_ppc_get_tb(CPUPPCState *env) { diff --git a/linux-user/ppc/signal.c b/linux-user/ppc/signal.c index edfad28a37..e4d0dfa3bf 100644 --- a/linux-user/ppc/signal.c +++ b/linux-user/ppc/signal.c @@ -18,6 +18,7 @@ */ #include "qemu/osdep.h" #include "qemu.h" +#include "user-internals.h" #include "signal-common.h" #include "linux-user/trace.h" diff --git a/linux-user/qemu.h b/linux-user/qemu.h index 3b0b6b75fe..5c713fa8ab 100644 --- a/linux-user/qemu.h +++ b/linux-user/qemu.h @@ -1,26 +1,24 @@ #ifndef QEMU_H #define QEMU_H -#include "hostdep.h" #include "cpu.h" -#include "exec/exec-all.h" #include "exec/cpu_ldst.h" #undef DEBUG_REMAP #include "exec/user/abitypes.h" -#include "exec/user/thunk.h" #include "syscall_defs.h" #include "target_syscall.h" -#include "exec/gdbstub.h" -/* This is the size of the host kernel's sigset_t, needed where we make +/* + * This is the size of the host kernel's sigset_t, needed where we make * direct system calls that take a sigset_t pointer and a size. */ #define SIGSET_T_SIZE (_NSIG / 8) -/* This struct is used to hold certain information about the image. +/* + * This struct is used to hold certain information about the image. * Basically, it replicates in user space what would be certain * task_struct fields in the kernel */ @@ -48,13 +46,13 @@ struct image_info { abi_ulong env_strings; abi_ulong file_string; uint32_t elf_flags; - int personality; + int personality; abi_ulong alignment; /* The fields below are used in FDPIC mode. */ abi_ulong loadmap_addr; uint16_t nsegs; - void *loadsegs; + void *loadsegs; abi_ulong pt_dynamic_addr; abi_ulong interpreter_loadmap_addr; abi_ulong interpreter_pt_dynamic_addr; @@ -98,8 +96,10 @@ struct emulated_sigtable { target_siginfo_t info; }; -/* NOTE: we force a big alignment so that the stack stored after is - aligned too */ +/* + * NOTE: we force a big alignment so that the stack stored after is + * aligned too + */ typedef struct TaskState { pid_t ts_tid; /* tid (or pid) of this task */ #ifdef TARGET_ARM @@ -134,20 +134,23 @@ typedef struct TaskState { struct emulated_sigtable sync_signal; struct emulated_sigtable sigtab[TARGET_NSIG]; - /* This thread's signal mask, as requested by the guest program. + /* + * This thread's signal mask, as requested by the guest program. * The actual signal mask of this thread may differ: * + we don't let SIGSEGV and SIGBUS be blocked while running guest code * + sometimes we block all signals to avoid races */ sigset_t signal_mask; - /* The signal mask imposed by a guest sigsuspend syscall, if we are + /* + * The signal mask imposed by a guest sigsuspend syscall, if we are * currently in the middle of such a syscall */ sigset_t sigsuspend_mask; /* Nonzero if we're leaving a sigsuspend and sigsuspend_mask is valid. */ int in_sigsuspend; - /* Nonzero if process_pending_signals() needs to do something (either + /* + * Nonzero if process_pending_signals() needs to do something (either * handle a pending signal or unblock signals). * This flag is written from a signal handler so should be accessed via * the qatomic_read() and qatomic_set() functions. (It is not accessed @@ -159,331 +162,7 @@ typedef struct TaskState { struct target_sigaltstack sigaltstack_used; } __attribute__((aligned(16))) TaskState; -extern char *exec_path; -void init_task_state(TaskState *ts); -void task_settid(TaskState *); -void stop_all_tasks(void); -extern const char *qemu_uname_release; -extern unsigned long mmap_min_addr; - -/* ??? See if we can avoid exposing so much of the loader internals. */ - -/* Read a good amount of data initially, to hopefully get all the - program headers loaded. */ -#define BPRM_BUF_SIZE 1024 - -/* - * This structure is used to hold the arguments that are - * used when loading binaries. - */ -struct linux_binprm { - char buf[BPRM_BUF_SIZE] __attribute__((aligned)); - abi_ulong p; - int fd; - int e_uid, e_gid; - int argc, envc; - char **argv; - char **envp; - char * filename; /* Name of binary */ - int (*core_dump)(int, const CPUArchState *); /* coredump routine */ -}; - -typedef struct IOCTLEntry IOCTLEntry; - -typedef abi_long do_ioctl_fn(const IOCTLEntry *ie, uint8_t *buf_temp, - int fd, int cmd, abi_long arg); - -struct IOCTLEntry { - int target_cmd; - unsigned int host_cmd; - const char *name; - int access; - do_ioctl_fn *do_ioctl; - const argtype arg_type[5]; -}; - -extern IOCTLEntry ioctl_entries[]; - -#define IOC_R 0x0001 -#define IOC_W 0x0002 -#define IOC_RW (IOC_R | IOC_W) - -void do_init_thread(struct target_pt_regs *regs, struct image_info *infop); -abi_ulong loader_build_argptr(int envc, int argc, abi_ulong sp, - abi_ulong stringp, int push_ptr); -int loader_exec(int fdexec, const char *filename, char **argv, char **envp, - struct target_pt_regs * regs, struct image_info *infop, - struct linux_binprm *); - -/* Returns true if the image uses the FDPIC ABI. If this is the case, - * we have to provide some information (loadmap, pt_dynamic_info) such - * that the program can be relocated adequately. This is also useful - * when handling signals. - */ -int info_is_fdpic(struct image_info *info); - -uint32_t get_elf_eflags(int fd); -int load_elf_binary(struct linux_binprm *bprm, struct image_info *info); -int load_flt_binary(struct linux_binprm *bprm, struct image_info *info); - -abi_long memcpy_to_target(abi_ulong dest, const void *src, - unsigned long len); -void target_set_brk(abi_ulong new_brk); 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 arg7, - abi_long arg8); -extern __thread CPUState *thread_cpu; -void cpu_loop(CPUArchState *env); -const char *target_strerror(int err); -int get_osversion(void); -void init_qemu_uname_release(void); -void fork_start(void); -void fork_end(int child); - -/** - * probe_guest_base: - * @image_name: the executable being loaded - * @loaddr: the lowest fixed address in the executable - * @hiaddr: the highest fixed address in the executable - * - * Creates the initial guest address space in the host memory space. - * - * If @loaddr == 0, then no address in the executable is fixed, - * i.e. it is fully relocatable. In that case @hiaddr is the size - * of the executable. - * - * This function will not return if a valid value for guest_base - * cannot be chosen. On return, the executable loader can expect - * - * target_mmap(loaddr, hiaddr - loaddr, ...) - * - * to succeed. - */ -void probe_guest_base(const char *image_name, - abi_ulong loaddr, abi_ulong hiaddr); - -#include "qemu/log.h" - -/* safe_syscall.S */ - -/** - * safe_syscall: - * @int number: number of system call to make - * ...: arguments to the system call - * - * Call a system call if guest signal not pending. - * This has the same API as the libc syscall() function, except that it - * may return -1 with errno == TARGET_ERESTARTSYS if a signal was pending. - * - * Returns: the system call result, or -1 with an error code in errno - * (Errnos are host errnos; we rely on TARGET_ERESTARTSYS not clashing - * with any of the host errno values.) - */ - -/* A guide to using safe_syscall() to handle interactions between guest - * syscalls and guest signals: - * - * Guest syscalls come in two flavours: - * - * (1) Non-interruptible syscalls - * - * These are guest syscalls that never get interrupted by signals and - * so never return EINTR. They can be implemented straightforwardly in - * QEMU: just make sure that if the implementation code has to make any - * blocking calls that those calls are retried if they return EINTR. - * It's also OK to implement these with safe_syscall, though it will be - * a little less efficient if a signal is delivered at the 'wrong' moment. - * - * Some non-interruptible syscalls need to be handled using block_signals() - * to block signals for the duration of the syscall. This mainly applies - * to code which needs to modify the data structures used by the - * host_signal_handler() function and the functions it calls, including - * all syscalls which change the thread's signal mask. - * - * (2) Interruptible syscalls - * - * These are guest syscalls that can be interrupted by signals and - * for which we need to either return EINTR or arrange for the guest - * syscall to be restarted. This category includes both syscalls which - * always restart (and in the kernel return -ERESTARTNOINTR), ones - * which only restart if there is no handler (kernel returns -ERESTARTNOHAND - * or -ERESTART_RESTARTBLOCK), and the most common kind which restart - * if the handler was registered with SA_RESTART (kernel returns - * -ERESTARTSYS). System calls which are only interruptible in some - * situations (like 'open') also need to be handled this way. - * - * Here it is important that the host syscall is made - * via this safe_syscall() function, and *not* via the host libc. - * If the host libc is used then the implementation will appear to work - * most of the time, but there will be a race condition where a - * signal could arrive just before we make the host syscall inside libc, - * and then then guest syscall will not correctly be interrupted. - * Instead the implementation of the guest syscall can use the safe_syscall - * function but otherwise just return the result or errno in the usual - * way; the main loop code will take care of restarting the syscall - * if appropriate. - * - * (If the implementation needs to make multiple host syscalls this is - * OK; any which might really block must be via safe_syscall(); for those - * which are only technically blocking (ie which we know in practice won't - * stay in the host kernel indefinitely) it's OK to use libc if necessary. - * You must be able to cope with backing out correctly if some safe_syscall - * you make in the implementation returns either -TARGET_ERESTARTSYS or - * EINTR though.) - * - * block_signals() cannot be used for interruptible syscalls. - * - * - * How and why the safe_syscall implementation works: - * - * The basic setup is that we make the host syscall via a known - * section of host native assembly. If a signal occurs, our signal - * handler checks the interrupted host PC against the addresse of that - * known section. If the PC is before or at the address of the syscall - * instruction then we change the PC to point at a "return - * -TARGET_ERESTARTSYS" code path instead, and then exit the signal handler - * (causing the safe_syscall() call to immediately return that value). - * Then in the main.c loop if we see this magic return value we adjust - * the guest PC to wind it back to before the system call, and invoke - * the guest signal handler as usual. - * - * This winding-back will happen in two cases: - * (1) signal came in just before we took the host syscall (a race); - * in this case we'll take the guest signal and have another go - * at the syscall afterwards, and this is indistinguishable for the - * guest from the timing having been different such that the guest - * signal really did win the race - * (2) signal came in while the host syscall was blocking, and the - * host kernel decided the syscall should be restarted; - * in this case we want to restart the guest syscall also, and so - * rewinding is the right thing. (Note that "restart" semantics mean - * "first call the signal handler, then reattempt the syscall".) - * The other situation to consider is when a signal came in while the - * host syscall was blocking, and the host kernel decided that the syscall - * should not be restarted; in this case QEMU's host signal handler will - * be invoked with the PC pointing just after the syscall instruction, - * with registers indicating an EINTR return; the special code in the - * handler will not kick in, and we will return EINTR to the guest as - * we should. - * - * Notice that we can leave the host kernel to make the decision for - * us about whether to do a restart of the syscall or not; we do not - * need to check SA_RESTART flags in QEMU or distinguish the various - * kinds of restartability. - */ -#ifdef HAVE_SAFE_SYSCALL -/* The core part of this function is implemented in assembly */ -extern long safe_syscall_base(int *pending, long number, ...); - -#define safe_syscall(...) \ - ({ \ - long ret_; \ - int *psp_ = &((TaskState *)thread_cpu->opaque)->signal_pending; \ - ret_ = safe_syscall_base(psp_, __VA_ARGS__); \ - if (is_error(ret_)) { \ - errno = -ret_; \ - ret_ = -1; \ - } \ - ret_; \ - }) - -#else - -/* Fallback for architectures which don't yet provide a safe-syscall assembly - * fragment; note that this is racy! - * This should go away when all host architectures have been updated. - */ -#define safe_syscall syscall - -#endif - -/* syscall.c */ -int host_to_target_waitstatus(int status); - -/* strace.c */ -void print_syscall(void *cpu_env, int num, - abi_long arg1, abi_long arg2, abi_long arg3, - abi_long arg4, abi_long arg5, abi_long arg6); -void print_syscall_ret(void *cpu_env, int num, abi_long ret, - abi_long arg1, abi_long arg2, abi_long arg3, - abi_long arg4, abi_long arg5, abi_long arg6); -/** - * print_taken_signal: - * @target_signum: target signal being taken - * @tinfo: target_siginfo_t which will be passed to the guest for the signal - * - * Print strace output indicating that this signal is being taken by the guest, - * in a format similar to: - * --- SIGSEGV {si_signo=SIGSEGV, si_code=SI_KERNEL, si_addr=0} --- - */ -void print_taken_signal(int target_signum, const target_siginfo_t *tinfo); - -/* signal.c */ -void process_pending_signals(CPUArchState *cpu_env); -void signal_init(void); -int queue_signal(CPUArchState *env, int sig, int si_type, - target_siginfo_t *info); -void host_to_target_siginfo(target_siginfo_t *tinfo, const siginfo_t *info); -void target_to_host_siginfo(siginfo_t *info, const target_siginfo_t *tinfo); -int target_to_host_signal(int sig); -int host_to_target_signal(int sig); -long do_sigreturn(CPUArchState *env); -long do_rt_sigreturn(CPUArchState *env); -abi_long do_sigaltstack(abi_ulong uss_addr, abi_ulong uoss_addr, - CPUArchState *env); -int do_sigprocmask(int how, const sigset_t *set, sigset_t *oldset); -abi_long do_swapcontext(CPUArchState *env, abi_ulong uold_ctx, - abi_ulong unew_ctx, abi_long ctx_size); -/** - * block_signals: block all signals while handling this guest syscall - * - * Block all signals, and arrange that the signal mask is returned to - * its correct value for the guest before we resume execution of guest code. - * If this function returns non-zero, then the caller should immediately - * return -TARGET_ERESTARTSYS to the main loop, which will take the pending - * signal and restart execution of the syscall. - * If block_signals() returns zero, then the caller can continue with - * emulation of the system call knowing that no signals can be taken - * (and therefore that no race conditions will result). - * This should only be called once, because if it is called a second time - * it will always return non-zero. (Think of it like a mutex that can't - * be recursively locked.) - * Signals will be unblocked again by process_pending_signals(). - * - * Return value: non-zero if there was a pending signal, zero if not. - */ -int block_signals(void); /* Returns non zero if signal pending */ - -#ifdef TARGET_I386 -/* vm86.c */ -void save_v86_state(CPUX86State *env); -void handle_vm86_trap(CPUX86State *env, int trapno); -void handle_vm86_fault(CPUX86State *env); -int do_vm86(CPUX86State *env, long subfunction, abi_ulong v86_addr); -#elif defined(TARGET_SPARC64) -void sparc64_set_context(CPUSPARCState *env); -void sparc64_get_context(CPUSPARCState *env); -#endif - -/* mmap.c */ -int target_mprotect(abi_ulong start, abi_ulong len, int prot); -abi_long target_mmap(abi_ulong start, abi_ulong len, int prot, - int flags, int fd, abi_ulong offset); -int target_munmap(abi_ulong start, abi_ulong len); -abi_long target_mremap(abi_ulong old_addr, abi_ulong old_size, - abi_ulong new_size, unsigned long flags, - abi_ulong new_addr); -extern unsigned long last_brk; -extern abi_ulong mmap_next_start; -abi_ulong mmap_find_vma(abi_ulong, abi_ulong, abi_ulong); -void mmap_fork_start(void); -void mmap_fork_end(int child); - -/* main.c */ -extern unsigned long guest_stack_size; /* user access */ @@ -667,80 +346,4 @@ void *lock_user_string(abi_ulong guest_addr); #define unlock_user_struct(host_ptr, guest_addr, copy) \ unlock_user(host_ptr, guest_addr, (copy) ? sizeof(*host_ptr) : 0) -#include <pthread.h> - -static inline int is_error(abi_long ret) -{ - return (abi_ulong)ret >= (abi_ulong)(-4096); -} - -#if TARGET_ABI_BITS == 32 -static inline uint64_t target_offset64(uint32_t word0, uint32_t word1) -{ -#ifdef TARGET_WORDS_BIGENDIAN - return ((uint64_t)word0 << 32) | word1; -#else - return ((uint64_t)word1 << 32) | word0; -#endif -} -#else /* TARGET_ABI_BITS == 32 */ -static inline uint64_t target_offset64(uint64_t word0, uint64_t word1) -{ - return word0; -} -#endif /* TARGET_ABI_BITS != 32 */ - -void print_termios(void *arg); - -/* ARM EABI and MIPS expect 64bit types aligned even on pairs or registers */ -#ifdef TARGET_ARM -static inline int regpairs_aligned(void *cpu_env, int num) -{ - return ((((CPUARMState *)cpu_env)->eabi) == 1) ; -} -#elif defined(TARGET_MIPS) && (TARGET_ABI_BITS == 32) -static inline int regpairs_aligned(void *cpu_env, int num) { return 1; } -#elif defined(TARGET_PPC) && !defined(TARGET_PPC64) -/* - * SysV AVI for PPC32 expects 64bit parameters to be passed on odd/even pairs - * of registers which translates to the same as ARM/MIPS, because we start with - * r3 as arg1 - */ -static inline int regpairs_aligned(void *cpu_env, int num) { return 1; } -#elif defined(TARGET_SH4) -/* SH4 doesn't align register pairs, except for p{read,write}64 */ -static inline int regpairs_aligned(void *cpu_env, int num) -{ - switch (num) { - case TARGET_NR_pread64: - case TARGET_NR_pwrite64: - return 1; - - default: - return 0; - } -} -#elif defined(TARGET_XTENSA) -static inline int regpairs_aligned(void *cpu_env, int num) { return 1; } -#elif defined(TARGET_HEXAGON) -static inline int regpairs_aligned(void *cpu_env, int num) { return 1; } -#else -static inline int regpairs_aligned(void *cpu_env, int num) { return 0; } -#endif - -/** - * preexit_cleanup: housekeeping before the guest exits - * - * env: the CPU state - * code: the exit code - */ -void preexit_cleanup(CPUArchState *env, int code); - -/* Include target-specific struct and function definitions; - * they may need access to the target-independent structures - * above, so include them last. - */ -#include "target_cpu.h" -#include "target_structs.h" - #endif /* QEMU_H */ diff --git a/linux-user/riscv/cpu_loop.c b/linux-user/riscv/cpu_loop.c index 74a9628dc9..9859a366e4 100644 --- a/linux-user/riscv/cpu_loop.c +++ b/linux-user/riscv/cpu_loop.c @@ -21,7 +21,9 @@ #include "qemu-common.h" #include "qemu/error-report.h" #include "qemu.h" +#include "user-internals.h" #include "cpu_loop-common.h" +#include "signal-common.h" #include "elf.h" #include "semihosting/common-semi.h" diff --git a/linux-user/riscv/signal.c b/linux-user/riscv/signal.c index 9405c7fd9a..f7f33bc90a 100644 --- a/linux-user/riscv/signal.c +++ b/linux-user/riscv/signal.c @@ -18,6 +18,7 @@ */ #include "qemu/osdep.h" #include "qemu.h" +#include "user-internals.h" #include "signal-common.h" #include "linux-user/trace.h" diff --git a/linux-user/s390x/cpu_loop.c b/linux-user/s390x/cpu_loop.c index 6a69a6dd26..69b69981f6 100644 --- a/linux-user/s390x/cpu_loop.c +++ b/linux-user/s390x/cpu_loop.c @@ -20,7 +20,9 @@ #include "qemu/osdep.h" #include "qemu-common.h" #include "qemu.h" +#include "user-internals.h" #include "cpu_loop-common.h" +#include "signal-common.h" /* s390x masks the fault address it reports in si_addr for SIGSEGV and SIGBUS */ #define S390X_FAIL_ADDR_MASK -4096LL diff --git a/linux-user/s390x/signal.c b/linux-user/s390x/signal.c index bf8a8fbfe9..80f34086d7 100644 --- a/linux-user/s390x/signal.c +++ b/linux-user/s390x/signal.c @@ -18,6 +18,7 @@ */ #include "qemu/osdep.h" #include "qemu.h" +#include "user-internals.h" #include "signal-common.h" #include "linux-user/trace.h" diff --git a/linux-user/safe-syscall.h b/linux-user/safe-syscall.h new file mode 100644 index 0000000000..6bc0390262 --- /dev/null +++ b/linux-user/safe-syscall.h @@ -0,0 +1,154 @@ +/* + * safe-syscall.h: prototypes for linux-user signal-race-safe syscalls + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef LINUX_USER_SAFE_SYSCALL_H +#define LINUX_USER_SAFE_SYSCALL_H + +/** + * safe_syscall: + * @int number: number of system call to make + * ...: arguments to the system call + * + * Call a system call if guest signal not pending. + * This has the same API as the libc syscall() function, except that it + * may return -1 with errno == TARGET_ERESTARTSYS if a signal was pending. + * + * Returns: the system call result, or -1 with an error code in errno + * (Errnos are host errnos; we rely on TARGET_ERESTARTSYS not clashing + * with any of the host errno values.) + */ + +/* + * A guide to using safe_syscall() to handle interactions between guest + * syscalls and guest signals: + * + * Guest syscalls come in two flavours: + * + * (1) Non-interruptible syscalls + * + * These are guest syscalls that never get interrupted by signals and + * so never return EINTR. They can be implemented straightforwardly in + * QEMU: just make sure that if the implementation code has to make any + * blocking calls that those calls are retried if they return EINTR. + * It's also OK to implement these with safe_syscall, though it will be + * a little less efficient if a signal is delivered at the 'wrong' moment. + * + * Some non-interruptible syscalls need to be handled using block_signals() + * to block signals for the duration of the syscall. This mainly applies + * to code which needs to modify the data structures used by the + * host_signal_handler() function and the functions it calls, including + * all syscalls which change the thread's signal mask. + * + * (2) Interruptible syscalls + * + * These are guest syscalls that can be interrupted by signals and + * for which we need to either return EINTR or arrange for the guest + * syscall to be restarted. This category includes both syscalls which + * always restart (and in the kernel return -ERESTARTNOINTR), ones + * which only restart if there is no handler (kernel returns -ERESTARTNOHAND + * or -ERESTART_RESTARTBLOCK), and the most common kind which restart + * if the handler was registered with SA_RESTART (kernel returns + * -ERESTARTSYS). System calls which are only interruptible in some + * situations (like 'open') also need to be handled this way. + * + * Here it is important that the host syscall is made + * via this safe_syscall() function, and *not* via the host libc. + * If the host libc is used then the implementation will appear to work + * most of the time, but there will be a race condition where a + * signal could arrive just before we make the host syscall inside libc, + * and then then guest syscall will not correctly be interrupted. + * Instead the implementation of the guest syscall can use the safe_syscall + * function but otherwise just return the result or errno in the usual + * way; the main loop code will take care of restarting the syscall + * if appropriate. + * + * (If the implementation needs to make multiple host syscalls this is + * OK; any which might really block must be via safe_syscall(); for those + * which are only technically blocking (ie which we know in practice won't + * stay in the host kernel indefinitely) it's OK to use libc if necessary. + * You must be able to cope with backing out correctly if some safe_syscall + * you make in the implementation returns either -TARGET_ERESTARTSYS or + * EINTR though.) + * + * block_signals() cannot be used for interruptible syscalls. + * + * + * How and why the safe_syscall implementation works: + * + * The basic setup is that we make the host syscall via a known + * section of host native assembly. If a signal occurs, our signal + * handler checks the interrupted host PC against the addresse of that + * known section. If the PC is before or at the address of the syscall + * instruction then we change the PC to point at a "return + * -TARGET_ERESTARTSYS" code path instead, and then exit the signal handler + * (causing the safe_syscall() call to immediately return that value). + * Then in the main.c loop if we see this magic return value we adjust + * the guest PC to wind it back to before the system call, and invoke + * the guest signal handler as usual. + * + * This winding-back will happen in two cases: + * (1) signal came in just before we took the host syscall (a race); + * in this case we'll take the guest signal and have another go + * at the syscall afterwards, and this is indistinguishable for the + * guest from the timing having been different such that the guest + * signal really did win the race + * (2) signal came in while the host syscall was blocking, and the + * host kernel decided the syscall should be restarted; + * in this case we want to restart the guest syscall also, and so + * rewinding is the right thing. (Note that "restart" semantics mean + * "first call the signal handler, then reattempt the syscall".) + * The other situation to consider is when a signal came in while the + * host syscall was blocking, and the host kernel decided that the syscall + * should not be restarted; in this case QEMU's host signal handler will + * be invoked with the PC pointing just after the syscall instruction, + * with registers indicating an EINTR return; the special code in the + * handler will not kick in, and we will return EINTR to the guest as + * we should. + * + * Notice that we can leave the host kernel to make the decision for + * us about whether to do a restart of the syscall or not; we do not + * need to check SA_RESTART flags in QEMU or distinguish the various + * kinds of restartability. + */ +#ifdef HAVE_SAFE_SYSCALL +/* The core part of this function is implemented in assembly */ +extern long safe_syscall_base(int *pending, long number, ...); + +#define safe_syscall(...) \ + ({ \ + long ret_; \ + int *psp_ = &((TaskState *)thread_cpu->opaque)->signal_pending; \ + ret_ = safe_syscall_base(psp_, __VA_ARGS__); \ + if (is_error(ret_)) { \ + errno = -ret_; \ + ret_ = -1; \ + } \ + ret_; \ + }) + +#else + +/* + * Fallback for architectures which don't yet provide a safe-syscall assembly + * fragment; note that this is racy! + * This should go away when all host architectures have been updated. + */ +#define safe_syscall syscall + +#endif + +#endif diff --git a/linux-user/semihost.c b/linux-user/semihost.c index f53ab526fb..17f074ac56 100644 --- a/linux-user/semihost.c +++ b/linux-user/semihost.c @@ -13,6 +13,7 @@ #include "qemu/osdep.h" #include "semihosting/console.h" #include "qemu.h" +#include "user-internals.h" #include <termios.h> int qemu_semihosting_console_outs(CPUArchState *env, target_ulong addr) diff --git a/linux-user/sh4/cpu_loop.c b/linux-user/sh4/cpu_loop.c index 222ed1c670..65b8972e3c 100644 --- a/linux-user/sh4/cpu_loop.c +++ b/linux-user/sh4/cpu_loop.c @@ -20,7 +20,9 @@ #include "qemu/osdep.h" #include "qemu-common.h" #include "qemu.h" +#include "user-internals.h" #include "cpu_loop-common.h" +#include "signal-common.h" void cpu_loop(CPUSH4State *env) { diff --git a/linux-user/sh4/signal.c b/linux-user/sh4/signal.c index 0451e65806..d70d744bef 100644 --- a/linux-user/sh4/signal.c +++ b/linux-user/sh4/signal.c @@ -18,6 +18,7 @@ */ #include "qemu/osdep.h" #include "qemu.h" +#include "user-internals.h" #include "signal-common.h" #include "linux-user/trace.h" diff --git a/linux-user/signal-common.h b/linux-user/signal-common.h index ea86328b28..58ea23f6ea 100644 --- a/linux-user/signal-common.h +++ b/linux-user/signal-common.h @@ -47,4 +47,40 @@ void setup_frame(int sig, struct target_sigaction *ka, void setup_rt_frame(int sig, struct target_sigaction *ka, target_siginfo_t *info, target_sigset_t *set, CPUArchState *env); + +void process_pending_signals(CPUArchState *cpu_env); +void signal_init(void); +int queue_signal(CPUArchState *env, int sig, int si_type, + target_siginfo_t *info); +void host_to_target_siginfo(target_siginfo_t *tinfo, const siginfo_t *info); +void target_to_host_siginfo(siginfo_t *info, const target_siginfo_t *tinfo); +int target_to_host_signal(int sig); +int host_to_target_signal(int sig); +long do_sigreturn(CPUArchState *env); +long do_rt_sigreturn(CPUArchState *env); +abi_long do_sigaltstack(abi_ulong uss_addr, abi_ulong uoss_addr, + CPUArchState *env); +int do_sigprocmask(int how, const sigset_t *set, sigset_t *oldset); +abi_long do_swapcontext(CPUArchState *env, abi_ulong uold_ctx, + abi_ulong unew_ctx, abi_long ctx_size); +/** + * block_signals: block all signals while handling this guest syscall + * + * Block all signals, and arrange that the signal mask is returned to + * its correct value for the guest before we resume execution of guest code. + * If this function returns non-zero, then the caller should immediately + * return -TARGET_ERESTARTSYS to the main loop, which will take the pending + * signal and restart execution of the syscall. + * If block_signals() returns zero, then the caller can continue with + * emulation of the system call knowing that no signals can be taken + * (and therefore that no race conditions will result). + * This should only be called once, because if it is called a second time + * it will always return non-zero. (Think of it like a mutex that can't + * be recursively locked.) + * Signals will be unblocked again by process_pending_signals(). + * + * Return value: non-zero if there was a pending signal, zero if not. + */ +int block_signals(void); /* Returns non zero if signal pending */ + #endif diff --git a/linux-user/signal.c b/linux-user/signal.c index a8faea6f09..f8346f5ec5 100644 --- a/linux-user/signal.c +++ b/linux-user/signal.c @@ -18,10 +18,15 @@ */ #include "qemu/osdep.h" #include "qemu/bitops.h" +#include "exec/gdbstub.h" + #include <sys/ucontext.h> #include <sys/resource.h> #include "qemu.h" +#include "user-internals.h" +#include "strace.h" +#include "loader.h" #include "trace.h" #include "signal-common.h" diff --git a/linux-user/sparc/cpu_loop.c b/linux-user/sparc/cpu_loop.c index 02532f198d..ad29b4eb6a 100644 --- a/linux-user/sparc/cpu_loop.c +++ b/linux-user/sparc/cpu_loop.c @@ -20,7 +20,9 @@ #include "qemu/osdep.h" #include "qemu-common.h" #include "qemu.h" +#include "user-internals.h" #include "cpu_loop-common.h" +#include "signal-common.h" #define SPARC64_STACK_BIAS 2047 diff --git a/linux-user/sparc/signal.c b/linux-user/sparc/signal.c index 0cc3db5570..3bc023d281 100644 --- a/linux-user/sparc/signal.c +++ b/linux-user/sparc/signal.c @@ -18,6 +18,7 @@ */ #include "qemu/osdep.h" #include "qemu.h" +#include "user-internals.h" #include "signal-common.h" #include "linux-user/trace.h" diff --git a/linux-user/strace.c b/linux-user/strace.c index cce0a5d1e3..2cdbf030ba 100644 --- a/linux-user/strace.c +++ b/linux-user/strace.c @@ -1,4 +1,5 @@ #include "qemu/osdep.h" + #include <sys/ipc.h> #include <sys/msg.h> #include <sys/sem.h> @@ -14,6 +15,8 @@ #include <linux/netlink.h> #include <sched.h> #include "qemu.h" +#include "user-internals.h" +#include "strace.h" struct syscallname { int nr; diff --git a/linux-user/strace.h b/linux-user/strace.h new file mode 100644 index 0000000000..1e232d07fc --- /dev/null +++ b/linux-user/strace.h @@ -0,0 +1,38 @@ +/* + * strace.h: prototypes for linux-user builtin strace handling + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef LINUX_USER_STRACE_H +#define LINUX_USER_STRACE_H + +void print_syscall(void *cpu_env, int num, + abi_long arg1, abi_long arg2, abi_long arg3, + abi_long arg4, abi_long arg5, abi_long arg6); +void print_syscall_ret(void *cpu_env, int num, abi_long ret, + abi_long arg1, abi_long arg2, abi_long arg3, + abi_long arg4, abi_long arg5, abi_long arg6); +/** + * print_taken_signal: + * @target_signum: target signal being taken + * @tinfo: target_siginfo_t which will be passed to the guest for the signal + * + * Print strace output indicating that this signal is being taken by the guest, + * in a format similar to: + * --- SIGSEGV {si_signo=SIGSEGV, si_code=SI_KERNEL, si_addr=0} --- + */ +void print_taken_signal(int target_signum, const target_siginfo_t *tinfo); + +#endif /* LINUX_USER_STRACE_H */ diff --git a/linux-user/syscall.c b/linux-user/syscall.c index ccd3892b2d..544f5b662f 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -127,6 +127,12 @@ #include "uname.h" #include "qemu.h" +#include "user-internals.h" +#include "strace.h" +#include "signal-common.h" +#include "loader.h" +#include "user-mmap.h" +#include "safe-syscall.h" #include "qemu/guest-random.h" #include "qemu/selfmap.h" #include "user/syscall-trace.h" @@ -2121,6 +2127,9 @@ static abi_long do_setsockopt(int sockfd, int level, int optname, return -TARGET_EINVAL; ip_mreq_source = lock_user(VERIFY_READ, optval_addr, optlen, 1); + if (!ip_mreq_source) { + return -TARGET_EFAULT; + } ret = get_errno(setsockopt(sockfd, level, optname, ip_mreq_source, optlen)); unlock_user (ip_mreq_source, optval_addr, 0); break; diff --git a/linux-user/uaccess.c b/linux-user/uaccess.c index 6a5b029607..425cbf677f 100644 --- a/linux-user/uaccess.c +++ b/linux-user/uaccess.c @@ -3,6 +3,7 @@ #include "qemu/cutils.h" #include "qemu.h" +#include "user-internals.h" void *lock_user(int type, abi_ulong guest_addr, ssize_t len, bool copy) { diff --git a/linux-user/uname.c b/linux-user/uname.c index a09ffe1ea7..1d82608c10 100644 --- a/linux-user/uname.c +++ b/linux-user/uname.c @@ -20,6 +20,7 @@ #include "qemu/osdep.h" #include "qemu.h" +#include "user-internals.h" //#include "qemu-common.h" #include "uname.h" diff --git a/linux-user/user-internals.h b/linux-user/user-internals.h new file mode 100644 index 0000000000..661612a088 --- /dev/null +++ b/linux-user/user-internals.h @@ -0,0 +1,186 @@ +/* + * user-internals.h: prototypes etc internal to the linux-user implementation + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef LINUX_USER_USER_INTERNALS_H +#define LINUX_USER_USER_INTERNALS_H + +#include "hostdep.h" +#include "exec/user/thunk.h" +#include "exec/exec-all.h" +#include "qemu/log.h" + +extern char *exec_path; +void init_task_state(TaskState *ts); +void task_settid(TaskState *); +void stop_all_tasks(void); +extern const char *qemu_uname_release; +extern unsigned long mmap_min_addr; + +typedef struct IOCTLEntry IOCTLEntry; + +typedef abi_long do_ioctl_fn(const IOCTLEntry *ie, uint8_t *buf_temp, + int fd, int cmd, abi_long arg); + +struct IOCTLEntry { + int target_cmd; + unsigned int host_cmd; + const char *name; + int access; + do_ioctl_fn *do_ioctl; + const argtype arg_type[5]; +}; + +extern IOCTLEntry ioctl_entries[]; + +#define IOC_R 0x0001 +#define IOC_W 0x0002 +#define IOC_RW (IOC_R | IOC_W) + +/* + * Returns true if the image uses the FDPIC ABI. If this is the case, + * we have to provide some information (loadmap, pt_dynamic_info) such + * that the program can be relocated adequately. This is also useful + * when handling signals. + */ +int info_is_fdpic(struct image_info *info); + +void target_set_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 arg7, + abi_long arg8); +extern __thread CPUState *thread_cpu; +void cpu_loop(CPUArchState *env); +const char *target_strerror(int err); +int get_osversion(void); +void init_qemu_uname_release(void); +void fork_start(void); +void fork_end(int child); + +/** + * probe_guest_base: + * @image_name: the executable being loaded + * @loaddr: the lowest fixed address in the executable + * @hiaddr: the highest fixed address in the executable + * + * Creates the initial guest address space in the host memory space. + * + * If @loaddr == 0, then no address in the executable is fixed, + * i.e. it is fully relocatable. In that case @hiaddr is the size + * of the executable. + * + * This function will not return if a valid value for guest_base + * cannot be chosen. On return, the executable loader can expect + * + * target_mmap(loaddr, hiaddr - loaddr, ...) + * + * to succeed. + */ +void probe_guest_base(const char *image_name, + abi_ulong loaddr, abi_ulong hiaddr); + +/* syscall.c */ +int host_to_target_waitstatus(int status); + +#ifdef TARGET_I386 +/* vm86.c */ +void save_v86_state(CPUX86State *env); +void handle_vm86_trap(CPUX86State *env, int trapno); +void handle_vm86_fault(CPUX86State *env); +int do_vm86(CPUX86State *env, long subfunction, abi_ulong v86_addr); +#elif defined(TARGET_SPARC64) +void sparc64_set_context(CPUSPARCState *env); +void sparc64_get_context(CPUSPARCState *env); +#endif + +static inline int is_error(abi_long ret) +{ + return (abi_ulong)ret >= (abi_ulong)(-4096); +} + +#if TARGET_ABI_BITS == 32 +static inline uint64_t target_offset64(uint32_t word0, uint32_t word1) +{ +#ifdef TARGET_WORDS_BIGENDIAN + return ((uint64_t)word0 << 32) | word1; +#else + return ((uint64_t)word1 << 32) | word0; +#endif +} +#else /* TARGET_ABI_BITS == 32 */ +static inline uint64_t target_offset64(uint64_t word0, uint64_t word1) +{ + return word0; +} +#endif /* TARGET_ABI_BITS != 32 */ + +void print_termios(void *arg); + +/* ARM EABI and MIPS expect 64bit types aligned even on pairs or registers */ +#ifdef TARGET_ARM +static inline int regpairs_aligned(void *cpu_env, int num) +{ + return ((((CPUARMState *)cpu_env)->eabi) == 1) ; +} +#elif defined(TARGET_MIPS) && (TARGET_ABI_BITS == 32) +static inline int regpairs_aligned(void *cpu_env, int num) { return 1; } +#elif defined(TARGET_PPC) && !defined(TARGET_PPC64) +/* + * SysV AVI for PPC32 expects 64bit parameters to be passed on odd/even pairs + * of registers which translates to the same as ARM/MIPS, because we start with + * r3 as arg1 + */ +static inline int regpairs_aligned(void *cpu_env, int num) { return 1; } +#elif defined(TARGET_SH4) +/* SH4 doesn't align register pairs, except for p{read,write}64 */ +static inline int regpairs_aligned(void *cpu_env, int num) +{ + switch (num) { + case TARGET_NR_pread64: + case TARGET_NR_pwrite64: + return 1; + + default: + return 0; + } +} +#elif defined(TARGET_XTENSA) +static inline int regpairs_aligned(void *cpu_env, int num) { return 1; } +#elif defined(TARGET_HEXAGON) +static inline int regpairs_aligned(void *cpu_env, int num) { return 1; } +#else +static inline int regpairs_aligned(void *cpu_env, int num) { return 0; } +#endif + +/** + * preexit_cleanup: housekeeping before the guest exits + * + * env: the CPU state + * code: the exit code + */ +void preexit_cleanup(CPUArchState *env, int code); + +/* + * Include target-specific struct and function definitions; + * they may need access to the target-independent structures + * above, so include them last. + */ +#include "target_cpu.h" +#include "target_structs.h" + +#endif diff --git a/linux-user/user-mmap.h b/linux-user/user-mmap.h new file mode 100644 index 0000000000..d1dec99c02 --- /dev/null +++ b/linux-user/user-mmap.h @@ -0,0 +1,34 @@ +/* + * user-mmap.h: prototypes for linux-user guest binary loader + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef LINUX_USER_USER_MMAP_H +#define LINUX_USER_USER_MMAP_H + +int target_mprotect(abi_ulong start, abi_ulong len, int prot); +abi_long target_mmap(abi_ulong start, abi_ulong len, int prot, + int flags, int fd, abi_ulong offset); +int target_munmap(abi_ulong start, abi_ulong len); +abi_long target_mremap(abi_ulong old_addr, abi_ulong old_size, + abi_ulong new_size, unsigned long flags, + abi_ulong new_addr); +extern unsigned long last_brk; +extern abi_ulong mmap_next_start; +abi_ulong mmap_find_vma(abi_ulong, abi_ulong, abi_ulong); +void mmap_fork_start(void); +void mmap_fork_end(int child); + +#endif /* LINUX_USER_USER_MMAP_H */ diff --git a/linux-user/vm86.c b/linux-user/vm86.c index 4412522c4c..c2facf3fc2 100644 --- a/linux-user/vm86.c +++ b/linux-user/vm86.c @@ -19,6 +19,7 @@ #include "qemu/osdep.h" #include "qemu.h" +#include "user-internals.h" //#define DEBUG_VM86 diff --git a/linux-user/xtensa/cpu_loop.c b/linux-user/xtensa/cpu_loop.c index 64831c9199..622afbcd34 100644 --- a/linux-user/xtensa/cpu_loop.c +++ b/linux-user/xtensa/cpu_loop.c @@ -19,7 +19,9 @@ #include "qemu/osdep.h" #include "qemu.h" +#include "user-internals.h" #include "cpu_loop-common.h" +#include "signal-common.h" static void xtensa_rfw(CPUXtensaState *env) { diff --git a/linux-user/xtensa/signal.c b/linux-user/xtensa/signal.c index 72771e1294..7a3bfb92ca 100644 --- a/linux-user/xtensa/signal.c +++ b/linux-user/xtensa/signal.c @@ -18,6 +18,7 @@ */ #include "qemu/osdep.h" #include "qemu.h" +#include "user-internals.h" #include "signal-common.h" #include "linux-user/trace.h" diff --git a/semihosting/arm-compat-semi.c b/semihosting/arm-compat-semi.c index 1c29146dcf..01badea99c 100644 --- a/semihosting/arm-compat-semi.c +++ b/semihosting/arm-compat-semi.c @@ -37,12 +37,12 @@ #include "semihosting/console.h" #include "semihosting/common-semi.h" #include "qemu/timer.h" +#include "exec/gdbstub.h" #ifdef CONFIG_USER_ONLY #include "qemu.h" #define COMMON_SEMI_HEAP_SIZE (128 * 1024 * 1024) #else -#include "exec/gdbstub.h" #include "qemu/cutils.h" #ifdef TARGET_ARM #include "hw/arm/boot.h" diff --git a/target/avr/translate.c b/target/avr/translate.c index 1111e08b83..438e7b13c1 100644 --- a/target/avr/translate.c +++ b/target/avr/translate.c @@ -70,11 +70,9 @@ static const char reg_names[NUMBER_OF_CPU_REGISTERS][8] = { }; #define REG(x) (cpu_r[x]) -enum { - DISAS_EXIT = DISAS_TARGET_0, /* We want return to the cpu main loop. */ - DISAS_LOOKUP = DISAS_TARGET_1, /* We have a variable condition exit. */ - DISAS_CHAIN = DISAS_TARGET_2, /* We have a single condition exit. */ -}; +#define DISAS_EXIT DISAS_TARGET_0 /* We want return to the cpu main loop. */ +#define DISAS_LOOKUP DISAS_TARGET_1 /* We have a variable condition exit. */ +#define DISAS_CHAIN DISAS_TARGET_2 /* We have a single condition exit. */ typedef struct DisasContext DisasContext; diff --git a/target/i386/cpu-sysemu.c b/target/i386/cpu-sysemu.c index 1078e3d157..37b7c562f5 100644 --- a/target/i386/cpu-sysemu.c +++ b/target/i386/cpu-sysemu.c @@ -335,7 +335,7 @@ void x86_cpu_get_crash_info_qom(Object *obj, Visitor *v, GuestPanicInformation *panic_info; if (!cs->crash_occurred) { - error_setg(errp, "No crash occured"); + error_setg(errp, "No crash occurred"); return; } diff --git a/target/m68k/m68k-semi.c b/target/m68k/m68k-semi.c index d919245e4f..44ec7e4612 100644 --- a/target/m68k/m68k-semi.c +++ b/target/m68k/m68k-semi.c @@ -20,11 +20,11 @@ #include "qemu/osdep.h" #include "cpu.h" +#include "exec/gdbstub.h" #if defined(CONFIG_USER_ONLY) #include "qemu.h" #define SEMIHOSTING_HEAP_SIZE (128 * 1024 * 1024) #else -#include "exec/gdbstub.h" #include "exec/softmmu-semi.h" #include "hw/boards.h" #endif diff --git a/target/nios2/nios2-semi.c b/target/nios2/nios2-semi.c index e508b2fafc..fe5598bae4 100644 --- a/target/nios2/nios2-semi.c +++ b/target/nios2/nios2-semi.c @@ -24,11 +24,11 @@ #include "qemu/osdep.h" #include "cpu.h" +#include "exec/gdbstub.h" #if defined(CONFIG_USER_ONLY) #include "qemu.h" #else #include "qemu-common.h" -#include "exec/gdbstub.h" #include "exec/softmmu-semi.h" #endif #include "qemu/log.h" diff --git a/target/sparc/cpu.c b/target/sparc/cpu.c index 5a8a4ce750..21dd27796d 100644 --- a/target/sparc/cpu.c +++ b/target/sparc/cpu.c @@ -612,7 +612,7 @@ static void cpu_print_cc(FILE *f, uint32_t cc) #define REGS_PER_LINE 8 #endif -void sparc_cpu_dump_state(CPUState *cs, FILE *f, int flags) +static void sparc_cpu_dump_state(CPUState *cs, FILE *f, int flags) { SPARCCPU *cpu = SPARC_CPU(cs); CPUSPARCState *env = &cpu->env; diff --git a/target/sparc/cpu.h b/target/sparc/cpu.h index ff8ae73002..1f40d768d8 100644 --- a/target/sparc/cpu.h +++ b/target/sparc/cpu.h @@ -571,7 +571,6 @@ extern const VMStateDescription vmstate_sparc_cpu; #endif void sparc_cpu_do_interrupt(CPUState *cpu); -void sparc_cpu_dump_state(CPUState *cpu, FILE *f, int flags); hwaddr sparc_cpu_get_phys_page_debug(CPUState *cpu, vaddr addr); int sparc_cpu_gdb_read_register(CPUState *cpu, GByteArray *buf, int reg); int sparc_cpu_gdb_write_register(CPUState *cpu, uint8_t *buf, int reg); diff --git a/thunk.c b/thunk.c index fc5be1a502..dac4bf11c6 100644 --- a/thunk.c +++ b/thunk.c @@ -17,6 +17,7 @@ * License along with this library; if not, see <http://www.gnu.org/licenses/>. */ #include "qemu/osdep.h" +#include "qemu/log.h" #include "qemu.h" #include "exec/user/thunk.h" diff --git a/tools/virtiofsd/fuse_lowlevel.h b/tools/virtiofsd/fuse_lowlevel.h index 4b4e8c9724..c55c0ca2fc 100644 --- a/tools/virtiofsd/fuse_lowlevel.h +++ b/tools/virtiofsd/fuse_lowlevel.h @@ -1603,7 +1603,7 @@ int fuse_lowlevel_notify_inval_inode(struct fuse_session *se, fuse_ino_t ino, * parent/name * * To avoid a deadlock this function must not be called in the - * execution path of a related filesytem operation or within any code + * execution path of a related filesystem operation or within any code * that could hold a lock that could be needed to execute such an * operation. As of kernel 4.18, a "related operation" is a lookup(), * symlink(), mknod(), mkdir(), unlink(), rename(), link() or create() @@ -1636,7 +1636,7 @@ int fuse_lowlevel_notify_inval_entry(struct fuse_session *se, fuse_ino_t parent, * that the dentry has been deleted. * * To avoid a deadlock this function must not be called while - * executing a related filesytem operation or while holding a lock + * executing a related filesystem operation or while holding a lock * that could be needed to execute such an operation (see the * description of fuse_lowlevel_notify_inval_entry() for more * details). diff --git a/ui/egl-helpers.c b/ui/egl-helpers.c index 6d0cb2b5cb..385a3fa752 100644 --- a/ui/egl-helpers.c +++ b/ui/egl-helpers.c @@ -287,6 +287,32 @@ void egl_dmabuf_release_texture(QemuDmaBuf *dmabuf) dmabuf->texture = 0; } +void egl_dmabuf_create_sync(QemuDmaBuf *dmabuf) +{ + EGLSyncKHR sync; + + if (epoxy_has_egl_extension(qemu_egl_display, + "EGL_KHR_fence_sync") && + epoxy_has_egl_extension(qemu_egl_display, + "EGL_ANDROID_native_fence_sync")) { + sync = eglCreateSyncKHR(qemu_egl_display, + EGL_SYNC_NATIVE_FENCE_ANDROID, NULL); + if (sync != EGL_NO_SYNC_KHR) { + dmabuf->sync = sync; + } + } +} + +void egl_dmabuf_create_fence(QemuDmaBuf *dmabuf) +{ + if (dmabuf->sync) { + dmabuf->fence_fd = eglDupNativeFenceFDANDROID(qemu_egl_display, + dmabuf->sync); + eglDestroySyncKHR(qemu_egl_display, dmabuf->sync); + dmabuf->sync = NULL; + } +} + #endif /* CONFIG_GBM */ /* ---------------------------------------------------------------------- */ diff --git a/ui/gtk-egl.c b/ui/gtk-egl.c index 2a2e6d3a17..72ce5e1f8f 100644 --- a/ui/gtk-egl.c +++ b/ui/gtk-egl.c @@ -12,6 +12,7 @@ */ #include "qemu/osdep.h" +#include "qemu/main-loop.h" #include "trace.h" @@ -94,6 +95,18 @@ void gd_egl_draw(VirtualConsole *vc) } glFlush(); +#ifdef CONFIG_GBM + if (vc->gfx.guest_fb.dmabuf) { + QemuDmaBuf *dmabuf = vc->gfx.guest_fb.dmabuf; + + egl_dmabuf_create_fence(dmabuf); + if (dmabuf->fence_fd > 0) { + qemu_set_fd_handler(dmabuf->fence_fd, gd_hw_gl_flushed, NULL, vc); + return; + } + graphic_hw_gl_block(vc->gfx.dcl.con, false); + } +#endif graphic_hw_gl_flushed(vc->gfx.dcl.con); } @@ -209,6 +222,8 @@ void gd_egl_scanout_dmabuf(DisplayChangeListener *dcl, QemuDmaBuf *dmabuf) { #ifdef CONFIG_GBM + VirtualConsole *vc = container_of(dcl, VirtualConsole, gfx.dcl); + egl_dmabuf_import_texture(dmabuf); if (!dmabuf->texture) { return; @@ -217,6 +232,10 @@ void gd_egl_scanout_dmabuf(DisplayChangeListener *dcl, gd_egl_scanout_texture(dcl, dmabuf->texture, false, dmabuf->width, dmabuf->height, 0, 0, dmabuf->width, dmabuf->height); + + if (dmabuf->allow_fences) { + vc->gfx.guest_fb.dmabuf = dmabuf; + } #endif } @@ -249,14 +268,6 @@ void gd_egl_cursor_position(DisplayChangeListener *dcl, vc->gfx.cursor_y = pos_y * vc->gfx.scale_y; } -void gd_egl_release_dmabuf(DisplayChangeListener *dcl, - QemuDmaBuf *dmabuf) -{ -#ifdef CONFIG_GBM - egl_dmabuf_release_texture(dmabuf); -#endif -} - void gd_egl_scanout_flush(DisplayChangeListener *dcl, uint32_t x, uint32_t y, uint32_t w, uint32_t h) { @@ -289,9 +300,30 @@ void gd_egl_scanout_flush(DisplayChangeListener *dcl, egl_fb_blit(&vc->gfx.win_fb, &vc->gfx.guest_fb, !vc->gfx.y0_top); } +#ifdef CONFIG_GBM + if (vc->gfx.guest_fb.dmabuf) { + egl_dmabuf_create_sync(vc->gfx.guest_fb.dmabuf); + } +#endif + eglSwapBuffers(qemu_egl_display, vc->gfx.esurface); } +void gd_egl_flush(DisplayChangeListener *dcl, + uint32_t x, uint32_t y, uint32_t w, uint32_t h) +{ + VirtualConsole *vc = container_of(dcl, VirtualConsole, gfx.dcl); + GtkWidget *area = vc->gfx.drawing_area; + + if (vc->gfx.guest_fb.dmabuf) { + graphic_hw_gl_block(vc->gfx.dcl.con, true); + gtk_widget_queue_draw_area(area, x, y, w, h); + return; + } + + gd_egl_scanout_flush(&vc->gfx.dcl, x, y, w, h); +} + void gtk_egl_init(DisplayGLMode mode) { GdkDisplay *gdk_display = gdk_display_get_default(); diff --git a/ui/gtk-gl-area.c b/ui/gtk-gl-area.c index dd5783fec7..b23523748e 100644 --- a/ui/gtk-gl-area.c +++ b/ui/gtk-gl-area.c @@ -8,6 +8,7 @@ */ #include "qemu/osdep.h" +#include "qemu/main-loop.h" #include "trace.h" @@ -71,7 +72,25 @@ void gd_gl_area_draw(VirtualConsole *vc) surface_gl_render_texture(vc->gfx.gls, vc->gfx.ds); } +#ifdef CONFIG_GBM + if (vc->gfx.guest_fb.dmabuf) { + egl_dmabuf_create_sync(vc->gfx.guest_fb.dmabuf); + } +#endif + glFlush(); +#ifdef CONFIG_GBM + if (vc->gfx.guest_fb.dmabuf) { + QemuDmaBuf *dmabuf = vc->gfx.guest_fb.dmabuf; + + egl_dmabuf_create_fence(dmabuf); + if (dmabuf->fence_fd > 0) { + qemu_set_fd_handler(dmabuf->fence_fd, gd_hw_gl_flushed, NULL, vc); + return; + } + graphic_hw_gl_block(vc->gfx.dcl.con, false); + } +#endif graphic_hw_gl_flushed(vc->gfx.dcl.con); } @@ -213,6 +232,9 @@ void gd_gl_area_scanout_flush(DisplayChangeListener *dcl, { VirtualConsole *vc = container_of(dcl, VirtualConsole, gfx.dcl); + if (vc->gfx.guest_fb.dmabuf) { + graphic_hw_gl_block(vc->gfx.dcl.con, true); + } gtk_gl_area_queue_render(GTK_GL_AREA(vc->gfx.drawing_area)); } @@ -231,6 +253,10 @@ void gd_gl_area_scanout_dmabuf(DisplayChangeListener *dcl, gd_gl_area_scanout_texture(dcl, dmabuf->texture, false, dmabuf->width, dmabuf->height, 0, 0, dmabuf->width, dmabuf->height); + + if (dmabuf->allow_fences) { + vc->gfx.guest_fb.dmabuf = dmabuf; + } #endif } diff --git a/ui/gtk.c b/ui/gtk.c index cfb0728d1f..b0564d80c1 100644 --- a/ui/gtk.c +++ b/ui/gtk.c @@ -36,6 +36,7 @@ #include "qapi/qapi-commands-machine.h" #include "qapi/qapi-commands-misc.h" #include "qemu/cutils.h" +#include "qemu/main-loop.h" #include "ui/console.h" #include "ui/gtk.h" @@ -575,6 +576,26 @@ static bool gd_has_dmabuf(DisplayChangeListener *dcl) return vc->gfx.has_dmabuf; } +static void gd_gl_release_dmabuf(DisplayChangeListener *dcl, + QemuDmaBuf *dmabuf) +{ +#ifdef CONFIG_GBM + egl_dmabuf_release_texture(dmabuf); +#endif +} + +void gd_hw_gl_flushed(void *vcon) +{ + VirtualConsole *vc = vcon; + QemuDmaBuf *dmabuf = vc->gfx.guest_fb.dmabuf; + + graphic_hw_gl_block(vc->gfx.dcl.con, false); + graphic_hw_gl_flushed(vc->gfx.dcl.con); + qemu_set_fd_handler(dmabuf->fence_fd, NULL, NULL, NULL); + close(dmabuf->fence_fd); + dmabuf->fence_fd = -1; +} + /** DisplayState Callbacks (opengl version) **/ static const DisplayChangeListenerOps dcl_gl_area_ops = { @@ -593,6 +614,7 @@ static const DisplayChangeListenerOps dcl_gl_area_ops = { .dpy_gl_scanout_disable = gd_gl_area_scanout_disable, .dpy_gl_update = gd_gl_area_scanout_flush, .dpy_gl_scanout_dmabuf = gd_gl_area_scanout_dmabuf, + .dpy_gl_release_dmabuf = gd_gl_release_dmabuf, .dpy_has_dmabuf = gd_has_dmabuf, }; @@ -615,8 +637,8 @@ static const DisplayChangeListenerOps dcl_egl_ops = { .dpy_gl_scanout_dmabuf = gd_egl_scanout_dmabuf, .dpy_gl_cursor_dmabuf = gd_egl_cursor_dmabuf, .dpy_gl_cursor_position = gd_egl_cursor_position, - .dpy_gl_release_dmabuf = gd_egl_release_dmabuf, - .dpy_gl_update = gd_egl_scanout_flush, + .dpy_gl_update = gd_egl_flush, + .dpy_gl_release_dmabuf = gd_gl_release_dmabuf, .dpy_has_dmabuf = gd_has_dmabuf, }; diff --git a/util/qemu-openpty.c b/util/qemu-openpty.c index eb17f5b0bc..427f43a769 100644 --- a/util/qemu-openpty.c +++ b/util/qemu-openpty.c @@ -80,10 +80,9 @@ static int openpty(int *amaster, int *aslave, char *name, (termp != NULL && tcgetattr(sfd, termp) < 0)) goto err; - if (amaster) - *amaster = mfd; - if (aslave) - *aslave = sfd; + *amaster = mfd; + *aslave = sfd; + if (winp) ioctl(sfd, TIOCSWINSZ, winp); |