Merge branch 'stable-10.0' into cr16-wip
This commit is contained in:
commit
86f9d26689
64 changed files with 743 additions and 378 deletions
2
VERSION
2
VERSION
|
|
@ -1 +1 @@
|
|||
10.0.2
|
||||
10.0.3
|
||||
|
|
|
|||
|
|
@ -2556,8 +2556,7 @@ static int kvm_init(MachineState *ms)
|
|||
{
|
||||
MachineClass *mc = MACHINE_GET_CLASS(ms);
|
||||
static const char upgrade_note[] =
|
||||
"Please upgrade to at least kernel 2.6.29 or recent kvm-kmod\n"
|
||||
"(see http://sourceforge.net/projects/kvm).\n";
|
||||
"Please upgrade to at least kernel 4.5.\n";
|
||||
const struct {
|
||||
const char *name;
|
||||
int num;
|
||||
|
|
|
|||
|
|
@ -905,6 +905,14 @@ size_t AUD_read(SWVoiceIn *sw, void *buf, size_t size)
|
|||
|
||||
int AUD_get_buffer_size_out(SWVoiceOut *sw)
|
||||
{
|
||||
if (!sw) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (audio_get_pdo_out(sw->s->dev)->mixing_engine) {
|
||||
return sw->resample_buf.size * sw->info.bytes_per_frame;
|
||||
}
|
||||
|
||||
return sw->hw->samples * sw->hw->info.bytes_per_frame;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -2484,9 +2484,9 @@ static inline bool raw_check_linux_aio(BDRVRawState *s)
|
|||
}
|
||||
#endif
|
||||
|
||||
static int coroutine_fn raw_co_prw(BlockDriverState *bs, int64_t *offset_ptr,
|
||||
uint64_t bytes, QEMUIOVector *qiov, int type,
|
||||
int flags)
|
||||
static int coroutine_fn GRAPH_RDLOCK
|
||||
raw_co_prw(BlockDriverState *bs, int64_t *offset_ptr, uint64_t bytes,
|
||||
QEMUIOVector *qiov, int type, int flags)
|
||||
{
|
||||
BDRVRawState *s = bs->opaque;
|
||||
RawPosixAIOData acb;
|
||||
|
|
@ -2545,7 +2545,7 @@ static int coroutine_fn raw_co_prw(BlockDriverState *bs, int64_t *offset_ptr,
|
|||
ret = raw_thread_pool_submit(handle_aiocb_rw, &acb);
|
||||
if (ret == 0 && (flags & BDRV_REQ_FUA)) {
|
||||
/* TODO Use pwritev2() instead if it's available */
|
||||
ret = raw_co_flush_to_disk(bs);
|
||||
ret = bdrv_co_flush(bs);
|
||||
}
|
||||
goto out; /* Avoid the compiler err of unused label */
|
||||
|
||||
|
|
@ -2580,16 +2580,16 @@ out:
|
|||
return ret;
|
||||
}
|
||||
|
||||
static int coroutine_fn raw_co_preadv(BlockDriverState *bs, int64_t offset,
|
||||
int64_t bytes, QEMUIOVector *qiov,
|
||||
BdrvRequestFlags flags)
|
||||
static int coroutine_fn GRAPH_RDLOCK
|
||||
raw_co_preadv(BlockDriverState *bs, int64_t offset, int64_t bytes,
|
||||
QEMUIOVector *qiov, BdrvRequestFlags flags)
|
||||
{
|
||||
return raw_co_prw(bs, &offset, bytes, qiov, QEMU_AIO_READ, flags);
|
||||
}
|
||||
|
||||
static int coroutine_fn raw_co_pwritev(BlockDriverState *bs, int64_t offset,
|
||||
int64_t bytes, QEMUIOVector *qiov,
|
||||
BdrvRequestFlags flags)
|
||||
static int coroutine_fn GRAPH_RDLOCK
|
||||
raw_co_pwritev(BlockDriverState *bs, int64_t offset, int64_t bytes,
|
||||
QEMUIOVector *qiov, BdrvRequestFlags flags)
|
||||
{
|
||||
return raw_co_prw(bs, &offset, bytes, qiov, QEMU_AIO_WRITE, flags);
|
||||
}
|
||||
|
|
@ -3525,10 +3525,11 @@ static int coroutine_fn raw_co_zone_mgmt(BlockDriverState *bs, BlockZoneOp op,
|
|||
#endif
|
||||
|
||||
#if defined(CONFIG_BLKZONED)
|
||||
static int coroutine_fn raw_co_zone_append(BlockDriverState *bs,
|
||||
int64_t *offset,
|
||||
QEMUIOVector *qiov,
|
||||
BdrvRequestFlags flags) {
|
||||
static int coroutine_fn GRAPH_RDLOCK
|
||||
raw_co_zone_append(BlockDriverState *bs,
|
||||
int64_t *offset,
|
||||
QEMUIOVector *qiov,
|
||||
BdrvRequestFlags flags) {
|
||||
assert(flags == 0);
|
||||
int64_t zone_size_mask = bs->bl.zone_size - 1;
|
||||
int64_t iov_len = 0;
|
||||
|
|
|
|||
|
|
@ -325,8 +325,9 @@ static void aspeed_ram_capacity_write(void *opaque, hwaddr addr, uint64_t data,
|
|||
* If writes the data to the address which is beyond the ram size,
|
||||
* it would write the data to the "address % ram_size".
|
||||
*/
|
||||
result = address_space_write(&s->dram_as, addr % ram_size,
|
||||
MEMTXATTRS_UNSPECIFIED, &data, 4);
|
||||
address_space_stl_le(&s->dram_as, addr % ram_size, data,
|
||||
MEMTXATTRS_UNSPECIFIED, &result);
|
||||
|
||||
if (result != MEMTX_OK) {
|
||||
qemu_log_mask(LOG_GUEST_ERROR,
|
||||
"%s: DRAM write failed, addr:0x%" HWADDR_PRIx
|
||||
|
|
@ -339,9 +340,10 @@ static const MemoryRegionOps aspeed_ram_capacity_ops = {
|
|||
.read = aspeed_ram_capacity_read,
|
||||
.write = aspeed_ram_capacity_write,
|
||||
.endianness = DEVICE_LITTLE_ENDIAN,
|
||||
.impl.min_access_size = 4,
|
||||
.valid = {
|
||||
.min_access_size = 1,
|
||||
.max_access_size = 8,
|
||||
.min_access_size = 4,
|
||||
.max_access_size = 4,
|
||||
},
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -356,6 +356,10 @@ static void fsl_imx8mp_realize(DeviceState *dev, Error **errp)
|
|||
qdev_get_gpio_in(cpudev, ARM_CPU_IRQ));
|
||||
sysbus_connect_irq(gicsbd, i + ms->smp.cpus,
|
||||
qdev_get_gpio_in(cpudev, ARM_CPU_FIQ));
|
||||
sysbus_connect_irq(gicsbd, i + 2 * ms->smp.cpus,
|
||||
qdev_get_gpio_in(cpudev, ARM_CPU_VIRQ));
|
||||
sysbus_connect_irq(gicsbd, i + 3 * ms->smp.cpus,
|
||||
qdev_get_gpio_in(cpudev, ARM_CPU_VFIQ));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -224,7 +224,11 @@ static void mps2_common_init(MachineState *machine)
|
|||
switch (mmc->fpga_type) {
|
||||
case FPGA_AN385:
|
||||
case FPGA_AN386:
|
||||
qdev_prop_set_uint32(armv7m, "num-irq", 32);
|
||||
break;
|
||||
case FPGA_AN500:
|
||||
/* The AN500 configures its Cortex-M7 with 16 MPU regions */
|
||||
qdev_prop_set_uint32(armv7m, "mpu-ns-regions", 16);
|
||||
qdev_prop_set_uint32(armv7m, "num-irq", 32);
|
||||
break;
|
||||
case FPGA_AN511:
|
||||
|
|
|
|||
|
|
@ -346,6 +346,7 @@ static struct arm_boot_info npcm8xx_binfo = {
|
|||
.secure_boot = false,
|
||||
.board_id = -1,
|
||||
.board_setup_addr = NPCM8XX_BOARD_SETUP_ADDR,
|
||||
.psci_conduit = QEMU_PSCI_CONDUIT_SMC,
|
||||
};
|
||||
|
||||
void npcm8xx_load_kernel(MachineState *machine, NPCM8xxState *soc)
|
||||
|
|
|
|||
|
|
@ -1492,9 +1492,12 @@ static void create_virtio_iommu_dt_bindings(VirtMachineState *vms)
|
|||
qemu_fdt_setprop_cell(ms->fdt, node, "phandle", vms->iommu_phandle);
|
||||
g_free(node);
|
||||
|
||||
qemu_fdt_setprop_cells(ms->fdt, vms->pciehb_nodename, "iommu-map",
|
||||
0x0, vms->iommu_phandle, 0x0, bdf,
|
||||
bdf + 1, vms->iommu_phandle, bdf + 1, 0xffff - bdf);
|
||||
if (!vms->default_bus_bypass_iommu) {
|
||||
qemu_fdt_setprop_cells(ms->fdt, vms->pciehb_nodename, "iommu-map",
|
||||
0x0, vms->iommu_phandle, 0x0, bdf,
|
||||
bdf + 1, vms->iommu_phandle, bdf + 1,
|
||||
0xffff - bdf);
|
||||
}
|
||||
}
|
||||
|
||||
static void create_pcie(VirtMachineState *vms)
|
||||
|
|
@ -1617,8 +1620,10 @@ static void create_pcie(VirtMachineState *vms)
|
|||
switch (vms->iommu) {
|
||||
case VIRT_IOMMU_SMMUV3:
|
||||
create_smmu(vms, vms->bus);
|
||||
qemu_fdt_setprop_cells(ms->fdt, nodename, "iommu-map",
|
||||
0x0, vms->iommu_phandle, 0x0, 0x10000);
|
||||
if (!vms->default_bus_bypass_iommu) {
|
||||
qemu_fdt_setprop_cells(ms->fdt, nodename, "iommu-map",
|
||||
0x0, vms->iommu_phandle, 0x0, 0x10000);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
g_assert_not_reached();
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@
|
|||
|
||||
#include "qemu/osdep.h"
|
||||
#include "qemu/timer.h"
|
||||
#include "qapi/error.h"
|
||||
#include "hw/sysbus.h"
|
||||
#include "hw/irq.h"
|
||||
#include "audio/audio.h"
|
||||
|
|
@ -654,6 +655,12 @@ static void asc_realize(DeviceState *dev, Error **errp)
|
|||
|
||||
s->voice = AUD_open_out(&s->card, s->voice, "asc.out", s, asc_out_cb,
|
||||
&as);
|
||||
if (!s->voice) {
|
||||
AUD_remove_card(&s->card);
|
||||
error_setg(errp, "Initializing audio stream failed");
|
||||
return;
|
||||
}
|
||||
|
||||
s->shift = 1;
|
||||
s->samples = AUD_get_buffer_size_out(s->voice) >> s->shift;
|
||||
s->mixbuf = g_malloc0(s->samples << s->shift);
|
||||
|
|
|
|||
|
|
@ -145,6 +145,7 @@ static void set_drive_helper(Object *obj, Visitor *v, const char *name,
|
|||
if (ctx != bdrv_get_aio_context(bs)) {
|
||||
error_setg(errp, "Different aio context is not supported for new "
|
||||
"node");
|
||||
return;
|
||||
}
|
||||
|
||||
blk_replace_bs(blk, bs, errp);
|
||||
|
|
|
|||
|
|
@ -970,6 +970,15 @@ void virtio_gpu_virgl_process_cmd(VirtIOGPU *g,
|
|||
}
|
||||
|
||||
trace_virtio_gpu_fence_ctrl(cmd->cmd_hdr.fence_id, cmd->cmd_hdr.type);
|
||||
#if VIRGL_VERSION_MAJOR >= 1
|
||||
if (cmd->cmd_hdr.flags & VIRTIO_GPU_FLAG_INFO_RING_IDX) {
|
||||
virgl_renderer_context_create_fence(cmd->cmd_hdr.ctx_id,
|
||||
VIRGL_RENDERER_FENCE_FLAG_MERGEABLE,
|
||||
cmd->cmd_hdr.ring_idx,
|
||||
cmd->cmd_hdr.fence_id);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
virgl_renderer_create_fence(cmd->cmd_hdr.fence_id, cmd->cmd_hdr.type);
|
||||
}
|
||||
|
||||
|
|
@ -983,6 +992,11 @@ static void virgl_write_fence(void *opaque, uint32_t fence)
|
|||
* the guest can end up emitting fences out of order
|
||||
* so we should check all fenced cmds not just the first one.
|
||||
*/
|
||||
#if VIRGL_VERSION_MAJOR >= 1
|
||||
if (cmd->cmd_hdr.flags & VIRTIO_GPU_FLAG_INFO_RING_IDX) {
|
||||
continue;
|
||||
}
|
||||
#endif
|
||||
if (cmd->cmd_hdr.fence_id > fence) {
|
||||
continue;
|
||||
}
|
||||
|
|
@ -997,6 +1011,29 @@ static void virgl_write_fence(void *opaque, uint32_t fence)
|
|||
}
|
||||
}
|
||||
|
||||
#if VIRGL_VERSION_MAJOR >= 1
|
||||
static void virgl_write_context_fence(void *opaque, uint32_t ctx_id,
|
||||
uint32_t ring_idx, uint64_t fence_id) {
|
||||
VirtIOGPU *g = opaque;
|
||||
struct virtio_gpu_ctrl_command *cmd, *tmp;
|
||||
|
||||
QTAILQ_FOREACH_SAFE(cmd, &g->fenceq, next, tmp) {
|
||||
if (cmd->cmd_hdr.flags & VIRTIO_GPU_FLAG_INFO_RING_IDX &&
|
||||
cmd->cmd_hdr.ctx_id == ctx_id && cmd->cmd_hdr.ring_idx == ring_idx &&
|
||||
cmd->cmd_hdr.fence_id <= fence_id) {
|
||||
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)) {
|
||||
trace_virtio_gpu_dec_inflight_fences(g->inflight);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
static virgl_renderer_gl_context
|
||||
virgl_create_context(void *opaque, int scanout_idx,
|
||||
struct virgl_renderer_gl_ctx_param *params)
|
||||
|
|
@ -1031,11 +1068,18 @@ static int virgl_make_context_current(void *opaque, int scanout_idx,
|
|||
}
|
||||
|
||||
static struct virgl_renderer_callbacks virtio_gpu_3d_cbs = {
|
||||
#if VIRGL_VERSION_MAJOR >= 1
|
||||
.version = 3,
|
||||
#else
|
||||
.version = 1,
|
||||
#endif
|
||||
.write_fence = virgl_write_fence,
|
||||
.create_gl_context = virgl_create_context,
|
||||
.destroy_gl_context = virgl_destroy_context,
|
||||
.make_current = virgl_make_context_current,
|
||||
#if VIRGL_VERSION_MAJOR >= 1
|
||||
.write_context_fence = virgl_write_context_fence,
|
||||
#endif
|
||||
};
|
||||
|
||||
static void virtio_gpu_print_stats(void *opaque)
|
||||
|
|
|
|||
|
|
@ -140,7 +140,7 @@ static void amdvi_writeq(AMDVIState *s, hwaddr addr, uint64_t val)
|
|||
{
|
||||
uint64_t romask = ldq_le_p(&s->romask[addr]);
|
||||
uint64_t w1cmask = ldq_le_p(&s->w1cmask[addr]);
|
||||
uint32_t oldval = ldq_le_p(&s->mmior[addr]);
|
||||
uint64_t oldval = ldq_le_p(&s->mmior[addr]);
|
||||
stq_le_p(&s->mmior[addr],
|
||||
((oldval & romask) | (val & ~romask)) & ~(val & w1cmask));
|
||||
}
|
||||
|
|
@ -508,7 +508,7 @@ static void amdvi_inval_inttable(AMDVIState *s, uint64_t *cmd)
|
|||
static void iommu_inval_iotlb(AMDVIState *s, uint64_t *cmd)
|
||||
{
|
||||
|
||||
uint16_t devid = extract64(cmd[0], 0, 16);
|
||||
uint16_t devid = cpu_to_le16(extract64(cmd[0], 0, 16));
|
||||
if (extract64(cmd[1], 1, 1) || extract64(cmd[1], 3, 1) ||
|
||||
extract64(cmd[1], 6, 6)) {
|
||||
amdvi_log_illegalcom_error(s, extract64(cmd[0], 60, 4),
|
||||
|
|
@ -521,7 +521,7 @@ static void iommu_inval_iotlb(AMDVIState *s, uint64_t *cmd)
|
|||
&devid);
|
||||
} else {
|
||||
amdvi_iotlb_remove_page(s, cpu_to_le64(extract64(cmd[1], 12, 52)) << 12,
|
||||
cpu_to_le16(extract64(cmd[1], 0, 16)));
|
||||
devid);
|
||||
}
|
||||
trace_amdvi_iotlb_inval();
|
||||
}
|
||||
|
|
@ -665,8 +665,8 @@ static inline void amdvi_handle_devtab_write(AMDVIState *s)
|
|||
uint64_t val = amdvi_readq(s, AMDVI_MMIO_DEVICE_TABLE);
|
||||
s->devtab = (val & AMDVI_MMIO_DEVTAB_BASE_MASK);
|
||||
|
||||
/* set device table length */
|
||||
s->devtab_len = ((val & AMDVI_MMIO_DEVTAB_SIZE_MASK) + 1 *
|
||||
/* set device table length (i.e. number of entries table can hold) */
|
||||
s->devtab_len = (((val & AMDVI_MMIO_DEVTAB_SIZE_MASK) + 1) *
|
||||
(AMDVI_MMIO_DEVTAB_SIZE_UNIT /
|
||||
AMDVI_MMIO_DEVTAB_ENTRY_SIZE));
|
||||
}
|
||||
|
|
@ -848,9 +848,10 @@ static inline uint64_t amdvi_get_perms(uint64_t entry)
|
|||
static bool amdvi_validate_dte(AMDVIState *s, uint16_t devid,
|
||||
uint64_t *dte)
|
||||
{
|
||||
if ((dte[0] & AMDVI_DTE_LOWER_QUAD_RESERVED)
|
||||
|| (dte[1] & AMDVI_DTE_MIDDLE_QUAD_RESERVED)
|
||||
|| (dte[2] & AMDVI_DTE_UPPER_QUAD_RESERVED) || dte[3]) {
|
||||
if ((dte[0] & AMDVI_DTE_QUAD0_RESERVED) ||
|
||||
(dte[1] & AMDVI_DTE_QUAD1_RESERVED) ||
|
||||
(dte[2] & AMDVI_DTE_QUAD2_RESERVED) ||
|
||||
(dte[3] & AMDVI_DTE_QUAD3_RESERVED)) {
|
||||
amdvi_log_illegaldevtab_error(s, devid,
|
||||
s->devtab +
|
||||
devid * AMDVI_DEVTAB_ENTRY_SIZE, 0);
|
||||
|
|
@ -1426,7 +1427,6 @@ static AddressSpace *amdvi_host_dma_iommu(PCIBus *bus, void *opaque, int devfn)
|
|||
AMDVIState *s = opaque;
|
||||
AMDVIAddressSpace **iommu_as, *amdvi_dev_as;
|
||||
int bus_num = pci_bus_num(bus);
|
||||
X86IOMMUState *x86_iommu = X86_IOMMU_DEVICE(s);
|
||||
|
||||
iommu_as = s->address_spaces[bus_num];
|
||||
|
||||
|
|
@ -1486,15 +1486,8 @@ static AddressSpace *amdvi_host_dma_iommu(PCIBus *bus, void *opaque, int devfn)
|
|||
AMDVI_INT_ADDR_FIRST,
|
||||
&amdvi_dev_as->iommu_ir, 1);
|
||||
|
||||
if (!x86_iommu->pt_supported) {
|
||||
memory_region_set_enabled(&amdvi_dev_as->iommu_nodma, false);
|
||||
memory_region_set_enabled(MEMORY_REGION(&amdvi_dev_as->iommu),
|
||||
true);
|
||||
} else {
|
||||
memory_region_set_enabled(MEMORY_REGION(&amdvi_dev_as->iommu),
|
||||
false);
|
||||
memory_region_set_enabled(&amdvi_dev_as->iommu_nodma, true);
|
||||
}
|
||||
memory_region_set_enabled(&amdvi_dev_as->iommu_nodma, false);
|
||||
memory_region_set_enabled(MEMORY_REGION(&amdvi_dev_as->iommu), true);
|
||||
}
|
||||
return &iommu_as[devfn]->as;
|
||||
}
|
||||
|
|
@ -1657,6 +1650,14 @@ static void amdvi_sysbus_realize(DeviceState *dev, Error **errp)
|
|||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
if (s->xtsup) {
|
||||
if (kvm_irqchip_is_split() && !kvm_enable_x2apic()) {
|
||||
error_report("AMD IOMMU xtsup=on requires x2APIC support on "
|
||||
"the KVM side");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
|
||||
pci_setup_iommu(bus, &amdvi_iommu_ops, s);
|
||||
amdvi_init(s);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -25,6 +25,8 @@
|
|||
#include "hw/i386/x86-iommu.h"
|
||||
#include "qom/object.h"
|
||||
|
||||
#define GENMASK64(h, l) (((~0ULL) >> (63 - (h) + (l))) << (l))
|
||||
|
||||
/* Capability registers */
|
||||
#define AMDVI_CAPAB_BAR_LOW 0x04
|
||||
#define AMDVI_CAPAB_BAR_HIGH 0x08
|
||||
|
|
@ -66,34 +68,34 @@
|
|||
|
||||
#define AMDVI_MMIO_SIZE 0x4000
|
||||
|
||||
#define AMDVI_MMIO_DEVTAB_SIZE_MASK ((1ULL << 12) - 1)
|
||||
#define AMDVI_MMIO_DEVTAB_BASE_MASK (((1ULL << 52) - 1) & ~ \
|
||||
AMDVI_MMIO_DEVTAB_SIZE_MASK)
|
||||
#define AMDVI_MMIO_DEVTAB_SIZE_MASK GENMASK64(8, 0)
|
||||
#define AMDVI_MMIO_DEVTAB_BASE_MASK GENMASK64(51, 12)
|
||||
|
||||
#define AMDVI_MMIO_DEVTAB_ENTRY_SIZE 32
|
||||
#define AMDVI_MMIO_DEVTAB_SIZE_UNIT 4096
|
||||
|
||||
/* some of this are similar but just for readability */
|
||||
#define AMDVI_MMIO_CMDBUF_SIZE_BYTE (AMDVI_MMIO_COMMAND_BASE + 7)
|
||||
#define AMDVI_MMIO_CMDBUF_SIZE_MASK 0x0f
|
||||
#define AMDVI_MMIO_CMDBUF_BASE_MASK AMDVI_MMIO_DEVTAB_BASE_MASK
|
||||
#define AMDVI_MMIO_CMDBUF_HEAD_MASK (((1ULL << 19) - 1) & ~0x0f)
|
||||
#define AMDVI_MMIO_CMDBUF_TAIL_MASK AMDVI_MMIO_EVTLOG_HEAD_MASK
|
||||
#define AMDVI_MMIO_CMDBUF_BASE_MASK GENMASK64(51, 12)
|
||||
#define AMDVI_MMIO_CMDBUF_HEAD_MASK GENMASK64(18, 4)
|
||||
#define AMDVI_MMIO_CMDBUF_TAIL_MASK GENMASK64(18, 4)
|
||||
|
||||
#define AMDVI_MMIO_EVTLOG_SIZE_BYTE (AMDVI_MMIO_EVENT_BASE + 7)
|
||||
#define AMDVI_MMIO_EVTLOG_SIZE_MASK AMDVI_MMIO_CMDBUF_SIZE_MASK
|
||||
#define AMDVI_MMIO_EVTLOG_BASE_MASK AMDVI_MMIO_CMDBUF_BASE_MASK
|
||||
#define AMDVI_MMIO_EVTLOG_HEAD_MASK (((1ULL << 19) - 1) & ~0x0f)
|
||||
#define AMDVI_MMIO_EVTLOG_TAIL_MASK AMDVI_MMIO_EVTLOG_HEAD_MASK
|
||||
#define AMDVI_MMIO_EVTLOG_SIZE_MASK 0x0f
|
||||
#define AMDVI_MMIO_EVTLOG_BASE_MASK GENMASK64(51, 12)
|
||||
#define AMDVI_MMIO_EVTLOG_HEAD_MASK GENMASK64(18, 4)
|
||||
#define AMDVI_MMIO_EVTLOG_TAIL_MASK GENMASK64(18, 4)
|
||||
|
||||
#define AMDVI_MMIO_PPRLOG_SIZE_BYTE (AMDVI_MMIO_EVENT_BASE + 7)
|
||||
#define AMDVI_MMIO_PPRLOG_HEAD_MASK AMDVI_MMIO_EVTLOG_HEAD_MASK
|
||||
#define AMDVI_MMIO_PPRLOG_TAIL_MASK AMDVI_MMIO_EVTLOG_HEAD_MASK
|
||||
#define AMDVI_MMIO_PPRLOG_BASE_MASK AMDVI_MMIO_EVTLOG_BASE_MASK
|
||||
#define AMDVI_MMIO_PPRLOG_SIZE_MASK AMDVI_MMIO_EVTLOG_SIZE_MASK
|
||||
#define AMDVI_MMIO_PPRLOG_SIZE_BYTE (AMDVI_MMIO_PPR_BASE + 7)
|
||||
#define AMDVI_MMIO_PPRLOG_SIZE_MASK 0x0f
|
||||
#define AMDVI_MMIO_PPRLOG_BASE_MASK GENMASK64(51, 12)
|
||||
#define AMDVI_MMIO_PPRLOG_HEAD_MASK GENMASK64(18, 4)
|
||||
#define AMDVI_MMIO_PPRLOG_TAIL_MASK GENMASK64(18, 4)
|
||||
|
||||
#define AMDVI_MMIO_EXCL_ENABLED_MASK (1ULL << 0)
|
||||
#define AMDVI_MMIO_EXCL_ALLOW_MASK (1ULL << 1)
|
||||
#define AMDVI_MMIO_EXCL_LIMIT_MASK AMDVI_MMIO_DEVTAB_BASE_MASK
|
||||
#define AMDVI_MMIO_EXCL_LIMIT_MASK GENMASK64(51, 12)
|
||||
#define AMDVI_MMIO_EXCL_LIMIT_LOW 0xfff
|
||||
|
||||
/* mmio control register flags */
|
||||
|
|
@ -130,14 +132,14 @@
|
|||
#define AMDVI_DEV_TRANSLATION_VALID (1ULL << 1)
|
||||
#define AMDVI_DEV_MODE_MASK 0x7
|
||||
#define AMDVI_DEV_MODE_RSHIFT 9
|
||||
#define AMDVI_DEV_PT_ROOT_MASK 0xffffffffff000
|
||||
#define AMDVI_DEV_PT_ROOT_MASK GENMASK64(51, 12)
|
||||
#define AMDVI_DEV_PT_ROOT_RSHIFT 12
|
||||
#define AMDVI_DEV_PERM_SHIFT 61
|
||||
#define AMDVI_DEV_PERM_READ (1ULL << 61)
|
||||
#define AMDVI_DEV_PERM_WRITE (1ULL << 62)
|
||||
|
||||
/* Device table entry bits 64:127 */
|
||||
#define AMDVI_DEV_DOMID_ID_MASK ((1ULL << 16) - 1)
|
||||
#define AMDVI_DEV_DOMID_ID_MASK GENMASK64(15, 0)
|
||||
|
||||
/* Event codes and flags, as stored in the info field */
|
||||
#define AMDVI_EVENT_ILLEGAL_DEVTAB_ENTRY (0x1U << 12)
|
||||
|
|
@ -162,9 +164,10 @@
|
|||
#define AMDVI_FEATURE_PC (1ULL << 9) /* Perf counters */
|
||||
|
||||
/* reserved DTE bits */
|
||||
#define AMDVI_DTE_LOWER_QUAD_RESERVED 0x80300000000000fc
|
||||
#define AMDVI_DTE_MIDDLE_QUAD_RESERVED 0x0000000000000100
|
||||
#define AMDVI_DTE_UPPER_QUAD_RESERVED 0x08f0000000000000
|
||||
#define AMDVI_DTE_QUAD0_RESERVED (GENMASK64(6, 2) | GENMASK64(63, 63))
|
||||
#define AMDVI_DTE_QUAD1_RESERVED 0
|
||||
#define AMDVI_DTE_QUAD2_RESERVED GENMASK64(53, 52)
|
||||
#define AMDVI_DTE_QUAD3_RESERVED (GENMASK64(14, 0) | GENMASK64(53, 48))
|
||||
|
||||
/* AMDVI paging mode */
|
||||
#define AMDVI_GATS_MODE (2ULL << 12)
|
||||
|
|
@ -194,19 +197,15 @@
|
|||
#define AMDVI_PAGE_SIZE (1ULL << AMDVI_PAGE_SHIFT)
|
||||
|
||||
#define AMDVI_PAGE_SHIFT_4K 12
|
||||
#define AMDVI_PAGE_MASK_4K (~((1ULL << AMDVI_PAGE_SHIFT_4K) - 1))
|
||||
#define AMDVI_PAGE_MASK_4K GENMASK64(63, 12)
|
||||
|
||||
#define AMDVI_MAX_VA_ADDR (48UL << 5)
|
||||
#define AMDVI_MAX_PH_ADDR (40UL << 8)
|
||||
#define AMDVI_MAX_GVA_ADDR (48UL << 15)
|
||||
#define AMDVI_MAX_GVA_ADDR (2UL << 5)
|
||||
#define AMDVI_MAX_PH_ADDR (40UL << 8)
|
||||
#define AMDVI_MAX_VA_ADDR (48UL << 15)
|
||||
|
||||
/* Completion Wait data size */
|
||||
#define AMDVI_COMPLETION_DATA_SIZE 8
|
||||
|
||||
#define AMDVI_COMMAND_SIZE 16
|
||||
/* Completion Wait data size */
|
||||
#define AMDVI_COMPLETION_DATA_SIZE 8
|
||||
|
||||
#define AMDVI_COMMAND_SIZE 16
|
||||
|
||||
#define AMDVI_INT_ADDR_FIRST 0xfee00000
|
||||
|
|
@ -228,7 +227,7 @@
|
|||
#define AMDVI_IR_INTCTL_PASS 1
|
||||
#define AMDVI_IR_INTCTL_REMAP 2
|
||||
|
||||
#define AMDVI_IR_PHYS_ADDR_MASK (((1ULL << 45) - 1) << 6)
|
||||
#define AMDVI_IR_PHYS_ADDR_MASK GENMASK64(51, 6)
|
||||
|
||||
/* MSI data 10:0 bits (section 2.2.5.1 Fig 14) */
|
||||
#define AMDVI_IRTE_OFFSET 0x7ff
|
||||
|
|
|
|||
|
|
@ -285,6 +285,8 @@ static void pc_init1(MachineState *machine, const char *pci_type)
|
|||
pcms->idebus[0] = qdev_get_child_bus(dev, "ide.0");
|
||||
pcms->idebus[1] = qdev_get_child_bus(dev, "ide.1");
|
||||
} else {
|
||||
uint32_t irq;
|
||||
|
||||
isa_bus = isa_bus_new(NULL, system_memory, system_io,
|
||||
&error_abort);
|
||||
isa_bus_register_input_irqs(isa_bus, x86ms->gsi);
|
||||
|
|
@ -292,6 +294,9 @@ static void pc_init1(MachineState *machine, const char *pci_type)
|
|||
x86ms->rtc = isa_new(TYPE_MC146818_RTC);
|
||||
qdev_prop_set_int32(DEVICE(x86ms->rtc), "base_year", 2000);
|
||||
isa_realize_and_unref(x86ms->rtc, isa_bus, &error_fatal);
|
||||
irq = object_property_get_uint(OBJECT(x86ms->rtc), "irq",
|
||||
&error_fatal);
|
||||
isa_connect_gpio_out(ISA_DEVICE(x86ms->rtc), 0, irq);
|
||||
|
||||
i8257_dma_init(OBJECT(machine), isa_bus, 0);
|
||||
pcms->hpet_enabled = false;
|
||||
|
|
|
|||
|
|
@ -575,8 +575,8 @@ static void acpi_build(AcpiBuildTables *tables, MachineState *machine)
|
|||
acpi_add_table(table_offsets, tables_blob);
|
||||
{
|
||||
AcpiMcfgInfo mcfg = {
|
||||
.base = cpu_to_le64(VIRT_PCI_CFG_BASE),
|
||||
.size = cpu_to_le64(VIRT_PCI_CFG_SIZE),
|
||||
.base = VIRT_PCI_CFG_BASE,
|
||||
.size = VIRT_PCI_CFG_SIZE,
|
||||
};
|
||||
build_mcfg(tables_blob, tables->linker, &mcfg, lvms->oem_id,
|
||||
lvms->oem_table_id);
|
||||
|
|
|
|||
|
|
@ -301,12 +301,6 @@ static void do_hash_operation(AspeedHACEState *s, int algo, bool sg_mode,
|
|||
iov[i - 1].iov_len, false,
|
||||
iov[i - 1].iov_len);
|
||||
}
|
||||
|
||||
/*
|
||||
* Set status bits to indicate completion. Testing shows hardware sets
|
||||
* these irrespective of HASH_IRQ_EN.
|
||||
*/
|
||||
s->regs[R_STATUS] |= HASH_IRQ;
|
||||
}
|
||||
|
||||
static uint64_t aspeed_hace_read(void *opaque, hwaddr addr, unsigned int size)
|
||||
|
|
@ -390,10 +384,16 @@ static void aspeed_hace_write(void *opaque, hwaddr addr, uint64_t data,
|
|||
qemu_log_mask(LOG_GUEST_ERROR,
|
||||
"%s: Invalid hash algorithm selection 0x%"PRIx64"\n",
|
||||
__func__, data & ahc->hash_mask);
|
||||
break;
|
||||
} else {
|
||||
do_hash_operation(s, algo, data & HASH_SG_EN,
|
||||
((data & HASH_HMAC_MASK) == HASH_DIGEST_ACCUM));
|
||||
}
|
||||
do_hash_operation(s, algo, data & HASH_SG_EN,
|
||||
((data & HASH_HMAC_MASK) == HASH_DIGEST_ACCUM));
|
||||
|
||||
/*
|
||||
* Set status bits to indicate completion. Testing shows hardware sets
|
||||
* these irrespective of HASH_IRQ_EN.
|
||||
*/
|
||||
s->regs[R_STATUS] |= HASH_IRQ;
|
||||
|
||||
if (data & HASH_IRQ_EN) {
|
||||
qemu_irq_raise(s->irq);
|
||||
|
|
|
|||
|
|
@ -615,6 +615,7 @@ static void gmac_try_send_next_packet(NPCMGMACState *gmac)
|
|||
trace_npcm_gmac_packet_sent(DEVICE(gmac)->canonical_path, length);
|
||||
buf = tx_send_buffer;
|
||||
length = 0;
|
||||
prev_buf_size = 0;
|
||||
}
|
||||
|
||||
/* step 6 */
|
||||
|
|
|
|||
|
|
@ -3021,11 +3021,10 @@ static void virtio_net_del_queue(VirtIONet *n, int index)
|
|||
virtio_del_queue(vdev, index * 2 + 1);
|
||||
}
|
||||
|
||||
static void virtio_net_change_num_queue_pairs(VirtIONet *n, int new_max_queue_pairs)
|
||||
static void virtio_net_change_num_queues(VirtIONet *n, int new_num_queues)
|
||||
{
|
||||
VirtIODevice *vdev = VIRTIO_DEVICE(n);
|
||||
int old_num_queues = virtio_get_num_queues(vdev);
|
||||
int new_num_queues = new_max_queue_pairs * 2 + 1;
|
||||
int i;
|
||||
|
||||
assert(old_num_queues >= 3);
|
||||
|
|
@ -3061,16 +3060,14 @@ static void virtio_net_set_multiqueue(VirtIONet *n, int multiqueue)
|
|||
int max = multiqueue ? n->max_queue_pairs : 1;
|
||||
|
||||
n->multiqueue = multiqueue;
|
||||
virtio_net_change_num_queue_pairs(n, max);
|
||||
virtio_net_change_num_queues(n, max * 2 + 1);
|
||||
|
||||
virtio_net_set_queue_pairs(n);
|
||||
}
|
||||
|
||||
static int virtio_net_pre_load_queues(VirtIODevice *vdev)
|
||||
static int virtio_net_pre_load_queues(VirtIODevice *vdev, uint32_t n)
|
||||
{
|
||||
virtio_net_set_multiqueue(VIRTIO_NET(vdev),
|
||||
virtio_has_feature(vdev->guest_features, VIRTIO_NET_F_RSS) ||
|
||||
virtio_has_feature(vdev->guest_features, VIRTIO_NET_F_MQ));
|
||||
virtio_net_change_num_queues(VIRTIO_NET(vdev), n);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1719,7 +1719,7 @@ static void pci_update_mappings(PCIDevice *d)
|
|||
pci_update_vga(d);
|
||||
}
|
||||
|
||||
static inline int pci_irq_disabled(PCIDevice *d)
|
||||
int pci_irq_disabled(PCIDevice *d)
|
||||
{
|
||||
return pci_get_word(d->config + PCI_COMMAND) & PCI_COMMAND_INTX_DISABLE;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -57,7 +57,7 @@ static void ccw_device_set_loadparm(Object *obj, Visitor *v,
|
|||
Error **errp)
|
||||
{
|
||||
CcwDevice *dev = CCW_DEVICE(obj);
|
||||
char *val;
|
||||
g_autofree char *val = NULL;
|
||||
int index;
|
||||
|
||||
index = object_property_get_int(obj, "bootindex", NULL);
|
||||
|
|
|
|||
|
|
@ -47,12 +47,6 @@ static struct vhost_log *vhost_log[VHOST_BACKEND_TYPE_MAX];
|
|||
static struct vhost_log *vhost_log_shm[VHOST_BACKEND_TYPE_MAX];
|
||||
static QLIST_HEAD(, vhost_dev) vhost_log_devs[VHOST_BACKEND_TYPE_MAX];
|
||||
|
||||
/* Memslots used by backends that support private memslots (without an fd). */
|
||||
static unsigned int used_memslots;
|
||||
|
||||
/* Memslots used by backends that only support shared memslots (with an fd). */
|
||||
static unsigned int used_shared_memslots;
|
||||
|
||||
static QLIST_HEAD(, vhost_dev) vhost_devices =
|
||||
QLIST_HEAD_INITIALIZER(vhost_devices);
|
||||
|
||||
|
|
@ -74,15 +68,15 @@ unsigned int vhost_get_free_memslots(void)
|
|||
|
||||
QLIST_FOREACH(hdev, &vhost_devices, entry) {
|
||||
unsigned int r = hdev->vhost_ops->vhost_backend_memslots_limit(hdev);
|
||||
unsigned int cur_free;
|
||||
unsigned int cur_free = r - hdev->mem->nregions;
|
||||
|
||||
if (hdev->vhost_ops->vhost_backend_no_private_memslots &&
|
||||
hdev->vhost_ops->vhost_backend_no_private_memslots(hdev)) {
|
||||
cur_free = r - used_shared_memslots;
|
||||
if (unlikely(r < hdev->mem->nregions)) {
|
||||
warn_report_once("used (%u) vhost backend memory slots exceed"
|
||||
" the device limit (%u).", hdev->mem->nregions, r);
|
||||
free = 0;
|
||||
} else {
|
||||
cur_free = r - used_memslots;
|
||||
free = MIN(free, cur_free);
|
||||
}
|
||||
free = MIN(free, cur_free);
|
||||
}
|
||||
return free;
|
||||
}
|
||||
|
|
@ -666,13 +660,6 @@ static void vhost_commit(MemoryListener *listener)
|
|||
dev->mem = g_realloc(dev->mem, regions_size);
|
||||
dev->mem->nregions = dev->n_mem_sections;
|
||||
|
||||
if (dev->vhost_ops->vhost_backend_no_private_memslots &&
|
||||
dev->vhost_ops->vhost_backend_no_private_memslots(dev)) {
|
||||
used_shared_memslots = dev->mem->nregions;
|
||||
} else {
|
||||
used_memslots = dev->mem->nregions;
|
||||
}
|
||||
|
||||
for (i = 0; i < dev->n_mem_sections; i++) {
|
||||
struct vhost_memory_region *cur_vmr = dev->mem->regions + i;
|
||||
struct MemoryRegionSection *mrs = dev->mem_sections + i;
|
||||
|
|
@ -1619,15 +1606,11 @@ int vhost_dev_init(struct vhost_dev *hdev, void *opaque,
|
|||
QLIST_INSERT_HEAD(&vhost_devices, hdev, entry);
|
||||
|
||||
/*
|
||||
* The listener we registered properly updated the corresponding counter.
|
||||
* So we can trust that these values are accurate.
|
||||
* The listener we registered properly setup the number of required
|
||||
* memslots in vhost_commit().
|
||||
*/
|
||||
if (hdev->vhost_ops->vhost_backend_no_private_memslots &&
|
||||
hdev->vhost_ops->vhost_backend_no_private_memslots(hdev)) {
|
||||
used = used_shared_memslots;
|
||||
} else {
|
||||
used = used_memslots;
|
||||
}
|
||||
used = hdev->mem->nregions;
|
||||
|
||||
/*
|
||||
* We assume that all reserved memslots actually require a real memslot
|
||||
* in our vhost backend. This might not be true, for example, if the
|
||||
|
|
|
|||
|
|
@ -1215,7 +1215,12 @@ static int virtio_pci_set_guest_notifier(DeviceState *d, int n, bool assign,
|
|||
static bool virtio_pci_query_guest_notifiers(DeviceState *d)
|
||||
{
|
||||
VirtIOPCIProxy *proxy = to_virtio_pci_proxy(d);
|
||||
return msix_enabled(&proxy->pci_dev);
|
||||
|
||||
if (msix_enabled(&proxy->pci_dev)) {
|
||||
return true;
|
||||
} else {
|
||||
return pci_irq_disabled(&proxy->pci_dev);
|
||||
}
|
||||
}
|
||||
|
||||
static int virtio_pci_set_guest_notifiers(DeviceState *d, int nvqs, bool assign)
|
||||
|
|
|
|||
|
|
@ -3257,13 +3257,6 @@ virtio_load(VirtIODevice *vdev, QEMUFile *f, int version_id)
|
|||
config_len--;
|
||||
}
|
||||
|
||||
if (vdc->pre_load_queues) {
|
||||
ret = vdc->pre_load_queues(vdev);
|
||||
if (ret) {
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
num = qemu_get_be32(f);
|
||||
|
||||
if (num > VIRTIO_QUEUE_MAX) {
|
||||
|
|
@ -3271,6 +3264,13 @@ virtio_load(VirtIODevice *vdev, QEMUFile *f, int version_id)
|
|||
return -1;
|
||||
}
|
||||
|
||||
if (vdc->pre_load_queues) {
|
||||
ret = vdc->pre_load_queues(vdev, num);
|
||||
if (ret) {
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < num; i++) {
|
||||
vdev->vq[i].vring.num = qemu_get_be32(f);
|
||||
if (k->has_variable_vring_alignment) {
|
||||
|
|
|
|||
|
|
@ -668,6 +668,7 @@ void lsi53c8xx_handle_legacy_cmdline(DeviceState *lsi_dev);
|
|||
|
||||
qemu_irq pci_allocate_irq(PCIDevice *pci_dev);
|
||||
void pci_set_irq(PCIDevice *pci_dev, int level);
|
||||
int pci_irq_disabled(PCIDevice *d);
|
||||
|
||||
static inline void pci_irq_assert(PCIDevice *pci_dev)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -210,8 +210,14 @@ struct VirtioDeviceClass {
|
|||
void (*guest_notifier_mask)(VirtIODevice *vdev, int n, bool mask);
|
||||
int (*start_ioeventfd)(VirtIODevice *vdev);
|
||||
void (*stop_ioeventfd)(VirtIODevice *vdev);
|
||||
/* Called before loading queues. Useful to add queues before loading. */
|
||||
int (*pre_load_queues)(VirtIODevice *vdev);
|
||||
/*
|
||||
* Called before loading queues.
|
||||
* If the number of queues change at runtime, use @n to know the
|
||||
* number and add or remove queues accordingly.
|
||||
* Note that this function is called in the middle of loading vmsd;
|
||||
* no assumption should be made on states being loaded from vmsd.
|
||||
*/
|
||||
int (*pre_load_queues)(VirtIODevice *vdev, uint32_t n);
|
||||
/* Saving and loading of a device; trying to deprecate save/load
|
||||
* use vmsd for new devices.
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -224,4 +224,6 @@ int gd_gl_area_make_current(DisplayGLCtx *dgc,
|
|||
/* gtk-clipboard.c */
|
||||
void gd_clipboard_init(GtkDisplayState *gd);
|
||||
|
||||
void gd_update_scale(VirtualConsole *vc, int ww, int wh, int fbw, int fbh);
|
||||
|
||||
#endif /* UI_GTK_H */
|
||||
|
|
|
|||
|
|
@ -75,12 +75,12 @@ PixelFormat qemu_pixelformat_from_pixman(pixman_format_code_t format);
|
|||
pixman_format_code_t qemu_default_pixman_format(int bpp, bool native_endian);
|
||||
pixman_format_code_t qemu_drm_format_to_pixman(uint32_t drm_format);
|
||||
uint32_t qemu_pixman_to_drm_format(pixman_format_code_t pixman);
|
||||
int qemu_pixman_get_type(int rshift, int gshift, int bshift);
|
||||
int qemu_pixman_get_type(int rshift, int gshift, int bshift, int endian);
|
||||
bool qemu_pixman_check_format(DisplayChangeListener *dcl,
|
||||
pixman_format_code_t format);
|
||||
|
||||
#ifdef CONFIG_PIXMAN
|
||||
pixman_format_code_t qemu_pixman_get_format(PixelFormat *pf);
|
||||
pixman_format_code_t qemu_pixman_get_format(PixelFormat *pf, int endian);
|
||||
pixman_image_t *qemu_pixman_linebuf_create(pixman_format_code_t format,
|
||||
int width);
|
||||
void qemu_pixman_linebuf_fill(pixman_image_t *linebuf, pixman_image_t *fb,
|
||||
|
|
|
|||
|
|
@ -362,6 +362,7 @@ void cpu_loop(CPUARMState *env)
|
|||
switch (n) {
|
||||
case ARM_NR_cacheflush:
|
||||
/* nop */
|
||||
env->regs[0] = 0;
|
||||
break;
|
||||
case ARM_NR_set_tls:
|
||||
cpu_set_tls(env, env->regs[0]);
|
||||
|
|
|
|||
|
|
@ -36,6 +36,16 @@ static inline void fd_trans_init(void)
|
|||
qemu_mutex_init(&target_fd_trans_lock);
|
||||
}
|
||||
|
||||
static inline void fd_trans_prefork(void)
|
||||
{
|
||||
qemu_mutex_lock(&target_fd_trans_lock);
|
||||
}
|
||||
|
||||
static inline void fd_trans_postfork(void)
|
||||
{
|
||||
qemu_mutex_unlock(&target_fd_trans_lock);
|
||||
}
|
||||
|
||||
static inline TargetFdDataFunc fd_trans_target_to_host_data(int fd)
|
||||
{
|
||||
if (fd < 0) {
|
||||
|
|
|
|||
|
|
@ -149,12 +149,14 @@ void fork_start(void)
|
|||
cpu_list_lock();
|
||||
qemu_plugin_user_prefork_lock();
|
||||
gdbserver_fork_start();
|
||||
fd_trans_prefork();
|
||||
}
|
||||
|
||||
void fork_end(pid_t pid)
|
||||
{
|
||||
bool child = pid == 0;
|
||||
|
||||
fd_trans_postfork();
|
||||
qemu_plugin_user_postfork(child);
|
||||
mmap_fork_end(child);
|
||||
if (child) {
|
||||
|
|
|
|||
|
|
@ -789,6 +789,10 @@ safe_syscall6(ssize_t, copy_file_range, int, infd, loff_t *, pinoff,
|
|||
int, outfd, loff_t *, poutoff, size_t, length,
|
||||
unsigned int, flags)
|
||||
#endif
|
||||
#if defined(TARGET_NR_fchmodat2) && defined(__NR_fchmodat2)
|
||||
safe_syscall4(int, fchmodat2, int, dfd, const char *, filename,
|
||||
unsigned short, mode, unsigned int, flags)
|
||||
#endif
|
||||
|
||||
/* We do ioctl like this rather than via safe_syscall3 to preserve the
|
||||
* "third argument might be integer or pointer or not present" behaviour of
|
||||
|
|
@ -6742,10 +6746,9 @@ static int do_fork(CPUArchState *env, unsigned int flags, abi_ulong newsp,
|
|||
int pid_child = ret;
|
||||
pid_fd = pidfd_open(pid_child, 0);
|
||||
if (pid_fd >= 0) {
|
||||
fcntl(pid_fd, F_SETFD, fcntl(pid_fd, F_GETFL)
|
||||
| FD_CLOEXEC);
|
||||
qemu_set_cloexec(pid_fd);
|
||||
} else {
|
||||
pid_fd = 0;
|
||||
pid_fd = 0;
|
||||
}
|
||||
#endif
|
||||
put_user_u32(pid_fd, parent_tidptr);
|
||||
|
|
@ -10709,6 +10712,15 @@ static abi_long do_syscall1(CPUArchState *cpu_env, int num, abi_long arg1,
|
|||
ret = get_errno(fchmodat(arg1, p, arg3, 0));
|
||||
unlock_user(p, arg2, 0);
|
||||
return ret;
|
||||
#endif
|
||||
#if defined(TARGET_NR_fchmodat2) && defined(__NR_fchmodat2)
|
||||
case TARGET_NR_fchmodat2:
|
||||
if (!(p = lock_user_string(arg2))) {
|
||||
return -TARGET_EFAULT;
|
||||
}
|
||||
ret = get_errno(safe_fchmodat2(arg1, p, arg3, arg4));
|
||||
unlock_user(p, arg2, 0);
|
||||
return ret;
|
||||
#endif
|
||||
case TARGET_NR_getpriority:
|
||||
/* Note that negative values are valid for getpriority, so we must
|
||||
|
|
@ -11626,10 +11638,14 @@ static abi_long do_syscall1(CPUArchState *cpu_env, int num, abi_long arg1,
|
|||
case TARGET_NR_nanosleep:
|
||||
{
|
||||
struct timespec req, rem;
|
||||
target_to_host_timespec(&req, arg1);
|
||||
if (target_to_host_timespec(&req, arg1)) {
|
||||
return -TARGET_EFAULT;
|
||||
}
|
||||
ret = get_errno(safe_nanosleep(&req, &rem));
|
||||
if (is_error(ret) && arg2) {
|
||||
host_to_target_timespec(arg2, &rem);
|
||||
if (host_to_target_timespec(arg2, &rem)) {
|
||||
return -TARGET_EFAULT;
|
||||
}
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
|
|
|
|||
|
|
@ -3598,7 +3598,9 @@ static int ram_load_cleanup(void *opaque)
|
|||
RAMBlock *rb;
|
||||
|
||||
RAMBLOCK_FOREACH_NOT_IGNORED(rb) {
|
||||
qemu_ram_block_writeback(rb);
|
||||
if (memory_region_is_nonvolatile(rb->mr)) {
|
||||
qemu_ram_block_writeback(rb);
|
||||
}
|
||||
}
|
||||
|
||||
xbzrle_load_cleanup();
|
||||
|
|
|
|||
|
|
@ -323,7 +323,7 @@ static int af_xdp_umem_create(AFXDPState *s, int sock_fd, Error **errp)
|
|||
|
||||
s->pool = g_new(uint64_t, n_descs);
|
||||
/* Fill the pool in the opposite order, because it's a LIFO queue. */
|
||||
for (i = n_descs; i >= 0; i--) {
|
||||
for (i = n_descs - 1; i >= 0; i--) {
|
||||
s->pool[i] = i * XSK_UMEM__DEFAULT_FRAME_SIZE;
|
||||
}
|
||||
s->n_pool = n_descs;
|
||||
|
|
|
|||
0
pc-bios/hppa-firmware.img
Executable file → Normal file
0
pc-bios/hppa-firmware.img
Executable file → Normal file
0
pc-bios/hppa-firmware64.img
Executable file → Normal file
0
pc-bios/hppa-firmware64.img
Executable file → Normal file
|
|
@ -4936,13 +4936,13 @@ SRST
|
|||
with actual performance.
|
||||
|
||||
When the virtual cpu is sleeping, the virtual time will advance at
|
||||
default speed unless ``sleep=on`` is specified. With
|
||||
``sleep=on``, the virtual time will jump to the next timer
|
||||
default speed unless ``sleep=off`` is specified. With
|
||||
``sleep=off``, the virtual time will jump to the next timer
|
||||
deadline instantly whenever the virtual cpu goes to sleep mode and
|
||||
will not advance if no timer is enabled. This behavior gives
|
||||
deterministic execution times from the guest point of view.
|
||||
The default if icount is enabled is ``sleep=off``.
|
||||
``sleep=on`` cannot be used together with either ``shift=auto``
|
||||
The default if icount is enabled is ``sleep=on``.
|
||||
``sleep=off`` cannot be used together with either ``shift=auto``
|
||||
or ``align=on``.
|
||||
|
||||
``align=on`` will activate the delay algorithm which will try to
|
||||
|
|
|
|||
|
|
@ -986,11 +986,20 @@ static const ARMCPRegInfo debug_cp_reginfo[] = {
|
|||
.opc0 = 2, .opc1 = 0, .crn = 0, .crm = 3, .opc2 = 2,
|
||||
.access = PL1_RW, .accessfn = access_tdcc,
|
||||
.type = ARM_CP_CONST, .resetvalue = 0 },
|
||||
/* DBGDTRTX_EL0/DBGDTRRX_EL0 depend on direction */
|
||||
{ .name = "DBGDTR_EL0", .state = ARM_CP_STATE_BOTH, .cp = 14,
|
||||
/* Architecturally DBGDTRTX is named DBGDTRRX when used for reads */
|
||||
{ .name = "DBGDTRTX_EL0", .state = ARM_CP_STATE_AA64,
|
||||
.opc0 = 2, .opc1 = 3, .crn = 0, .crm = 5, .opc2 = 0,
|
||||
.access = PL0_RW, .accessfn = access_tdcc,
|
||||
.type = ARM_CP_CONST, .resetvalue = 0 },
|
||||
{ .name = "DBGDTRTX", .state = ARM_CP_STATE_AA32, .cp = 14,
|
||||
.opc1 = 0, .crn = 0, .crm = 5, .opc2 = 0,
|
||||
.access = PL0_RW, .accessfn = access_tdcc,
|
||||
.type = ARM_CP_CONST, .resetvalue = 0 },
|
||||
/* This is AArch64-only and is a combination of DBGDTRTX and DBGDTRRX */
|
||||
{ .name = "DBGDTR_EL0", .state = ARM_CP_STATE_AA64,
|
||||
.opc0 = 2, .opc1 = 3, .crn = 0, .crm = 4, .opc2 = 0,
|
||||
.access = PL0_RW, .accessfn = access_tdcc,
|
||||
.type = ARM_CP_CONST, .resetvalue = 0 },
|
||||
/*
|
||||
* OSECCR_EL1 provides a mechanism for an operating system
|
||||
* to access the contents of EDECCR. EDECCR is not implemented though,
|
||||
|
|
|
|||
|
|
@ -878,7 +878,7 @@ static bool hvf_arm_get_host_cpu_features(ARMHostCPUFeatures *ahcf)
|
|||
hv_vcpu_exit_t *exit;
|
||||
int i;
|
||||
|
||||
ahcf->dtb_compatible = "arm,arm-v8";
|
||||
ahcf->dtb_compatible = "arm,armv8";
|
||||
ahcf->features = (1ULL << ARM_FEATURE_V8) |
|
||||
(1ULL << ARM_FEATURE_NEON) |
|
||||
(1ULL << ARM_FEATURE_AARCH64) |
|
||||
|
|
@ -1352,6 +1352,7 @@ static int hvf_sysreg_read(CPUState *cpu, uint32_t reg, uint64_t *val)
|
|||
case SYSREG_ICC_IGRPEN0_EL1:
|
||||
case SYSREG_ICC_IGRPEN1_EL1:
|
||||
case SYSREG_ICC_PMR_EL1:
|
||||
case SYSREG_ICC_RPR_EL1:
|
||||
case SYSREG_ICC_SGI0R_EL1:
|
||||
case SYSREG_ICC_SGI1R_EL1:
|
||||
case SYSREG_ICC_SRE_EL1:
|
||||
|
|
@ -1666,6 +1667,7 @@ static int hvf_sysreg_write(CPUState *cpu, uint32_t reg, uint64_t val)
|
|||
case SYSREG_ICC_IGRPEN0_EL1:
|
||||
case SYSREG_ICC_IGRPEN1_EL1:
|
||||
case SYSREG_ICC_PMR_EL1:
|
||||
case SYSREG_ICC_RPR_EL1:
|
||||
case SYSREG_ICC_SGI0R_EL1:
|
||||
case SYSREG_ICC_SGI1R_EL1:
|
||||
case SYSREG_ICC_SRE_EL1:
|
||||
|
|
|
|||
|
|
@ -305,7 +305,7 @@ static bool kvm_arm_get_host_cpu_features(ARMHostCPUFeatures *ahcf)
|
|||
}
|
||||
|
||||
ahcf->target = init.target;
|
||||
ahcf->dtb_compatible = "arm,arm-v8";
|
||||
ahcf->dtb_compatible = "arm,armv8";
|
||||
|
||||
err = read_sys_reg64(fdarray[2], &ahcf->isar.id_aa64pfr0,
|
||||
ARM64_SYS_REG(3, 0, 0, 4, 0));
|
||||
|
|
|
|||
|
|
@ -653,15 +653,6 @@ void HELPER(exception_return)(CPUARMState *env, uint64_t new_pc)
|
|||
spsr &= ~PSTATE_SS;
|
||||
}
|
||||
|
||||
/*
|
||||
* FEAT_RME forbids return from EL3 with an invalid security state.
|
||||
* We don't need an explicit check for FEAT_RME here because we enforce
|
||||
* in scr_write() that you can't set the NSE bit without it.
|
||||
*/
|
||||
if (cur_el == 3 && (env->cp15.scr_el3 & (SCR_NS | SCR_NSE)) == SCR_NSE) {
|
||||
goto illegal_return;
|
||||
}
|
||||
|
||||
new_el = el_from_spsr(spsr);
|
||||
if (new_el == -1) {
|
||||
goto illegal_return;
|
||||
|
|
@ -673,6 +664,17 @@ void HELPER(exception_return)(CPUARMState *env, uint64_t new_pc)
|
|||
goto illegal_return;
|
||||
}
|
||||
|
||||
/*
|
||||
* FEAT_RME forbids return from EL3 to a lower exception level
|
||||
* with an invalid security state.
|
||||
* We don't need an explicit check for FEAT_RME here because we enforce
|
||||
* in scr_write() that you can't set the NSE bit without it.
|
||||
*/
|
||||
if (cur_el == 3 && new_el < 3 &&
|
||||
(env->cp15.scr_el3 & (SCR_NS | SCR_NSE)) == SCR_NSE) {
|
||||
goto illegal_return;
|
||||
}
|
||||
|
||||
if (new_el != 0 && arm_el_is_aa64(env, new_el) != return_to_aa64) {
|
||||
/* Return to an EL which is configured for a different register width */
|
||||
goto illegal_return;
|
||||
|
|
|
|||
|
|
@ -1005,25 +1005,55 @@ static float32 f16_dotadd(float32 sum, uint32_t e1, uint32_t e2,
|
|||
* - we have pre-set-up copy of s_std which is set to round-to-odd,
|
||||
* for the multiply (see below)
|
||||
*/
|
||||
float64 e1r = float16_to_float64(e1 & 0xffff, true, s_f16);
|
||||
float64 e1c = float16_to_float64(e1 >> 16, true, s_f16);
|
||||
float64 e2r = float16_to_float64(e2 & 0xffff, true, s_f16);
|
||||
float64 e2c = float16_to_float64(e2 >> 16, true, s_f16);
|
||||
float64 t64;
|
||||
float16 h1r = e1 & 0xffff;
|
||||
float16 h1c = e1 >> 16;
|
||||
float16 h2r = e2 & 0xffff;
|
||||
float16 h2c = e2 >> 16;
|
||||
float32 t32;
|
||||
|
||||
/*
|
||||
* The ARM pseudocode function FPDot performs both multiplies
|
||||
* and the add with a single rounding operation. Emulate this
|
||||
* by performing the first multiply in round-to-odd, then doing
|
||||
* the second multiply as fused multiply-add, and rounding to
|
||||
* float32 all in one step.
|
||||
*/
|
||||
t64 = float64_mul(e1r, e2r, s_odd);
|
||||
t64 = float64r32_muladd(e1c, e2c, t64, 0, s_std);
|
||||
/* C.f. FPProcessNaNs4 */
|
||||
if (float16_is_any_nan(h1r) || float16_is_any_nan(h1c) ||
|
||||
float16_is_any_nan(h2r) || float16_is_any_nan(h2c)) {
|
||||
float16 t16;
|
||||
|
||||
/* This conversion is exact, because we've already rounded. */
|
||||
t32 = float64_to_float32(t64, s_std);
|
||||
if (float16_is_signaling_nan(h1r, s_f16)) {
|
||||
t16 = h1r;
|
||||
} else if (float16_is_signaling_nan(h1c, s_f16)) {
|
||||
t16 = h1c;
|
||||
} else if (float16_is_signaling_nan(h2r, s_f16)) {
|
||||
t16 = h2r;
|
||||
} else if (float16_is_signaling_nan(h2c, s_f16)) {
|
||||
t16 = h2c;
|
||||
} else if (float16_is_any_nan(h1r)) {
|
||||
t16 = h1r;
|
||||
} else if (float16_is_any_nan(h1c)) {
|
||||
t16 = h1c;
|
||||
} else if (float16_is_any_nan(h2r)) {
|
||||
t16 = h2r;
|
||||
} else {
|
||||
t16 = h2c;
|
||||
}
|
||||
t32 = float16_to_float32(t16, true, s_f16);
|
||||
} else {
|
||||
float64 e1r = float16_to_float64(h1r, true, s_f16);
|
||||
float64 e1c = float16_to_float64(h1c, true, s_f16);
|
||||
float64 e2r = float16_to_float64(h2r, true, s_f16);
|
||||
float64 e2c = float16_to_float64(h2c, true, s_f16);
|
||||
float64 t64;
|
||||
|
||||
/*
|
||||
* The ARM pseudocode function FPDot performs both multiplies
|
||||
* and the add with a single rounding operation. Emulate this
|
||||
* by performing the first multiply in round-to-odd, then doing
|
||||
* the second multiply as fused multiply-add, and rounding to
|
||||
* float32 all in one step.
|
||||
*/
|
||||
t64 = float64_mul(e1r, e2r, s_odd);
|
||||
t64 = float64r32_muladd(e1c, e2c, t64, 0, s_std);
|
||||
|
||||
/* This conversion is exact, because we've already rounded. */
|
||||
t32 = float64_to_float32(t64, s_std);
|
||||
}
|
||||
|
||||
/* The final accumulation step is not fused. */
|
||||
return float32_add(sum, t32, s_std);
|
||||
|
|
|
|||
|
|
@ -1392,11 +1392,8 @@ static bool fp_access_check_only(DisasContext *s)
|
|||
return true;
|
||||
}
|
||||
|
||||
static bool fp_access_check(DisasContext *s)
|
||||
static bool nonstreaming_check(DisasContext *s)
|
||||
{
|
||||
if (!fp_access_check_only(s)) {
|
||||
return false;
|
||||
}
|
||||
if (s->sme_trap_nonstreaming && s->is_nonstreaming) {
|
||||
gen_exception_insn(s, 0, EXCP_UDEF,
|
||||
syn_smetrap(SME_ET_Streaming, false));
|
||||
|
|
@ -1405,6 +1402,11 @@ static bool fp_access_check(DisasContext *s)
|
|||
return true;
|
||||
}
|
||||
|
||||
static bool fp_access_check(DisasContext *s)
|
||||
{
|
||||
return fp_access_check_only(s) && nonstreaming_check(s);
|
||||
}
|
||||
|
||||
/*
|
||||
* Return <0 for non-supported element sizes, with MO_16 controlled by
|
||||
* FEAT_FP16; return 0 for fp disabled; otherwise return >0 for success.
|
||||
|
|
@ -1455,14 +1457,24 @@ static int fp_access_check_vector_hsd(DisasContext *s, bool is_q, MemOp esz)
|
|||
*/
|
||||
bool sve_access_check(DisasContext *s)
|
||||
{
|
||||
if (s->pstate_sm || !dc_isar_feature(aa64_sve, s)) {
|
||||
if (dc_isar_feature(aa64_sme, s)) {
|
||||
bool ret;
|
||||
|
||||
assert(dc_isar_feature(aa64_sme, s));
|
||||
ret = sme_sm_enabled_check(s);
|
||||
if (s->pstate_sm) {
|
||||
ret = sme_enabled_check(s);
|
||||
} else if (dc_isar_feature(aa64_sve, s)) {
|
||||
goto continue_sve;
|
||||
} else {
|
||||
ret = sme_sm_enabled_check(s);
|
||||
}
|
||||
if (ret) {
|
||||
ret = nonstreaming_check(s);
|
||||
}
|
||||
s->sve_access_checked = (ret ? 1 : -1);
|
||||
return ret;
|
||||
}
|
||||
|
||||
continue_sve:
|
||||
if (s->sve_excp_el) {
|
||||
/* Assert that we only raise one exception per instruction. */
|
||||
assert(!s->sve_access_checked);
|
||||
|
|
@ -1499,7 +1511,8 @@ bool sme_enabled_check(DisasContext *s)
|
|||
* to be zero when fp_excp_el has priority. This is because we need
|
||||
* sme_excp_el by itself for cpregs access checks.
|
||||
*/
|
||||
if (!s->fp_excp_el || s->sme_excp_el < s->fp_excp_el) {
|
||||
if (s->sme_excp_el
|
||||
&& (!s->fp_excp_el || s->sme_excp_el <= s->fp_excp_el)) {
|
||||
bool ret = sme_access_check(s);
|
||||
s->fp_access_checked = (ret ? 1 : -1);
|
||||
return ret;
|
||||
|
|
@ -1821,6 +1834,10 @@ static bool trans_RETA(DisasContext *s, arg_reta *a)
|
|||
{
|
||||
TCGv_i64 dst;
|
||||
|
||||
if (!dc_isar_feature(aa64_pauth, s)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
dst = auth_branch_target(s, cpu_reg(s, 30), cpu_X[31], !a->m);
|
||||
gen_a64_set_pc(s, dst);
|
||||
s->base.is_jmp = DISAS_JUMP;
|
||||
|
|
|
|||
|
|
@ -2352,6 +2352,23 @@ TRANS_FEAT(PUNPKHI, aa64_sve, do_perm_pred2, a, 1, gen_helper_sve_punpk_p)
|
|||
*** SVE Permute - Interleaving Group
|
||||
*/
|
||||
|
||||
static bool do_interleave_q(DisasContext *s, gen_helper_gvec_3 *fn,
|
||||
arg_rrr_esz *a, int data)
|
||||
{
|
||||
if (sve_access_check(s)) {
|
||||
unsigned vsz = vec_full_reg_size(s);
|
||||
if (vsz < 32) {
|
||||
unallocated_encoding(s);
|
||||
} else {
|
||||
tcg_gen_gvec_3_ool(vec_full_reg_offset(s, a->rd),
|
||||
vec_full_reg_offset(s, a->rn),
|
||||
vec_full_reg_offset(s, a->rm),
|
||||
vsz, vsz, data, fn);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static gen_helper_gvec_3 * const zip_fns[4] = {
|
||||
gen_helper_sve_zip_b, gen_helper_sve_zip_h,
|
||||
gen_helper_sve_zip_s, gen_helper_sve_zip_d,
|
||||
|
|
@ -2361,11 +2378,11 @@ TRANS_FEAT(ZIP1_z, aa64_sve, gen_gvec_ool_arg_zzz,
|
|||
TRANS_FEAT(ZIP2_z, aa64_sve, gen_gvec_ool_arg_zzz,
|
||||
zip_fns[a->esz], a, vec_full_reg_size(s) / 2)
|
||||
|
||||
TRANS_FEAT(ZIP1_q, aa64_sve_f64mm, gen_gvec_ool_arg_zzz,
|
||||
gen_helper_sve2_zip_q, a, 0)
|
||||
TRANS_FEAT(ZIP2_q, aa64_sve_f64mm, gen_gvec_ool_arg_zzz,
|
||||
gen_helper_sve2_zip_q, a,
|
||||
QEMU_ALIGN_DOWN(vec_full_reg_size(s), 32) / 2)
|
||||
TRANS_FEAT_NONSTREAMING(ZIP1_q, aa64_sve_f64mm, do_interleave_q,
|
||||
gen_helper_sve2_zip_q, a, 0)
|
||||
TRANS_FEAT_NONSTREAMING(ZIP2_q, aa64_sve_f64mm, do_interleave_q,
|
||||
gen_helper_sve2_zip_q, a,
|
||||
QEMU_ALIGN_DOWN(vec_full_reg_size(s), 32) / 2)
|
||||
|
||||
static gen_helper_gvec_3 * const uzp_fns[4] = {
|
||||
gen_helper_sve_uzp_b, gen_helper_sve_uzp_h,
|
||||
|
|
@ -2377,10 +2394,10 @@ TRANS_FEAT(UZP1_z, aa64_sve, gen_gvec_ool_arg_zzz,
|
|||
TRANS_FEAT(UZP2_z, aa64_sve, gen_gvec_ool_arg_zzz,
|
||||
uzp_fns[a->esz], a, 1 << a->esz)
|
||||
|
||||
TRANS_FEAT(UZP1_q, aa64_sve_f64mm, gen_gvec_ool_arg_zzz,
|
||||
gen_helper_sve2_uzp_q, a, 0)
|
||||
TRANS_FEAT(UZP2_q, aa64_sve_f64mm, gen_gvec_ool_arg_zzz,
|
||||
gen_helper_sve2_uzp_q, a, 16)
|
||||
TRANS_FEAT_NONSTREAMING(UZP1_q, aa64_sve_f64mm, do_interleave_q,
|
||||
gen_helper_sve2_uzp_q, a, 0)
|
||||
TRANS_FEAT_NONSTREAMING(UZP2_q, aa64_sve_f64mm, do_interleave_q,
|
||||
gen_helper_sve2_uzp_q, a, 16)
|
||||
|
||||
static gen_helper_gvec_3 * const trn_fns[4] = {
|
||||
gen_helper_sve_trn_b, gen_helper_sve_trn_h,
|
||||
|
|
@ -2392,10 +2409,10 @@ TRANS_FEAT(TRN1_z, aa64_sve, gen_gvec_ool_arg_zzz,
|
|||
TRANS_FEAT(TRN2_z, aa64_sve, gen_gvec_ool_arg_zzz,
|
||||
trn_fns[a->esz], a, 1 << a->esz)
|
||||
|
||||
TRANS_FEAT(TRN1_q, aa64_sve_f64mm, gen_gvec_ool_arg_zzz,
|
||||
gen_helper_sve2_trn_q, a, 0)
|
||||
TRANS_FEAT(TRN2_q, aa64_sve_f64mm, gen_gvec_ool_arg_zzz,
|
||||
gen_helper_sve2_trn_q, a, 16)
|
||||
TRANS_FEAT_NONSTREAMING(TRN1_q, aa64_sve_f64mm, do_interleave_q,
|
||||
gen_helper_sve2_trn_q, a, 0)
|
||||
TRANS_FEAT_NONSTREAMING(TRN2_q, aa64_sve_f64mm, do_interleave_q,
|
||||
gen_helper_sve2_trn_q, a, 16)
|
||||
|
||||
/*
|
||||
*** SVE Permute Vector - Predicated Group
|
||||
|
|
@ -7265,6 +7282,7 @@ static bool trans_PSEL(DisasContext *s, arg_psel *a)
|
|||
tcg_gen_neg_i64(tmp, tmp);
|
||||
|
||||
/* Apply to either copy the source, or write zeros. */
|
||||
pl = size_for_gvec(pl);
|
||||
tcg_gen_gvec_ands(MO_64, pred_full_reg_offset(s, a->pd),
|
||||
pred_full_reg_offset(s, a->pn), tmp, pl, pl);
|
||||
return true;
|
||||
|
|
|
|||
|
|
@ -2989,31 +2989,62 @@ float32 bfdotadd(float32 sum, uint32_t e1, uint32_t e2, float_status *fpst)
|
|||
float32 bfdotadd_ebf(float32 sum, uint32_t e1, uint32_t e2,
|
||||
float_status *fpst, float_status *fpst_odd)
|
||||
{
|
||||
/*
|
||||
* Compare f16_dotadd() in sme_helper.c, but here we have
|
||||
* bfloat16 inputs. In particular that means that we do not
|
||||
* want the FPCR.FZ16 flush semantics, so we use the normal
|
||||
* float_status for the input handling here.
|
||||
*/
|
||||
float64 e1r = float32_to_float64(e1 << 16, fpst);
|
||||
float64 e1c = float32_to_float64(e1 & 0xffff0000u, fpst);
|
||||
float64 e2r = float32_to_float64(e2 << 16, fpst);
|
||||
float64 e2c = float32_to_float64(e2 & 0xffff0000u, fpst);
|
||||
float64 t64;
|
||||
float32 s1r = e1 << 16;
|
||||
float32 s1c = e1 & 0xffff0000u;
|
||||
float32 s2r = e2 << 16;
|
||||
float32 s2c = e2 & 0xffff0000u;
|
||||
float32 t32;
|
||||
|
||||
/*
|
||||
* The ARM pseudocode function FPDot performs both multiplies
|
||||
* and the add with a single rounding operation. Emulate this
|
||||
* by performing the first multiply in round-to-odd, then doing
|
||||
* the second multiply as fused multiply-add, and rounding to
|
||||
* float32 all in one step.
|
||||
*/
|
||||
t64 = float64_mul(e1r, e2r, fpst_odd);
|
||||
t64 = float64r32_muladd(e1c, e2c, t64, 0, fpst);
|
||||
/* C.f. FPProcessNaNs4 */
|
||||
if (float32_is_any_nan(s1r) || float32_is_any_nan(s1c) ||
|
||||
float32_is_any_nan(s2r) || float32_is_any_nan(s2c)) {
|
||||
if (float32_is_signaling_nan(s1r, fpst)) {
|
||||
t32 = s1r;
|
||||
} else if (float32_is_signaling_nan(s1c, fpst)) {
|
||||
t32 = s1c;
|
||||
} else if (float32_is_signaling_nan(s2r, fpst)) {
|
||||
t32 = s2r;
|
||||
} else if (float32_is_signaling_nan(s2c, fpst)) {
|
||||
t32 = s2c;
|
||||
} else if (float32_is_any_nan(s1r)) {
|
||||
t32 = s1r;
|
||||
} else if (float32_is_any_nan(s1c)) {
|
||||
t32 = s1c;
|
||||
} else if (float32_is_any_nan(s2r)) {
|
||||
t32 = s2r;
|
||||
} else {
|
||||
t32 = s2c;
|
||||
}
|
||||
/*
|
||||
* FPConvertNaN(FPProcessNaN(t32)) will be done as part
|
||||
* of the final addition below.
|
||||
*/
|
||||
} else {
|
||||
/*
|
||||
* Compare f16_dotadd() in sme_helper.c, but here we have
|
||||
* bfloat16 inputs. In particular that means that we do not
|
||||
* want the FPCR.FZ16 flush semantics, so we use the normal
|
||||
* float_status for the input handling here.
|
||||
*/
|
||||
float64 e1r = float32_to_float64(s1r, fpst);
|
||||
float64 e1c = float32_to_float64(s1c, fpst);
|
||||
float64 e2r = float32_to_float64(s2r, fpst);
|
||||
float64 e2c = float32_to_float64(s2c, fpst);
|
||||
float64 t64;
|
||||
|
||||
/* This conversion is exact, because we've already rounded. */
|
||||
t32 = float64_to_float32(t64, fpst);
|
||||
/*
|
||||
* The ARM pseudocode function FPDot performs both multiplies
|
||||
* and the add with a single rounding operation. Emulate this
|
||||
* by performing the first multiply in round-to-odd, then doing
|
||||
* the second multiply as fused multiply-add, and rounding to
|
||||
* float32 all in one step.
|
||||
*/
|
||||
t64 = float64_mul(e1r, e2r, fpst_odd);
|
||||
t64 = float64r32_muladd(e1c, e2c, t64, 0, fpst);
|
||||
|
||||
/* This conversion is exact, because we've already rounded. */
|
||||
t32 = float64_to_float32(t64, fpst);
|
||||
}
|
||||
|
||||
/* The final accumulation step is not fused. */
|
||||
return float32_add(sum, t32, fpst);
|
||||
|
|
|
|||
|
|
@ -283,11 +283,17 @@ static void encode_cache_cpuid4(CPUCacheInfo *cache,
|
|||
assert(cache->size == cache->line_size * cache->associativity *
|
||||
cache->partitions * cache->sets);
|
||||
|
||||
/*
|
||||
* The following fields have bit-width limitations, so consider the
|
||||
* maximum values to avoid overflow:
|
||||
* Bits 25-14: maximum 4095.
|
||||
* Bits 31-26: maximum 63.
|
||||
*/
|
||||
*eax = CACHE_TYPE(cache->type) |
|
||||
CACHE_LEVEL(cache->level) |
|
||||
(cache->self_init ? CACHE_SELF_INIT_LEVEL : 0) |
|
||||
(max_core_ids_in_package(topo_info) << 26) |
|
||||
(max_thread_ids_for_cache(topo_info, cache->share_level) << 14);
|
||||
(MIN(max_core_ids_in_package(topo_info), 63) << 26) |
|
||||
(MIN(max_thread_ids_for_cache(topo_info, cache->share_level), 4095) << 14);
|
||||
|
||||
assert(cache->line_size > 0);
|
||||
assert(cache->partitions > 0);
|
||||
|
|
@ -490,7 +496,8 @@ static void encode_cache_cpuid8000001d(CPUCacheInfo *cache,
|
|||
|
||||
*eax = CACHE_TYPE(cache->type) | CACHE_LEVEL(cache->level) |
|
||||
(cache->self_init ? CACHE_SELF_INIT_LEVEL : 0);
|
||||
*eax |= max_thread_ids_for_cache(topo_info, cache->share_level) << 14;
|
||||
/* Bits 25:14 - NumSharingCache: maximum 4095. */
|
||||
*eax |= MIN(max_thread_ids_for_cache(topo_info, cache->share_level), 4095) << 14;
|
||||
|
||||
assert(cache->line_size > 0);
|
||||
assert(cache->partitions > 0);
|
||||
|
|
@ -1774,10 +1781,6 @@ static FeatureDep feature_dependencies[] = {
|
|||
.from = { FEAT_7_1_EAX, CPUID_7_1_EAX_LKGS },
|
||||
.to = { FEAT_7_1_EAX, CPUID_7_1_EAX_FRED },
|
||||
},
|
||||
{
|
||||
.from = { FEAT_7_1_EAX, CPUID_7_1_EAX_WRMSRNS },
|
||||
.to = { FEAT_7_1_EAX, CPUID_7_1_EAX_FRED },
|
||||
},
|
||||
{
|
||||
.from = { FEAT_7_0_EBX, CPUID_7_0_EBX_SGX },
|
||||
.to = { FEAT_7_0_ECX, CPUID_7_0_ECX_SGX_LC },
|
||||
|
|
@ -6832,7 +6835,8 @@ void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count,
|
|||
}
|
||||
*edx = env->features[FEAT_1_EDX];
|
||||
if (threads_per_pkg > 1) {
|
||||
*ebx |= threads_per_pkg << 16;
|
||||
/* Fixup overflow: max value for bits 23-16 is 255. */
|
||||
*ebx |= MIN(threads_per_pkg, 255) << 16;
|
||||
}
|
||||
if (!cpu->enable_pmu) {
|
||||
*ecx &= ~CPUID_EXT_PDCM;
|
||||
|
|
@ -6870,13 +6874,13 @@ void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count,
|
|||
int host_vcpus_per_cache = 1 + ((*eax & 0x3FFC000) >> 14);
|
||||
|
||||
*eax &= ~0xFC000000;
|
||||
*eax |= max_core_ids_in_package(topo_info) << 26;
|
||||
*eax |= MIN(max_core_ids_in_package(topo_info), 63) << 26;
|
||||
if (host_vcpus_per_cache > threads_per_pkg) {
|
||||
*eax &= ~0x3FFC000;
|
||||
|
||||
/* Share the cache at package level. */
|
||||
*eax |= max_thread_ids_for_cache(topo_info,
|
||||
CPU_TOPOLOGY_LEVEL_SOCKET) << 14;
|
||||
*eax |= MIN(max_thread_ids_for_cache(topo_info,
|
||||
CPU_TOPOLOGY_LEVEL_SOCKET), 4095) << 14;
|
||||
}
|
||||
}
|
||||
} else if (cpu->vendor_cpuid_only && IS_AMD_CPU(env)) {
|
||||
|
|
|
|||
|
|
@ -500,8 +500,12 @@ uint32_t kvm_arch_get_supported_cpuid(KVMState *s, uint32_t function,
|
|||
* Linux v4.17-v4.20 incorrectly return ARCH_CAPABILITIES on SVM hosts.
|
||||
* We can detect the bug by checking if MSR_IA32_ARCH_CAPABILITIES is
|
||||
* returned by KVM_GET_MSR_INDEX_LIST.
|
||||
*
|
||||
* But also, because Windows does not like ARCH_CAPABILITIES on AMD
|
||||
* mcahines at all, do not show the fake ARCH_CAPABILITIES MSR that
|
||||
* KVM sets up.
|
||||
*/
|
||||
if (!has_msr_arch_capabs) {
|
||||
if (!has_msr_arch_capabs || !(edx & CPUID_7_0_EDX_ARCH_CAPABILITIES)) {
|
||||
ret &= ~CPUID_7_0_EDX_ARCH_CAPABILITIES;
|
||||
}
|
||||
} else if (function == 7 && index == 1 && reg == R_EAX) {
|
||||
|
|
|
|||
|
|
@ -2000,8 +2000,11 @@ static void gen_movl_seg(DisasContext *s, X86Seg seg_reg, TCGv src, bool inhibit
|
|||
tcg_gen_trunc_tl_i32(sel, src);
|
||||
gen_helper_load_seg(tcg_env, tcg_constant_i32(seg_reg), sel);
|
||||
|
||||
/* For move to DS/ES/SS, the addseg or ss32 flags may change. */
|
||||
if (CODE32(s) && seg_reg < R_FS) {
|
||||
/*
|
||||
* For moves to SS, the SS32 flag may change. For CODE32 only, changes
|
||||
* to SS, DS and ES may change the ADDSEG flags.
|
||||
*/
|
||||
if (seg_reg == R_SS || (CODE32(s) && seg_reg < R_FS)) {
|
||||
s->base.is_jmp = DISAS_EOB_NEXT;
|
||||
}
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -4,10 +4,15 @@
|
|||
*/
|
||||
|
||||
/* bit0(signaling/quiet) bit1(lt) bit2(eq) bit3(un) bit4(neq) */
|
||||
static uint32_t get_fcmp_flags(int cond)
|
||||
static uint32_t get_fcmp_flags(DisasContext *ctx, int cond)
|
||||
{
|
||||
uint32_t flags = 0;
|
||||
|
||||
/*check cond , cond =[0-8,10,12] */
|
||||
if ((cond > 8) &&(cond != 10) && (cond != 12)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (cond & 0x1) {
|
||||
flags |= FCMP_LT;
|
||||
}
|
||||
|
|
@ -26,9 +31,14 @@ static uint32_t get_fcmp_flags(int cond)
|
|||
static bool trans_fcmp_cond_s(DisasContext *ctx, arg_fcmp_cond_s *a)
|
||||
{
|
||||
TCGv var, src1, src2;
|
||||
uint32_t flags;
|
||||
uint32_t flags = get_fcmp_flags(ctx, a->fcond >>1);
|
||||
void (*fn)(TCGv, TCGv_env, TCGv, TCGv, TCGv_i32);
|
||||
|
||||
if (flags == -1) {
|
||||
generate_exception(ctx, EXCCODE_INE);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!avail_FP_SP(ctx)) {
|
||||
return false;
|
||||
}
|
||||
|
|
@ -39,8 +49,6 @@ static bool trans_fcmp_cond_s(DisasContext *ctx, arg_fcmp_cond_s *a)
|
|||
src1 = get_fpr(ctx, a->fj);
|
||||
src2 = get_fpr(ctx, a->fk);
|
||||
fn = (a->fcond & 1 ? gen_helper_fcmp_s_s : gen_helper_fcmp_c_s);
|
||||
flags = get_fcmp_flags(a->fcond >> 1);
|
||||
|
||||
fn(var, tcg_env, src1, src2, tcg_constant_i32(flags));
|
||||
|
||||
tcg_gen_st8_tl(var, tcg_env, offsetof(CPULoongArchState, cf[a->cd]));
|
||||
|
|
@ -50,9 +58,14 @@ static bool trans_fcmp_cond_s(DisasContext *ctx, arg_fcmp_cond_s *a)
|
|||
static bool trans_fcmp_cond_d(DisasContext *ctx, arg_fcmp_cond_d *a)
|
||||
{
|
||||
TCGv var, src1, src2;
|
||||
uint32_t flags;
|
||||
uint32_t flags = get_fcmp_flags(ctx, a->fcond >> 1);
|
||||
void (*fn)(TCGv, TCGv_env, TCGv, TCGv, TCGv_i32);
|
||||
|
||||
if (flags == -1) {
|
||||
generate_exception(ctx, EXCCODE_INE);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!avail_FP_DP(ctx)) {
|
||||
return false;
|
||||
}
|
||||
|
|
@ -63,8 +76,6 @@ static bool trans_fcmp_cond_d(DisasContext *ctx, arg_fcmp_cond_d *a)
|
|||
src1 = get_fpr(ctx, a->fj);
|
||||
src2 = get_fpr(ctx, a->fk);
|
||||
fn = (a->fcond & 1 ? gen_helper_fcmp_s_d : gen_helper_fcmp_c_d);
|
||||
flags = get_fcmp_flags(a->fcond >> 1);
|
||||
|
||||
fn(var, tcg_env, src1, src2, tcg_constant_i32(flags));
|
||||
|
||||
tcg_gen_st8_tl(var, tcg_env, offsetof(CPULoongArchState, cf[a->cd]));
|
||||
|
|
|
|||
|
|
@ -3465,7 +3465,7 @@ TRANS(xvmsknz_b, LASX, gen_xx, gen_helper_vmsknz_b)
|
|||
static uint64_t vldi_get_value(DisasContext *ctx, uint32_t imm)
|
||||
{
|
||||
int mode;
|
||||
uint64_t data, t;
|
||||
uint64_t data = 0, t;
|
||||
|
||||
/*
|
||||
* imm bit [11:8] is mode, mode value is 0-12.
|
||||
|
|
@ -3570,17 +3570,26 @@ static uint64_t vldi_get_value(DisasContext *ctx, uint32_t imm)
|
|||
}
|
||||
break;
|
||||
default:
|
||||
generate_exception(ctx, EXCCODE_INE);
|
||||
g_assert_not_reached();
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
static bool check_valid_vldi_mode(arg_vldi *a)
|
||||
{
|
||||
return extract32(a->imm, 8, 4) <= 12;
|
||||
}
|
||||
|
||||
static bool gen_vldi(DisasContext *ctx, arg_vldi *a, uint32_t oprsz)
|
||||
{
|
||||
int sel, vece;
|
||||
uint64_t value;
|
||||
|
||||
if (!check_valid_vldi_mode(a)) {
|
||||
generate_exception(ctx, EXCCODE_INE);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!check_vec(ctx, oprsz)) {
|
||||
return true;
|
||||
}
|
||||
|
|
@ -4655,19 +4664,23 @@ TRANS(xvslti_du, LASX, do_xcmpi, MO_64, TCG_COND_LTU)
|
|||
|
||||
static bool do_vfcmp_cond_s(DisasContext *ctx, arg_vvv_fcond *a, uint32_t sz)
|
||||
{
|
||||
uint32_t flags;
|
||||
uint32_t flags = get_fcmp_flags(ctx, a->fcond >> 1);
|
||||
void (*fn)(TCGv_env, TCGv_i32, TCGv_i32, TCGv_i32, TCGv_i32, TCGv_i32);
|
||||
TCGv_i32 vd = tcg_constant_i32(a->vd);
|
||||
TCGv_i32 vj = tcg_constant_i32(a->vj);
|
||||
TCGv_i32 vk = tcg_constant_i32(a->vk);
|
||||
TCGv_i32 oprsz = tcg_constant_i32(sz);
|
||||
|
||||
if(flags == -1){
|
||||
generate_exception(ctx, EXCCODE_INE);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!check_vec(ctx, sz)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
fn = (a->fcond & 1 ? gen_helper_vfcmp_s_s : gen_helper_vfcmp_c_s);
|
||||
flags = get_fcmp_flags(a->fcond >> 1);
|
||||
fn(tcg_env, oprsz, vd, vj, vk, tcg_constant_i32(flags));
|
||||
|
||||
return true;
|
||||
|
|
@ -4675,19 +4688,23 @@ static bool do_vfcmp_cond_s(DisasContext *ctx, arg_vvv_fcond *a, uint32_t sz)
|
|||
|
||||
static bool do_vfcmp_cond_d(DisasContext *ctx, arg_vvv_fcond *a, uint32_t sz)
|
||||
{
|
||||
uint32_t flags;
|
||||
uint32_t flags = get_fcmp_flags(ctx, a->fcond >> 1);
|
||||
void (*fn)(TCGv_env, TCGv_i32, TCGv_i32, TCGv_i32, TCGv_i32, TCGv_i32);
|
||||
TCGv_i32 vd = tcg_constant_i32(a->vd);
|
||||
TCGv_i32 vj = tcg_constant_i32(a->vj);
|
||||
TCGv_i32 vk = tcg_constant_i32(a->vk);
|
||||
TCGv_i32 oprsz = tcg_constant_i32(sz);
|
||||
|
||||
if (flags == -1) {
|
||||
generate_exception(ctx, EXCCODE_INE);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!check_vec(ctx, sz)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
fn = (a->fcond & 1 ? gen_helper_vfcmp_s_d : gen_helper_vfcmp_c_d);
|
||||
flags = get_fcmp_flags(a->fcond >> 1);
|
||||
fn(tcg_env, oprsz, vd, vj, vk, tcg_constant_i32(flags));
|
||||
|
||||
return true;
|
||||
|
|
|
|||
|
|
@ -4927,7 +4927,7 @@ static void tcg_reg_alloc_dup(TCGContext *s, const TCGOp *op)
|
|||
|
||||
if (its->val_type == TEMP_VAL_CONST) {
|
||||
/* Propagate constant via movi -> dupi. */
|
||||
tcg_target_ulong val = its->val;
|
||||
tcg_target_ulong val = dup_const(vece, its->val);
|
||||
if (IS_DEAD_ARG(1)) {
|
||||
temp_dead(s, its);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -81,8 +81,6 @@ class TestCase(iotests.QMPTestCase):
|
|||
|
||||
self.vm.qmp_log('device_del', id='scsi-hd0')
|
||||
self.vm.event_wait('DEVICE_DELETED')
|
||||
self.vm.qmp_log('device_add', id='scsi-hd1', driver='scsi-hd', drive='hd0', bus="scsi1.0")
|
||||
|
||||
self.vm.qmp_log('device_del', id='scsi-hd1')
|
||||
self.vm.event_wait('DEVICE_DELETED')
|
||||
self.vm.qmp_log('blockdev-del', node_name='hd0')
|
||||
|
|
|
|||
|
|
@ -46,10 +46,8 @@
|
|||
{"execute": "device_add", "arguments": {"bus": "scsi0.0", "drive": "hd0", "driver": "scsi-hd", "id": "scsi-hd0"}}
|
||||
{"return": {}}
|
||||
{"execute": "device_add", "arguments": {"bus": "scsi1.0", "drive": "hd0", "driver": "scsi-hd", "id": "scsi-hd1"}}
|
||||
{"error": {"class": "GenericError", "desc": "Cannot change iothread of active block backend"}}
|
||||
{"execute": "device_del", "arguments": {"id": "scsi-hd0"}}
|
||||
{"return": {}}
|
||||
{"execute": "device_add", "arguments": {"bus": "scsi1.0", "drive": "hd0", "driver": "scsi-hd", "id": "scsi-hd1"}}
|
||||
{"execute": "device_del", "arguments": {"id": "scsi-hd0"}}
|
||||
{"return": {}}
|
||||
{"execute": "device_del", "arguments": {"id": "scsi-hd1"}}
|
||||
{"return": {}}
|
||||
|
|
|
|||
12
ui/gtk-egl.c
12
ui/gtk-egl.c
|
|
@ -70,16 +70,18 @@ void gd_egl_draw(VirtualConsole *vc)
|
|||
QemuDmaBuf *dmabuf = vc->gfx.guest_fb.dmabuf;
|
||||
int fence_fd;
|
||||
#endif
|
||||
int ww, wh, ws;
|
||||
int ww, wh, pw, ph, gs;
|
||||
|
||||
if (!vc->gfx.gls) {
|
||||
return;
|
||||
}
|
||||
|
||||
window = gtk_widget_get_window(vc->gfx.drawing_area);
|
||||
ws = gdk_window_get_scale_factor(window);
|
||||
ww = gdk_window_get_width(window) * ws;
|
||||
wh = gdk_window_get_height(window) * ws;
|
||||
gs = gdk_window_get_scale_factor(window);
|
||||
ww = gdk_window_get_width(window);
|
||||
wh = gdk_window_get_height(window);
|
||||
pw = ww * gs;
|
||||
ph = wh * gs;
|
||||
|
||||
if (vc->gfx.scanout_mode) {
|
||||
#ifdef CONFIG_GBM
|
||||
|
|
@ -115,7 +117,7 @@ void gd_egl_draw(VirtualConsole *vc)
|
|||
eglMakeCurrent(qemu_egl_display, vc->gfx.esurface,
|
||||
vc->gfx.esurface, vc->gfx.ectx);
|
||||
|
||||
surface_gl_setup_viewport(vc->gfx.gls, vc->gfx.ds, ww, wh);
|
||||
surface_gl_setup_viewport(vc->gfx.gls, vc->gfx.ds, pw, ph);
|
||||
surface_gl_render_texture(vc->gfx.gls, vc->gfx.ds);
|
||||
|
||||
eglSwapBuffers(qemu_egl_display, vc->gfx.esurface);
|
||||
|
|
|
|||
|
|
@ -42,16 +42,24 @@ void gd_gl_area_draw(VirtualConsole *vc)
|
|||
#ifdef CONFIG_GBM
|
||||
QemuDmaBuf *dmabuf = vc->gfx.guest_fb.dmabuf;
|
||||
#endif
|
||||
int ww, wh, ws, y1, y2;
|
||||
int pw, ph, gs, y1, y2;
|
||||
int ww, wh;
|
||||
int fbw, fbh;
|
||||
|
||||
if (!vc->gfx.gls) {
|
||||
return;
|
||||
}
|
||||
|
||||
gtk_gl_area_make_current(GTK_GL_AREA(vc->gfx.drawing_area));
|
||||
ws = gdk_window_get_scale_factor(gtk_widget_get_window(vc->gfx.drawing_area));
|
||||
ww = gtk_widget_get_allocated_width(vc->gfx.drawing_area) * ws;
|
||||
wh = gtk_widget_get_allocated_height(vc->gfx.drawing_area) * ws;
|
||||
gs = gdk_window_get_scale_factor(gtk_widget_get_window(vc->gfx.drawing_area));
|
||||
fbw = surface_width(vc->gfx.ds);
|
||||
fbh = surface_height(vc->gfx.ds);
|
||||
ww = gtk_widget_get_allocated_width(vc->gfx.drawing_area);
|
||||
wh = gtk_widget_get_allocated_height(vc->gfx.drawing_area);
|
||||
pw = ww * gs;
|
||||
ph = wh * gs;
|
||||
|
||||
gd_update_scale(vc, ww, wh, fbw, fbh);
|
||||
|
||||
if (vc->gfx.scanout_mode) {
|
||||
if (!vc->gfx.guest_fb.framebuffer) {
|
||||
|
|
@ -71,11 +79,11 @@ void gd_gl_area_draw(VirtualConsole *vc)
|
|||
glBindFramebuffer(GL_READ_FRAMEBUFFER, vc->gfx.guest_fb.framebuffer);
|
||||
/* GtkGLArea sets GL_DRAW_FRAMEBUFFER for us */
|
||||
|
||||
glViewport(0, 0, ww, wh);
|
||||
glViewport(0, 0, pw, ph);
|
||||
y1 = vc->gfx.y0_top ? 0 : vc->gfx.h;
|
||||
y2 = vc->gfx.y0_top ? vc->gfx.h : 0;
|
||||
glBlitFramebuffer(0, y1, vc->gfx.w, y2,
|
||||
0, 0, ww, wh,
|
||||
0, 0, pw, ph,
|
||||
GL_COLOR_BUFFER_BIT, GL_NEAREST);
|
||||
#ifdef CONFIG_GBM
|
||||
if (dmabuf) {
|
||||
|
|
@ -101,7 +109,7 @@ void gd_gl_area_draw(VirtualConsole *vc)
|
|||
}
|
||||
gtk_gl_area_make_current(GTK_GL_AREA(vc->gfx.drawing_area));
|
||||
|
||||
surface_gl_setup_viewport(vc->gfx.gls, vc->gfx.ds, ww, wh);
|
||||
surface_gl_setup_viewport(vc->gfx.gls, vc->gfx.ds, pw, ph);
|
||||
surface_gl_render_texture(vc->gfx.gls, vc->gfx.ds);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
222
ui/gtk.c
222
ui/gtk.c
|
|
@ -387,16 +387,16 @@ static void *gd_win32_get_hwnd(VirtualConsole *vc)
|
|||
/** DisplayState Callbacks **/
|
||||
|
||||
static void gd_update(DisplayChangeListener *dcl,
|
||||
int x, int y, int w, int h)
|
||||
int fbx, int fby, int fbw, int fbh)
|
||||
{
|
||||
VirtualConsole *vc = container_of(dcl, VirtualConsole, gfx.dcl);
|
||||
GdkWindow *win;
|
||||
int x1, x2, y1, y2;
|
||||
int mx, my;
|
||||
int fbw, fbh;
|
||||
int ww, wh;
|
||||
int wx1, wx2, wy1, wy2;
|
||||
int wx_offset, wy_offset;
|
||||
int ww_surface, wh_surface;
|
||||
int ww_widget, wh_widget;
|
||||
|
||||
trace_gd_update(vc->label, x, y, w, h);
|
||||
trace_gd_update(vc->label, fbx, fby, fbw, fbh);
|
||||
|
||||
if (!gtk_widget_get_realized(vc->gfx.drawing_area)) {
|
||||
return;
|
||||
|
|
@ -405,35 +405,36 @@ static void gd_update(DisplayChangeListener *dcl,
|
|||
if (vc->gfx.convert) {
|
||||
pixman_image_composite(PIXMAN_OP_SRC, vc->gfx.ds->image,
|
||||
NULL, vc->gfx.convert,
|
||||
x, y, 0, 0, x, y, w, h);
|
||||
fbx, fby, 0, 0, fbx, fby, fbw, fbh);
|
||||
}
|
||||
|
||||
x1 = floor(x * vc->gfx.scale_x);
|
||||
y1 = floor(y * vc->gfx.scale_y);
|
||||
wx1 = floor(fbx * vc->gfx.scale_x);
|
||||
wy1 = floor(fby * vc->gfx.scale_y);
|
||||
|
||||
x2 = ceil(x * vc->gfx.scale_x + w * vc->gfx.scale_x);
|
||||
y2 = ceil(y * vc->gfx.scale_y + h * vc->gfx.scale_y);
|
||||
wx2 = ceil(fbx * vc->gfx.scale_x + fbw * vc->gfx.scale_x);
|
||||
wy2 = ceil(fby * vc->gfx.scale_y + fbh * vc->gfx.scale_y);
|
||||
|
||||
fbw = surface_width(vc->gfx.ds) * vc->gfx.scale_x;
|
||||
fbh = surface_height(vc->gfx.ds) * vc->gfx.scale_y;
|
||||
ww_surface = surface_width(vc->gfx.ds) * vc->gfx.scale_x;
|
||||
wh_surface = surface_height(vc->gfx.ds) * vc->gfx.scale_y;
|
||||
|
||||
win = gtk_widget_get_window(vc->gfx.drawing_area);
|
||||
if (!win) {
|
||||
return;
|
||||
}
|
||||
ww = gdk_window_get_width(win);
|
||||
wh = gdk_window_get_height(win);
|
||||
ww_widget = gdk_window_get_width(win);
|
||||
wh_widget = gdk_window_get_height(win);
|
||||
|
||||
mx = my = 0;
|
||||
if (ww > fbw) {
|
||||
mx = (ww - fbw) / 2;
|
||||
wx_offset = wy_offset = 0;
|
||||
if (ww_widget > ww_surface) {
|
||||
wx_offset = (ww_widget - ww_surface) / 2;
|
||||
}
|
||||
if (wh > fbh) {
|
||||
my = (wh - fbh) / 2;
|
||||
if (wh_widget > wh_surface) {
|
||||
wy_offset = (wh_widget - wh_surface) / 2;
|
||||
}
|
||||
|
||||
gtk_widget_queue_draw_area(vc->gfx.drawing_area,
|
||||
mx + x1, my + y1, (x2 - x1), (y2 - y1));
|
||||
wx_offset + wx1, wy_offset + wy1,
|
||||
(wx2 - wx1), (wy2 - wy1));
|
||||
}
|
||||
|
||||
static void gd_refresh(DisplayChangeListener *dcl)
|
||||
|
|
@ -800,12 +801,95 @@ void gd_update_monitor_refresh_rate(VirtualConsole *vc, GtkWidget *widget)
|
|||
#endif
|
||||
}
|
||||
|
||||
void gd_update_scale(VirtualConsole *vc, int ww, int wh, int fbw, int fbh)
|
||||
{
|
||||
if (!vc) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (vc->s->full_screen) {
|
||||
vc->gfx.scale_x = (double)ww / fbw;
|
||||
vc->gfx.scale_y = (double)wh / fbh;
|
||||
} else if (vc->s->free_scale) {
|
||||
double sx, sy;
|
||||
|
||||
sx = (double)ww / fbw;
|
||||
sy = (double)wh / fbh;
|
||||
|
||||
vc->gfx.scale_x = vc->gfx.scale_y = MIN(sx, sy);
|
||||
}
|
||||
}
|
||||
/**
|
||||
* DOC: Coordinate handling.
|
||||
*
|
||||
* We are coping with sizes and positions in various coordinates and the
|
||||
* handling of these coordinates is somewhat confusing. It would benefit us
|
||||
* all if we define these coordinates explicitly and clearly. Besides, it's
|
||||
* also helpful to follow the same naming convention for variables
|
||||
* representing values in different coordinates.
|
||||
*
|
||||
* I. Definitions
|
||||
*
|
||||
* - (guest) buffer coordinate: this is the coordinates that the guest will
|
||||
* see. The x/y offsets and width/height specified in commands sent by
|
||||
* guest is basically in buffer coordinate.
|
||||
*
|
||||
* - (host) pixel coordinate: this is the coordinate in pixel level on the
|
||||
* host destop. A window/widget of width 300 in pixel coordinate means it
|
||||
* occupies 300 pixels horizontally.
|
||||
*
|
||||
* - (host) logical window coordinate: the existence of global scaling
|
||||
* factor in desktop level makes this kind of coordinate play a role. It
|
||||
* always holds that (logical window size) * (global scale factor) =
|
||||
* (pixel size).
|
||||
*
|
||||
* - global scale factor: this is specified in desktop level and is
|
||||
* typically invariant during the life cycle of the process. Users with
|
||||
* high-DPI monitors might set this scale, for example, to 2, in order to
|
||||
* make the UI look larger.
|
||||
*
|
||||
* - zooming scale: this can be freely controlled by the QEMU user to zoom
|
||||
* in/out the guest content.
|
||||
*
|
||||
* II. Representation
|
||||
*
|
||||
* We'd like to use consistent representation for variables in different
|
||||
* coordinates:
|
||||
* - buffer coordinate: prefix fb
|
||||
* - pixel coordinate: prefix p
|
||||
* - logical window coordinate: prefix w
|
||||
*
|
||||
* For scales:
|
||||
* - global scale factor: prefix gs
|
||||
* - zooming scale: prefix scale/s
|
||||
*
|
||||
* Example: fbw, pw, ww for width in different coordinates
|
||||
*
|
||||
* III. Equation
|
||||
*
|
||||
* - fbw * gs * scale_x = pw
|
||||
* - pw = gs * ww
|
||||
*
|
||||
* Consequently we have
|
||||
*
|
||||
* - fbw * scale_x = ww
|
||||
*
|
||||
* Example: assuming we are running QEMU on a 3840x2160 screen and have set
|
||||
* global scaling factor to 2, if the guest buffer size is 1920x1080 and the
|
||||
* zooming scale is 0.5, then we have:
|
||||
* - fbw = 1920, fbh = 1080
|
||||
* - pw = 1920, ph = 1080
|
||||
* - ww = 960, wh = 540
|
||||
* A bonus of this configuration is that we can achieve pixel to pixel
|
||||
* presentation of the guest content.
|
||||
*/
|
||||
|
||||
static gboolean gd_draw_event(GtkWidget *widget, cairo_t *cr, void *opaque)
|
||||
{
|
||||
VirtualConsole *vc = opaque;
|
||||
GtkDisplayState *s = vc->s;
|
||||
int mx, my;
|
||||
int ww, wh;
|
||||
int wx_offset, wy_offset;
|
||||
int ww_widget, wh_widget, ww_surface, wh_surface;
|
||||
int fbw, fbh;
|
||||
|
||||
#if defined(CONFIG_OPENGL)
|
||||
|
|
@ -839,46 +923,37 @@ static gboolean gd_draw_event(GtkWidget *widget, cairo_t *cr, void *opaque)
|
|||
fbw = surface_width(vc->gfx.ds);
|
||||
fbh = surface_height(vc->gfx.ds);
|
||||
|
||||
ww = gdk_window_get_width(gtk_widget_get_window(widget));
|
||||
wh = gdk_window_get_height(gtk_widget_get_window(widget));
|
||||
ww_widget = gdk_window_get_width(gtk_widget_get_window(widget));
|
||||
wh_widget = gdk_window_get_height(gtk_widget_get_window(widget));
|
||||
|
||||
if (s->full_screen) {
|
||||
vc->gfx.scale_x = (double)ww / fbw;
|
||||
vc->gfx.scale_y = (double)wh / fbh;
|
||||
} else if (s->free_scale) {
|
||||
double sx, sy;
|
||||
gd_update_scale(vc, ww_widget, wh_widget, fbw, fbh);
|
||||
|
||||
sx = (double)ww / fbw;
|
||||
sy = (double)wh / fbh;
|
||||
ww_surface = fbw * vc->gfx.scale_x;
|
||||
wh_surface = fbh * vc->gfx.scale_y;
|
||||
|
||||
vc->gfx.scale_x = vc->gfx.scale_y = MIN(sx, sy);
|
||||
wx_offset = wy_offset = 0;
|
||||
if (ww_widget > ww_surface) {
|
||||
wx_offset = (ww_widget - ww_surface) / 2;
|
||||
}
|
||||
if (wh_widget > wh_surface) {
|
||||
wy_offset = (wh_widget - wh_surface) / 2;
|
||||
}
|
||||
|
||||
fbw *= vc->gfx.scale_x;
|
||||
fbh *= vc->gfx.scale_y;
|
||||
|
||||
mx = my = 0;
|
||||
if (ww > fbw) {
|
||||
mx = (ww - fbw) / 2;
|
||||
}
|
||||
if (wh > fbh) {
|
||||
my = (wh - fbh) / 2;
|
||||
}
|
||||
|
||||
cairo_rectangle(cr, 0, 0, ww, wh);
|
||||
cairo_rectangle(cr, 0, 0, ww_widget, wh_widget);
|
||||
|
||||
/* Optionally cut out the inner area where the pixmap
|
||||
will be drawn. This avoids 'flashing' since we're
|
||||
not double-buffering. Note we're using the undocumented
|
||||
behaviour of drawing the rectangle from right to left
|
||||
to cut out the whole */
|
||||
cairo_rectangle(cr, mx + fbw, my,
|
||||
-1 * fbw, fbh);
|
||||
cairo_rectangle(cr, wx_offset + ww_surface, wy_offset,
|
||||
-1 * ww_surface, wh_surface);
|
||||
cairo_fill(cr);
|
||||
|
||||
cairo_scale(cr, vc->gfx.scale_x, vc->gfx.scale_y);
|
||||
cairo_set_source_surface(cr, vc->gfx.surface,
|
||||
mx / vc->gfx.scale_x, my / vc->gfx.scale_y);
|
||||
wx_offset / vc->gfx.scale_x,
|
||||
wy_offset / vc->gfx.scale_y);
|
||||
cairo_paint(cr);
|
||||
|
||||
return TRUE;
|
||||
|
|
@ -889,19 +964,19 @@ static gboolean gd_motion_event(GtkWidget *widget, GdkEventMotion *motion,
|
|||
{
|
||||
VirtualConsole *vc = opaque;
|
||||
GtkDisplayState *s = vc->s;
|
||||
int x, y;
|
||||
int mx, my;
|
||||
int fbh, fbw;
|
||||
int ww, wh;
|
||||
int fbx, fby;
|
||||
int wx_offset, wy_offset;
|
||||
int wh_surface, ww_surface;
|
||||
int ww_widget, wh_widget;
|
||||
|
||||
if (!vc->gfx.ds) {
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
fbw = surface_width(vc->gfx.ds) * vc->gfx.scale_x;
|
||||
fbh = surface_height(vc->gfx.ds) * vc->gfx.scale_y;
|
||||
ww = gtk_widget_get_allocated_width(widget);
|
||||
wh = gtk_widget_get_allocated_height(widget);
|
||||
ww_surface = surface_width(vc->gfx.ds) * vc->gfx.scale_x;
|
||||
wh_surface = surface_height(vc->gfx.ds) * vc->gfx.scale_y;
|
||||
ww_widget = gtk_widget_get_allocated_width(widget);
|
||||
wh_widget = gtk_widget_get_allocated_height(widget);
|
||||
|
||||
/*
|
||||
* `widget` may not have the same size with the frame buffer.
|
||||
|
|
@ -909,41 +984,42 @@ static gboolean gd_motion_event(GtkWidget *widget, GdkEventMotion *motion,
|
|||
* To achieve that, `vc` will be displayed at (mx, my)
|
||||
* so that it is displayed at the center of the widget.
|
||||
*/
|
||||
mx = my = 0;
|
||||
if (ww > fbw) {
|
||||
mx = (ww - fbw) / 2;
|
||||
wx_offset = wy_offset = 0;
|
||||
if (ww_widget > ww_surface) {
|
||||
wx_offset = (ww_widget - ww_surface) / 2;
|
||||
}
|
||||
if (wh > fbh) {
|
||||
my = (wh - fbh) / 2;
|
||||
if (wh_widget > wh_surface) {
|
||||
wy_offset = (wh_widget - wh_surface) / 2;
|
||||
}
|
||||
|
||||
/*
|
||||
* `motion` is reported in `widget` coordinates
|
||||
* so translating it to the coordinates in `vc`.
|
||||
*/
|
||||
x = (motion->x - mx) / vc->gfx.scale_x;
|
||||
y = (motion->y - my) / vc->gfx.scale_y;
|
||||
fbx = (motion->x - wx_offset) / vc->gfx.scale_x;
|
||||
fby = (motion->y - wy_offset) / vc->gfx.scale_y;
|
||||
|
||||
trace_gd_motion_event(ww, wh, gtk_widget_get_scale_factor(widget), x, y);
|
||||
trace_gd_motion_event(ww_widget, wh_widget,
|
||||
gtk_widget_get_scale_factor(widget), fbx, fby);
|
||||
|
||||
if (qemu_input_is_absolute(vc->gfx.dcl.con)) {
|
||||
if (x < 0 || y < 0 ||
|
||||
x >= surface_width(vc->gfx.ds) ||
|
||||
y >= surface_height(vc->gfx.ds)) {
|
||||
if (fbx < 0 || fby < 0 ||
|
||||
fbx >= surface_width(vc->gfx.ds) ||
|
||||
fby >= surface_height(vc->gfx.ds)) {
|
||||
return TRUE;
|
||||
}
|
||||
qemu_input_queue_abs(vc->gfx.dcl.con, INPUT_AXIS_X, x,
|
||||
qemu_input_queue_abs(vc->gfx.dcl.con, INPUT_AXIS_X, fbx,
|
||||
0, surface_width(vc->gfx.ds));
|
||||
qemu_input_queue_abs(vc->gfx.dcl.con, INPUT_AXIS_Y, y,
|
||||
qemu_input_queue_abs(vc->gfx.dcl.con, INPUT_AXIS_Y, fby,
|
||||
0, surface_height(vc->gfx.ds));
|
||||
qemu_input_event_sync();
|
||||
} else if (s->last_set && s->ptr_owner == vc) {
|
||||
qemu_input_queue_rel(vc->gfx.dcl.con, INPUT_AXIS_X, x - s->last_x);
|
||||
qemu_input_queue_rel(vc->gfx.dcl.con, INPUT_AXIS_Y, y - s->last_y);
|
||||
qemu_input_queue_rel(vc->gfx.dcl.con, INPUT_AXIS_X, fbx - s->last_x);
|
||||
qemu_input_queue_rel(vc->gfx.dcl.con, INPUT_AXIS_Y, fby - s->last_y);
|
||||
qemu_input_event_sync();
|
||||
}
|
||||
s->last_x = x;
|
||||
s->last_y = y;
|
||||
s->last_x = fbx;
|
||||
s->last_y = fby;
|
||||
s->last_set = TRUE;
|
||||
|
||||
if (!qemu_input_is_absolute(vc->gfx.dcl.con) && s->ptr_owner == vc) {
|
||||
|
|
|
|||
|
|
@ -126,33 +126,34 @@ uint32_t qemu_pixman_to_drm_format(pixman_format_code_t pixman_format)
|
|||
return 0;
|
||||
}
|
||||
|
||||
int qemu_pixman_get_type(int rshift, int gshift, int bshift)
|
||||
int qemu_pixman_get_type(int rshift, int gshift, int bshift, int endian)
|
||||
{
|
||||
int type = PIXMAN_TYPE_OTHER;
|
||||
bool native_endian = (endian == G_BYTE_ORDER);
|
||||
|
||||
if (rshift > gshift && gshift > bshift) {
|
||||
if (bshift == 0) {
|
||||
type = PIXMAN_TYPE_ARGB;
|
||||
type = native_endian ? PIXMAN_TYPE_ARGB : PIXMAN_TYPE_BGRA;
|
||||
} else {
|
||||
type = PIXMAN_TYPE_RGBA;
|
||||
type = native_endian ? PIXMAN_TYPE_RGBA : PIXMAN_TYPE_ABGR;
|
||||
}
|
||||
} else if (rshift < gshift && gshift < bshift) {
|
||||
if (rshift == 0) {
|
||||
type = PIXMAN_TYPE_ABGR;
|
||||
type = native_endian ? PIXMAN_TYPE_ABGR : PIXMAN_TYPE_RGBA;
|
||||
} else {
|
||||
type = PIXMAN_TYPE_BGRA;
|
||||
type = native_endian ? PIXMAN_TYPE_BGRA : PIXMAN_TYPE_ARGB;
|
||||
}
|
||||
}
|
||||
return type;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PIXMAN
|
||||
pixman_format_code_t qemu_pixman_get_format(PixelFormat *pf)
|
||||
pixman_format_code_t qemu_pixman_get_format(PixelFormat *pf, int endian)
|
||||
{
|
||||
pixman_format_code_t format;
|
||||
int type;
|
||||
|
||||
type = qemu_pixman_get_type(pf->rshift, pf->gshift, pf->bshift);
|
||||
type = qemu_pixman_get_type(pf->rshift, pf->gshift, pf->bshift, endian);
|
||||
format = PIXMAN_FORMAT(pf->bits_per_pixel, type,
|
||||
pf->abits, pf->rbits, pf->gbits, pf->bbits);
|
||||
if (!pixman_format_supported_source(format)) {
|
||||
|
|
|
|||
20
ui/sdl2.c
20
ui/sdl2.c
|
|
@ -488,14 +488,14 @@ static void handle_mousemotion(SDL_Event *ev)
|
|||
{
|
||||
int max_x, max_y;
|
||||
struct sdl2_console *scon = get_scon_from_window(ev->motion.windowID);
|
||||
int scr_w, scr_h, surf_w, surf_h, x, y, dx, dy;
|
||||
|
||||
if (!scon || !qemu_console_is_graphic(scon->dcl.con)) {
|
||||
return;
|
||||
}
|
||||
|
||||
SDL_GetWindowSize(scon->real_window, &scr_w, &scr_h);
|
||||
if (qemu_input_is_absolute(scon->dcl.con) || absolute_enabled) {
|
||||
int scr_w, scr_h;
|
||||
SDL_GetWindowSize(scon->real_window, &scr_w, &scr_h);
|
||||
max_x = scr_w - 1;
|
||||
max_y = scr_h - 1;
|
||||
if (gui_grab && !gui_fullscreen
|
||||
|
|
@ -509,9 +509,14 @@ static void handle_mousemotion(SDL_Event *ev)
|
|||
sdl_grab_start(scon);
|
||||
}
|
||||
}
|
||||
surf_w = surface_width(scon->surface);
|
||||
surf_h = surface_height(scon->surface);
|
||||
x = (int64_t)ev->motion.x * surf_w / scr_w;
|
||||
y = (int64_t)ev->motion.y * surf_h / scr_h;
|
||||
dx = (int64_t)ev->motion.xrel * surf_w / scr_w;
|
||||
dy = (int64_t)ev->motion.yrel * surf_h / scr_h;
|
||||
if (gui_grab || qemu_input_is_absolute(scon->dcl.con) || absolute_enabled) {
|
||||
sdl_send_mouse_event(scon, ev->motion.xrel, ev->motion.yrel,
|
||||
ev->motion.x, ev->motion.y, ev->motion.state);
|
||||
sdl_send_mouse_event(scon, dx, dy, x, y, ev->motion.state);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -520,12 +525,17 @@ static void handle_mousebutton(SDL_Event *ev)
|
|||
int buttonstate = SDL_GetMouseState(NULL, NULL);
|
||||
SDL_MouseButtonEvent *bev;
|
||||
struct sdl2_console *scon = get_scon_from_window(ev->button.windowID);
|
||||
int scr_w, scr_h, x, y;
|
||||
|
||||
if (!scon || !qemu_console_is_graphic(scon->dcl.con)) {
|
||||
return;
|
||||
}
|
||||
|
||||
bev = &ev->button;
|
||||
SDL_GetWindowSize(scon->real_window, &scr_w, &scr_h);
|
||||
x = (int64_t)bev->x * surface_width(scon->surface) / scr_w;
|
||||
y = (int64_t)bev->y * surface_height(scon->surface) / scr_h;
|
||||
|
||||
if (!gui_grab && !qemu_input_is_absolute(scon->dcl.con)) {
|
||||
if (ev->type == SDL_MOUSEBUTTONUP && bev->button == SDL_BUTTON_LEFT) {
|
||||
/* start grabbing all events */
|
||||
|
|
@ -537,7 +547,7 @@ static void handle_mousebutton(SDL_Event *ev)
|
|||
} else {
|
||||
buttonstate &= ~SDL_BUTTON(bev->button);
|
||||
}
|
||||
sdl_send_mouse_event(scon, 0, 0, bev->x, bev->y, buttonstate);
|
||||
sdl_send_mouse_event(scon, 0, 0, x, y, buttonstate);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -150,7 +150,7 @@ tight_detect_smooth_image24(VncState *vs, int w, int h)
|
|||
* If client is big-endian, color samples begin from the second
|
||||
* byte (offset 1) of a 32-bit pixel value.
|
||||
*/
|
||||
off = vs->client_be;
|
||||
off = vs->client_endian == G_BIG_ENDIAN ? 1 : 0;
|
||||
|
||||
memset(stats, 0, sizeof (stats));
|
||||
|
||||
|
|
@ -891,7 +891,7 @@ static void tight_pack24(VncState *vs, uint8_t *buf, size_t count, size_t *ret)
|
|||
|
||||
buf8 = buf;
|
||||
|
||||
if (1 /* FIXME */) {
|
||||
if (vs->client_endian == G_BYTE_ORDER) {
|
||||
rshift = vs->client_pf.rshift;
|
||||
gshift = vs->client_pf.gshift;
|
||||
bshift = vs->client_pf.bshift;
|
||||
|
|
@ -1001,16 +1001,24 @@ static int send_mono_rect(VncState *vs, int x, int y,
|
|||
break;
|
||||
}
|
||||
case 2:
|
||||
vnc_write(vs, &bg, 2);
|
||||
vnc_write(vs, &fg, 2);
|
||||
{
|
||||
uint16_t bg16 = bg;
|
||||
uint16_t fg16 = fg;
|
||||
vnc_write(vs, &bg16, 2);
|
||||
vnc_write(vs, &fg16, 2);
|
||||
tight_encode_mono_rect16(vs->tight->tight.buffer, w, h, bg, fg);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
vnc_write_u8(vs, bg);
|
||||
vnc_write_u8(vs, fg);
|
||||
{
|
||||
uint8_t bg8 = bg;
|
||||
uint8_t fg8 = fg;
|
||||
vnc_write_u8(vs, bg8);
|
||||
vnc_write_u8(vs, fg8);
|
||||
tight_encode_mono_rect8(vs->tight->tight.buffer, w, h, bg, fg);
|
||||
break;
|
||||
}
|
||||
}
|
||||
vs->tight->tight.offset = bytes;
|
||||
|
||||
bytes = tight_compress_data(vs, stream, bytes, level, Z_DEFAULT_STRATEGY);
|
||||
|
|
|
|||
|
|
@ -48,21 +48,21 @@ void vnc_zlib_zfree(void *x, void *addr)
|
|||
|
||||
static void vnc_zlib_start(VncState *vs)
|
||||
{
|
||||
buffer_reset(&vs->zlib.zlib);
|
||||
buffer_reset(&vs->zlib->zlib);
|
||||
|
||||
// make the output buffer be the zlib buffer, so we can compress it later
|
||||
vs->zlib.tmp = vs->output;
|
||||
vs->output = vs->zlib.zlib;
|
||||
vs->zlib->tmp = vs->output;
|
||||
vs->output = vs->zlib->zlib;
|
||||
}
|
||||
|
||||
static int vnc_zlib_stop(VncState *vs)
|
||||
{
|
||||
z_streamp zstream = &vs->zlib.stream;
|
||||
z_streamp zstream = &vs->zlib->stream;
|
||||
int previous_out;
|
||||
|
||||
// switch back to normal output/zlib buffers
|
||||
vs->zlib.zlib = vs->output;
|
||||
vs->output = vs->zlib.tmp;
|
||||
vs->zlib->zlib = vs->output;
|
||||
vs->output = vs->zlib->tmp;
|
||||
|
||||
// compress the zlib buffer
|
||||
|
||||
|
|
@ -85,24 +85,24 @@ static int vnc_zlib_stop(VncState *vs)
|
|||
return -1;
|
||||
}
|
||||
|
||||
vs->zlib.level = vs->tight->compression;
|
||||
vs->zlib->level = vs->tight->compression;
|
||||
zstream->opaque = vs;
|
||||
}
|
||||
|
||||
if (vs->tight->compression != vs->zlib.level) {
|
||||
if (vs->tight->compression != vs->zlib->level) {
|
||||
if (deflateParams(zstream, vs->tight->compression,
|
||||
Z_DEFAULT_STRATEGY) != Z_OK) {
|
||||
return -1;
|
||||
}
|
||||
vs->zlib.level = vs->tight->compression;
|
||||
vs->zlib->level = vs->tight->compression;
|
||||
}
|
||||
|
||||
// reserve memory in output buffer
|
||||
buffer_reserve(&vs->output, vs->zlib.zlib.offset + 64);
|
||||
buffer_reserve(&vs->output, vs->zlib->zlib.offset + 64);
|
||||
|
||||
// set pointers
|
||||
zstream->next_in = vs->zlib.zlib.buffer;
|
||||
zstream->avail_in = vs->zlib.zlib.offset;
|
||||
zstream->next_in = vs->zlib->zlib.buffer;
|
||||
zstream->avail_in = vs->zlib->zlib.offset;
|
||||
zstream->next_out = vs->output.buffer + vs->output.offset;
|
||||
zstream->avail_out = vs->output.capacity - vs->output.offset;
|
||||
previous_out = zstream->avail_out;
|
||||
|
|
@ -147,8 +147,8 @@ int vnc_zlib_send_framebuffer_update(VncState *vs, int x, int y, int w, int h)
|
|||
|
||||
void vnc_zlib_clear(VncState *vs)
|
||||
{
|
||||
if (vs->zlib.stream.opaque) {
|
||||
deflateEnd(&vs->zlib.stream);
|
||||
if (vs->zlib->stream.opaque) {
|
||||
deflateEnd(&vs->zlib->stream);
|
||||
}
|
||||
buffer_free(&vs->zlib.zlib);
|
||||
buffer_free(&vs->zlib->zlib);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -255,7 +255,7 @@ static void zrle_write_u8(VncState *vs, uint8_t value)
|
|||
static int zrle_send_framebuffer_update(VncState *vs, int x, int y,
|
||||
int w, int h)
|
||||
{
|
||||
bool be = vs->client_be;
|
||||
bool be = vs->client_endian == G_BIG_ENDIAN;
|
||||
size_t bytes;
|
||||
int zywrle_level;
|
||||
|
||||
|
|
|
|||
|
|
@ -188,7 +188,7 @@ static void vnc_async_encoding_start(VncState *orig, VncState *local)
|
|||
local->lossy_rect = orig->lossy_rect;
|
||||
local->write_pixels = orig->write_pixels;
|
||||
local->client_pf = orig->client_pf;
|
||||
local->client_be = orig->client_be;
|
||||
local->client_endian = orig->client_endian;
|
||||
local->tight = orig->tight;
|
||||
local->zlib = orig->zlib;
|
||||
local->hextile = orig->hextile;
|
||||
|
|
|
|||
23
ui/vnc.c
23
ui/vnc.c
|
|
@ -56,6 +56,11 @@
|
|||
#include "io/dns-resolver.h"
|
||||
#include "monitor/monitor.h"
|
||||
|
||||
typedef struct VncConnection {
|
||||
VncState vs;
|
||||
VncZlib zlib;
|
||||
} VncConnection;
|
||||
|
||||
#define VNC_REFRESH_INTERVAL_BASE GUI_REFRESH_INTERVAL_DEFAULT
|
||||
#define VNC_REFRESH_INTERVAL_INC 50
|
||||
#define VNC_REFRESH_INTERVAL_MAX GUI_REFRESH_INTERVAL_IDLE
|
||||
|
|
@ -893,7 +898,7 @@ void vnc_convert_pixel(VncState *vs, uint8_t *buf, uint32_t v)
|
|||
buf[0] = v;
|
||||
break;
|
||||
case 2:
|
||||
if (vs->client_be) {
|
||||
if (vs->client_endian == G_BIG_ENDIAN) {
|
||||
buf[0] = v >> 8;
|
||||
buf[1] = v;
|
||||
} else {
|
||||
|
|
@ -903,7 +908,7 @@ void vnc_convert_pixel(VncState *vs, uint8_t *buf, uint32_t v)
|
|||
break;
|
||||
default:
|
||||
case 4:
|
||||
if (vs->client_be) {
|
||||
if (vs->client_endian == G_BIG_ENDIAN) {
|
||||
buf[0] = v >> 24;
|
||||
buf[1] = v >> 16;
|
||||
buf[2] = v >> 8;
|
||||
|
|
@ -1364,7 +1369,7 @@ void vnc_disconnect_finish(VncState *vs)
|
|||
vs->magic = 0;
|
||||
g_free(vs->zrle);
|
||||
g_free(vs->tight);
|
||||
g_free(vs);
|
||||
g_free(container_of(vs, VncConnection, vs));
|
||||
}
|
||||
|
||||
size_t vnc_client_io_error(VncState *vs, ssize_t ret, Error *err)
|
||||
|
|
@ -2242,7 +2247,8 @@ static void set_encodings(VncState *vs, int32_t *encodings, size_t n_encodings)
|
|||
|
||||
static void set_pixel_conversion(VncState *vs)
|
||||
{
|
||||
pixman_format_code_t fmt = qemu_pixman_get_format(&vs->client_pf);
|
||||
pixman_format_code_t fmt = qemu_pixman_get_format(&vs->client_pf,
|
||||
vs->client_endian);
|
||||
|
||||
if (fmt == VNC_SERVER_FB_FORMAT) {
|
||||
vs->write_pixels = vnc_write_pixels_copy;
|
||||
|
|
@ -2314,7 +2320,7 @@ static void set_pixel_format(VncState *vs, int bits_per_pixel,
|
|||
vs->client_pf.bits_per_pixel = bits_per_pixel;
|
||||
vs->client_pf.bytes_per_pixel = bits_per_pixel / 8;
|
||||
vs->client_pf.depth = bits_per_pixel == 32 ? 24 : bits_per_pixel;
|
||||
vs->client_be = big_endian_flag;
|
||||
vs->client_endian = big_endian_flag ? G_BIG_ENDIAN : G_LITTLE_ENDIAN;
|
||||
|
||||
if (!true_color_flag) {
|
||||
send_color_map(vs);
|
||||
|
|
@ -2330,6 +2336,7 @@ static void pixel_format_message (VncState *vs) {
|
|||
char pad[3] = { 0, 0, 0 };
|
||||
|
||||
vs->client_pf = qemu_default_pixelformat(32);
|
||||
vs->client_endian = G_BYTE_ORDER;
|
||||
|
||||
vnc_write_u8(vs, vs->client_pf.bits_per_pixel); /* bits-per-pixel */
|
||||
vnc_write_u8(vs, vs->client_pf.depth); /* depth */
|
||||
|
|
@ -3242,11 +3249,13 @@ static void vnc_refresh(DisplayChangeListener *dcl)
|
|||
static void vnc_connect(VncDisplay *vd, QIOChannelSocket *sioc,
|
||||
bool skipauth, bool websocket)
|
||||
{
|
||||
VncState *vs = g_new0(VncState, 1);
|
||||
VncConnection *vc = g_new0(VncConnection, 1);
|
||||
VncState *vs = &vc->vs;
|
||||
bool first_client = QTAILQ_EMPTY(&vd->clients);
|
||||
int i;
|
||||
|
||||
trace_vnc_client_connect(vs, sioc);
|
||||
vs->zlib = &vc->zlib;
|
||||
vs->zrle = g_new0(VncZrle, 1);
|
||||
vs->tight = g_new0(VncTight, 1);
|
||||
vs->magic = VNC_MAGIC;
|
||||
|
|
@ -3269,7 +3278,7 @@ static void vnc_connect(VncDisplay *vd, QIOChannelSocket *sioc,
|
|||
#ifdef CONFIG_PNG
|
||||
buffer_init(&vs->tight->png, "vnc-tight-png/%p", sioc);
|
||||
#endif
|
||||
buffer_init(&vs->zlib.zlib, "vnc-zlib/%p", sioc);
|
||||
buffer_init(&vc->zlib.zlib, "vnc-zlib/%p", sioc);
|
||||
buffer_init(&vs->zrle->zrle, "vnc-zrle/%p", sioc);
|
||||
buffer_init(&vs->zrle->fb, "vnc-zrle-fb/%p", sioc);
|
||||
buffer_init(&vs->zrle->zlib, "vnc-zrle-zlib/%p", sioc);
|
||||
|
|
|
|||
4
ui/vnc.h
4
ui/vnc.h
|
|
@ -323,7 +323,7 @@ struct VncState
|
|||
VncWritePixels *write_pixels;
|
||||
PixelFormat client_pf;
|
||||
pixman_format_code_t client_format;
|
||||
bool client_be;
|
||||
int client_endian; /* G_LITTLE_ENDIAN or G_BIG_ENDIAN */
|
||||
|
||||
CaptureVoiceOut *audio_cap;
|
||||
struct audsettings as;
|
||||
|
|
@ -340,7 +340,7 @@ struct VncState
|
|||
* update vnc_async_encoding_start()
|
||||
*/
|
||||
VncTight *tight;
|
||||
VncZlib zlib;
|
||||
VncZlib *zlib;
|
||||
VncHextile hextile;
|
||||
VncZrle *zrle;
|
||||
VncZywrle zywrle;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue