Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
66d21643c2 | ||
|
|
a5ac9803d5 | ||
|
|
3341f5cd5c | ||
|
|
08fa61a365 | ||
|
|
9561a8c140 | ||
|
|
24778b1c7e | ||
|
|
82517381c5 | ||
|
|
1822478999 | ||
|
|
d097553158 | ||
|
|
2df7954daa | ||
|
|
12e88c0c6c | ||
|
|
2533500b4a | ||
|
|
e50ca171e2 | ||
|
|
787a817cd5 | ||
|
|
fc1ad5124f | ||
|
|
90c635c926 | ||
|
|
18e70a46c3 | ||
|
|
caaa648508 | ||
|
|
d1ea4a1b0e | ||
|
|
1ca9d2e0c2 | ||
|
|
10a9eedc20 | ||
|
|
f272f318c0 | ||
|
|
6624ff3972 | ||
|
|
a655b6548f | ||
|
|
c49db93c36 | ||
|
|
b4ead90726 | ||
|
|
a4e31f5d8e | ||
|
|
1759558915 | ||
|
|
1714828a56 | ||
|
|
676bc0f4a7 | ||
|
|
fe000c4648 | ||
|
|
cae6ddfd7e | ||
|
|
005184da9d | ||
|
|
9a98db505f | ||
|
|
9af1de0c4b | ||
|
|
c76ec8d575 | ||
|
|
0e5f0d87f8 | ||
|
|
83b48a500f | ||
|
|
b8f48f4033 | ||
|
|
fb9bad329c | ||
|
|
5df7910a23 | ||
|
|
ed4bad29e7 | ||
|
|
22909a1397 | ||
|
|
46cdfdfe92 | ||
|
|
fdd20285ae | ||
|
|
3cf25f4c71 | ||
|
|
b7da1f5f5d | ||
|
|
436b3dd8cc | ||
|
|
c902fc66c9 | ||
|
|
6276ce6d70 | ||
|
|
ab96ea4b4d | ||
|
|
d8e6f3f885 | ||
|
|
9f80e4707c | ||
|
|
92d08b3c0d | ||
|
|
6b12cb6edc | ||
|
|
47ddae806b | ||
|
|
c3e1181baf | ||
|
|
8399ccb480 | ||
|
|
325d039d25 | ||
|
|
21f86e2951 | ||
|
|
1702044371 | ||
|
|
9238fd846d | ||
|
|
531cbd8e26 | ||
|
|
a610978bc5 | ||
|
|
613f05a4c6 | ||
|
|
a5a805068a | ||
|
|
43fecc5dde | ||
|
|
91fec603bd | ||
|
|
6eea0cd511 | ||
|
|
80a03b51b2 | ||
|
|
c9afc732e2 | ||
|
|
ff3419cbac | ||
|
|
6f7a53e58e | ||
|
|
fd0b1a5b13 | ||
|
|
3d5b2f81fb | ||
|
|
6966e0ba1d | ||
|
|
5f119c69ff | ||
|
|
679450c926 | ||
|
|
8a48520c17 | ||
|
|
7484d61bdb | ||
|
|
5e8ef1da89 | ||
|
|
ef1655962f | ||
|
|
cdf3fb0617 | ||
|
|
3e59fccb03 | ||
|
|
2f6357ca96 | ||
|
|
9ac56fb385 | ||
|
|
6ba14ba513 | ||
|
|
90f7e23cb7 | ||
|
|
ea8eb871ab | ||
|
|
04b855727f | ||
|
|
c500814317 | ||
|
|
95c0e6e065 | ||
|
|
7b21781562 | ||
|
|
43a4f232fa | ||
|
|
be6e117a83 | ||
|
|
faaeaa955c | ||
|
|
19d107468e | ||
|
|
2a0eb3c2a1 | ||
|
|
0bfd8dd14b | ||
|
|
bc502d4de9 | ||
|
|
027ea4a2f5 | ||
|
|
336fed6bb8 | ||
|
|
70dbbc2811 | ||
|
|
156321d18e | ||
|
|
b76d4a5657 | ||
|
|
bc15a8db4f | ||
|
|
504dcda206 | ||
|
|
f82dd2837c | ||
|
|
15143814cd | ||
|
|
40558266b1 | ||
|
|
8efe15927b | ||
|
|
a0f326228a | ||
|
|
5081dc508d | ||
|
|
9340920c3f | ||
|
|
bfa3f55f0f | ||
|
|
a03d7d6e32 | ||
|
|
827be9d37a | ||
|
|
f60033d379 | ||
|
|
01a9f1a6c5 | ||
|
|
be7b08eb9f | ||
|
|
ac32612b93 | ||
|
|
07f034c7f4 | ||
|
|
86b846f902 | ||
|
|
8a9a719314 | ||
|
|
e1ccfea380 | ||
|
|
1604055e4e | ||
|
|
7bff88a745 | ||
|
|
e60bbdad93 | ||
|
|
dbbb444d72 | ||
|
|
94da90b8c7 | ||
|
|
2da497fd4f | ||
|
|
00a5dc2899 | ||
|
|
86ffc25d35 | ||
|
|
3af56fc07f |
+6
-5
@@ -437,9 +437,8 @@ int kvm_unpark_vcpu(KVMState *s, unsigned long vcpu_id)
|
||||
return kvm_fd;
|
||||
}
|
||||
|
||||
static void kvm_reset_parked_vcpus(void *param)
|
||||
static void kvm_reset_parked_vcpus(KVMState *s)
|
||||
{
|
||||
KVMState *s = param;
|
||||
struct KVMParkedVcpu *cpu;
|
||||
|
||||
QLIST_FOREACH(cpu, &s->kvm_parked_vcpus, node) {
|
||||
@@ -2557,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;
|
||||
@@ -2738,7 +2736,6 @@ static int kvm_init(MachineState *ms)
|
||||
}
|
||||
|
||||
qemu_register_reset(kvm_unpoison_all, NULL);
|
||||
qemu_register_reset(kvm_reset_parked_vcpus, s);
|
||||
|
||||
if (s->kernel_irqchip_allowed) {
|
||||
kvm_irqchip_create(s);
|
||||
@@ -2908,6 +2905,10 @@ static void do_kvm_cpu_synchronize_post_reset(CPUState *cpu, run_on_cpu_data arg
|
||||
void kvm_cpu_synchronize_post_reset(CPUState *cpu)
|
||||
{
|
||||
run_on_cpu(cpu, do_kvm_cpu_synchronize_post_reset, RUN_ON_CPU_NULL);
|
||||
|
||||
if (cpu == first_cpu) {
|
||||
kvm_reset_parked_vcpus(kvm_state);
|
||||
}
|
||||
}
|
||||
|
||||
static void do_kvm_cpu_synchronize_post_init(CPUState *cpu, run_on_cpu_data arg)
|
||||
|
||||
@@ -106,7 +106,7 @@ static int64_t decode_sleb128(const uint8_t **pp)
|
||||
val |= (int64_t)(byte & 0x7f) << shift;
|
||||
shift += 7;
|
||||
} while (byte & 0x80);
|
||||
if (shift < TARGET_LONG_BITS && (byte & 0x40)) {
|
||||
if (shift < 64 && (byte & 0x40)) {
|
||||
val |= -(int64_t)1 << shift;
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
+15
-14
@@ -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;
|
||||
|
||||
@@ -69,11 +69,11 @@ safe_syscall_end:
|
||||
|
||||
/* code path setting errno */
|
||||
0: neg a0, a0
|
||||
j safe_syscall_set_errno_tail
|
||||
tail safe_syscall_set_errno_tail
|
||||
|
||||
/* code path when we didn't execute the syscall */
|
||||
2: li a0, QEMU_ERESTARTSYS
|
||||
j safe_syscall_set_errno_tail
|
||||
tail safe_syscall_set_errno_tail
|
||||
|
||||
.cfi_endproc
|
||||
.size safe_syscall_base, .-safe_syscall_base
|
||||
|
||||
@@ -116,7 +116,7 @@ yet, so sometimes the source code is all you have.
|
||||
* `monitor <https://gitlab.com/qemu-project/qemu/-/tree/master/monitor>`_:
|
||||
`Monitor <QEMU monitor>` implementation (HMP & QMP).
|
||||
* `nbd <https://gitlab.com/qemu-project/qemu/-/tree/master/nbd>`_:
|
||||
QEMU `NBD (Network Block Device) <nbd>` server.
|
||||
QEMU NBD (Network Block Device) server.
|
||||
* `net <https://gitlab.com/qemu-project/qemu/-/tree/master/net>`_:
|
||||
Network (host) support.
|
||||
* `pc-bios <https://gitlab.com/qemu-project/qemu/-/tree/master/pc-bios>`_:
|
||||
|
||||
@@ -500,8 +500,6 @@ What you should *never* do:
|
||||
- expect it to work when loadvm'ing
|
||||
- write to the FAT directory on the host system while accessing it with the guest system
|
||||
|
||||
.. _nbd:
|
||||
|
||||
NBD access
|
||||
~~~~~~~~~~
|
||||
|
||||
|
||||
+30
-9
@@ -434,16 +434,24 @@ void coroutine_fn v9fs_reclaim_fd(V9fsPDU *pdu)
|
||||
V9fsFidState *f;
|
||||
GHashTableIter iter;
|
||||
gpointer fid;
|
||||
int err;
|
||||
int nclosed = 0;
|
||||
|
||||
/* prevent multiple coroutines running this function simultaniously */
|
||||
if (s->reclaiming) {
|
||||
return;
|
||||
}
|
||||
s->reclaiming = true;
|
||||
|
||||
g_hash_table_iter_init(&iter, s->fids);
|
||||
|
||||
QSLIST_HEAD(, V9fsFidState) reclaim_list =
|
||||
QSLIST_HEAD_INITIALIZER(reclaim_list);
|
||||
|
||||
/* Pick FIDs to be closed, collect them on reclaim_list. */
|
||||
while (g_hash_table_iter_next(&iter, &fid, (gpointer *) &f)) {
|
||||
/*
|
||||
* Unlink fids cannot be reclaimed. Check
|
||||
* for them and skip them. Also skip fids
|
||||
* Unlinked fids cannot be reclaimed, skip those, and also skip fids
|
||||
* currently being operated on.
|
||||
*/
|
||||
if (f->ref || f->flags & FID_NON_RECLAIMABLE) {
|
||||
@@ -493,23 +501,34 @@ void coroutine_fn v9fs_reclaim_fd(V9fsPDU *pdu)
|
||||
}
|
||||
}
|
||||
/*
|
||||
* Now close the fid in reclaim list. Free them if they
|
||||
* are already clunked.
|
||||
* Close the picked FIDs altogether on a background I/O driver thread. Do
|
||||
* this all at once to keep latency (i.e. amount of thread hops between main
|
||||
* thread <-> fs driver background thread) as low as possible.
|
||||
*/
|
||||
v9fs_co_run_in_worker({
|
||||
QSLIST_FOREACH(f, &reclaim_list, reclaim_next) {
|
||||
err = (f->fid_type == P9_FID_DIR) ?
|
||||
s->ops->closedir(&s->ctx, &f->fs_reclaim) :
|
||||
s->ops->close(&s->ctx, &f->fs_reclaim);
|
||||
if (!err) {
|
||||
/* total_open_fd must only be mutated on main thread */
|
||||
nclosed++;
|
||||
}
|
||||
}
|
||||
});
|
||||
total_open_fd -= nclosed;
|
||||
/* Free the closed FIDs. */
|
||||
while (!QSLIST_EMPTY(&reclaim_list)) {
|
||||
f = QSLIST_FIRST(&reclaim_list);
|
||||
QSLIST_REMOVE(&reclaim_list, f, V9fsFidState, reclaim_next);
|
||||
if (f->fid_type == P9_FID_FILE) {
|
||||
v9fs_co_close(pdu, &f->fs_reclaim);
|
||||
} else if (f->fid_type == P9_FID_DIR) {
|
||||
v9fs_co_closedir(pdu, &f->fs_reclaim);
|
||||
}
|
||||
/*
|
||||
* Now drop the fid reference, free it
|
||||
* if clunked.
|
||||
*/
|
||||
put_fid(pdu, f);
|
||||
}
|
||||
|
||||
s->reclaiming = false;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -4324,6 +4343,8 @@ int v9fs_device_realize_common(V9fsState *s, const V9fsTransport *t,
|
||||
s->ctx.fst = &fse->fst;
|
||||
fsdev_throttle_init(s->ctx.fst);
|
||||
|
||||
s->reclaiming = false;
|
||||
|
||||
rc = 0;
|
||||
out:
|
||||
if (rc) {
|
||||
|
||||
@@ -362,6 +362,7 @@ struct V9fsState {
|
||||
uint64_t qp_ndevices; /* Amount of entries in qpd_table. */
|
||||
uint16_t qp_affix_next;
|
||||
uint64_t qp_fullpath_next;
|
||||
bool reclaiming;
|
||||
};
|
||||
|
||||
/* 9p2000.L open flags */
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -213,7 +213,7 @@ static void npcm8xx_machine_class_init(ObjectClass *oc, void *data)
|
||||
{
|
||||
MachineClass *mc = MACHINE_CLASS(oc);
|
||||
static const char * const valid_cpu_types[] = {
|
||||
ARM_CPU_TYPE_NAME("cortex-a9"),
|
||||
ARM_CPU_TYPE_NAME("cortex-a35"),
|
||||
NULL
|
||||
};
|
||||
|
||||
|
||||
+10
-5
@@ -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);
|
||||
|
||||
@@ -72,6 +72,7 @@ MachineInfoList *qmp_query_machines(bool has_compat_props, bool compat_props,
|
||||
|
||||
for (el = machines; el; el = el->next) {
|
||||
MachineClass *mc = el->data;
|
||||
const char *default_cpu_type = machine_class_default_cpu_type(mc);
|
||||
MachineInfo *info;
|
||||
|
||||
info = g_malloc0(sizeof(*info));
|
||||
@@ -90,8 +91,8 @@ MachineInfoList *qmp_query_machines(bool has_compat_props, bool compat_props,
|
||||
info->numa_mem_supported = mc->numa_mem_supported;
|
||||
info->deprecated = !!mc->deprecation_reason;
|
||||
info->acpi = !!object_class_property_find(OBJECT_CLASS(mc), "acpi");
|
||||
if (mc->default_cpu_type) {
|
||||
info->default_cpu_type = g_strdup(mc->default_cpu_type);
|
||||
if (default_cpu_type) {
|
||||
info->default_cpu_type = g_strdup(default_cpu_type);
|
||||
}
|
||||
if (mc->default_ram_id) {
|
||||
info->default_ram_id = g_strdup(mc->default_ram_id);
|
||||
|
||||
@@ -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)
|
||||
|
||||
+1
-1
@@ -72,7 +72,7 @@ static void imx_gpio_update_int(IMXGPIOState *s)
|
||||
static void imx_gpio_set_int_line(IMXGPIOState *s, int line, IMXGPIOLevel level)
|
||||
{
|
||||
/* if this signal isn't configured as an input signal, nothing to do */
|
||||
if (!extract32(s->gdir, line, 1)) {
|
||||
if (extract32(s->gdir, line, 1)) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
+5
-6
@@ -79,13 +79,12 @@ static void imx_i2c_reset(DeviceState *dev)
|
||||
|
||||
static inline void imx_i2c_raise_interrupt(IMXI2CState *s)
|
||||
{
|
||||
/*
|
||||
* raise an interrupt if the device is enabled and it is configured
|
||||
* to generate some interrupts.
|
||||
*/
|
||||
if (imx_i2c_is_enabled(s) && imx_i2c_interrupt_is_enabled(s)) {
|
||||
if (imx_i2c_is_enabled(s)) {
|
||||
s->i2sr |= I2SR_IIF;
|
||||
qemu_irq_raise(s->irq);
|
||||
|
||||
if (imx_i2c_interrupt_is_enabled(s)) {
|
||||
qemu_irq_raise(s->irq);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+19
-18
@@ -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);
|
||||
}
|
||||
|
||||
+29
-30
@@ -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 */
|
||||
|
||||
+4
-7
@@ -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;
|
||||
}
|
||||
|
||||
@@ -226,7 +226,6 @@ static void nvme_subsys_class_init(ObjectClass *oc, void *data)
|
||||
|
||||
dc->realize = nvme_subsys_realize;
|
||||
dc->desc = "Virtual NVMe subsystem";
|
||||
dc->hotpluggable = false;
|
||||
|
||||
device_class_set_props(dc, nvme_subsystem_props);
|
||||
}
|
||||
|
||||
+48
-34
@@ -320,38 +320,6 @@ static void gt64120_isd_mapping(GT64120State *s)
|
||||
memory_region_transaction_commit();
|
||||
}
|
||||
|
||||
static void gt64120_update_pci_cfgdata_mapping(GT64120State *s)
|
||||
{
|
||||
/* Indexed on MByteSwap bit, see Table 158: PCI_0 Command, Offset: 0xc00 */
|
||||
static const MemoryRegionOps *pci_host_data_ops[] = {
|
||||
&pci_host_data_be_ops, &pci_host_data_le_ops
|
||||
};
|
||||
PCIHostState *phb = PCI_HOST_BRIDGE(s);
|
||||
|
||||
memory_region_transaction_begin();
|
||||
|
||||
/*
|
||||
* The setting of the MByteSwap bit and MWordSwap bit in the PCI Internal
|
||||
* Command Register determines how data transactions from the CPU to/from
|
||||
* PCI are handled along with the setting of the Endianness bit in the CPU
|
||||
* Configuration Register. See:
|
||||
* - Table 16: 32-bit PCI Transaction Endianness
|
||||
* - Table 158: PCI_0 Command, Offset: 0xc00
|
||||
*/
|
||||
|
||||
if (memory_region_is_mapped(&phb->data_mem)) {
|
||||
memory_region_del_subregion(&s->ISD_mem, &phb->data_mem);
|
||||
object_unparent(OBJECT(&phb->data_mem));
|
||||
}
|
||||
memory_region_init_io(&phb->data_mem, OBJECT(phb),
|
||||
pci_host_data_ops[s->regs[GT_PCI0_CMD] & 1],
|
||||
s, "pci-conf-data", 4);
|
||||
memory_region_add_subregion_overlap(&s->ISD_mem, GT_PCI0_CFGDATA << 2,
|
||||
&phb->data_mem, 1);
|
||||
|
||||
memory_region_transaction_commit();
|
||||
}
|
||||
|
||||
static void gt64120_pci_mapping(GT64120State *s)
|
||||
{
|
||||
memory_region_transaction_begin();
|
||||
@@ -645,7 +613,6 @@ static void gt64120_writel(void *opaque, hwaddr addr,
|
||||
case GT_PCI0_CMD:
|
||||
case GT_PCI1_CMD:
|
||||
s->regs[saddr] = val & 0x0401fc0f;
|
||||
gt64120_update_pci_cfgdata_mapping(s);
|
||||
break;
|
||||
case GT_PCI0_TOR:
|
||||
case GT_PCI0_BS_SCS10:
|
||||
@@ -1024,6 +991,48 @@ static const MemoryRegionOps isd_mem_ops = {
|
||||
},
|
||||
};
|
||||
|
||||
static bool bswap(const GT64120State *s)
|
||||
{
|
||||
PCIHostState *phb = PCI_HOST_BRIDGE(s);
|
||||
/*check for bus == 0 && device == 0, Bits 11:15 = Device , Bits 16:23 = Bus*/
|
||||
bool is_phb_dev0 = extract32(phb->config_reg, 11, 13) == 0;
|
||||
bool le_mode = FIELD_EX32(s->regs[GT_PCI0_CMD], GT_PCI0_CMD, MByteSwap);
|
||||
/* Only swap for non-bridge devices in big-endian mode */
|
||||
return !le_mode && !is_phb_dev0;
|
||||
}
|
||||
|
||||
static uint64_t gt64120_pci_data_read(void *opaque, hwaddr addr, unsigned size)
|
||||
{
|
||||
GT64120State *s = opaque;
|
||||
uint32_t val = pci_host_data_le_ops.read(opaque, addr, size);
|
||||
|
||||
if (bswap(s)) {
|
||||
val = bswap32(val);
|
||||
}
|
||||
return val;
|
||||
}
|
||||
|
||||
static void gt64120_pci_data_write(void *opaque, hwaddr addr,
|
||||
uint64_t val, unsigned size)
|
||||
{
|
||||
GT64120State *s = opaque;
|
||||
|
||||
if (bswap(s)) {
|
||||
val = bswap32(val);
|
||||
}
|
||||
pci_host_data_le_ops.write(opaque, addr, val, size);
|
||||
}
|
||||
|
||||
static const MemoryRegionOps gt64120_pci_data_ops = {
|
||||
.read = gt64120_pci_data_read,
|
||||
.write = gt64120_pci_data_write,
|
||||
.endianness = DEVICE_LITTLE_ENDIAN,
|
||||
.valid = {
|
||||
.min_access_size = 4,
|
||||
.max_access_size = 4,
|
||||
},
|
||||
};
|
||||
|
||||
static void gt64120_reset(DeviceState *dev)
|
||||
{
|
||||
GT64120State *s = GT64120_PCI_HOST_BRIDGE(dev);
|
||||
@@ -1178,7 +1187,6 @@ static void gt64120_reset(DeviceState *dev)
|
||||
|
||||
gt64120_isd_mapping(s);
|
||||
gt64120_pci_mapping(s);
|
||||
gt64120_update_pci_cfgdata_mapping(s);
|
||||
}
|
||||
|
||||
static void gt64120_realize(DeviceState *dev, Error **errp)
|
||||
@@ -1202,6 +1210,12 @@ static void gt64120_realize(DeviceState *dev, Error **errp)
|
||||
memory_region_add_subregion_overlap(&s->ISD_mem, GT_PCI0_CFGADDR << 2,
|
||||
&phb->conf_mem, 1);
|
||||
|
||||
memory_region_init_io(&phb->data_mem, OBJECT(phb),
|
||||
>64120_pci_data_ops,
|
||||
s, "pci-conf-data", 4);
|
||||
memory_region_add_subregion_overlap(&s->ISD_mem, GT_PCI0_CFGDATA << 2,
|
||||
&phb->data_mem, 1);
|
||||
|
||||
|
||||
/*
|
||||
* The whole address space decoded by the GT-64120A doesn't generate
|
||||
|
||||
+1
-1
@@ -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;
|
||||
}
|
||||
|
||||
@@ -217,12 +217,6 @@ const MemoryRegionOps pci_host_data_le_ops = {
|
||||
.endianness = DEVICE_LITTLE_ENDIAN,
|
||||
};
|
||||
|
||||
const MemoryRegionOps pci_host_data_be_ops = {
|
||||
.read = pci_host_data_read,
|
||||
.write = pci_host_data_write,
|
||||
.endianness = DEVICE_BIG_ENDIAN,
|
||||
};
|
||||
|
||||
static bool pci_host_needed(void *opaque)
|
||||
{
|
||||
PCIHostState *s = opaque;
|
||||
|
||||
@@ -104,8 +104,11 @@ static bool csr_qtest_callback(CharBackend *chr, gchar **words)
|
||||
|
||||
static void riscv_cpu_register_csr_qtest_callback(void)
|
||||
{
|
||||
static GOnce once;
|
||||
g_once(&once, (GThreadFunc)qtest_set_command_cb, csr_qtest_callback);
|
||||
static bool first = true;
|
||||
if (first) {
|
||||
first = false;
|
||||
qtest_set_command_cb(csr_qtest_callback);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -802,6 +802,7 @@ static void machine_set_loadparm(Object *obj, Visitor *v,
|
||||
}
|
||||
|
||||
s390_ipl_fmt_loadparm(ms->loadparm, val, errp);
|
||||
g_free(val);
|
||||
}
|
||||
|
||||
static void ccw_machine_class_init(ObjectClass *oc, void *data)
|
||||
|
||||
+10
-27
@@ -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)
|
||||
|
||||
+10
-8
@@ -2316,6 +2316,8 @@ void virtio_queue_enable(VirtIODevice *vdev, uint32_t queue_index)
|
||||
}
|
||||
}
|
||||
|
||||
static int virtio_set_features_nocheck(VirtIODevice *vdev, uint64_t val);
|
||||
|
||||
void virtio_reset(void *opaque)
|
||||
{
|
||||
VirtIODevice *vdev = opaque;
|
||||
@@ -2346,7 +2348,7 @@ void virtio_reset(void *opaque)
|
||||
vdev->start_on_kick = false;
|
||||
vdev->started = false;
|
||||
vdev->broken = false;
|
||||
vdev->guest_features = 0;
|
||||
virtio_set_features_nocheck(vdev, 0);
|
||||
vdev->queue_sel = 0;
|
||||
vdev->status = 0;
|
||||
vdev->disabled = false;
|
||||
@@ -3255,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) {
|
||||
@@ -3269,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) {
|
||||
|
||||
+22
-10
@@ -75,7 +75,8 @@ typedef struct MapCache {
|
||||
} MapCache;
|
||||
|
||||
static MapCache *mapcache;
|
||||
static MapCache *mapcache_grants;
|
||||
static MapCache *mapcache_grants_ro;
|
||||
static MapCache *mapcache_grants_rw;
|
||||
static xengnttab_handle *xen_region_gnttabdev;
|
||||
|
||||
static inline void mapcache_lock(MapCache *mc)
|
||||
@@ -176,9 +177,12 @@ void xen_map_cache_init(phys_offset_to_gaddr_t f, void *opaque)
|
||||
* Grant mappings must use XC_PAGE_SIZE granularity since we can't
|
||||
* map anything beyond the number of pages granted to us.
|
||||
*/
|
||||
mapcache_grants = xen_map_cache_init_single(f, opaque,
|
||||
XC_PAGE_SHIFT,
|
||||
max_mcache_size);
|
||||
mapcache_grants_ro = xen_map_cache_init_single(f, opaque,
|
||||
XC_PAGE_SHIFT,
|
||||
max_mcache_size);
|
||||
mapcache_grants_rw = xen_map_cache_init_single(f, opaque,
|
||||
XC_PAGE_SHIFT,
|
||||
max_mcache_size);
|
||||
|
||||
setrlimit(RLIMIT_AS, &rlimit_as);
|
||||
}
|
||||
@@ -376,12 +380,12 @@ tryagain:
|
||||
|
||||
entry = &mc->entry[address_index % mc->nr_buckets];
|
||||
|
||||
while (entry && (lock || entry->lock) && entry->vaddr_base &&
|
||||
(entry->paddr_index != address_index || entry->size != cache_size ||
|
||||
while (entry && (!entry->vaddr_base ||
|
||||
entry->paddr_index != address_index || entry->size != cache_size ||
|
||||
!test_bits(address_offset >> XC_PAGE_SHIFT,
|
||||
test_bit_size >> XC_PAGE_SHIFT,
|
||||
entry->valid_mapping))) {
|
||||
if (!free_entry && !entry->lock) {
|
||||
if (!free_entry && (!entry->lock || !entry->vaddr_base)) {
|
||||
free_entry = entry;
|
||||
free_pentry = pentry;
|
||||
}
|
||||
@@ -456,9 +460,13 @@ uint8_t *xen_map_cache(MemoryRegion *mr,
|
||||
bool is_write)
|
||||
{
|
||||
bool grant = xen_mr_is_grants(mr);
|
||||
MapCache *mc = grant ? mapcache_grants : mapcache;
|
||||
MapCache *mc = mapcache;
|
||||
uint8_t *p;
|
||||
|
||||
if (grant) {
|
||||
mc = is_write ? mapcache_grants_rw : mapcache_grants_ro;
|
||||
}
|
||||
|
||||
if (grant && !lock) {
|
||||
/*
|
||||
* Grants are only supported via address_space_map(). Anything
|
||||
@@ -523,7 +531,10 @@ ram_addr_t xen_ram_addr_from_mapcache(void *ptr)
|
||||
|
||||
addr = xen_ram_addr_from_mapcache_single(mapcache, ptr);
|
||||
if (addr == RAM_ADDR_INVALID) {
|
||||
addr = xen_ram_addr_from_mapcache_single(mapcache_grants, ptr);
|
||||
addr = xen_ram_addr_from_mapcache_single(mapcache_grants_ro, ptr);
|
||||
}
|
||||
if (addr == RAM_ADDR_INVALID) {
|
||||
addr = xen_ram_addr_from_mapcache_single(mapcache_grants_rw, ptr);
|
||||
}
|
||||
|
||||
return addr;
|
||||
@@ -626,7 +637,8 @@ static void xen_invalidate_map_cache_entry_single(MapCache *mc, uint8_t *buffer)
|
||||
static void xen_invalidate_map_cache_entry_all(uint8_t *buffer)
|
||||
{
|
||||
xen_invalidate_map_cache_entry_single(mapcache, buffer);
|
||||
xen_invalidate_map_cache_entry_single(mapcache_grants, buffer);
|
||||
xen_invalidate_map_cache_entry_single(mapcache_grants_ro, buffer);
|
||||
xen_invalidate_map_cache_entry_single(mapcache_grants_rw, buffer);
|
||||
}
|
||||
|
||||
static void xen_invalidate_map_cache_entry_bh(void *opaque)
|
||||
|
||||
@@ -135,7 +135,8 @@ struct SysemuCPUOps;
|
||||
* @gdb_stop_before_watchpoint: Indicates whether GDB expects the CPU to stop
|
||||
* before the insn which triggers a watchpoint rather than after it.
|
||||
* @gdb_arch_name: Optional callback that returns the architecture name known
|
||||
* to GDB. The caller must free the returned string with g_free.
|
||||
* to GDB. The returned value is expected to be a simple constant string:
|
||||
* the caller will not g_free() it.
|
||||
* @disas_set_info: Setup architecture specific components of disassembly info
|
||||
* @adjust_watchpoint_address: Perform a target-specific adjustment to an
|
||||
* address before attempting to match it against watchpoints.
|
||||
|
||||
@@ -109,10 +109,6 @@ static const uint32_t reg800_keep_bits[DINO800_REGS] = {
|
||||
struct DinoState {
|
||||
PCIHostState parent_obj;
|
||||
|
||||
/*
|
||||
* PCI_CONFIG_ADDR is parent_obj.config_reg, via pci_host_conf_be_ops,
|
||||
* so that we can map PCI_CONFIG_DATA to pci_host_data_be_ops.
|
||||
*/
|
||||
uint32_t config_reg_dino; /* keep original copy, including 2 lowest bits */
|
||||
|
||||
uint32_t iar0;
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -68,6 +68,5 @@ uint32_t pci_data_read(PCIBus *s, uint32_t addr, unsigned len);
|
||||
extern const MemoryRegionOps pci_host_conf_le_ops;
|
||||
extern const MemoryRegionOps pci_host_conf_be_ops;
|
||||
extern const MemoryRegionOps pci_host_data_le_ops;
|
||||
extern const MemoryRegionOps pci_host_data_be_ops;
|
||||
|
||||
#endif /* PCI_HOST_H */
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -112,7 +112,7 @@ static abi_ulong hppa_lws(CPUHPPAState *env)
|
||||
void cpu_loop(CPUHPPAState *env)
|
||||
{
|
||||
CPUState *cs = env_cpu(env);
|
||||
abi_ulong ret;
|
||||
abi_ulong ret, si_code = 0;
|
||||
int trapnr;
|
||||
|
||||
while (1) {
|
||||
@@ -169,7 +169,15 @@ void cpu_loop(CPUHPPAState *env)
|
||||
force_sig_fault(TARGET_SIGFPE, TARGET_FPE_CONDTRAP, env->iaoq_f);
|
||||
break;
|
||||
case EXCP_ASSIST:
|
||||
force_sig_fault(TARGET_SIGFPE, 0, env->iaoq_f);
|
||||
#define set_si_code(mask, val) \
|
||||
if (env->fr[0] & mask) { si_code = val; }
|
||||
set_si_code(R_FPSR_FLG_I_MASK, TARGET_FPE_FLTRES);
|
||||
set_si_code(R_FPSR_FLG_U_MASK, TARGET_FPE_FLTUND);
|
||||
set_si_code(R_FPSR_FLG_O_MASK, TARGET_FPE_FLTOVF);
|
||||
set_si_code(R_FPSR_FLG_Z_MASK, TARGET_FPE_FLTDIV);
|
||||
set_si_code(R_FPSR_FLG_V_MASK, TARGET_FPE_FLTINV);
|
||||
#undef set_si_code
|
||||
force_sig_fault(TARGET_SIGFPE, si_code, env->iaoq_f);
|
||||
break;
|
||||
case EXCP_BREAK:
|
||||
force_sig_fault(TARGET_SIGTRAP, TARGET_TRAP_BRKPT, env->iaoq_f);
|
||||
|
||||
@@ -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) {
|
||||
|
||||
+21
-5
@@ -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;
|
||||
|
||||
+35
-47
@@ -2185,20 +2185,24 @@ if not has_malloc_trim and get_option('malloc_trim').enabled()
|
||||
endif
|
||||
endif
|
||||
|
||||
gnu_source_prefix = '''
|
||||
osdep_prefix = '''
|
||||
#ifndef _GNU_SOURCE
|
||||
#define _GNU_SOURCE
|
||||
#endif
|
||||
|
||||
#include <stddef.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#include <string.h>
|
||||
#include <limits.h>
|
||||
/* Put unistd.h before time.h as that triggers localtime_r/gmtime_r
|
||||
* function availability on recentish Mingw-w64 platforms. */
|
||||
#include <unistd.h>
|
||||
#include <time.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
'''
|
||||
|
||||
# Check whether the glibc provides STATX_BASIC_STATS
|
||||
|
||||
has_statx = cc.has_header_symbol('sys/stat.h', 'STATX_BASIC_STATS', prefix: gnu_source_prefix)
|
||||
|
||||
# Check whether statx() provides mount ID information
|
||||
|
||||
has_statx_mnt_id = cc.has_header_symbol('sys/stat.h', 'STATX_MNT_ID', prefix: gnu_source_prefix)
|
||||
|
||||
have_vhost_user_blk_server = get_option('vhost_user_blk_server') \
|
||||
.require(host_os == 'linux',
|
||||
error_message: 'vhost_user_blk_server requires linux') \
|
||||
@@ -2560,8 +2564,6 @@ config_host_data.set('CONFIG_CRYPTO_SM3', crypto_sm3.found())
|
||||
config_host_data.set('CONFIG_HOGWEED', hogweed.found())
|
||||
config_host_data.set('CONFIG_QEMU_PRIVATE_XTS', xts == 'private')
|
||||
config_host_data.set('CONFIG_MALLOC_TRIM', has_malloc_trim)
|
||||
config_host_data.set('CONFIG_STATX', has_statx)
|
||||
config_host_data.set('CONFIG_STATX_MNT_ID', has_statx_mnt_id)
|
||||
config_host_data.set('CONFIG_ZSTD', zstd.found())
|
||||
config_host_data.set('CONFIG_QPL', qpl.found())
|
||||
config_host_data.set('CONFIG_UADK', uadk.found())
|
||||
@@ -2635,7 +2637,6 @@ config_host_data.set('CONFIG_CLOCK_ADJTIME', cc.has_function('clock_adjtime'))
|
||||
config_host_data.set('CONFIG_DUP3', cc.has_function('dup3'))
|
||||
config_host_data.set('CONFIG_FALLOCATE', cc.has_function('fallocate'))
|
||||
config_host_data.set('CONFIG_POSIX_FALLOCATE', cc.has_function('posix_fallocate'))
|
||||
config_host_data.set('CONFIG_GETCPU', cc.has_function('getcpu', prefix: gnu_source_prefix))
|
||||
config_host_data.set('CONFIG_SCHED_GETCPU', cc.has_function('sched_getcpu', prefix: '#include <sched.h>'))
|
||||
# Note that we need to specify prefix: here to avoid incorrectly
|
||||
# thinking that Windows has posix_memalign()
|
||||
@@ -2657,7 +2658,7 @@ config_host_data.set('HAVE_GETIFADDRS', cc.has_function('getifaddrs'))
|
||||
config_host_data.set('HAVE_GLIB_WITH_SLICE_ALLOCATOR', glib_has_gslice)
|
||||
config_host_data.set('HAVE_GLIB_WITH_ALIGNED_ALLOC', glib_has_aligned_alloc)
|
||||
config_host_data.set('HAVE_OPENPTY', cc.has_function('openpty', dependencies: util))
|
||||
config_host_data.set('HAVE_STRCHRNUL', cc.has_function('strchrnul'))
|
||||
config_host_data.set('HAVE_STRCHRNUL', cc.has_function('strchrnul', prefix: osdep_prefix))
|
||||
config_host_data.set('HAVE_SYSTEM_FUNCTION', cc.has_function('system', prefix: '#include <stdlib.h>'))
|
||||
if rbd.found()
|
||||
config_host_data.set('HAVE_RBD_NAMESPACE_EXISTS',
|
||||
@@ -2713,6 +2714,8 @@ config_host_data.set('CONFIG_FALLOCATE_ZERO_RANGE',
|
||||
config_host_data.set('CONFIG_FIEMAP',
|
||||
cc.has_header('linux/fiemap.h') and
|
||||
cc.has_header_symbol('linux/fs.h', 'FS_IOC_FIEMAP'))
|
||||
config_host_data.set('CONFIG_GETCPU',
|
||||
cc.has_header_symbol('sched.h', 'getcpu', prefix: osdep_prefix))
|
||||
config_host_data.set('CONFIG_GETRANDOM',
|
||||
cc.has_function('getrandom') and
|
||||
cc.has_header_symbol('sys/random.h', 'GRND_NONBLOCK'))
|
||||
@@ -2757,8 +2760,7 @@ config_host_data.set('HAVE_UTMPX',
|
||||
config_host_data.set('CONFIG_EVENTFD', cc.links('''
|
||||
#include <sys/eventfd.h>
|
||||
int main(void) { return eventfd(0, EFD_NONBLOCK | EFD_CLOEXEC); }'''))
|
||||
config_host_data.set('CONFIG_FDATASYNC', cc.links(gnu_source_prefix + '''
|
||||
#include <unistd.h>
|
||||
config_host_data.set('CONFIG_FDATASYNC', cc.links(osdep_prefix + '''
|
||||
int main(void) {
|
||||
#if defined(_POSIX_SYNCHRONIZED_IO) && _POSIX_SYNCHRONIZED_IO > 0
|
||||
return fdatasync(0);
|
||||
@@ -2767,10 +2769,8 @@ config_host_data.set('CONFIG_FDATASYNC', cc.links(gnu_source_prefix + '''
|
||||
#endif
|
||||
}'''))
|
||||
|
||||
has_madvise = cc.links(gnu_source_prefix + '''
|
||||
#include <sys/types.h>
|
||||
has_madvise = cc.links(osdep_prefix + '''
|
||||
#include <sys/mman.h>
|
||||
#include <stddef.h>
|
||||
int main(void) { return madvise(NULL, 0, MADV_DONTNEED); }''')
|
||||
missing_madvise_proto = false
|
||||
if has_madvise
|
||||
@@ -2780,21 +2780,18 @@ if has_madvise
|
||||
# missing-prototype case, we try again with a definitely-bogus prototype.
|
||||
# This will only compile if the system headers don't provide the prototype;
|
||||
# otherwise the conflicting prototypes will cause a compiler error.
|
||||
missing_madvise_proto = cc.links(gnu_source_prefix + '''
|
||||
#include <sys/types.h>
|
||||
missing_madvise_proto = cc.links(osdep_prefix + '''>
|
||||
#include <sys/mman.h>
|
||||
#include <stddef.h>
|
||||
extern int madvise(int);
|
||||
int main(void) { return madvise(0); }''')
|
||||
endif
|
||||
config_host_data.set('CONFIG_MADVISE', has_madvise)
|
||||
config_host_data.set('HAVE_MADVISE_WITHOUT_PROTOTYPE', missing_madvise_proto)
|
||||
|
||||
config_host_data.set('CONFIG_MEMFD', cc.links(gnu_source_prefix + '''
|
||||
config_host_data.set('CONFIG_MEMFD', cc.links(osdep_prefix + '''
|
||||
#include <sys/mman.h>
|
||||
int main(void) { return memfd_create("foo", MFD_ALLOW_SEALING); }'''))
|
||||
config_host_data.set('CONFIG_OPEN_BY_HANDLE', cc.links(gnu_source_prefix + '''
|
||||
#include <fcntl.h>
|
||||
config_host_data.set('CONFIG_OPEN_BY_HANDLE', cc.links(osdep_prefix + '''
|
||||
#if !defined(AT_EMPTY_PATH)
|
||||
# error missing definition
|
||||
#else
|
||||
@@ -2805,13 +2802,12 @@ config_host_data.set('CONFIG_OPEN_BY_HANDLE', cc.links(gnu_source_prefix + '''
|
||||
# i.e. errno is set and -1 is returned. That's not really how POSIX defines the
|
||||
# function. On the flip side, it has madvise() which is preferred anyways.
|
||||
if host_os != 'darwin'
|
||||
config_host_data.set('CONFIG_POSIX_MADVISE', cc.links(gnu_source_prefix + '''
|
||||
config_host_data.set('CONFIG_POSIX_MADVISE', cc.links(osdep_prefix + '''
|
||||
#include <sys/mman.h>
|
||||
#include <stddef.h>
|
||||
int main(void) { return posix_madvise(NULL, 0, POSIX_MADV_DONTNEED); }'''))
|
||||
endif
|
||||
|
||||
config_host_data.set('CONFIG_PTHREAD_SETNAME_NP_W_TID', cc.links(gnu_source_prefix + '''
|
||||
config_host_data.set('CONFIG_PTHREAD_SETNAME_NP_W_TID', cc.links(osdep_prefix + '''
|
||||
#include <pthread.h>
|
||||
|
||||
static void *f(void *p) { return NULL; }
|
||||
@@ -2822,7 +2818,7 @@ config_host_data.set('CONFIG_PTHREAD_SETNAME_NP_W_TID', cc.links(gnu_source_pref
|
||||
pthread_setname_np(thread, "QEMU");
|
||||
return 0;
|
||||
}''', dependencies: threads))
|
||||
config_host_data.set('CONFIG_PTHREAD_SETNAME_NP_WO_TID', cc.links(gnu_source_prefix + '''
|
||||
config_host_data.set('CONFIG_PTHREAD_SETNAME_NP_WO_TID', cc.links(osdep_prefix + '''
|
||||
#include <pthread.h>
|
||||
|
||||
static void *f(void *p) { pthread_setname_np("QEMU"); return NULL; }
|
||||
@@ -2832,7 +2828,7 @@ config_host_data.set('CONFIG_PTHREAD_SETNAME_NP_WO_TID', cc.links(gnu_source_pre
|
||||
pthread_create(&thread, 0, f, 0);
|
||||
return 0;
|
||||
}''', dependencies: threads))
|
||||
config_host_data.set('CONFIG_PTHREAD_SET_NAME_NP', cc.links(gnu_source_prefix + '''
|
||||
config_host_data.set('CONFIG_PTHREAD_SET_NAME_NP', cc.links(osdep_prefix + '''
|
||||
#include <pthread.h>
|
||||
#include <pthread_np.h>
|
||||
|
||||
@@ -2844,9 +2840,8 @@ config_host_data.set('CONFIG_PTHREAD_SET_NAME_NP', cc.links(gnu_source_prefix +
|
||||
pthread_set_name_np(thread, "QEMU");
|
||||
return 0;
|
||||
}''', dependencies: threads))
|
||||
config_host_data.set('CONFIG_PTHREAD_CONDATTR_SETCLOCK', cc.links(gnu_source_prefix + '''
|
||||
config_host_data.set('CONFIG_PTHREAD_CONDATTR_SETCLOCK', cc.links(osdep_prefix + '''
|
||||
#include <pthread.h>
|
||||
#include <time.h>
|
||||
|
||||
int main(void)
|
||||
{
|
||||
@@ -2855,7 +2850,7 @@ config_host_data.set('CONFIG_PTHREAD_CONDATTR_SETCLOCK', cc.links(gnu_source_pre
|
||||
pthread_condattr_setclock(&attr, CLOCK_MONOTONIC);
|
||||
return 0;
|
||||
}''', dependencies: threads))
|
||||
config_host_data.set('CONFIG_PTHREAD_AFFINITY_NP', cc.links(gnu_source_prefix + '''
|
||||
config_host_data.set('CONFIG_PTHREAD_AFFINITY_NP', cc.links(osdep_prefix + '''
|
||||
#include <pthread.h>
|
||||
|
||||
static void *f(void *p) { return NULL; }
|
||||
@@ -2872,15 +2867,10 @@ config_host_data.set('CONFIG_PTHREAD_AFFINITY_NP', cc.links(gnu_source_prefix +
|
||||
CPU_FREE(cpuset);
|
||||
return 0;
|
||||
}''', dependencies: threads))
|
||||
config_host_data.set('CONFIG_SIGNALFD', cc.links(gnu_source_prefix + '''
|
||||
config_host_data.set('CONFIG_SIGNALFD', cc.links(osdep_prefix + '''
|
||||
#include <sys/signalfd.h>
|
||||
#include <stddef.h>
|
||||
int main(void) { return signalfd(-1, NULL, SFD_CLOEXEC); }'''))
|
||||
config_host_data.set('CONFIG_SPLICE', cc.links(gnu_source_prefix + '''
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <limits.h>
|
||||
|
||||
config_host_data.set('CONFIG_SPLICE', cc.links(osdep_prefix + '''
|
||||
int main(void)
|
||||
{
|
||||
int len, fd = 0;
|
||||
@@ -2889,13 +2879,13 @@ config_host_data.set('CONFIG_SPLICE', cc.links(gnu_source_prefix + '''
|
||||
return 0;
|
||||
}'''))
|
||||
|
||||
config_host_data.set('HAVE_MLOCKALL', cc.links(gnu_source_prefix + '''
|
||||
config_host_data.set('HAVE_MLOCKALL', cc.links(osdep_prefix + '''
|
||||
#include <sys/mman.h>
|
||||
int main(void) {
|
||||
return mlockall(MCL_FUTURE);
|
||||
}'''))
|
||||
|
||||
config_host_data.set('HAVE_MLOCK_ONFAULT', cc.links(gnu_source_prefix + '''
|
||||
config_host_data.set('HAVE_MLOCK_ONFAULT', cc.links(osdep_prefix + '''
|
||||
#include <sys/mman.h>
|
||||
int main(void) {
|
||||
return mlockall(MCL_FUTURE | MCL_ONFAULT);
|
||||
@@ -2904,7 +2894,7 @@ config_host_data.set('HAVE_MLOCK_ONFAULT', cc.links(gnu_source_prefix + '''
|
||||
have_l2tpv3 = false
|
||||
if get_option('l2tpv3').allowed() and have_system
|
||||
have_l2tpv3 = cc.has_type('struct mmsghdr',
|
||||
prefix: gnu_source_prefix + '''
|
||||
prefix: osdep_prefix + '''
|
||||
#include <sys/socket.h>
|
||||
#include <linux/ip.h>''')
|
||||
endif
|
||||
@@ -3020,13 +3010,13 @@ if has_int128_type
|
||||
endif
|
||||
endif
|
||||
|
||||
config_host_data.set('CONFIG_GETAUXVAL', cc.links(gnu_source_prefix + '''
|
||||
config_host_data.set('CONFIG_GETAUXVAL', cc.links(osdep_prefix + '''
|
||||
#include <sys/auxv.h>
|
||||
int main(void) {
|
||||
return getauxval(AT_HWCAP) == 0;
|
||||
}'''))
|
||||
|
||||
config_host_data.set('CONFIG_ELF_AUX_INFO', cc.links(gnu_source_prefix + '''
|
||||
config_host_data.set('CONFIG_ELF_AUX_INFO', cc.links(osdep_prefix + '''
|
||||
#include <sys/auxv.h>
|
||||
int main(void) {
|
||||
unsigned long hwcap = 0;
|
||||
@@ -3139,9 +3129,7 @@ config_host_data.set('CONFIG_MEMBARRIER', get_option('membarrier') \
|
||||
.allowed())
|
||||
|
||||
have_afalg = get_option('crypto_afalg') \
|
||||
.require(cc.compiles(gnu_source_prefix + '''
|
||||
#include <errno.h>
|
||||
#include <sys/types.h>
|
||||
.require(cc.compiles(osdep_prefix + '''
|
||||
#include <sys/socket.h>
|
||||
#include <linux/if_alg.h>
|
||||
int main(void) {
|
||||
|
||||
+6
-1
@@ -695,6 +695,7 @@ static void *multifd_send_thread(void *opaque)
|
||||
if (qatomic_load_acquire(&p->pending_job)) {
|
||||
bool is_device_state = multifd_payload_device_state(p->data);
|
||||
size_t total_size;
|
||||
int write_flags_masked = 0;
|
||||
|
||||
p->flags = 0;
|
||||
p->iovs_num = 0;
|
||||
@@ -702,6 +703,9 @@ static void *multifd_send_thread(void *opaque)
|
||||
|
||||
if (is_device_state) {
|
||||
multifd_device_state_send_prepare(p);
|
||||
|
||||
/* Device state packets cannot be sent via zerocopy */
|
||||
write_flags_masked |= QIO_CHANNEL_WRITE_FLAG_ZERO_COPY;
|
||||
} else {
|
||||
ret = multifd_send_state->ops->send_prepare(p, &local_err);
|
||||
if (ret != 0) {
|
||||
@@ -723,7 +727,8 @@ static void *multifd_send_thread(void *opaque)
|
||||
&p->data->u.ram, &local_err);
|
||||
} else {
|
||||
ret = qio_channel_writev_full_all(p->c, p->iov, p->iovs_num,
|
||||
NULL, 0, p->write_flags,
|
||||
NULL, 0,
|
||||
p->write_flags & ~write_flags_masked,
|
||||
&local_err);
|
||||
}
|
||||
|
||||
|
||||
+2
-2
@@ -555,7 +555,7 @@ bool migrate_caps_check(bool *old_caps, bool *new_caps, Error **errp)
|
||||
return false;
|
||||
}
|
||||
|
||||
if (migrate_incoming_started()) {
|
||||
if (!migrate_postcopy_preempt() && migrate_incoming_started()) {
|
||||
error_setg(errp,
|
||||
"Postcopy preempt must be set before incoming starts");
|
||||
return false;
|
||||
@@ -563,7 +563,7 @@ bool migrate_caps_check(bool *old_caps, bool *new_caps, Error **errp)
|
||||
}
|
||||
|
||||
if (new_caps[MIGRATION_CAPABILITY_MULTIFD]) {
|
||||
if (migrate_incoming_started()) {
|
||||
if (!migrate_multifd() && migrate_incoming_started()) {
|
||||
error_setg(errp, "Multifd must be set before incoming starts");
|
||||
return false;
|
||||
}
|
||||
|
||||
+3
-1
@@ -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();
|
||||
|
||||
+1
-1
@@ -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;
|
||||
|
||||
Executable → Regular
Executable → Regular
@@ -380,7 +380,7 @@
|
||||
##
|
||||
# @query-sgx:
|
||||
#
|
||||
# Returns information about SGX
|
||||
# Returns information about configured SGX capabilities of guest
|
||||
#
|
||||
# Returns: @SGXInfo
|
||||
#
|
||||
@@ -399,7 +399,7 @@
|
||||
##
|
||||
# @query-sgx-capabilities:
|
||||
#
|
||||
# Returns information from host SGX capabilities
|
||||
# Returns information about SGX capabilities of host
|
||||
#
|
||||
# Returns: @SGXInfo
|
||||
#
|
||||
|
||||
+4
-4
@@ -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:
|
||||
|
||||
+1
-1
@@ -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;
|
||||
|
||||
+46
-16
@@ -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;
|
||||
|
||||
@@ -7770,7 +7770,8 @@ static bool arm_check_ss_active(DisasContext *dc)
|
||||
|
||||
static void arm_post_translate_insn(DisasContext *dc)
|
||||
{
|
||||
if (dc->condjmp && dc->base.is_jmp == DISAS_NEXT) {
|
||||
if (dc->condjmp &&
|
||||
(dc->base.is_jmp == DISAS_NEXT || dc->base.is_jmp == DISAS_TOO_MANY)) {
|
||||
if (dc->pc_save != dc->condlabel.pc_save) {
|
||||
gen_update_pc(dc, dc->condlabel.pc_save - dc->pc_save);
|
||||
}
|
||||
|
||||
+53
-22
@@ -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);
|
||||
|
||||
@@ -118,11 +118,8 @@ BRBC 1111 01 ....... ... @op_bit_imm
|
||||
@io_rd_imm .... . .. ..... .... &rd_imm rd=%rd imm=%io_imm
|
||||
@ldst_d .. . . .. . rd:5 . ... &rd_imm imm=%ldst_d_imm
|
||||
|
||||
# The 16-bit immediate is completely in the next word.
|
||||
# Fields cannot be defined with no bits, so we cannot play
|
||||
# the same trick and append to a zero-bit value.
|
||||
# Defer reading the immediate until trans_{LDS,STS}.
|
||||
@ldst_s .... ... rd:5 .... imm=0
|
||||
%ldst_imm !function=next_word
|
||||
@ldst_s .... ... rd:5 .... imm=%ldst_imm
|
||||
|
||||
MOV 0010 11 . ..... .... @op_rd_rr
|
||||
MOVW 0000 0001 .... .... &rd_rr rd=%rd_d rr=%rr_d
|
||||
|
||||
@@ -1578,7 +1578,6 @@ static bool trans_LDS(DisasContext *ctx, arg_LDS *a)
|
||||
TCGv Rd = cpu_r[a->rd];
|
||||
TCGv addr = tcg_temp_new_i32();
|
||||
TCGv H = cpu_rampD;
|
||||
a->imm = next_word(ctx);
|
||||
|
||||
tcg_gen_mov_tl(addr, H); /* addr = H:M:L */
|
||||
tcg_gen_shli_tl(addr, addr, 16);
|
||||
@@ -1783,7 +1782,6 @@ static bool trans_STS(DisasContext *ctx, arg_STS *a)
|
||||
TCGv Rd = cpu_r[a->rd];
|
||||
TCGv addr = tcg_temp_new_i32();
|
||||
TCGv H = cpu_rampD;
|
||||
a->imm = next_word(ctx);
|
||||
|
||||
tcg_gen_mov_tl(addr, H); /* addr = H:M:L */
|
||||
tcg_gen_shli_tl(addr, addr, 16);
|
||||
|
||||
@@ -95,7 +95,8 @@ static void update_fr0_op(CPUHPPAState *env, uintptr_t ra)
|
||||
{
|
||||
uint32_t soft_exp = get_float_exception_flags(&env->fp_status);
|
||||
uint32_t hard_exp = 0;
|
||||
uint32_t shadow = env->fr0_shadow;
|
||||
uint32_t shadow = env->fr0_shadow & 0x3ffffff;
|
||||
uint32_t fr1 = 0;
|
||||
|
||||
if (likely(soft_exp == 0)) {
|
||||
env->fr[0] = (uint64_t)shadow << 32;
|
||||
@@ -108,9 +109,22 @@ static void update_fr0_op(CPUHPPAState *env, uintptr_t ra)
|
||||
hard_exp |= CONVERT_BIT(soft_exp, float_flag_overflow, R_FPSR_ENA_O_MASK);
|
||||
hard_exp |= CONVERT_BIT(soft_exp, float_flag_divbyzero, R_FPSR_ENA_Z_MASK);
|
||||
hard_exp |= CONVERT_BIT(soft_exp, float_flag_invalid, R_FPSR_ENA_V_MASK);
|
||||
shadow |= hard_exp << (R_FPSR_FLAGS_SHIFT - R_FPSR_ENABLES_SHIFT);
|
||||
if (hard_exp & shadow) {
|
||||
shadow = FIELD_DP32(shadow, FPSR, T, 1);
|
||||
/* fill exception register #1, which is lower 32-bits of fr[0] */
|
||||
#if !defined(CONFIG_USER_ONLY)
|
||||
if (hard_exp & (R_FPSR_ENA_O_MASK | R_FPSR_ENA_U_MASK)) {
|
||||
/* over- and underflow both set overflow flag only */
|
||||
fr1 = FIELD_DP32(fr1, FPSR, C, 1);
|
||||
fr1 = FIELD_DP32(fr1, FPSR, FLG_O, 1);
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
fr1 |= hard_exp << (R_FPSR_FLAGS_SHIFT - R_FPSR_ENABLES_SHIFT);
|
||||
}
|
||||
}
|
||||
env->fr0_shadow = shadow;
|
||||
env->fr[0] = (uint64_t)shadow << 32;
|
||||
env->fr[0] = (uint64_t)shadow << 32 | fr1;
|
||||
|
||||
if (hard_exp & shadow) {
|
||||
hppa_dynamic_excp(env, EXCP_ASSIST, ra);
|
||||
|
||||
@@ -177,6 +177,10 @@ void hppa_cpu_do_interrupt(CPUState *cs)
|
||||
}
|
||||
}
|
||||
env->cr[CR_IIR] = ldl_phys(cs->as, paddr);
|
||||
if (i == EXCP_ASSIST) {
|
||||
/* stuff insn code into bits of FP exception register #1 */
|
||||
env->fr[0] |= (env->cr[CR_IIR] & 0x03ffffff);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
|
||||
+32
-14
@@ -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);
|
||||
@@ -774,11 +781,12 @@ void x86_cpu_vendor_words2str(char *dst, uint32_t vendor1,
|
||||
CPUID_PAE | CPUID_MCE | CPUID_CX8 | CPUID_APIC | CPUID_SEP | \
|
||||
CPUID_MTRR | CPUID_PGE | CPUID_MCA | CPUID_CMOV | CPUID_PAT | \
|
||||
CPUID_PSE36 | CPUID_CLFLUSH | CPUID_ACPI | CPUID_MMX | \
|
||||
CPUID_FXSR | CPUID_SSE | CPUID_SSE2 | CPUID_SS | CPUID_DE)
|
||||
CPUID_FXSR | CPUID_SSE | CPUID_SSE2 | CPUID_SS | CPUID_DE | \
|
||||
CPUID_HT)
|
||||
/* partly implemented:
|
||||
CPUID_MTRR, CPUID_MCA, CPUID_CLFLUSH (needed for Win64) */
|
||||
/* missing:
|
||||
CPUID_VME, CPUID_DTS, CPUID_SS, CPUID_HT, CPUID_TM, CPUID_PBE */
|
||||
CPUID_VME, CPUID_DTS, CPUID_SS, CPUID_TM, CPUID_PBE */
|
||||
|
||||
/*
|
||||
* Kernel-only features that can be shown to usermode programs even if
|
||||
@@ -846,7 +854,8 @@ void x86_cpu_vendor_words2str(char *dst, uint32_t vendor1,
|
||||
|
||||
#define TCG_EXT3_FEATURES (CPUID_EXT3_LAHF_LM | CPUID_EXT3_SVM | \
|
||||
CPUID_EXT3_CR8LEG | CPUID_EXT3_ABM | CPUID_EXT3_SSE4A | \
|
||||
CPUID_EXT3_3DNOWPREFETCH | CPUID_EXT3_KERNEL_FEATURES)
|
||||
CPUID_EXT3_3DNOWPREFETCH | CPUID_EXT3_KERNEL_FEATURES | \
|
||||
CPUID_EXT3_CMP_LEG)
|
||||
|
||||
#define TCG_EXT4_FEATURES 0
|
||||
|
||||
@@ -1772,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 },
|
||||
@@ -5621,6 +5626,18 @@ static const X86CPUDefinition builtin_x86_defs[] = {
|
||||
.features[FEAT_VMX_VMFUNC] = MSR_VMX_VMFUNC_EPT_SWITCHING,
|
||||
.xlevel = 0x80000008,
|
||||
.model_id = "Zhaoxin YongFeng Processor",
|
||||
.versions = (X86CPUVersionDefinition[]) {
|
||||
{ .version = 1 },
|
||||
{
|
||||
.version = 2,
|
||||
.note = "with the correct model number",
|
||||
.props = (PropValue[]) {
|
||||
{ "model", "0x5b" },
|
||||
{ /* end of list */ }
|
||||
}
|
||||
},
|
||||
{ /* end of list */ }
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
@@ -6818,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;
|
||||
@@ -6856,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)) {
|
||||
|
||||
@@ -73,7 +73,7 @@ uint32_t hvf_get_supported_cpuid(uint32_t func, uint32_t idx,
|
||||
CPUID_MSR | CPUID_PAE | CPUID_MCE | CPUID_CX8 | CPUID_APIC |
|
||||
CPUID_SEP | CPUID_MTRR | CPUID_PGE | CPUID_MCA | CPUID_CMOV |
|
||||
CPUID_PAT | CPUID_PSE36 | CPUID_CLFLUSH | CPUID_MMX |
|
||||
CPUID_FXSR | CPUID_SSE | CPUID_SSE2 | CPUID_SS;
|
||||
CPUID_FXSR | CPUID_SSE | CPUID_SSE2 | CPUID_SS | CPUID_HT;
|
||||
ecx &= CPUID_EXT_SSE3 | CPUID_EXT_PCLMULQDQ | CPUID_EXT_SSSE3 |
|
||||
CPUID_EXT_FMA | CPUID_EXT_CX16 | CPUID_EXT_PCID |
|
||||
CPUID_EXT_SSE41 | CPUID_EXT_SSE42 | CPUID_EXT_MOVBE |
|
||||
|
||||
@@ -293,6 +293,7 @@ void set_SF(CPUX86State *env, bool val)
|
||||
|
||||
void lflags_to_rflags(CPUX86State *env)
|
||||
{
|
||||
env->eflags &= ~(CC_C|CC_P|CC_A|CC_Z|CC_S|CC_O);
|
||||
env->eflags |= get_CF(env) ? CC_C : 0;
|
||||
env->eflags |= get_PF(env) ? CC_P : 0;
|
||||
env->eflags |= get_AF(env) ? CC_A : 0;
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -352,7 +352,7 @@ static void gen_writeback(DisasContext *s, X86DecodedInsn *decode, int opn, TCGv
|
||||
break;
|
||||
case X86_OP_SEG:
|
||||
/* Note that gen_movl_seg takes care of interrupt shadow and TF. */
|
||||
gen_movl_seg(s, op->n, s->T0);
|
||||
gen_movl_seg(s, op->n, v, op->n == R_SS);
|
||||
break;
|
||||
case X86_OP_INT:
|
||||
if (op->has_ea) {
|
||||
@@ -2372,7 +2372,7 @@ static void gen_lxx_seg(DisasContext *s, X86DecodedInsn *decode, int seg)
|
||||
gen_op_ld_v(s, MO_16, s->T1, s->A0);
|
||||
|
||||
/* load the segment here to handle exceptions properly */
|
||||
gen_movl_seg(s, seg, s->T1);
|
||||
gen_movl_seg(s, seg, s->T1, false);
|
||||
}
|
||||
|
||||
static void gen_LDS(DisasContext *s, X86DecodedInsn *decode)
|
||||
|
||||
+28
-14
@@ -1992,25 +1992,39 @@ static void gen_op_movl_seg_real(DisasContext *s, X86Seg seg_reg, TCGv seg)
|
||||
|
||||
/* move SRC to seg_reg and compute if the CPU state may change. Never
|
||||
call this function with seg_reg == R_CS */
|
||||
static void gen_movl_seg(DisasContext *s, X86Seg seg_reg, TCGv src)
|
||||
static void gen_movl_seg(DisasContext *s, X86Seg seg_reg, TCGv src, bool inhibit_irq)
|
||||
{
|
||||
if (PE(s) && !VM86(s)) {
|
||||
tcg_gen_trunc_tl_i32(s->tmp2_i32, src);
|
||||
gen_helper_load_seg(tcg_env, tcg_constant_i32(seg_reg), s->tmp2_i32);
|
||||
/* abort translation because the addseg value may change or
|
||||
because ss32 may change. For R_SS, translation must always
|
||||
stop as a special handling must be done to disable hardware
|
||||
interrupts for the next instruction */
|
||||
if (seg_reg == R_SS) {
|
||||
s->base.is_jmp = DISAS_EOB_INHIBIT_IRQ;
|
||||
} else if (CODE32(s) && seg_reg < R_FS) {
|
||||
TCGv_i32 sel = tcg_temp_new_i32();
|
||||
|
||||
tcg_gen_trunc_tl_i32(sel, src);
|
||||
gen_helper_load_seg(tcg_env, tcg_constant_i32(seg_reg), sel);
|
||||
|
||||
/*
|
||||
* 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 {
|
||||
gen_op_movl_seg_real(s, seg_reg, src);
|
||||
if (seg_reg == R_SS) {
|
||||
s->base.is_jmp = DISAS_EOB_INHIBIT_IRQ;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* For MOV or POP to SS (but not LSS) translation must always
|
||||
* stop as a special handling must be done to disable hardware
|
||||
* interrupts for the next instruction.
|
||||
*
|
||||
* This is the last instruction, so it's okay to overwrite
|
||||
* HF_TF_MASK; the next TB will start with the flag set.
|
||||
*
|
||||
* DISAS_EOB_INHIBIT_IRQ is a superset of DISAS_EOB_NEXT which
|
||||
* might have been set above.
|
||||
*/
|
||||
if (inhibit_irq) {
|
||||
s->base.is_jmp = DISAS_EOB_INHIBIT_IRQ;
|
||||
s->flags &= ~HF_TF_MASK;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2258,7 +2272,7 @@ gen_eob(DisasContext *s, int mode)
|
||||
if (mode == DISAS_EOB_RECHECK_TF) {
|
||||
gen_helper_rechecking_single_step(tcg_env);
|
||||
tcg_gen_exit_tb(NULL, 0);
|
||||
} else if ((s->flags & HF_TF_MASK) && mode != DISAS_EOB_INHIBIT_IRQ) {
|
||||
} else if (s->flags & HF_TF_MASK) {
|
||||
gen_helper_single_step(tcg_env);
|
||||
} else if (mode == DISAS_JUMP &&
|
||||
/* give irqs a chance to happen */
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -306,7 +306,7 @@ static void gen_mips16_restore(DisasContext *ctx,
|
||||
int astatic;
|
||||
TCGv t0 = tcg_temp_new();
|
||||
|
||||
gen_op_addr_addi(ctx, t0, cpu_gpr[29], -framesize);
|
||||
gen_op_addr_addi(ctx, t0, cpu_gpr[29], framesize);
|
||||
|
||||
if (do_ra) {
|
||||
decr_and_load(ctx, 31, t0);
|
||||
@@ -386,7 +386,7 @@ static void gen_mips16_restore(DisasContext *ctx,
|
||||
}
|
||||
}
|
||||
|
||||
gen_op_addr_addi(ctx, cpu_gpr[29], cpu_gpr[29], -framesize);
|
||||
gen_op_addr_addi(ctx, cpu_gpr[29], cpu_gpr[29], framesize);
|
||||
}
|
||||
|
||||
#if defined(TARGET_MIPS64)
|
||||
|
||||
@@ -7082,7 +7082,7 @@ ObjectClass *ppc_cpu_class_by_name(const char *name)
|
||||
if (strcmp(name, "max") == 0) {
|
||||
MachineClass *mc = MACHINE_GET_CLASS(qdev_get_machine());
|
||||
if (mc) {
|
||||
return object_class_by_name(mc->default_cpu_type);
|
||||
return object_class_by_name(machine_class_default_cpu_type(mc));
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -79,6 +79,7 @@ const char *riscv_get_misa_ext_name(uint32_t bit);
|
||||
const char *riscv_get_misa_ext_description(uint32_t bit);
|
||||
|
||||
#define CPU_CFG_OFFSET(_prop) offsetof(struct RISCVCPUConfig, _prop)
|
||||
#define ENV_CSR_OFFSET(_csr) offsetof(CPURISCVState, _csr)
|
||||
|
||||
typedef struct riscv_cpu_profile {
|
||||
struct riscv_cpu_profile *u_parent;
|
||||
|
||||
@@ -1662,9 +1662,11 @@ static int get_physical_address(CPURISCVState *env, hwaddr *physical,
|
||||
target_ulong *pte_pa = qemu_map_ram_ptr(mr->ram_block, addr1);
|
||||
target_ulong old_pte;
|
||||
if (riscv_cpu_sxl(env) == MXL_RV32) {
|
||||
old_pte = qatomic_cmpxchg((uint32_t *)pte_pa, pte, updated_pte);
|
||||
old_pte = qatomic_cmpxchg((uint32_t *)pte_pa, cpu_to_le32(pte), cpu_to_le32(updated_pte));
|
||||
old_pte = le32_to_cpu(old_pte);
|
||||
} else {
|
||||
old_pte = qatomic_cmpxchg(pte_pa, pte, updated_pte);
|
||||
old_pte = qatomic_cmpxchg(pte_pa, cpu_to_le64(pte), cpu_to_le64(updated_pte));
|
||||
old_pte = le64_to_cpu(old_pte);
|
||||
}
|
||||
if (old_pte != pte) {
|
||||
goto restart;
|
||||
|
||||
@@ -703,14 +703,14 @@ vfredmax_vs 000111 . ..... ..... 001 ..... 1010111 @r_vm
|
||||
# Vector widening ordered and unordered float reduction sum
|
||||
vfwredusum_vs 110001 . ..... ..... 001 ..... 1010111 @r_vm
|
||||
vfwredosum_vs 110011 . ..... ..... 001 ..... 1010111 @r_vm
|
||||
vmand_mm 011001 - ..... ..... 010 ..... 1010111 @r
|
||||
vmnand_mm 011101 - ..... ..... 010 ..... 1010111 @r
|
||||
vmandn_mm 011000 - ..... ..... 010 ..... 1010111 @r
|
||||
vmxor_mm 011011 - ..... ..... 010 ..... 1010111 @r
|
||||
vmor_mm 011010 - ..... ..... 010 ..... 1010111 @r
|
||||
vmnor_mm 011110 - ..... ..... 010 ..... 1010111 @r
|
||||
vmorn_mm 011100 - ..... ..... 010 ..... 1010111 @r
|
||||
vmxnor_mm 011111 - ..... ..... 010 ..... 1010111 @r
|
||||
vmand_mm 011001 1 ..... ..... 010 ..... 1010111 @r
|
||||
vmnand_mm 011101 1 ..... ..... 010 ..... 1010111 @r
|
||||
vmandn_mm 011000 1 ..... ..... 010 ..... 1010111 @r
|
||||
vmxor_mm 011011 1 ..... ..... 010 ..... 1010111 @r
|
||||
vmor_mm 011010 1 ..... ..... 010 ..... 1010111 @r
|
||||
vmnor_mm 011110 1 ..... ..... 010 ..... 1010111 @r
|
||||
vmorn_mm 011100 1 ..... ..... 010 ..... 1010111 @r
|
||||
vmxnor_mm 011111 1 ..... ..... 010 ..... 1010111 @r
|
||||
vcpop_m 010000 . ..... 10000 010 ..... 1010111 @r2_vm
|
||||
vfirst_m 010000 . ..... 10001 010 ..... 1010111 @r2_vm
|
||||
vmsbf_m 010100 . ..... 00001 010 ..... 1010111 @r2_vm
|
||||
@@ -732,7 +732,7 @@ vrgather_vv 001100 . ..... ..... 000 ..... 1010111 @r_vm
|
||||
vrgatherei16_vv 001110 . ..... ..... 000 ..... 1010111 @r_vm
|
||||
vrgather_vx 001100 . ..... ..... 100 ..... 1010111 @r_vm
|
||||
vrgather_vi 001100 . ..... ..... 011 ..... 1010111 @r_vm
|
||||
vcompress_vm 010111 - ..... ..... 010 ..... 1010111 @r
|
||||
vcompress_vm 010111 1 ..... ..... 010 ..... 1010111 @r
|
||||
vmv1r_v 100111 1 ..... 00000 011 ..... 1010111 @r2rd
|
||||
vmv2r_v 100111 1 ..... 00001 011 ..... 1010111 @r2rd
|
||||
vmv4r_v 100111 1 ..... 00011 011 ..... 1010111 @r2rd
|
||||
|
||||
@@ -119,8 +119,11 @@ static bool trans_vfwmaccbf16_vv(DisasContext *ctx, arg_vfwmaccbf16_vv *a)
|
||||
REQUIRE_FPU;
|
||||
REQUIRE_ZVFBFWMA(ctx);
|
||||
|
||||
uint8_t sew = ctx->sew;
|
||||
if (require_rvv(ctx) && vext_check_isa_ill(ctx) && (ctx->sew == MO_16) &&
|
||||
vext_check_dss(ctx, a->rd, a->rs1, a->rs2, a->vm)) {
|
||||
vext_check_dss(ctx, a->rd, a->rs1, a->rs2, a->vm) &&
|
||||
vext_check_input_eew(ctx, a->rd, sew + 1, a->rs1, sew, a->vm) &&
|
||||
vext_check_input_eew(ctx, a->rd, sew + 1, a->rs2, sew, a->vm)) {
|
||||
uint32_t data = 0;
|
||||
|
||||
gen_set_rm_chkfrm(ctx, RISCV_FRM_DYN);
|
||||
@@ -146,8 +149,10 @@ static bool trans_vfwmaccbf16_vf(DisasContext *ctx, arg_vfwmaccbf16_vf *a)
|
||||
REQUIRE_FPU;
|
||||
REQUIRE_ZVFBFWMA(ctx);
|
||||
|
||||
uint8_t sew = ctx->sew;
|
||||
if (require_rvv(ctx) && (ctx->sew == MO_16) && vext_check_isa_ill(ctx) &&
|
||||
vext_check_ds(ctx, a->rd, a->rs2, a->vm)) {
|
||||
vext_check_ds(ctx, a->rd, a->rs2, a->vm) &&
|
||||
vext_check_input_eew(ctx, a->rd, sew + 1, a->rs2, sew, a->vm)) {
|
||||
uint32_t data = 0;
|
||||
|
||||
gen_set_rm(ctx, RISCV_FRM_DYN);
|
||||
|
||||
@@ -100,10 +100,33 @@ static bool require_scale_rvfmin(DisasContext *s)
|
||||
}
|
||||
}
|
||||
|
||||
/* Destination vector register group cannot overlap source mask register. */
|
||||
static bool require_vm(int vm, int vd)
|
||||
/*
|
||||
* Source and destination vector register groups cannot overlap source mask
|
||||
* register:
|
||||
*
|
||||
* A vector register cannot be used to provide source operands with more than
|
||||
* one EEW for a single instruction. A mask register source is considered to
|
||||
* have EEW=1 for this constraint. An encoding that would result in the same
|
||||
* vector register being read with two or more different EEWs, including when
|
||||
* the vector register appears at different positions within two or more vector
|
||||
* register groups, is reserved.
|
||||
* (Section 5.2)
|
||||
*
|
||||
* A destination vector register group can overlap a source vector
|
||||
* register group only if one of the following holds:
|
||||
* 1. The destination EEW equals the source EEW.
|
||||
* 2. The destination EEW is smaller than the source EEW and the overlap
|
||||
* is in the lowest-numbered part of the source register group.
|
||||
* 3. The destination EEW is greater than the source EEW, the source EMUL
|
||||
* is at least 1, and the overlap is in the highest-numbered part of
|
||||
* the destination register group.
|
||||
* For the purpose of determining register group overlap constraints, mask
|
||||
* elements have EEW=1.
|
||||
* (Section 5.2)
|
||||
*/
|
||||
static bool require_vm(int vm, int v)
|
||||
{
|
||||
return (vm != 0 || vd != 0);
|
||||
return (vm != 0 || v != 0);
|
||||
}
|
||||
|
||||
static bool require_nf(int vd, int nf, int lmul)
|
||||
@@ -356,11 +379,41 @@ static bool vext_check_ld_index(DisasContext *s, int vd, int vs2,
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* Check whether a vector register is used to provide source operands with
|
||||
* more than one EEW for the vector instruction.
|
||||
* Returns true if the instruction has valid encoding
|
||||
* Returns false if encoding violates the mismatched input EEWs constraint
|
||||
*/
|
||||
static bool vext_check_input_eew(DisasContext *s, int vs1, uint8_t eew_vs1,
|
||||
int vs2, uint8_t eew_vs2, int vm)
|
||||
{
|
||||
bool is_valid = true;
|
||||
int8_t emul_vs1 = eew_vs1 - s->sew + s->lmul;
|
||||
int8_t emul_vs2 = eew_vs2 - s->sew + s->lmul;
|
||||
|
||||
/* When vm is 0, vs1 & vs2(EEW!=1) group can't overlap v0 (EEW=1) */
|
||||
if ((vs1 != -1 && !require_vm(vm, vs1)) ||
|
||||
(vs2 != -1 && !require_vm(vm, vs2))) {
|
||||
is_valid = false;
|
||||
}
|
||||
|
||||
/* When eew_vs1 != eew_vs2, check whether vs1 and vs2 are overlapped */
|
||||
if ((vs1 != -1 && vs2 != -1) && (eew_vs1 != eew_vs2) &&
|
||||
is_overlapped(vs1, 1 << MAX(emul_vs1, 0),
|
||||
vs2, 1 << MAX(emul_vs2, 0))) {
|
||||
is_valid = false;
|
||||
}
|
||||
|
||||
return is_valid;
|
||||
}
|
||||
|
||||
static bool vext_check_ss(DisasContext *s, int vd, int vs, int vm)
|
||||
{
|
||||
return require_vm(vm, vd) &&
|
||||
require_align(vd, s->lmul) &&
|
||||
require_align(vs, s->lmul);
|
||||
require_align(vs, s->lmul) &&
|
||||
vext_check_input_eew(s, vs, s->sew, -1, s->sew, vm);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -379,6 +432,7 @@ static bool vext_check_ss(DisasContext *s, int vd, int vs, int vm)
|
||||
static bool vext_check_sss(DisasContext *s, int vd, int vs1, int vs2, int vm)
|
||||
{
|
||||
return vext_check_ss(s, vd, vs2, vm) &&
|
||||
vext_check_input_eew(s, vs1, s->sew, vs2, s->sew, vm) &&
|
||||
require_align(vs1, s->lmul);
|
||||
}
|
||||
|
||||
@@ -474,6 +528,7 @@ static bool vext_narrow_check_common(DisasContext *s, int vd, int vs2,
|
||||
static bool vext_check_ds(DisasContext *s, int vd, int vs, int vm)
|
||||
{
|
||||
return vext_wide_check_common(s, vd, vm) &&
|
||||
vext_check_input_eew(s, vs, s->sew, -1, 0, vm) &&
|
||||
require_align(vs, s->lmul) &&
|
||||
require_noover(vd, s->lmul + 1, vs, s->lmul);
|
||||
}
|
||||
@@ -481,6 +536,7 @@ static bool vext_check_ds(DisasContext *s, int vd, int vs, int vm)
|
||||
static bool vext_check_dd(DisasContext *s, int vd, int vs, int vm)
|
||||
{
|
||||
return vext_wide_check_common(s, vd, vm) &&
|
||||
vext_check_input_eew(s, vs, s->sew + 1, -1, 0, vm) &&
|
||||
require_align(vs, s->lmul + 1);
|
||||
}
|
||||
|
||||
@@ -499,6 +555,7 @@ static bool vext_check_dd(DisasContext *s, int vd, int vs, int vm)
|
||||
static bool vext_check_dss(DisasContext *s, int vd, int vs1, int vs2, int vm)
|
||||
{
|
||||
return vext_check_ds(s, vd, vs2, vm) &&
|
||||
vext_check_input_eew(s, vs1, s->sew, vs2, s->sew, vm) &&
|
||||
require_align(vs1, s->lmul) &&
|
||||
require_noover(vd, s->lmul + 1, vs1, s->lmul);
|
||||
}
|
||||
@@ -521,12 +578,14 @@ static bool vext_check_dss(DisasContext *s, int vd, int vs1, int vs2, int vm)
|
||||
static bool vext_check_dds(DisasContext *s, int vd, int vs1, int vs2, int vm)
|
||||
{
|
||||
return vext_check_ds(s, vd, vs1, vm) &&
|
||||
vext_check_input_eew(s, vs1, s->sew, vs2, s->sew + 1, vm) &&
|
||||
require_align(vs2, s->lmul + 1);
|
||||
}
|
||||
|
||||
static bool vext_check_sd(DisasContext *s, int vd, int vs, int vm)
|
||||
{
|
||||
bool ret = vext_narrow_check_common(s, vd, vs, vm);
|
||||
bool ret = vext_narrow_check_common(s, vd, vs, vm) &&
|
||||
vext_check_input_eew(s, vs, s->sew + 1, -1, 0, vm);
|
||||
if (vd != vs) {
|
||||
ret &= require_noover(vd, s->lmul, vs, s->lmul + 1);
|
||||
}
|
||||
@@ -549,6 +608,7 @@ static bool vext_check_sd(DisasContext *s, int vd, int vs, int vm)
|
||||
static bool vext_check_sds(DisasContext *s, int vd, int vs1, int vs2, int vm)
|
||||
{
|
||||
return vext_check_sd(s, vd, vs2, vm) &&
|
||||
vext_check_input_eew(s, vs1, s->sew, vs2, s->sew + 1, vm) &&
|
||||
require_align(vs1, s->lmul);
|
||||
}
|
||||
|
||||
@@ -584,7 +644,9 @@ static bool vext_check_slide(DisasContext *s, int vd, int vs2,
|
||||
{
|
||||
bool ret = require_align(vs2, s->lmul) &&
|
||||
require_align(vd, s->lmul) &&
|
||||
require_vm(vm, vd);
|
||||
require_vm(vm, vd) &&
|
||||
vext_check_input_eew(s, -1, 0, vs2, s->sew, vm);
|
||||
|
||||
if (is_over) {
|
||||
ret &= (vd != vs2);
|
||||
}
|
||||
@@ -981,7 +1043,8 @@ static bool ld_index_check(DisasContext *s, arg_rnfvm* a, uint8_t eew)
|
||||
{
|
||||
return require_rvv(s) &&
|
||||
vext_check_isa_ill(s) &&
|
||||
vext_check_ld_index(s, a->rd, a->rs2, a->nf, a->vm, eew);
|
||||
vext_check_ld_index(s, a->rd, a->rs2, a->nf, a->vm, eew) &&
|
||||
vext_check_input_eew(s, -1, 0, a->rs2, eew, a->vm);
|
||||
}
|
||||
|
||||
GEN_VEXT_TRANS(vlxei8_v, MO_8, rnfvm, ld_index_op, ld_index_check)
|
||||
@@ -1033,7 +1096,8 @@ static bool st_index_check(DisasContext *s, arg_rnfvm* a, uint8_t eew)
|
||||
{
|
||||
return require_rvv(s) &&
|
||||
vext_check_isa_ill(s) &&
|
||||
vext_check_st_index(s, a->rd, a->rs2, a->nf, eew);
|
||||
vext_check_st_index(s, a->rd, a->rs2, a->nf, eew) &&
|
||||
vext_check_input_eew(s, a->rd, s->sew, a->rs2, eew, a->vm);
|
||||
}
|
||||
|
||||
GEN_VEXT_TRANS(vsxei8_v, MO_8, rnfvm, st_index_op, st_index_check)
|
||||
@@ -1475,6 +1539,16 @@ static bool opivv_widen_check(DisasContext *s, arg_rmrr *a)
|
||||
vext_check_dss(s, a->rd, a->rs1, a->rs2, a->vm);
|
||||
}
|
||||
|
||||
/* OPIVV with overwrite and WIDEN */
|
||||
static bool opivv_overwrite_widen_check(DisasContext *s, arg_rmrr *a)
|
||||
{
|
||||
return require_rvv(s) &&
|
||||
vext_check_isa_ill(s) &&
|
||||
vext_check_dss(s, a->rd, a->rs1, a->rs2, a->vm) &&
|
||||
vext_check_input_eew(s, a->rd, s->sew + 1, a->rs1, s->sew, a->vm) &&
|
||||
vext_check_input_eew(s, a->rd, s->sew + 1, a->rs2, s->sew, a->vm);
|
||||
}
|
||||
|
||||
static bool do_opivv_widen(DisasContext *s, arg_rmrr *a,
|
||||
gen_helper_gvec_4_ptr *fn,
|
||||
bool (*checkfn)(DisasContext *, arg_rmrr *))
|
||||
@@ -1522,6 +1596,14 @@ static bool opivx_widen_check(DisasContext *s, arg_rmrr *a)
|
||||
vext_check_ds(s, a->rd, a->rs2, a->vm);
|
||||
}
|
||||
|
||||
static bool opivx_overwrite_widen_check(DisasContext *s, arg_rmrr *a)
|
||||
{
|
||||
return require_rvv(s) &&
|
||||
vext_check_isa_ill(s) &&
|
||||
vext_check_ds(s, a->rd, a->rs2, a->vm) &&
|
||||
vext_check_input_eew(s, a->rd, s->sew + 1, a->rs2, s->sew, a->vm);
|
||||
}
|
||||
|
||||
#define GEN_OPIVX_WIDEN_TRANS(NAME, CHECK) \
|
||||
static bool trans_##NAME(DisasContext *s, arg_rmrr *a) \
|
||||
{ \
|
||||
@@ -1993,13 +2075,13 @@ GEN_OPIVX_TRANS(vmadd_vx, opivx_check)
|
||||
GEN_OPIVX_TRANS(vnmsub_vx, opivx_check)
|
||||
|
||||
/* Vector Widening Integer Multiply-Add Instructions */
|
||||
GEN_OPIVV_WIDEN_TRANS(vwmaccu_vv, opivv_widen_check)
|
||||
GEN_OPIVV_WIDEN_TRANS(vwmacc_vv, opivv_widen_check)
|
||||
GEN_OPIVV_WIDEN_TRANS(vwmaccsu_vv, opivv_widen_check)
|
||||
GEN_OPIVX_WIDEN_TRANS(vwmaccu_vx, opivx_widen_check)
|
||||
GEN_OPIVX_WIDEN_TRANS(vwmacc_vx, opivx_widen_check)
|
||||
GEN_OPIVX_WIDEN_TRANS(vwmaccsu_vx, opivx_widen_check)
|
||||
GEN_OPIVX_WIDEN_TRANS(vwmaccus_vx, opivx_widen_check)
|
||||
GEN_OPIVV_WIDEN_TRANS(vwmaccu_vv, opivv_overwrite_widen_check)
|
||||
GEN_OPIVV_WIDEN_TRANS(vwmacc_vv, opivv_overwrite_widen_check)
|
||||
GEN_OPIVV_WIDEN_TRANS(vwmaccsu_vv, opivv_overwrite_widen_check)
|
||||
GEN_OPIVX_WIDEN_TRANS(vwmaccu_vx, opivx_overwrite_widen_check)
|
||||
GEN_OPIVX_WIDEN_TRANS(vwmacc_vx, opivx_overwrite_widen_check)
|
||||
GEN_OPIVX_WIDEN_TRANS(vwmaccsu_vx, opivx_overwrite_widen_check)
|
||||
GEN_OPIVX_WIDEN_TRANS(vwmaccus_vx, opivx_overwrite_widen_check)
|
||||
|
||||
/* Vector Integer Merge and Move Instructions */
|
||||
static bool trans_vmv_v_v(DisasContext *s, arg_vmv_v_v *a)
|
||||
@@ -2340,6 +2422,17 @@ static bool opfvv_widen_check(DisasContext *s, arg_rmrr *a)
|
||||
vext_check_dss(s, a->rd, a->rs1, a->rs2, a->vm);
|
||||
}
|
||||
|
||||
static bool opfvv_overwrite_widen_check(DisasContext *s, arg_rmrr *a)
|
||||
{
|
||||
return require_rvv(s) &&
|
||||
require_rvf(s) &&
|
||||
require_scale_rvf(s) &&
|
||||
vext_check_isa_ill(s) &&
|
||||
vext_check_dss(s, a->rd, a->rs1, a->rs2, a->vm) &&
|
||||
vext_check_input_eew(s, a->rd, s->sew + 1, a->rs1, s->sew, a->vm) &&
|
||||
vext_check_input_eew(s, a->rd, s->sew + 1, a->rs2, s->sew, a->vm);
|
||||
}
|
||||
|
||||
/* OPFVV with WIDEN */
|
||||
#define GEN_OPFVV_WIDEN_TRANS(NAME, CHECK) \
|
||||
static bool trans_##NAME(DisasContext *s, arg_rmrr *a) \
|
||||
@@ -2379,11 +2472,21 @@ static bool opfvf_widen_check(DisasContext *s, arg_rmrr *a)
|
||||
vext_check_ds(s, a->rd, a->rs2, a->vm);
|
||||
}
|
||||
|
||||
static bool opfvf_overwrite_widen_check(DisasContext *s, arg_rmrr *a)
|
||||
{
|
||||
return require_rvv(s) &&
|
||||
require_rvf(s) &&
|
||||
require_scale_rvf(s) &&
|
||||
vext_check_isa_ill(s) &&
|
||||
vext_check_ds(s, a->rd, a->rs2, a->vm) &&
|
||||
vext_check_input_eew(s, a->rd, s->sew + 1, a->rs2, s->sew, a->vm);
|
||||
}
|
||||
|
||||
/* OPFVF with WIDEN */
|
||||
#define GEN_OPFVF_WIDEN_TRANS(NAME) \
|
||||
#define GEN_OPFVF_WIDEN_TRANS(NAME, CHECK) \
|
||||
static bool trans_##NAME(DisasContext *s, arg_rmrr *a) \
|
||||
{ \
|
||||
if (opfvf_widen_check(s, a)) { \
|
||||
if (CHECK(s, a)) { \
|
||||
uint32_t data = 0; \
|
||||
static gen_helper_opfvf *const fns[2] = { \
|
||||
gen_helper_##NAME##_h, gen_helper_##NAME##_w, \
|
||||
@@ -2399,8 +2502,8 @@ static bool trans_##NAME(DisasContext *s, arg_rmrr *a) \
|
||||
return false; \
|
||||
}
|
||||
|
||||
GEN_OPFVF_WIDEN_TRANS(vfwadd_vf)
|
||||
GEN_OPFVF_WIDEN_TRANS(vfwsub_vf)
|
||||
GEN_OPFVF_WIDEN_TRANS(vfwadd_vf, opfvf_widen_check)
|
||||
GEN_OPFVF_WIDEN_TRANS(vfwsub_vf, opfvf_widen_check)
|
||||
|
||||
static bool opfwv_widen_check(DisasContext *s, arg_rmrr *a)
|
||||
{
|
||||
@@ -2482,7 +2585,7 @@ GEN_OPFVF_TRANS(vfrdiv_vf, opfvf_check)
|
||||
|
||||
/* Vector Widening Floating-Point Multiply */
|
||||
GEN_OPFVV_WIDEN_TRANS(vfwmul_vv, opfvv_widen_check)
|
||||
GEN_OPFVF_WIDEN_TRANS(vfwmul_vf)
|
||||
GEN_OPFVF_WIDEN_TRANS(vfwmul_vf, opfvf_widen_check)
|
||||
|
||||
/* Vector Single-Width Floating-Point Fused Multiply-Add Instructions */
|
||||
GEN_OPFVV_TRANS(vfmacc_vv, opfvv_check)
|
||||
@@ -2503,14 +2606,14 @@ GEN_OPFVF_TRANS(vfmsub_vf, opfvf_check)
|
||||
GEN_OPFVF_TRANS(vfnmsub_vf, opfvf_check)
|
||||
|
||||
/* Vector Widening Floating-Point Fused Multiply-Add Instructions */
|
||||
GEN_OPFVV_WIDEN_TRANS(vfwmacc_vv, opfvv_widen_check)
|
||||
GEN_OPFVV_WIDEN_TRANS(vfwnmacc_vv, opfvv_widen_check)
|
||||
GEN_OPFVV_WIDEN_TRANS(vfwmsac_vv, opfvv_widen_check)
|
||||
GEN_OPFVV_WIDEN_TRANS(vfwnmsac_vv, opfvv_widen_check)
|
||||
GEN_OPFVF_WIDEN_TRANS(vfwmacc_vf)
|
||||
GEN_OPFVF_WIDEN_TRANS(vfwnmacc_vf)
|
||||
GEN_OPFVF_WIDEN_TRANS(vfwmsac_vf)
|
||||
GEN_OPFVF_WIDEN_TRANS(vfwnmsac_vf)
|
||||
GEN_OPFVV_WIDEN_TRANS(vfwmacc_vv, opfvv_overwrite_widen_check)
|
||||
GEN_OPFVV_WIDEN_TRANS(vfwnmacc_vv, opfvv_overwrite_widen_check)
|
||||
GEN_OPFVV_WIDEN_TRANS(vfwmsac_vv, opfvv_overwrite_widen_check)
|
||||
GEN_OPFVV_WIDEN_TRANS(vfwnmsac_vv, opfvv_overwrite_widen_check)
|
||||
GEN_OPFVF_WIDEN_TRANS(vfwmacc_vf, opfvf_overwrite_widen_check)
|
||||
GEN_OPFVF_WIDEN_TRANS(vfwnmacc_vf, opfvf_overwrite_widen_check)
|
||||
GEN_OPFVF_WIDEN_TRANS(vfwmsac_vf, opfvf_overwrite_widen_check)
|
||||
GEN_OPFVF_WIDEN_TRANS(vfwnmsac_vf, opfvf_overwrite_widen_check)
|
||||
|
||||
/* Vector Floating-Point Square-Root Instruction */
|
||||
|
||||
@@ -3426,6 +3529,7 @@ static bool vrgather_vv_check(DisasContext *s, arg_rmrr *a)
|
||||
{
|
||||
return require_rvv(s) &&
|
||||
vext_check_isa_ill(s) &&
|
||||
vext_check_input_eew(s, a->rs1, s->sew, a->rs2, s->sew, a->vm) &&
|
||||
require_align(a->rd, s->lmul) &&
|
||||
require_align(a->rs1, s->lmul) &&
|
||||
require_align(a->rs2, s->lmul) &&
|
||||
@@ -3438,6 +3542,7 @@ static bool vrgatherei16_vv_check(DisasContext *s, arg_rmrr *a)
|
||||
int8_t emul = MO_16 - s->sew + s->lmul;
|
||||
return require_rvv(s) &&
|
||||
vext_check_isa_ill(s) &&
|
||||
vext_check_input_eew(s, a->rs1, MO_16, a->rs2, s->sew, a->vm) &&
|
||||
(emul >= -3 && emul <= 3) &&
|
||||
require_align(a->rd, s->lmul) &&
|
||||
require_align(a->rs1, emul) &&
|
||||
@@ -3457,6 +3562,7 @@ static bool vrgather_vx_check(DisasContext *s, arg_rmrr *a)
|
||||
{
|
||||
return require_rvv(s) &&
|
||||
vext_check_isa_ill(s) &&
|
||||
vext_check_input_eew(s, -1, MO_64, a->rs2, s->sew, a->vm) &&
|
||||
require_align(a->rd, s->lmul) &&
|
||||
require_align(a->rs2, s->lmul) &&
|
||||
(a->rd != a->rs2) &&
|
||||
@@ -3600,7 +3706,9 @@ static bool int_ext_check(DisasContext *s, arg_rmr *a, uint8_t div)
|
||||
require_align(a->rd, s->lmul) &&
|
||||
require_align(a->rs2, s->lmul - div) &&
|
||||
require_vm(a->vm, a->rd) &&
|
||||
require_noover(a->rd, s->lmul, a->rs2, s->lmul - div);
|
||||
require_noover(a->rd, s->lmul, a->rs2, s->lmul - div) &&
|
||||
vext_check_input_eew(s, -1, 0, a->rs2, s->sew, a->vm);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
+206
-123
@@ -58,33 +58,17 @@ void riscv_kvm_aplic_request(void *opaque, int irq, int level)
|
||||
|
||||
static bool cap_has_mp_state;
|
||||
|
||||
static uint64_t kvm_riscv_reg_id_ulong(CPURISCVState *env, uint64_t type,
|
||||
uint64_t idx)
|
||||
{
|
||||
uint64_t id = KVM_REG_RISCV | type | idx;
|
||||
#define KVM_RISCV_REG_ID_U32(type, idx) (KVM_REG_RISCV | KVM_REG_SIZE_U32 | \
|
||||
type | idx)
|
||||
|
||||
switch (riscv_cpu_mxl(env)) {
|
||||
case MXL_RV32:
|
||||
id |= KVM_REG_SIZE_U32;
|
||||
break;
|
||||
case MXL_RV64:
|
||||
id |= KVM_REG_SIZE_U64;
|
||||
break;
|
||||
default:
|
||||
g_assert_not_reached();
|
||||
}
|
||||
return id;
|
||||
}
|
||||
#define KVM_RISCV_REG_ID_U64(type, idx) (KVM_REG_RISCV | KVM_REG_SIZE_U64 | \
|
||||
type | idx)
|
||||
|
||||
static uint64_t kvm_riscv_reg_id_u32(uint64_t type, uint64_t idx)
|
||||
{
|
||||
return KVM_REG_RISCV | KVM_REG_SIZE_U32 | type | idx;
|
||||
}
|
||||
|
||||
static uint64_t kvm_riscv_reg_id_u64(uint64_t type, uint64_t idx)
|
||||
{
|
||||
return KVM_REG_RISCV | KVM_REG_SIZE_U64 | type | idx;
|
||||
}
|
||||
#if defined(TARGET_RISCV64)
|
||||
#define KVM_RISCV_REG_ID_ULONG(type, idx) KVM_RISCV_REG_ID_U64(type, idx)
|
||||
#else
|
||||
#define KVM_RISCV_REG_ID_ULONG(type, idx) KVM_RISCV_REG_ID_U32(type, idx)
|
||||
#endif
|
||||
|
||||
static uint64_t kvm_encode_reg_size_id(uint64_t id, size_t size_b)
|
||||
{
|
||||
@@ -107,45 +91,29 @@ static uint64_t kvm_riscv_vector_reg_id(RISCVCPU *cpu,
|
||||
return kvm_encode_reg_size_id(id, size_b);
|
||||
}
|
||||
|
||||
#define RISCV_CORE_REG(env, name) \
|
||||
kvm_riscv_reg_id_ulong(env, KVM_REG_RISCV_CORE, \
|
||||
#define RISCV_CORE_REG(name) \
|
||||
KVM_RISCV_REG_ID_ULONG(KVM_REG_RISCV_CORE, \
|
||||
KVM_REG_RISCV_CORE_REG(name))
|
||||
|
||||
#define RISCV_CSR_REG(env, name) \
|
||||
kvm_riscv_reg_id_ulong(env, KVM_REG_RISCV_CSR, \
|
||||
#define RISCV_CSR_REG(name) \
|
||||
KVM_RISCV_REG_ID_ULONG(KVM_REG_RISCV_CSR, \
|
||||
KVM_REG_RISCV_CSR_REG(name))
|
||||
|
||||
#define RISCV_CONFIG_REG(env, name) \
|
||||
kvm_riscv_reg_id_ulong(env, KVM_REG_RISCV_CONFIG, \
|
||||
#define RISCV_CONFIG_REG(name) \
|
||||
KVM_RISCV_REG_ID_ULONG(KVM_REG_RISCV_CONFIG, \
|
||||
KVM_REG_RISCV_CONFIG_REG(name))
|
||||
|
||||
#define RISCV_TIMER_REG(name) kvm_riscv_reg_id_u64(KVM_REG_RISCV_TIMER, \
|
||||
#define RISCV_TIMER_REG(name) KVM_RISCV_REG_ID_U64(KVM_REG_RISCV_TIMER, \
|
||||
KVM_REG_RISCV_TIMER_REG(name))
|
||||
|
||||
#define RISCV_FP_F_REG(idx) kvm_riscv_reg_id_u32(KVM_REG_RISCV_FP_F, idx)
|
||||
#define RISCV_FP_F_REG(idx) KVM_RISCV_REG_ID_U32(KVM_REG_RISCV_FP_F, idx)
|
||||
|
||||
#define RISCV_FP_D_REG(idx) kvm_riscv_reg_id_u64(KVM_REG_RISCV_FP_D, idx)
|
||||
#define RISCV_FP_D_REG(idx) KVM_RISCV_REG_ID_U64(KVM_REG_RISCV_FP_D, idx)
|
||||
|
||||
#define RISCV_VECTOR_CSR_REG(env, name) \
|
||||
kvm_riscv_reg_id_ulong(env, KVM_REG_RISCV_VECTOR, \
|
||||
#define RISCV_VECTOR_CSR_REG(name) \
|
||||
KVM_RISCV_REG_ID_ULONG(KVM_REG_RISCV_VECTOR, \
|
||||
KVM_REG_RISCV_VECTOR_CSR_REG(name))
|
||||
|
||||
#define KVM_RISCV_GET_CSR(cs, env, csr, reg) \
|
||||
do { \
|
||||
int _ret = kvm_get_one_reg(cs, RISCV_CSR_REG(env, csr), ®); \
|
||||
if (_ret) { \
|
||||
return _ret; \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define KVM_RISCV_SET_CSR(cs, env, csr, reg) \
|
||||
do { \
|
||||
int _ret = kvm_set_one_reg(cs, RISCV_CSR_REG(env, csr), ®); \
|
||||
if (_ret) { \
|
||||
return _ret; \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define KVM_RISCV_GET_TIMER(cs, name, reg) \
|
||||
do { \
|
||||
int ret = kvm_get_one_reg(cs, RISCV_TIMER_REG(name), ®); \
|
||||
@@ -248,7 +216,7 @@ static void kvm_riscv_update_cpu_misa_ext(RISCVCPU *cpu, CPUState *cs)
|
||||
|
||||
/* If we're here we're going to disable the MISA bit */
|
||||
reg = 0;
|
||||
id = kvm_riscv_reg_id_ulong(env, KVM_REG_RISCV_ISA_EXT,
|
||||
id = KVM_RISCV_REG_ID_ULONG(KVM_REG_RISCV_ISA_EXT,
|
||||
misa_cfg->kvm_reg_id);
|
||||
ret = kvm_set_one_reg(cs, id, ®);
|
||||
if (ret != 0) {
|
||||
@@ -267,6 +235,53 @@ static void kvm_riscv_update_cpu_misa_ext(RISCVCPU *cpu, CPUState *cs)
|
||||
}
|
||||
}
|
||||
|
||||
#define KVM_CSR_CFG(_name, _env_prop, reg_id) \
|
||||
{.name = _name, .offset = ENV_CSR_OFFSET(_env_prop), \
|
||||
.kvm_reg_id = reg_id}
|
||||
|
||||
static KVMCPUConfig kvm_csr_cfgs[] = {
|
||||
KVM_CSR_CFG("sstatus", mstatus, RISCV_CSR_REG(sstatus)),
|
||||
KVM_CSR_CFG("sie", mie, RISCV_CSR_REG(sie)),
|
||||
KVM_CSR_CFG("stvec", stvec, RISCV_CSR_REG(stvec)),
|
||||
KVM_CSR_CFG("sscratch", sscratch, RISCV_CSR_REG(sscratch)),
|
||||
KVM_CSR_CFG("sepc", sepc, RISCV_CSR_REG(sepc)),
|
||||
KVM_CSR_CFG("scause", scause, RISCV_CSR_REG(scause)),
|
||||
KVM_CSR_CFG("stval", stval, RISCV_CSR_REG(stval)),
|
||||
KVM_CSR_CFG("sip", mip, RISCV_CSR_REG(sip)),
|
||||
KVM_CSR_CFG("satp", satp, RISCV_CSR_REG(satp)),
|
||||
};
|
||||
|
||||
static void *kvmconfig_get_env_addr(RISCVCPU *cpu, KVMCPUConfig *csr_cfg)
|
||||
{
|
||||
return (void *)&cpu->env + csr_cfg->offset;
|
||||
}
|
||||
|
||||
static uint32_t kvm_cpu_csr_get_u32(RISCVCPU *cpu, KVMCPUConfig *csr_cfg)
|
||||
{
|
||||
uint32_t *val32 = kvmconfig_get_env_addr(cpu, csr_cfg);
|
||||
return *val32;
|
||||
}
|
||||
|
||||
static uint64_t kvm_cpu_csr_get_u64(RISCVCPU *cpu, KVMCPUConfig *csr_cfg)
|
||||
{
|
||||
uint64_t *val64 = kvmconfig_get_env_addr(cpu, csr_cfg);
|
||||
return *val64;
|
||||
}
|
||||
|
||||
static void kvm_cpu_csr_set_u32(RISCVCPU *cpu, KVMCPUConfig *csr_cfg,
|
||||
uint32_t val)
|
||||
{
|
||||
uint32_t *val32 = kvmconfig_get_env_addr(cpu, csr_cfg);
|
||||
*val32 = val;
|
||||
}
|
||||
|
||||
static void kvm_cpu_csr_set_u64(RISCVCPU *cpu, KVMCPUConfig *csr_cfg,
|
||||
uint64_t val)
|
||||
{
|
||||
uint64_t *val64 = kvmconfig_get_env_addr(cpu, csr_cfg);
|
||||
*val64 = val;
|
||||
}
|
||||
|
||||
#define KVM_EXT_CFG(_name, _prop, _reg_id) \
|
||||
{.name = _name, .offset = CPU_CFG_OFFSET(_prop), \
|
||||
.kvm_reg_id = _reg_id}
|
||||
@@ -434,7 +449,6 @@ static KVMCPUConfig kvm_sbi_dbcn = {
|
||||
|
||||
static void kvm_riscv_update_cpu_cfg_isa_ext(RISCVCPU *cpu, CPUState *cs)
|
||||
{
|
||||
CPURISCVState *env = &cpu->env;
|
||||
uint64_t id, reg;
|
||||
int i, ret;
|
||||
|
||||
@@ -445,7 +459,7 @@ static void kvm_riscv_update_cpu_cfg_isa_ext(RISCVCPU *cpu, CPUState *cs)
|
||||
continue;
|
||||
}
|
||||
|
||||
id = kvm_riscv_reg_id_ulong(env, KVM_REG_RISCV_ISA_EXT,
|
||||
id = KVM_RISCV_REG_ID_ULONG(KVM_REG_RISCV_ISA_EXT,
|
||||
multi_ext_cfg->kvm_reg_id);
|
||||
reg = kvm_cpu_cfg_get(cpu, multi_ext_cfg);
|
||||
ret = kvm_set_one_reg(cs, id, ®);
|
||||
@@ -570,14 +584,14 @@ static int kvm_riscv_get_regs_core(CPUState *cs)
|
||||
target_ulong reg;
|
||||
CPURISCVState *env = &RISCV_CPU(cs)->env;
|
||||
|
||||
ret = kvm_get_one_reg(cs, RISCV_CORE_REG(env, regs.pc), ®);
|
||||
ret = kvm_get_one_reg(cs, RISCV_CORE_REG(regs.pc), ®);
|
||||
if (ret) {
|
||||
return ret;
|
||||
}
|
||||
env->pc = reg;
|
||||
|
||||
for (i = 1; i < 32; i++) {
|
||||
uint64_t id = kvm_riscv_reg_id_ulong(env, KVM_REG_RISCV_CORE, i);
|
||||
uint64_t id = KVM_RISCV_REG_ID_ULONG(KVM_REG_RISCV_CORE, i);
|
||||
ret = kvm_get_one_reg(cs, id, ®);
|
||||
if (ret) {
|
||||
return ret;
|
||||
@@ -596,13 +610,13 @@ static int kvm_riscv_put_regs_core(CPUState *cs)
|
||||
CPURISCVState *env = &RISCV_CPU(cs)->env;
|
||||
|
||||
reg = env->pc;
|
||||
ret = kvm_set_one_reg(cs, RISCV_CORE_REG(env, regs.pc), ®);
|
||||
ret = kvm_set_one_reg(cs, RISCV_CORE_REG(regs.pc), ®);
|
||||
if (ret) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
for (i = 1; i < 32; i++) {
|
||||
uint64_t id = kvm_riscv_reg_id_ulong(env, KVM_REG_RISCV_CORE, i);
|
||||
uint64_t id = KVM_RISCV_REG_ID_ULONG(KVM_REG_RISCV_CORE, i);
|
||||
reg = env->gpr[i];
|
||||
ret = kvm_set_one_reg(cs, id, ®);
|
||||
if (ret) {
|
||||
@@ -613,6 +627,66 @@ static int kvm_riscv_put_regs_core(CPUState *cs)
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int kvm_riscv_get_regs_csr(CPUState *cs)
|
||||
{
|
||||
RISCVCPU *cpu = RISCV_CPU(cs);
|
||||
uint64_t reg;
|
||||
int i, ret;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(kvm_csr_cfgs); i++) {
|
||||
KVMCPUConfig *csr_cfg = &kvm_csr_cfgs[i];
|
||||
|
||||
if (!csr_cfg->supported) {
|
||||
continue;
|
||||
}
|
||||
|
||||
ret = kvm_get_one_reg(cs, csr_cfg->kvm_reg_id, ®);
|
||||
if (ret) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (KVM_REG_SIZE(csr_cfg->kvm_reg_id) == sizeof(uint32_t)) {
|
||||
kvm_cpu_csr_set_u32(cpu, csr_cfg, reg);
|
||||
} else if (KVM_REG_SIZE(csr_cfg->kvm_reg_id) == sizeof(uint64_t)) {
|
||||
kvm_cpu_csr_set_u64(cpu, csr_cfg, reg);
|
||||
} else {
|
||||
g_assert_not_reached();
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int kvm_riscv_put_regs_csr(CPUState *cs)
|
||||
{
|
||||
RISCVCPU *cpu = RISCV_CPU(cs);
|
||||
uint64_t reg;
|
||||
int i, ret;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(kvm_csr_cfgs); i++) {
|
||||
KVMCPUConfig *csr_cfg = &kvm_csr_cfgs[i];
|
||||
|
||||
if (!csr_cfg->supported) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (KVM_REG_SIZE(csr_cfg->kvm_reg_id) == sizeof(uint32_t)) {
|
||||
reg = kvm_cpu_csr_get_u32(cpu, csr_cfg);
|
||||
} else if (KVM_REG_SIZE(csr_cfg->kvm_reg_id) == sizeof(uint64_t)) {
|
||||
reg = kvm_cpu_csr_get_u64(cpu, csr_cfg);
|
||||
} else {
|
||||
g_assert_not_reached();
|
||||
}
|
||||
|
||||
ret = kvm_set_one_reg(cs, csr_cfg->kvm_reg_id, ®);
|
||||
if (ret) {
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void kvm_riscv_reset_regs_csr(CPURISCVState *env)
|
||||
{
|
||||
env->mstatus = 0;
|
||||
@@ -626,40 +700,6 @@ static void kvm_riscv_reset_regs_csr(CPURISCVState *env)
|
||||
env->satp = 0;
|
||||
}
|
||||
|
||||
static int kvm_riscv_get_regs_csr(CPUState *cs)
|
||||
{
|
||||
CPURISCVState *env = &RISCV_CPU(cs)->env;
|
||||
|
||||
KVM_RISCV_GET_CSR(cs, env, sstatus, env->mstatus);
|
||||
KVM_RISCV_GET_CSR(cs, env, sie, env->mie);
|
||||
KVM_RISCV_GET_CSR(cs, env, stvec, env->stvec);
|
||||
KVM_RISCV_GET_CSR(cs, env, sscratch, env->sscratch);
|
||||
KVM_RISCV_GET_CSR(cs, env, sepc, env->sepc);
|
||||
KVM_RISCV_GET_CSR(cs, env, scause, env->scause);
|
||||
KVM_RISCV_GET_CSR(cs, env, stval, env->stval);
|
||||
KVM_RISCV_GET_CSR(cs, env, sip, env->mip);
|
||||
KVM_RISCV_GET_CSR(cs, env, satp, env->satp);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int kvm_riscv_put_regs_csr(CPUState *cs)
|
||||
{
|
||||
CPURISCVState *env = &RISCV_CPU(cs)->env;
|
||||
|
||||
KVM_RISCV_SET_CSR(cs, env, sstatus, env->mstatus);
|
||||
KVM_RISCV_SET_CSR(cs, env, sie, env->mie);
|
||||
KVM_RISCV_SET_CSR(cs, env, stvec, env->stvec);
|
||||
KVM_RISCV_SET_CSR(cs, env, sscratch, env->sscratch);
|
||||
KVM_RISCV_SET_CSR(cs, env, sepc, env->sepc);
|
||||
KVM_RISCV_SET_CSR(cs, env, scause, env->scause);
|
||||
KVM_RISCV_SET_CSR(cs, env, stval, env->stval);
|
||||
KVM_RISCV_SET_CSR(cs, env, sip, env->mip);
|
||||
KVM_RISCV_SET_CSR(cs, env, satp, env->satp);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int kvm_riscv_get_regs_fp(CPUState *cs)
|
||||
{
|
||||
int ret = 0;
|
||||
@@ -800,26 +840,26 @@ static int kvm_riscv_get_regs_vector(CPUState *cs)
|
||||
return 0;
|
||||
}
|
||||
|
||||
ret = kvm_get_one_reg(cs, RISCV_VECTOR_CSR_REG(env, vstart), ®);
|
||||
ret = kvm_get_one_reg(cs, RISCV_VECTOR_CSR_REG(vstart), ®);
|
||||
if (ret) {
|
||||
return ret;
|
||||
}
|
||||
env->vstart = reg;
|
||||
|
||||
ret = kvm_get_one_reg(cs, RISCV_VECTOR_CSR_REG(env, vl), ®);
|
||||
ret = kvm_get_one_reg(cs, RISCV_VECTOR_CSR_REG(vl), ®);
|
||||
if (ret) {
|
||||
return ret;
|
||||
}
|
||||
env->vl = reg;
|
||||
|
||||
ret = kvm_get_one_reg(cs, RISCV_VECTOR_CSR_REG(env, vtype), ®);
|
||||
ret = kvm_get_one_reg(cs, RISCV_VECTOR_CSR_REG(vtype), ®);
|
||||
if (ret) {
|
||||
return ret;
|
||||
}
|
||||
env->vtype = reg;
|
||||
|
||||
if (kvm_v_vlenb.supported) {
|
||||
ret = kvm_get_one_reg(cs, RISCV_VECTOR_CSR_REG(env, vlenb), ®);
|
||||
ret = kvm_get_one_reg(cs, RISCV_VECTOR_CSR_REG(vlenb), ®);
|
||||
if (ret) {
|
||||
return ret;
|
||||
}
|
||||
@@ -857,26 +897,26 @@ static int kvm_riscv_put_regs_vector(CPUState *cs)
|
||||
}
|
||||
|
||||
reg = env->vstart;
|
||||
ret = kvm_set_one_reg(cs, RISCV_VECTOR_CSR_REG(env, vstart), ®);
|
||||
ret = kvm_set_one_reg(cs, RISCV_VECTOR_CSR_REG(vstart), ®);
|
||||
if (ret) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
reg = env->vl;
|
||||
ret = kvm_set_one_reg(cs, RISCV_VECTOR_CSR_REG(env, vl), ®);
|
||||
ret = kvm_set_one_reg(cs, RISCV_VECTOR_CSR_REG(vl), ®);
|
||||
if (ret) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
reg = env->vtype;
|
||||
ret = kvm_set_one_reg(cs, RISCV_VECTOR_CSR_REG(env, vtype), ®);
|
||||
ret = kvm_set_one_reg(cs, RISCV_VECTOR_CSR_REG(vtype), ®);
|
||||
if (ret) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (kvm_v_vlenb.supported) {
|
||||
reg = cpu->cfg.vlenb;
|
||||
ret = kvm_set_one_reg(cs, RISCV_VECTOR_CSR_REG(env, vlenb), ®);
|
||||
ret = kvm_set_one_reg(cs, RISCV_VECTOR_CSR_REG(vlenb), ®);
|
||||
|
||||
for (int i = 0; i < 32; i++) {
|
||||
/*
|
||||
@@ -955,25 +995,24 @@ static void kvm_riscv_destroy_scratch_vcpu(KVMScratchCPU *scratch)
|
||||
|
||||
static void kvm_riscv_init_machine_ids(RISCVCPU *cpu, KVMScratchCPU *kvmcpu)
|
||||
{
|
||||
CPURISCVState *env = &cpu->env;
|
||||
struct kvm_one_reg reg;
|
||||
int ret;
|
||||
|
||||
reg.id = RISCV_CONFIG_REG(env, mvendorid);
|
||||
reg.id = RISCV_CONFIG_REG(mvendorid);
|
||||
reg.addr = (uint64_t)&cpu->cfg.mvendorid;
|
||||
ret = ioctl(kvmcpu->cpufd, KVM_GET_ONE_REG, ®);
|
||||
if (ret != 0) {
|
||||
error_report("Unable to retrieve mvendorid from host, error %d", ret);
|
||||
}
|
||||
|
||||
reg.id = RISCV_CONFIG_REG(env, marchid);
|
||||
reg.id = RISCV_CONFIG_REG(marchid);
|
||||
reg.addr = (uint64_t)&cpu->cfg.marchid;
|
||||
ret = ioctl(kvmcpu->cpufd, KVM_GET_ONE_REG, ®);
|
||||
if (ret != 0) {
|
||||
error_report("Unable to retrieve marchid from host, error %d", ret);
|
||||
}
|
||||
|
||||
reg.id = RISCV_CONFIG_REG(env, mimpid);
|
||||
reg.id = RISCV_CONFIG_REG(mimpid);
|
||||
reg.addr = (uint64_t)&cpu->cfg.mimpid;
|
||||
ret = ioctl(kvmcpu->cpufd, KVM_GET_ONE_REG, ®);
|
||||
if (ret != 0) {
|
||||
@@ -988,7 +1027,7 @@ static void kvm_riscv_init_misa_ext_mask(RISCVCPU *cpu,
|
||||
struct kvm_one_reg reg;
|
||||
int ret;
|
||||
|
||||
reg.id = RISCV_CONFIG_REG(env, isa);
|
||||
reg.id = RISCV_CONFIG_REG(isa);
|
||||
reg.addr = (uint64_t)&env->misa_ext_mask;
|
||||
ret = ioctl(kvmcpu->cpufd, KVM_GET_ONE_REG, ®);
|
||||
|
||||
@@ -1005,11 +1044,10 @@ static void kvm_riscv_init_misa_ext_mask(RISCVCPU *cpu,
|
||||
static void kvm_riscv_read_cbomz_blksize(RISCVCPU *cpu, KVMScratchCPU *kvmcpu,
|
||||
KVMCPUConfig *cbomz_cfg)
|
||||
{
|
||||
CPURISCVState *env = &cpu->env;
|
||||
struct kvm_one_reg reg;
|
||||
int ret;
|
||||
|
||||
reg.id = kvm_riscv_reg_id_ulong(env, KVM_REG_RISCV_CONFIG,
|
||||
reg.id = KVM_RISCV_REG_ID_ULONG(KVM_REG_RISCV_CONFIG,
|
||||
cbomz_cfg->kvm_reg_id);
|
||||
reg.addr = (uint64_t)kvmconfig_get_cfg_addr(cpu, cbomz_cfg);
|
||||
ret = ioctl(kvmcpu->cpufd, KVM_GET_ONE_REG, ®);
|
||||
@@ -1023,7 +1061,6 @@ static void kvm_riscv_read_cbomz_blksize(RISCVCPU *cpu, KVMScratchCPU *kvmcpu,
|
||||
static void kvm_riscv_read_multiext_legacy(RISCVCPU *cpu,
|
||||
KVMScratchCPU *kvmcpu)
|
||||
{
|
||||
CPURISCVState *env = &cpu->env;
|
||||
uint64_t val;
|
||||
int i, ret;
|
||||
|
||||
@@ -1031,7 +1068,7 @@ static void kvm_riscv_read_multiext_legacy(RISCVCPU *cpu,
|
||||
KVMCPUConfig *multi_ext_cfg = &kvm_multi_ext_cfgs[i];
|
||||
struct kvm_one_reg reg;
|
||||
|
||||
reg.id = kvm_riscv_reg_id_ulong(env, KVM_REG_RISCV_ISA_EXT,
|
||||
reg.id = KVM_RISCV_REG_ID_ULONG(KVM_REG_RISCV_ISA_EXT,
|
||||
multi_ext_cfg->kvm_reg_id);
|
||||
reg.addr = (uint64_t)&val;
|
||||
ret = ioctl(kvmcpu->cpufd, KVM_GET_ONE_REG, ®);
|
||||
@@ -1061,6 +1098,32 @@ static void kvm_riscv_read_multiext_legacy(RISCVCPU *cpu,
|
||||
}
|
||||
}
|
||||
|
||||
static void kvm_riscv_read_csr_cfg_legacy(KVMScratchCPU *kvmcpu)
|
||||
{
|
||||
uint64_t val;
|
||||
int i, ret;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(kvm_csr_cfgs); i++) {
|
||||
KVMCPUConfig *csr_cfg = &kvm_csr_cfgs[i];
|
||||
struct kvm_one_reg reg;
|
||||
|
||||
reg.id = csr_cfg->kvm_reg_id;
|
||||
reg.addr = (uint64_t)&val;
|
||||
ret = ioctl(kvmcpu->cpufd, KVM_GET_ONE_REG, ®);
|
||||
if (ret != 0) {
|
||||
if (errno == EINVAL) {
|
||||
csr_cfg->supported = false;
|
||||
} else {
|
||||
error_report("Unable to read KVM CSR %s: %s",
|
||||
csr_cfg->name, strerror(errno));
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
} else {
|
||||
csr_cfg->supported = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static int uint64_cmp(const void *a, const void *b)
|
||||
{
|
||||
uint64_t val1 = *(const uint64_t *)a;
|
||||
@@ -1078,7 +1141,6 @@ static int uint64_cmp(const void *a, const void *b)
|
||||
}
|
||||
|
||||
static void kvm_riscv_check_sbi_dbcn_support(RISCVCPU *cpu,
|
||||
KVMScratchCPU *kvmcpu,
|
||||
struct kvm_reg_list *reglist)
|
||||
{
|
||||
struct kvm_reg_list *reg_search;
|
||||
@@ -1118,12 +1180,31 @@ static void kvm_riscv_read_vlenb(RISCVCPU *cpu, KVMScratchCPU *kvmcpu,
|
||||
}
|
||||
}
|
||||
|
||||
static void kvm_riscv_init_multiext_cfg(RISCVCPU *cpu, KVMScratchCPU *kvmcpu)
|
||||
static void kvm_riscv_read_csr_cfg(struct kvm_reg_list *reglist)
|
||||
{
|
||||
struct kvm_reg_list *reg_search;
|
||||
uint64_t reg_id;
|
||||
|
||||
for (int i = 0; i < ARRAY_SIZE(kvm_csr_cfgs); i++) {
|
||||
KVMCPUConfig *csr_cfg = &kvm_csr_cfgs[i];
|
||||
|
||||
reg_id = csr_cfg->kvm_reg_id;
|
||||
reg_search = bsearch(®_id, reglist->reg, reglist->n,
|
||||
sizeof(uint64_t), uint64_cmp);
|
||||
if (!reg_search) {
|
||||
continue;
|
||||
}
|
||||
|
||||
csr_cfg->supported = true;
|
||||
}
|
||||
}
|
||||
|
||||
static void kvm_riscv_init_cfg(RISCVCPU *cpu, KVMScratchCPU *kvmcpu)
|
||||
{
|
||||
g_autofree struct kvm_reg_list *reglist = NULL;
|
||||
KVMCPUConfig *multi_ext_cfg;
|
||||
struct kvm_one_reg reg;
|
||||
struct kvm_reg_list rl_struct;
|
||||
struct kvm_reg_list *reglist;
|
||||
uint64_t val, reg_id, *reg_search;
|
||||
int i, ret;
|
||||
|
||||
@@ -1135,7 +1216,9 @@ static void kvm_riscv_init_multiext_cfg(RISCVCPU *cpu, KVMScratchCPU *kvmcpu)
|
||||
* (EINVAL). Use read_legacy() in this case.
|
||||
*/
|
||||
if (errno == EINVAL) {
|
||||
return kvm_riscv_read_multiext_legacy(cpu, kvmcpu);
|
||||
kvm_riscv_read_multiext_legacy(cpu, kvmcpu);
|
||||
kvm_riscv_read_csr_cfg_legacy(kvmcpu);
|
||||
return;
|
||||
} else if (errno != E2BIG) {
|
||||
/*
|
||||
* E2BIG is an expected error message for the API since we
|
||||
@@ -1164,7 +1247,7 @@ static void kvm_riscv_init_multiext_cfg(RISCVCPU *cpu, KVMScratchCPU *kvmcpu)
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(kvm_multi_ext_cfgs); i++) {
|
||||
multi_ext_cfg = &kvm_multi_ext_cfgs[i];
|
||||
reg_id = kvm_riscv_reg_id_ulong(&cpu->env, KVM_REG_RISCV_ISA_EXT,
|
||||
reg_id = KVM_RISCV_REG_ID_ULONG(KVM_REG_RISCV_ISA_EXT,
|
||||
multi_ext_cfg->kvm_reg_id);
|
||||
reg_search = bsearch(®_id, reglist->reg, reglist->n,
|
||||
sizeof(uint64_t), uint64_cmp);
|
||||
@@ -1197,7 +1280,8 @@ static void kvm_riscv_init_multiext_cfg(RISCVCPU *cpu, KVMScratchCPU *kvmcpu)
|
||||
kvm_riscv_read_vlenb(cpu, kvmcpu, reglist);
|
||||
}
|
||||
|
||||
kvm_riscv_check_sbi_dbcn_support(cpu, kvmcpu, reglist);
|
||||
kvm_riscv_check_sbi_dbcn_support(cpu, reglist);
|
||||
kvm_riscv_read_csr_cfg(reglist);
|
||||
}
|
||||
|
||||
static void riscv_init_kvm_registers(Object *cpu_obj)
|
||||
@@ -1211,7 +1295,7 @@ static void riscv_init_kvm_registers(Object *cpu_obj)
|
||||
|
||||
kvm_riscv_init_machine_ids(cpu, &kvmcpu);
|
||||
kvm_riscv_init_misa_ext_mask(cpu, &kvmcpu);
|
||||
kvm_riscv_init_multiext_cfg(cpu, &kvmcpu);
|
||||
kvm_riscv_init_cfg(cpu, &kvmcpu);
|
||||
|
||||
kvm_riscv_destroy_scratch_vcpu(&kvmcpu);
|
||||
}
|
||||
@@ -1343,12 +1427,11 @@ void kvm_arch_init_irq_routing(KVMState *s)
|
||||
|
||||
static int kvm_vcpu_set_machine_ids(RISCVCPU *cpu, CPUState *cs)
|
||||
{
|
||||
CPURISCVState *env = &cpu->env;
|
||||
target_ulong reg;
|
||||
uint64_t id;
|
||||
int ret;
|
||||
|
||||
id = RISCV_CONFIG_REG(env, mvendorid);
|
||||
id = RISCV_CONFIG_REG(mvendorid);
|
||||
/*
|
||||
* cfg.mvendorid is an uint32 but a target_ulong will
|
||||
* be written. Assign it to a target_ulong var to avoid
|
||||
@@ -1360,13 +1443,13 @@ static int kvm_vcpu_set_machine_ids(RISCVCPU *cpu, CPUState *cs)
|
||||
return ret;
|
||||
}
|
||||
|
||||
id = RISCV_CONFIG_REG(env, marchid);
|
||||
id = RISCV_CONFIG_REG(marchid);
|
||||
ret = kvm_set_one_reg(cs, id, &cpu->cfg.marchid);
|
||||
if (ret != 0) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
id = RISCV_CONFIG_REG(env, mimpid);
|
||||
id = RISCV_CONFIG_REG(mimpid);
|
||||
ret = kvm_set_one_reg(cs, id, &cpu->cfg.mimpid);
|
||||
|
||||
return ret;
|
||||
@@ -1916,7 +1999,7 @@ void riscv_kvm_cpu_finalize_features(RISCVCPU *cpu, Error **errp)
|
||||
if (cpu->cfg.ext_zicbom &&
|
||||
riscv_cpu_option_set(kvm_cbom_blocksize.name)) {
|
||||
|
||||
reg.id = kvm_riscv_reg_id_ulong(env, KVM_REG_RISCV_CONFIG,
|
||||
reg.id = KVM_RISCV_REG_ID_ULONG(KVM_REG_RISCV_CONFIG,
|
||||
kvm_cbom_blocksize.kvm_reg_id);
|
||||
reg.addr = (uint64_t)&val;
|
||||
ret = ioctl(kvmcpu.cpufd, KVM_GET_ONE_REG, ®);
|
||||
@@ -1935,7 +2018,7 @@ void riscv_kvm_cpu_finalize_features(RISCVCPU *cpu, Error **errp)
|
||||
if (cpu->cfg.ext_zicboz &&
|
||||
riscv_cpu_option_set(kvm_cboz_blocksize.name)) {
|
||||
|
||||
reg.id = kvm_riscv_reg_id_ulong(env, KVM_REG_RISCV_CONFIG,
|
||||
reg.id = KVM_RISCV_REG_ID_ULONG(KVM_REG_RISCV_CONFIG,
|
||||
kvm_cboz_blocksize.kvm_reg_id);
|
||||
reg.addr = (uint64_t)&val;
|
||||
ret = ioctl(kvmcpu.cpufd, KVM_GET_ONE_REG, ®);
|
||||
|
||||
+69
-57
@@ -31,6 +31,15 @@ static bool pmp_write_cfg(CPURISCVState *env, uint32_t addr_index,
|
||||
uint8_t val);
|
||||
static uint8_t pmp_read_cfg(CPURISCVState *env, uint32_t addr_index);
|
||||
|
||||
/*
|
||||
* Convert the PMP permissions to match the truth table in the Smepmp spec.
|
||||
*/
|
||||
static inline uint8_t pmp_get_smepmp_operation(uint8_t cfg)
|
||||
{
|
||||
return ((cfg & PMP_LOCK) >> 4) | ((cfg & PMP_READ) << 2) |
|
||||
(cfg & PMP_WRITE) | ((cfg & PMP_EXEC) >> 2);
|
||||
}
|
||||
|
||||
/*
|
||||
* Accessor method to extract address matching type 'a field' from cfg reg
|
||||
*/
|
||||
@@ -45,11 +54,6 @@ static inline uint8_t pmp_get_a_field(uint8_t cfg)
|
||||
*/
|
||||
static inline int pmp_is_locked(CPURISCVState *env, uint32_t pmp_index)
|
||||
{
|
||||
/* mseccfg.RLB is set */
|
||||
if (MSECCFG_RLB_ISSET(env)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (env->pmp_state.pmp[pmp_index].cfg_reg & PMP_LOCK) {
|
||||
return 1;
|
||||
}
|
||||
@@ -62,6 +66,53 @@ static inline int pmp_is_locked(CPURISCVState *env, uint32_t pmp_index)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Check whether a PMP is locked for writing or not.
|
||||
* (i.e. has LOCK flag and mseccfg.RLB is unset)
|
||||
*/
|
||||
static int pmp_is_readonly(CPURISCVState *env, uint32_t pmp_index)
|
||||
{
|
||||
return pmp_is_locked(env, pmp_index) && !MSECCFG_RLB_ISSET(env);
|
||||
}
|
||||
|
||||
/*
|
||||
* Check whether `val` is an invalid Smepmp config value
|
||||
*/
|
||||
static int pmp_is_invalid_smepmp_cfg(CPURISCVState *env, uint8_t val)
|
||||
{
|
||||
/* No check if mseccfg.MML is not set or if mseccfg.RLB is set */
|
||||
if (!MSECCFG_MML_ISSET(env) || MSECCFG_RLB_ISSET(env)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Adding a rule with executable privileges that either is M-mode-only
|
||||
* or a locked Shared-Region is not possible
|
||||
*/
|
||||
switch (pmp_get_smepmp_operation(val)) {
|
||||
case 0:
|
||||
case 1:
|
||||
case 2:
|
||||
case 3:
|
||||
case 4:
|
||||
case 5:
|
||||
case 6:
|
||||
case 7:
|
||||
case 8:
|
||||
case 12:
|
||||
case 14:
|
||||
case 15:
|
||||
return 0;
|
||||
case 9:
|
||||
case 10:
|
||||
case 11:
|
||||
case 13:
|
||||
return 1;
|
||||
default:
|
||||
g_assert_not_reached();
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Count the number of active rules.
|
||||
*/
|
||||
@@ -90,45 +141,13 @@ static inline uint8_t pmp_read_cfg(CPURISCVState *env, uint32_t pmp_index)
|
||||
static bool pmp_write_cfg(CPURISCVState *env, uint32_t pmp_index, uint8_t val)
|
||||
{
|
||||
if (pmp_index < MAX_RISCV_PMPS) {
|
||||
bool locked = true;
|
||||
|
||||
if (riscv_cpu_cfg(env)->ext_smepmp) {
|
||||
/* mseccfg.RLB is set */
|
||||
if (MSECCFG_RLB_ISSET(env)) {
|
||||
locked = false;
|
||||
}
|
||||
|
||||
/* mseccfg.MML is not set */
|
||||
if (!MSECCFG_MML_ISSET(env) && !pmp_is_locked(env, pmp_index)) {
|
||||
locked = false;
|
||||
}
|
||||
|
||||
/* mseccfg.MML is set */
|
||||
if (MSECCFG_MML_ISSET(env)) {
|
||||
/* not adding execute bit */
|
||||
if ((val & PMP_LOCK) != 0 && (val & PMP_EXEC) != PMP_EXEC) {
|
||||
locked = false;
|
||||
}
|
||||
/* shared region and not adding X bit */
|
||||
if ((val & PMP_LOCK) != PMP_LOCK &&
|
||||
(val & 0x7) != (PMP_WRITE | PMP_EXEC)) {
|
||||
locked = false;
|
||||
}
|
||||
}
|
||||
if (pmp_is_readonly(env, pmp_index)) {
|
||||
qemu_log_mask(LOG_GUEST_ERROR,
|
||||
"ignoring pmpcfg write - read only\n");
|
||||
} else if (pmp_is_invalid_smepmp_cfg(env, val)) {
|
||||
qemu_log_mask(LOG_GUEST_ERROR,
|
||||
"ignoring pmpcfg write - invalid\n");
|
||||
} else {
|
||||
if (!pmp_is_locked(env, pmp_index)) {
|
||||
locked = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (locked) {
|
||||
qemu_log_mask(LOG_GUEST_ERROR, "ignoring pmpcfg write - locked\n");
|
||||
} else if (env->pmp_state.pmp[pmp_index].cfg_reg != val) {
|
||||
/* If !mseccfg.MML then ignore writes with encoding RW=01 */
|
||||
if ((val & PMP_WRITE) && !(val & PMP_READ) &&
|
||||
!MSECCFG_MML_ISSET(env)) {
|
||||
return false;
|
||||
}
|
||||
env->pmp_state.pmp[pmp_index].cfg_reg = val;
|
||||
pmp_update_rule_addr(env, pmp_index);
|
||||
return true;
|
||||
@@ -352,16 +371,6 @@ bool pmp_hart_has_privs(CPURISCVState *env, hwaddr addr,
|
||||
const uint8_t a_field =
|
||||
pmp_get_a_field(env->pmp_state.pmp[i].cfg_reg);
|
||||
|
||||
/*
|
||||
* Convert the PMP permissions to match the truth table in the
|
||||
* Smepmp spec.
|
||||
*/
|
||||
const uint8_t smepmp_operation =
|
||||
((env->pmp_state.pmp[i].cfg_reg & PMP_LOCK) >> 4) |
|
||||
((env->pmp_state.pmp[i].cfg_reg & PMP_READ) << 2) |
|
||||
(env->pmp_state.pmp[i].cfg_reg & PMP_WRITE) |
|
||||
((env->pmp_state.pmp[i].cfg_reg & PMP_EXEC) >> 2);
|
||||
|
||||
if (((s + e) == 2) && (PMP_AMATCH_OFF != a_field)) {
|
||||
/*
|
||||
* If the PMP entry is not off and the address is in range,
|
||||
@@ -380,6 +389,9 @@ bool pmp_hart_has_privs(CPURISCVState *env, hwaddr addr,
|
||||
/*
|
||||
* If mseccfg.MML Bit set, do the enhanced pmp priv check
|
||||
*/
|
||||
const uint8_t smepmp_operation =
|
||||
pmp_get_smepmp_operation(env->pmp_state.pmp[i].cfg_reg);
|
||||
|
||||
if (mode == PRV_M) {
|
||||
switch (smepmp_operation) {
|
||||
case 0:
|
||||
@@ -524,14 +536,14 @@ void pmpaddr_csr_write(CPURISCVState *env, uint32_t addr_index,
|
||||
uint8_t pmp_cfg = env->pmp_state.pmp[addr_index + 1].cfg_reg;
|
||||
is_next_cfg_tor = PMP_AMATCH_TOR == pmp_get_a_field(pmp_cfg);
|
||||
|
||||
if (pmp_is_locked(env, addr_index + 1) && is_next_cfg_tor) {
|
||||
if (pmp_is_readonly(env, addr_index + 1) && is_next_cfg_tor) {
|
||||
qemu_log_mask(LOG_GUEST_ERROR,
|
||||
"ignoring pmpaddr write - pmpcfg + 1 locked\n");
|
||||
"ignoring pmpaddr write - pmpcfg+1 read only\n");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (!pmp_is_locked(env, addr_index)) {
|
||||
if (!pmp_is_readonly(env, addr_index)) {
|
||||
if (env->pmp_state.pmp[addr_index].addr_reg != val) {
|
||||
env->pmp_state.pmp[addr_index].addr_reg = val;
|
||||
pmp_update_rule_addr(env, addr_index);
|
||||
@@ -542,7 +554,7 @@ void pmpaddr_csr_write(CPURISCVState *env, uint32_t addr_index,
|
||||
}
|
||||
} else {
|
||||
qemu_log_mask(LOG_GUEST_ERROR,
|
||||
"ignoring pmpaddr write - locked\n");
|
||||
"ignoring pmpaddr write - read only\n");
|
||||
}
|
||||
} else {
|
||||
qemu_log_mask(LOG_GUEST_ERROR,
|
||||
|
||||
@@ -5113,9 +5113,11 @@ void HELPER(NAME)(void *vd, void *v0, target_ulong s1, void *vs2, \
|
||||
} \
|
||||
\
|
||||
for (i = i_max; i < vl; ++i) { \
|
||||
if (vm || vext_elem_mask(v0, i)) { \
|
||||
*((ETYPE *)vd + H(i)) = 0; \
|
||||
if (!vm && !vext_elem_mask(v0, i)) { \
|
||||
vext_set_elems_1s(vd, vma, i * esz, (i + 1) * esz); \
|
||||
continue; \
|
||||
} \
|
||||
*((ETYPE *)vd + H(i)) = 0; \
|
||||
} \
|
||||
\
|
||||
env->vstart = 0; \
|
||||
|
||||
@@ -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": {}}
|
||||
|
||||
+7
-5
@@ -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);
|
||||
|
||||
+15
-7
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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) {
|
||||
|
||||
+8
-7
@@ -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)) {
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user