Compare commits
35 Commits
pull-input
...
v1.1.1
Author | SHA1 | Date | |
---|---|---|---|
|
785adb09b9 | ||
|
f52d0d639e | ||
|
4082e889ee | ||
|
b7093f294c | ||
|
cd63a77e99 | ||
|
8456852657 | ||
|
7d440f20bd | ||
|
feba8ae20b | ||
|
c9c2479289 | ||
|
4c45bf61d3 | ||
|
70d582074f | ||
|
0da4c07322 | ||
|
ee7735fa63 | ||
|
02fe741375 | ||
|
dbe4ac16bb | ||
|
f63e60327b | ||
|
0ec3907571 | ||
|
1658e3cd89 | ||
|
065436479b | ||
|
f6db26e4f8 | ||
|
c49dd1bf64 | ||
|
b4fcb4b499 | ||
|
7672b714b2 | ||
|
ca09717e8e | ||
|
0cc21de484 | ||
|
08375616a0 | ||
|
b993b863e7 | ||
|
07ff37597b | ||
|
e77326d99c | ||
|
8b3ac66120 | ||
|
2eb4d314ce | ||
|
adda59173c | ||
|
b696aeab6a | ||
|
6514fe5047 | ||
|
c63c453889 |
1
Makefile
1
Makefile
@@ -271,6 +271,7 @@ endif
|
|||||||
install-doc: $(DOCS)
|
install-doc: $(DOCS)
|
||||||
$(INSTALL_DIR) "$(DESTDIR)$(qemu_docdir)"
|
$(INSTALL_DIR) "$(DESTDIR)$(qemu_docdir)"
|
||||||
$(INSTALL_DATA) qemu-doc.html qemu-tech.html "$(DESTDIR)$(qemu_docdir)"
|
$(INSTALL_DATA) qemu-doc.html qemu-tech.html "$(DESTDIR)$(qemu_docdir)"
|
||||||
|
$(INSTALL_DATA) QMP/qmp-commands.txt "$(DESTDIR)$(qemu_docdir)"
|
||||||
ifdef CONFIG_POSIX
|
ifdef CONFIG_POSIX
|
||||||
$(INSTALL_DIR) "$(DESTDIR)$(mandir)/man1"
|
$(INSTALL_DIR) "$(DESTDIR)$(mandir)/man1"
|
||||||
$(INSTALL_DATA) qemu.1 qemu-img.1 "$(DESTDIR)$(mandir)/man1"
|
$(INSTALL_DATA) qemu.1 qemu-img.1 "$(DESTDIR)$(mandir)/man1"
|
||||||
|
@@ -471,6 +471,8 @@ int qcow2_get_cluster_offset(BlockDriverState *bs, uint64_t offset,
|
|||||||
QCOW_OFLAG_COMPRESSED | QCOW_OFLAG_ZERO);
|
QCOW_OFLAG_COMPRESSED | QCOW_OFLAG_ZERO);
|
||||||
*cluster_offset &= L2E_OFFSET_MASK;
|
*cluster_offset &= L2E_OFFSET_MASK;
|
||||||
break;
|
break;
|
||||||
|
default:
|
||||||
|
abort();
|
||||||
}
|
}
|
||||||
|
|
||||||
qcow2_cache_put(bs, s->l2_table_cache, (void**) &l2_table);
|
qcow2_cache_put(bs, s->l2_table_cache, (void**) &l2_table);
|
||||||
|
@@ -367,7 +367,7 @@ static int alloc_refcount_block(BlockDriverState *bs,
|
|||||||
}
|
}
|
||||||
|
|
||||||
for(i = 0; i < table_size; i++) {
|
for(i = 0; i < table_size; i++) {
|
||||||
cpu_to_be64s(&new_table[i]);
|
be64_to_cpus(&new_table[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Hook up the new refcount table in the qcow2 header */
|
/* Hook up the new refcount table in the qcow2 header */
|
||||||
|
@@ -298,14 +298,6 @@ static int qcow2_open(BlockDriverState *bs, int flags)
|
|||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!bs->read_only && s->autoclear_features != 0) {
|
|
||||||
s->autoclear_features = 0;
|
|
||||||
ret = qcow2_update_header(bs);
|
|
||||||
if (ret < 0) {
|
|
||||||
goto fail;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Check support for various header values */
|
/* Check support for various header values */
|
||||||
if (header.refcount_order != 4) {
|
if (header.refcount_order != 4) {
|
||||||
report_unsupported(bs, "%d bit reference counts",
|
report_unsupported(bs, "%d bit reference counts",
|
||||||
@@ -411,6 +403,15 @@ static int qcow2_open(BlockDriverState *bs, int flags)
|
|||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Clear unknown autoclear feature bits */
|
||||||
|
if (!bs->read_only && s->autoclear_features != 0) {
|
||||||
|
s->autoclear_features = 0;
|
||||||
|
ret = qcow2_update_header(bs);
|
||||||
|
if (ret < 0) {
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* Initialise locks */
|
/* Initialise locks */
|
||||||
qemu_co_mutex_init(&s->lock);
|
qemu_co_mutex_init(&s->lock);
|
||||||
|
|
||||||
|
@@ -1957,7 +1957,7 @@ static int do_load_save_vmstate(BDRVSheepdogState *s, uint8_t *data,
|
|||||||
int64_t pos, int size, int load)
|
int64_t pos, int size, int load)
|
||||||
{
|
{
|
||||||
int fd, create;
|
int fd, create;
|
||||||
int ret = 0;
|
int ret = 0, remaining = size;
|
||||||
unsigned int data_len;
|
unsigned int data_len;
|
||||||
uint64_t vmstate_oid;
|
uint64_t vmstate_oid;
|
||||||
uint32_t vdi_index;
|
uint32_t vdi_index;
|
||||||
@@ -1968,11 +1968,11 @@ static int do_load_save_vmstate(BDRVSheepdogState *s, uint8_t *data,
|
|||||||
return fd;
|
return fd;
|
||||||
}
|
}
|
||||||
|
|
||||||
while (size) {
|
while (remaining) {
|
||||||
vdi_index = pos / SD_DATA_OBJ_SIZE;
|
vdi_index = pos / SD_DATA_OBJ_SIZE;
|
||||||
offset = pos % SD_DATA_OBJ_SIZE;
|
offset = pos % SD_DATA_OBJ_SIZE;
|
||||||
|
|
||||||
data_len = MIN(size, SD_DATA_OBJ_SIZE);
|
data_len = MIN(remaining, SD_DATA_OBJ_SIZE);
|
||||||
|
|
||||||
vmstate_oid = vid_to_vmstate_oid(s->inode.vdi_id, vdi_index);
|
vmstate_oid = vid_to_vmstate_oid(s->inode.vdi_id, vdi_index);
|
||||||
|
|
||||||
@@ -1993,9 +1993,9 @@ static int do_load_save_vmstate(BDRVSheepdogState *s, uint8_t *data,
|
|||||||
}
|
}
|
||||||
|
|
||||||
pos += data_len;
|
pos += data_len;
|
||||||
size -= data_len;
|
remaining -= data_len;
|
||||||
ret += data_len;
|
|
||||||
}
|
}
|
||||||
|
ret = size;
|
||||||
cleanup:
|
cleanup:
|
||||||
closesocket(fd);
|
closesocket(fd);
|
||||||
return ret;
|
return ret;
|
||||||
|
7
configure
vendored
7
configure
vendored
@@ -2811,7 +2811,11 @@ fi
|
|||||||
open_by_hande_at=no
|
open_by_hande_at=no
|
||||||
cat > $TMPC << EOF
|
cat > $TMPC << EOF
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
|
#if !defined(AT_EMPTY_PATH)
|
||||||
|
# error missing definition
|
||||||
|
#else
|
||||||
int main(void) { struct file_handle fh; return open_by_handle_at(0, &fh, 0); }
|
int main(void) { struct file_handle fh; return open_by_handle_at(0, &fh, 0); }
|
||||||
|
#endif
|
||||||
EOF
|
EOF
|
||||||
if compile_prog "" "" ; then
|
if compile_prog "" "" ; then
|
||||||
open_by_handle_at=yes
|
open_by_handle_at=yes
|
||||||
@@ -2915,7 +2919,8 @@ if test "$softmmu" = yes ; then
|
|||||||
tools="$tools fsdev/virtfs-proxy-helper\$(EXESUF)"
|
tools="$tools fsdev/virtfs-proxy-helper\$(EXESUF)"
|
||||||
else
|
else
|
||||||
if test "$virtfs" = yes; then
|
if test "$virtfs" = yes; then
|
||||||
feature_not_found "virtfs"
|
echo "VirtFS is supported only on Linux and requires libcap-devel and libattr-devel"
|
||||||
|
exit 1
|
||||||
fi
|
fi
|
||||||
virtfs=no
|
virtfs=no
|
||||||
fi
|
fi
|
||||||
|
3
exec.c
3
exec.c
@@ -1492,7 +1492,8 @@ void tb_invalidate_phys_addr(target_phys_addr_t addr)
|
|||||||
|
|
||||||
static void breakpoint_invalidate(CPUArchState *env, target_ulong pc)
|
static void breakpoint_invalidate(CPUArchState *env, target_ulong pc)
|
||||||
{
|
{
|
||||||
tb_invalidate_phys_addr(cpu_get_phys_page_debug(env, pc));
|
tb_invalidate_phys_addr(cpu_get_phys_page_debug(env, pc) |
|
||||||
|
(pc & ~TARGET_PAGE_MASK));
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
#endif /* TARGET_HAS_ICE */
|
#endif /* TARGET_HAS_ICE */
|
||||||
|
4
hw/fdc.c
4
hw/fdc.c
@@ -159,6 +159,10 @@ static int fd_seek(FDrive *drv, uint8_t head, uint8_t track, uint8_t sect,
|
|||||||
drv->sect = sect;
|
drv->sect = sect;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (drv->bs == NULL || !bdrv_is_inserted(drv->bs)) {
|
||||||
|
ret = 2;
|
||||||
|
}
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -462,7 +462,7 @@ static void ahci_check_cmd_bh(void *opaque)
|
|||||||
|
|
||||||
static void ahci_init_d2h(AHCIDevice *ad)
|
static void ahci_init_d2h(AHCIDevice *ad)
|
||||||
{
|
{
|
||||||
uint8_t init_fis[0x20];
|
uint8_t init_fis[20];
|
||||||
IDEState *ide_state = &ad->port.ifs[0];
|
IDEState *ide_state = &ad->port.ifs[0];
|
||||||
|
|
||||||
memset(init_fis, 0, sizeof(init_fis));
|
memset(init_fis, 0, sizeof(init_fis));
|
||||||
@@ -619,7 +619,7 @@ static void ahci_write_fis_d2h(AHCIDevice *ad, uint8_t *cmd_fis)
|
|||||||
d2h_fis[11] = cmd_fis[11];
|
d2h_fis[11] = cmd_fis[11];
|
||||||
d2h_fis[12] = cmd_fis[12];
|
d2h_fis[12] = cmd_fis[12];
|
||||||
d2h_fis[13] = cmd_fis[13];
|
d2h_fis[13] = cmd_fis[13];
|
||||||
for (i = 14; i < 0x20; i++) {
|
for (i = 14; i < 20; i++) {
|
||||||
d2h_fis[i] = 0;
|
d2h_fis[i] = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
12
hw/ide/ich.c
12
hw/ide/ich.c
@@ -84,6 +84,14 @@ static const VMStateDescription vmstate_ahci = {
|
|||||||
.unmigratable = 1,
|
.unmigratable = 1,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static void pci_ich9_reset(void *opaque)
|
||||||
|
{
|
||||||
|
struct AHCIPCIState *d = opaque;
|
||||||
|
|
||||||
|
msi_reset(&d->card);
|
||||||
|
ahci_reset(opaque);
|
||||||
|
}
|
||||||
|
|
||||||
static int pci_ich9_ahci_init(PCIDevice *dev)
|
static int pci_ich9_ahci_init(PCIDevice *dev)
|
||||||
{
|
{
|
||||||
struct AHCIPCIState *d;
|
struct AHCIPCIState *d;
|
||||||
@@ -102,7 +110,7 @@ static int pci_ich9_ahci_init(PCIDevice *dev)
|
|||||||
/* XXX Software should program this register */
|
/* XXX Software should program this register */
|
||||||
d->card.config[0x90] = 1 << 6; /* Address Map Register - AHCI mode */
|
d->card.config[0x90] = 1 << 6; /* Address Map Register - AHCI mode */
|
||||||
|
|
||||||
qemu_register_reset(ahci_reset, d);
|
qemu_register_reset(pci_ich9_reset, d);
|
||||||
|
|
||||||
msi_init(dev, 0x50, 1, true, false);
|
msi_init(dev, 0x50, 1, true, false);
|
||||||
d->ahci.irq = d->card.irq[0];
|
d->ahci.irq = d->card.irq[0];
|
||||||
@@ -133,7 +141,7 @@ static int pci_ich9_uninit(PCIDevice *dev)
|
|||||||
d = DO_UPCAST(struct AHCIPCIState, card, dev);
|
d = DO_UPCAST(struct AHCIPCIState, card, dev);
|
||||||
|
|
||||||
msi_uninit(dev);
|
msi_uninit(dev);
|
||||||
qemu_unregister_reset(ahci_reset, d);
|
qemu_unregister_reset(pci_ich9_reset, d);
|
||||||
ahci_uninit(&d->ahci);
|
ahci_uninit(&d->ahci);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
@@ -1107,6 +1107,9 @@ static void intel_hda_reset(DeviceState *dev)
|
|||||||
DeviceState *qdev;
|
DeviceState *qdev;
|
||||||
HDACodecDevice *cdev;
|
HDACodecDevice *cdev;
|
||||||
|
|
||||||
|
if (d->msi) {
|
||||||
|
msi_reset(&d->pci);
|
||||||
|
}
|
||||||
intel_hda_regs_reset(d);
|
intel_hda_regs_reset(d);
|
||||||
d->wall_base_ns = qemu_get_clock_ns(vm_clock);
|
d->wall_base_ns = qemu_get_clock_ns(vm_clock);
|
||||||
|
|
||||||
|
@@ -29,7 +29,7 @@ void kvm_put_apic_state(DeviceState *d, struct kvm_lapic_state *kapic)
|
|||||||
APICCommonState *s = DO_UPCAST(APICCommonState, busdev.qdev, d);
|
APICCommonState *s = DO_UPCAST(APICCommonState, busdev.qdev, d);
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
memset(kapic, 0, sizeof(kapic));
|
memset(kapic, 0, sizeof(*kapic));
|
||||||
kvm_apic_set_reg(kapic, 0x2, s->id << 24);
|
kvm_apic_set_reg(kapic, 0x2, s->id << 24);
|
||||||
kvm_apic_set_reg(kapic, 0x8, s->tpr);
|
kvm_apic_set_reg(kapic, 0x8, s->tpr);
|
||||||
kvm_apic_set_reg(kapic, 0xd, s->log_dest << 24);
|
kvm_apic_set_reg(kapic, 0xd, s->log_dest << 24);
|
||||||
|
@@ -23,31 +23,63 @@
|
|||||||
* THE SOFTWARE.
|
* THE SOFTWARE.
|
||||||
*/
|
*/
|
||||||
#include "qemu-timer.h"
|
#include "qemu-timer.h"
|
||||||
|
#include "sysemu.h"
|
||||||
#include "hw/i8254.h"
|
#include "hw/i8254.h"
|
||||||
#include "hw/i8254_internal.h"
|
#include "hw/i8254_internal.h"
|
||||||
#include "kvm.h"
|
#include "kvm.h"
|
||||||
|
|
||||||
#define KVM_PIT_REINJECT_BIT 0
|
#define KVM_PIT_REINJECT_BIT 0
|
||||||
|
|
||||||
|
#define CALIBRATION_ROUNDS 3
|
||||||
|
|
||||||
typedef struct KVMPITState {
|
typedef struct KVMPITState {
|
||||||
PITCommonState pit;
|
PITCommonState pit;
|
||||||
LostTickPolicy lost_tick_policy;
|
LostTickPolicy lost_tick_policy;
|
||||||
|
bool state_valid;
|
||||||
} KVMPITState;
|
} KVMPITState;
|
||||||
|
|
||||||
static void kvm_pit_get(PITCommonState *s)
|
static int64_t abs64(int64_t v)
|
||||||
{
|
{
|
||||||
|
return v < 0 ? -v : v;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void kvm_pit_get(PITCommonState *pit)
|
||||||
|
{
|
||||||
|
KVMPITState *s = DO_UPCAST(KVMPITState, pit, pit);
|
||||||
struct kvm_pit_state2 kpit;
|
struct kvm_pit_state2 kpit;
|
||||||
struct kvm_pit_channel_state *kchan;
|
struct kvm_pit_channel_state *kchan;
|
||||||
struct PITChannelState *sc;
|
struct PITChannelState *sc;
|
||||||
|
int64_t offset, clock_offset;
|
||||||
|
struct timespec ts;
|
||||||
int i, ret;
|
int i, ret;
|
||||||
|
|
||||||
|
if (s->state_valid) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Measure the delta between CLOCK_MONOTONIC, the base used for
|
||||||
|
* kvm_pit_channel_state::count_load_time, and vm_clock. Take the
|
||||||
|
* minimum of several samples to filter out scheduling noise.
|
||||||
|
*/
|
||||||
|
clock_offset = INT64_MAX;
|
||||||
|
for (i = 0; i < CALIBRATION_ROUNDS; i++) {
|
||||||
|
offset = qemu_get_clock_ns(vm_clock);
|
||||||
|
clock_gettime(CLOCK_MONOTONIC, &ts);
|
||||||
|
offset -= ts.tv_nsec;
|
||||||
|
offset -= (int64_t)ts.tv_sec * 1000000000;
|
||||||
|
if (abs64(offset) < abs64(clock_offset)) {
|
||||||
|
clock_offset = offset;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (kvm_has_pit_state2()) {
|
if (kvm_has_pit_state2()) {
|
||||||
ret = kvm_vm_ioctl(kvm_state, KVM_GET_PIT2, &kpit);
|
ret = kvm_vm_ioctl(kvm_state, KVM_GET_PIT2, &kpit);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
fprintf(stderr, "KVM_GET_PIT2 failed: %s\n", strerror(ret));
|
fprintf(stderr, "KVM_GET_PIT2 failed: %s\n", strerror(ret));
|
||||||
abort();
|
abort();
|
||||||
}
|
}
|
||||||
s->channels[0].irq_disabled = kpit.flags & KVM_PIT_FLAGS_HPET_LEGACY;
|
pit->channels[0].irq_disabled = kpit.flags & KVM_PIT_FLAGS_HPET_LEGACY;
|
||||||
} else {
|
} else {
|
||||||
/*
|
/*
|
||||||
* kvm_pit_state2 is superset of kvm_pit_state struct,
|
* kvm_pit_state2 is superset of kvm_pit_state struct,
|
||||||
@@ -61,7 +93,7 @@ static void kvm_pit_get(PITCommonState *s)
|
|||||||
}
|
}
|
||||||
for (i = 0; i < 3; i++) {
|
for (i = 0; i < 3; i++) {
|
||||||
kchan = &kpit.channels[i];
|
kchan = &kpit.channels[i];
|
||||||
sc = &s->channels[i];
|
sc = &pit->channels[i];
|
||||||
sc->count = kchan->count;
|
sc->count = kchan->count;
|
||||||
sc->latched_count = kchan->latched_count;
|
sc->latched_count = kchan->latched_count;
|
||||||
sc->count_latched = kchan->count_latched;
|
sc->count_latched = kchan->count_latched;
|
||||||
@@ -74,10 +106,10 @@ static void kvm_pit_get(PITCommonState *s)
|
|||||||
sc->mode = kchan->mode;
|
sc->mode = kchan->mode;
|
||||||
sc->bcd = kchan->bcd;
|
sc->bcd = kchan->bcd;
|
||||||
sc->gate = kchan->gate;
|
sc->gate = kchan->gate;
|
||||||
sc->count_load_time = kchan->count_load_time;
|
sc->count_load_time = kchan->count_load_time + clock_offset;
|
||||||
}
|
}
|
||||||
|
|
||||||
sc = &s->channels[0];
|
sc = &pit->channels[0];
|
||||||
sc->next_transition_time =
|
sc->next_transition_time =
|
||||||
pit_get_next_transition_time(sc, sc->count_load_time);
|
pit_get_next_transition_time(sc, sc->count_load_time);
|
||||||
}
|
}
|
||||||
@@ -173,6 +205,19 @@ static void kvm_pit_irq_control(void *opaque, int n, int enable)
|
|||||||
kvm_pit_put(pit);
|
kvm_pit_put(pit);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void kvm_pit_vm_state_change(void *opaque, int running,
|
||||||
|
RunState state)
|
||||||
|
{
|
||||||
|
KVMPITState *s = opaque;
|
||||||
|
|
||||||
|
if (running) {
|
||||||
|
s->state_valid = false;
|
||||||
|
} else {
|
||||||
|
kvm_pit_get(&s->pit);
|
||||||
|
s->state_valid = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static int kvm_pit_initfn(PITCommonState *pit)
|
static int kvm_pit_initfn(PITCommonState *pit)
|
||||||
{
|
{
|
||||||
KVMPITState *s = DO_UPCAST(KVMPITState, pit, pit);
|
KVMPITState *s = DO_UPCAST(KVMPITState, pit, pit);
|
||||||
@@ -215,6 +260,8 @@ static int kvm_pit_initfn(PITCommonState *pit)
|
|||||||
|
|
||||||
qdev_init_gpio_in(&pit->dev.qdev, kvm_pit_irq_control, 1);
|
qdev_init_gpio_in(&pit->dev.qdev, kvm_pit_irq_control, 1);
|
||||||
|
|
||||||
|
qemu_add_vm_change_state_handler(kvm_pit_vm_state_change, s);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -52,7 +52,7 @@ static int pci_bridge_dev_initfn(PCIDevice *dev)
|
|||||||
{
|
{
|
||||||
PCIBridge *br = DO_UPCAST(PCIBridge, dev, dev);
|
PCIBridge *br = DO_UPCAST(PCIBridge, dev, dev);
|
||||||
PCIBridgeDev *bridge_dev = DO_UPCAST(PCIBridgeDev, bridge, br);
|
PCIBridgeDev *bridge_dev = DO_UPCAST(PCIBridgeDev, bridge, br);
|
||||||
int err;
|
int err, ret;
|
||||||
pci_bridge_map_irq(br, NULL, pci_bridge_dev_map_irq_fn);
|
pci_bridge_map_irq(br, NULL, pci_bridge_dev_map_irq_fn);
|
||||||
err = pci_bridge_initfn(dev);
|
err = pci_bridge_initfn(dev);
|
||||||
if (err) {
|
if (err) {
|
||||||
@@ -86,6 +86,8 @@ slotid_error:
|
|||||||
shpc_cleanup(dev, &bridge_dev->bar);
|
shpc_cleanup(dev, &bridge_dev->bar);
|
||||||
shpc_error:
|
shpc_error:
|
||||||
memory_region_destroy(&bridge_dev->bar);
|
memory_region_destroy(&bridge_dev->bar);
|
||||||
|
ret = pci_bridge_exitfn(dev);
|
||||||
|
assert(!ret);
|
||||||
bridge_error:
|
bridge_error:
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
@@ -20,6 +20,7 @@
|
|||||||
#include "qdev.h"
|
#include "qdev.h"
|
||||||
#include "monitor.h"
|
#include "monitor.h"
|
||||||
#include "qmp-commands.h"
|
#include "qmp-commands.h"
|
||||||
|
#include "arch_init.h"
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Aliases were a bad idea from the start. Let's keep them
|
* Aliases were a bad idea from the start. Let's keep them
|
||||||
@@ -29,16 +30,18 @@ typedef struct QDevAlias
|
|||||||
{
|
{
|
||||||
const char *typename;
|
const char *typename;
|
||||||
const char *alias;
|
const char *alias;
|
||||||
|
uint32_t arch_mask;
|
||||||
} QDevAlias;
|
} QDevAlias;
|
||||||
|
|
||||||
static const QDevAlias qdev_alias_table[] = {
|
static const QDevAlias qdev_alias_table[] = {
|
||||||
{ "virtio-blk-pci", "virtio-blk" },
|
{ "virtio-blk-pci", "virtio-blk", QEMU_ARCH_ALL & ~QEMU_ARCH_S390X },
|
||||||
{ "virtio-net-pci", "virtio-net" },
|
{ "virtio-net-pci", "virtio-net", QEMU_ARCH_ALL & ~QEMU_ARCH_S390X },
|
||||||
{ "virtio-serial-pci", "virtio-serial" },
|
{ "virtio-serial-pci", "virtio-serial", QEMU_ARCH_ALL & ~QEMU_ARCH_S390X },
|
||||||
{ "virtio-balloon-pci", "virtio-balloon" },
|
{ "virtio-balloon-pci", "virtio-balloon",
|
||||||
{ "virtio-blk-s390", "virtio-blk" },
|
QEMU_ARCH_ALL & ~QEMU_ARCH_S390X },
|
||||||
{ "virtio-net-s390", "virtio-net" },
|
{ "virtio-blk-s390", "virtio-blk", QEMU_ARCH_S390X },
|
||||||
{ "virtio-serial-s390", "virtio-serial" },
|
{ "virtio-net-s390", "virtio-net", QEMU_ARCH_S390X },
|
||||||
|
{ "virtio-serial-s390", "virtio-serial", QEMU_ARCH_S390X },
|
||||||
{ "lsi53c895a", "lsi" },
|
{ "lsi53c895a", "lsi" },
|
||||||
{ "ich9-ahci", "ahci" },
|
{ "ich9-ahci", "ahci" },
|
||||||
{ }
|
{ }
|
||||||
@@ -50,6 +53,11 @@ static const char *qdev_class_get_alias(DeviceClass *dc)
|
|||||||
int i;
|
int i;
|
||||||
|
|
||||||
for (i = 0; qdev_alias_table[i].typename; i++) {
|
for (i = 0; qdev_alias_table[i].typename; i++) {
|
||||||
|
if (qdev_alias_table[i].arch_mask &&
|
||||||
|
!(qdev_alias_table[i].arch_mask & arch_type)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
if (strcmp(qdev_alias_table[i].typename, typename) == 0) {
|
if (strcmp(qdev_alias_table[i].typename, typename) == 0) {
|
||||||
return qdev_alias_table[i].alias;
|
return qdev_alias_table[i].alias;
|
||||||
}
|
}
|
||||||
@@ -110,6 +118,11 @@ static const char *find_typename_by_alias(const char *alias)
|
|||||||
int i;
|
int i;
|
||||||
|
|
||||||
for (i = 0; qdev_alias_table[i].alias; i++) {
|
for (i = 0; qdev_alias_table[i].alias; i++) {
|
||||||
|
if (qdev_alias_table[i].arch_mask &&
|
||||||
|
!(qdev_alias_table[i].arch_mask & arch_type)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
if (strcmp(qdev_alias_table[i].alias, alias) == 0) {
|
if (strcmp(qdev_alias_table[i].alias, alias) == 0) {
|
||||||
return qdev_alias_table[i].typename;
|
return qdev_alias_table[i].typename;
|
||||||
}
|
}
|
||||||
|
@@ -150,6 +150,7 @@ int qdev_init(DeviceState *dev)
|
|||||||
|
|
||||||
rc = dc->init(dev);
|
rc = dc->init(dev);
|
||||||
if (rc < 0) {
|
if (rc < 0) {
|
||||||
|
object_unparent(OBJECT(dev));
|
||||||
qdev_free(dev);
|
qdev_free(dev);
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
24
hw/rtl8139.c
24
hw/rtl8139.c
@@ -781,6 +781,13 @@ static inline dma_addr_t rtl8139_addr64(uint32_t low, uint32_t high)
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Workaround for buggy guest driver such as linux who allocates rx
|
||||||
|
* rings after the receiver were enabled. */
|
||||||
|
static bool rtl8139_cp_rx_valid(RTL8139State *s)
|
||||||
|
{
|
||||||
|
return !(s->RxRingAddrLO == 0 && s->RxRingAddrHI == 0);
|
||||||
|
}
|
||||||
|
|
||||||
static int rtl8139_can_receive(VLANClientState *nc)
|
static int rtl8139_can_receive(VLANClientState *nc)
|
||||||
{
|
{
|
||||||
RTL8139State *s = DO_UPCAST(NICState, nc, nc)->opaque;
|
RTL8139State *s = DO_UPCAST(NICState, nc, nc)->opaque;
|
||||||
@@ -791,18 +798,15 @@ static int rtl8139_can_receive(VLANClientState *nc)
|
|||||||
return 1;
|
return 1;
|
||||||
if (!rtl8139_receiver_enabled(s))
|
if (!rtl8139_receiver_enabled(s))
|
||||||
return 1;
|
return 1;
|
||||||
/* network/host communication happens only in normal mode */
|
|
||||||
if ((s->Cfg9346 & Chip9346_op_mask) != Cfg9346_Normal)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
if (rtl8139_cp_receiver_enabled(s)) {
|
if (rtl8139_cp_receiver_enabled(s) && rtl8139_cp_rx_valid(s)) {
|
||||||
/* ??? Flow control not implemented in c+ mode.
|
/* ??? Flow control not implemented in c+ mode.
|
||||||
This is a hack to work around slirp deficiencies anyway. */
|
This is a hack to work around slirp deficiencies anyway. */
|
||||||
return 1;
|
return 1;
|
||||||
} else {
|
} else {
|
||||||
avail = MOD2(s->RxBufferSize + s->RxBufPtr - s->RxBufAddr,
|
avail = MOD2(s->RxBufferSize + s->RxBufPtr - s->RxBufAddr,
|
||||||
s->RxBufferSize);
|
s->RxBufferSize);
|
||||||
return (avail == 0 || avail >= 1514);
|
return (avail == 0 || avail >= 1514 || (s->IntrMask & RxOverflow));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -836,12 +840,6 @@ static ssize_t rtl8139_do_receive(VLANClientState *nc, const uint8_t *buf, size_
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* check whether we are in normal mode */
|
|
||||||
if ((s->Cfg9346 & Chip9346_op_mask) != Cfg9346_Normal) {
|
|
||||||
DPRINTF("not in normal op mode\n");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* XXX: check this */
|
/* XXX: check this */
|
||||||
if (s->RxConfig & AcceptAllPhys) {
|
if (s->RxConfig & AcceptAllPhys) {
|
||||||
/* promiscuous: receive all */
|
/* promiscuous: receive all */
|
||||||
@@ -946,6 +944,10 @@ static ssize_t rtl8139_do_receive(VLANClientState *nc, const uint8_t *buf, size_
|
|||||||
|
|
||||||
if (rtl8139_cp_receiver_enabled(s))
|
if (rtl8139_cp_receiver_enabled(s))
|
||||||
{
|
{
|
||||||
|
if (!rtl8139_cp_rx_valid(s)) {
|
||||||
|
return size;
|
||||||
|
}
|
||||||
|
|
||||||
DPRINTF("in C+ Rx mode ================\n");
|
DPRINTF("in C+ Rx mode ================\n");
|
||||||
|
|
||||||
/* begin C+ receiver mode */
|
/* begin C+ receiver mode */
|
||||||
|
@@ -147,9 +147,11 @@ static VirtIOBlockReq *virtio_blk_get_request(VirtIOBlock *s)
|
|||||||
|
|
||||||
static void virtio_blk_handle_scsi(VirtIOBlockReq *req)
|
static void virtio_blk_handle_scsi(VirtIOBlockReq *req)
|
||||||
{
|
{
|
||||||
|
#ifdef __linux__
|
||||||
int ret;
|
int ret;
|
||||||
int status = VIRTIO_BLK_S_OK;
|
|
||||||
int i;
|
int i;
|
||||||
|
#endif
|
||||||
|
int status = VIRTIO_BLK_S_OK;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* We require at least one output segment each for the virtio_blk_outhdr
|
* We require at least one output segment each for the virtio_blk_outhdr
|
||||||
@@ -489,7 +491,22 @@ static void virtio_blk_update_config(VirtIODevice *vdev, uint8_t *config)
|
|||||||
stw_raw(&blkcfg.min_io_size, s->conf->min_io_size / blk_size);
|
stw_raw(&blkcfg.min_io_size, s->conf->min_io_size / blk_size);
|
||||||
stw_raw(&blkcfg.opt_io_size, s->conf->opt_io_size / blk_size);
|
stw_raw(&blkcfg.opt_io_size, s->conf->opt_io_size / blk_size);
|
||||||
blkcfg.heads = heads;
|
blkcfg.heads = heads;
|
||||||
blkcfg.sectors = secs & ~s->sector_mask;
|
/*
|
||||||
|
* We must ensure that the block device capacity is a multiple of
|
||||||
|
* the logical block size. If that is not the case, lets use
|
||||||
|
* sector_mask to adopt the geometry to have a correct picture.
|
||||||
|
* For those devices where the capacity is ok for the given geometry
|
||||||
|
* we dont touch the sector value of the geometry, since some devices
|
||||||
|
* (like s390 dasd) need a specific value. Here the capacity is already
|
||||||
|
* cyls*heads*secs*blk_size and the sector value is not block size
|
||||||
|
* divided by 512 - instead it is the amount of blk_size blocks
|
||||||
|
* per track (cylinder).
|
||||||
|
*/
|
||||||
|
if (bdrv_getlength(s->bs) / heads / secs % blk_size) {
|
||||||
|
blkcfg.sectors = secs & ~s->sector_mask;
|
||||||
|
} else {
|
||||||
|
blkcfg.sectors = secs;
|
||||||
|
}
|
||||||
blkcfg.size_max = 0;
|
blkcfg.size_max = 0;
|
||||||
blkcfg.physical_block_exp = get_physical_block_exp(s->conf);
|
blkcfg.physical_block_exp = get_physical_block_exp(s->conf);
|
||||||
blkcfg.alignment_offset = 0;
|
blkcfg.alignment_offset = 0;
|
||||||
|
@@ -537,6 +537,15 @@ static void blk_bh(void *opaque)
|
|||||||
blk_handle_requests(blkdev);
|
blk_handle_requests(blkdev);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* We need to account for the grant allocations requiring contiguous
|
||||||
|
* chunks; the worst case number would be
|
||||||
|
* max_req * max_seg + (max_req - 1) * (max_seg - 1) + 1,
|
||||||
|
* but in order to keep things simple just use
|
||||||
|
* 2 * max_req * max_seg.
|
||||||
|
*/
|
||||||
|
#define MAX_GRANTS(max_req, max_seg) (2 * (max_req) * (max_seg))
|
||||||
|
|
||||||
static void blk_alloc(struct XenDevice *xendev)
|
static void blk_alloc(struct XenDevice *xendev)
|
||||||
{
|
{
|
||||||
struct XenBlkDev *blkdev = container_of(xendev, struct XenBlkDev, xendev);
|
struct XenBlkDev *blkdev = container_of(xendev, struct XenBlkDev, xendev);
|
||||||
@@ -548,6 +557,11 @@ static void blk_alloc(struct XenDevice *xendev)
|
|||||||
if (xen_mode != XEN_EMULATE) {
|
if (xen_mode != XEN_EMULATE) {
|
||||||
batch_maps = 1;
|
batch_maps = 1;
|
||||||
}
|
}
|
||||||
|
if (xc_gnttab_set_max_grants(xendev->gnttabdev,
|
||||||
|
MAX_GRANTS(max_requests, BLKIF_MAX_SEGMENTS_PER_REQUEST)) < 0) {
|
||||||
|
xen_be_printf(xendev, 0, "xc_gnttab_set_max_grants failed: %s\n",
|
||||||
|
strerror(errno));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static int blk_init(struct XenDevice *xendev)
|
static int blk_init(struct XenDevice *xendev)
|
||||||
|
@@ -57,7 +57,13 @@ int setenv(const char *name, const char *value, int overwrite)
|
|||||||
|
|
||||||
static BOOL WINAPI qemu_ctrl_handler(DWORD type)
|
static BOOL WINAPI qemu_ctrl_handler(DWORD type)
|
||||||
{
|
{
|
||||||
exit(STATUS_CONTROL_C_EXIT);
|
qemu_system_shutdown_request();
|
||||||
|
/* Windows 7 kills application when the function returns.
|
||||||
|
Sleep here to give QEMU a try for closing.
|
||||||
|
Sleep period is 10000ms because Windows kills the program
|
||||||
|
after 10 seconds anyway. */
|
||||||
|
Sleep(10000);
|
||||||
|
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -232,6 +232,29 @@ to grow.
|
|||||||
|
|
||||||
@end table
|
@end table
|
||||||
|
|
||||||
|
@item qed
|
||||||
|
Image format with support for backing files and compact image files (when your
|
||||||
|
filesystem or transport medium does not support holes). Good performance due
|
||||||
|
to less metadata than the more featureful qcow2 format, especially with
|
||||||
|
cache=writethrough or cache=directsync. Consider using qcow2 which will soon
|
||||||
|
have a similar optimization and is most actively developed.
|
||||||
|
|
||||||
|
Supported options:
|
||||||
|
@table @code
|
||||||
|
@item backing_file
|
||||||
|
File name of a base image (see @option{create} subcommand).
|
||||||
|
@item backing_fmt
|
||||||
|
Image file format of backing file (optional). Useful if the format cannot be
|
||||||
|
autodetected because it has no header, like some vhd/vpc files.
|
||||||
|
@item cluster_size
|
||||||
|
Changes the cluster size (must be power-of-2 between 4K and 64K). Smaller
|
||||||
|
cluster sizes can improve the image file size whereas larger cluster sizes
|
||||||
|
generally provide better performance.
|
||||||
|
@item table_size
|
||||||
|
Changes the number of clusters per L1/L2 table (must be power-of-2 between 1
|
||||||
|
and 16). There is normally no need to change this value but this option can be
|
||||||
|
used for performance benchmarking.
|
||||||
|
@end table
|
||||||
|
|
||||||
@item qcow
|
@item qcow
|
||||||
Old QEMU image format. Left for compatibility.
|
Old QEMU image format. Left for compatibility.
|
||||||
|
@@ -337,6 +337,9 @@ static void readline_completion(ReadLineState *rs)
|
|||||||
}
|
}
|
||||||
readline_show_prompt(rs);
|
readline_show_prompt(rs);
|
||||||
}
|
}
|
||||||
|
for (i = 0; i < rs->nb_completions; i++) {
|
||||||
|
g_free(rs->completions[i]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* return true if command handled */
|
/* return true if command handled */
|
||||||
|
@@ -370,9 +370,12 @@ void split_tlb_entry_spec_way(const CPUXtensaState *env, uint32_t v, bool dtlb,
|
|||||||
uint32_t *vpn, uint32_t wi, uint32_t *ei);
|
uint32_t *vpn, uint32_t wi, uint32_t *ei);
|
||||||
int xtensa_tlb_lookup(const CPUXtensaState *env, uint32_t addr, bool dtlb,
|
int xtensa_tlb_lookup(const CPUXtensaState *env, uint32_t addr, bool dtlb,
|
||||||
uint32_t *pwi, uint32_t *pei, uint8_t *pring);
|
uint32_t *pwi, uint32_t *pei, uint8_t *pring);
|
||||||
|
void xtensa_tlb_set_entry_mmu(const CPUXtensaState *env,
|
||||||
|
xtensa_tlb_entry *entry, bool dtlb,
|
||||||
|
unsigned wi, unsigned ei, uint32_t vpn, uint32_t pte);
|
||||||
void xtensa_tlb_set_entry(CPUXtensaState *env, bool dtlb,
|
void xtensa_tlb_set_entry(CPUXtensaState *env, bool dtlb,
|
||||||
unsigned wi, unsigned ei, uint32_t vpn, uint32_t pte);
|
unsigned wi, unsigned ei, uint32_t vpn, uint32_t pte);
|
||||||
int xtensa_get_physical_addr(CPUXtensaState *env,
|
int xtensa_get_physical_addr(CPUXtensaState *env, bool update_tlb,
|
||||||
uint32_t vaddr, int is_write, int mmu_idx,
|
uint32_t vaddr, int is_write, int mmu_idx,
|
||||||
uint32_t *paddr, uint32_t *page_size, unsigned *access);
|
uint32_t *paddr, uint32_t *page_size, unsigned *access);
|
||||||
void reset_mmu(CPUXtensaState *env);
|
void reset_mmu(CPUXtensaState *env);
|
||||||
|
@@ -135,11 +135,11 @@ target_phys_addr_t cpu_get_phys_page_debug(CPUXtensaState *env, target_ulong add
|
|||||||
uint32_t page_size;
|
uint32_t page_size;
|
||||||
unsigned access;
|
unsigned access;
|
||||||
|
|
||||||
if (xtensa_get_physical_addr(env, addr, 0, 0,
|
if (xtensa_get_physical_addr(env, false, addr, 0, 0,
|
||||||
&paddr, &page_size, &access) == 0) {
|
&paddr, &page_size, &access) == 0) {
|
||||||
return paddr;
|
return paddr;
|
||||||
}
|
}
|
||||||
if (xtensa_get_physical_addr(env, addr, 2, 0,
|
if (xtensa_get_physical_addr(env, false, addr, 2, 0,
|
||||||
&paddr, &page_size, &access) == 0) {
|
&paddr, &page_size, &access) == 0) {
|
||||||
return paddr;
|
return paddr;
|
||||||
}
|
}
|
||||||
@@ -448,30 +448,48 @@ static bool is_access_granted(unsigned access, int is_write)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static int autorefill_mmu(CPUXtensaState *env, uint32_t vaddr, bool dtlb,
|
static int get_pte(CPUXtensaState *env, uint32_t vaddr, uint32_t *pte);
|
||||||
uint32_t *wi, uint32_t *ei, uint8_t *ring);
|
|
||||||
|
|
||||||
static int get_physical_addr_mmu(CPUXtensaState *env,
|
static int get_physical_addr_mmu(CPUXtensaState *env, bool update_tlb,
|
||||||
uint32_t vaddr, int is_write, int mmu_idx,
|
uint32_t vaddr, int is_write, int mmu_idx,
|
||||||
uint32_t *paddr, uint32_t *page_size, unsigned *access)
|
uint32_t *paddr, uint32_t *page_size, unsigned *access,
|
||||||
|
bool may_lookup_pt)
|
||||||
{
|
{
|
||||||
bool dtlb = is_write != 2;
|
bool dtlb = is_write != 2;
|
||||||
uint32_t wi;
|
uint32_t wi;
|
||||||
uint32_t ei;
|
uint32_t ei;
|
||||||
uint8_t ring;
|
uint8_t ring;
|
||||||
|
uint32_t vpn;
|
||||||
|
uint32_t pte;
|
||||||
|
const xtensa_tlb_entry *entry = NULL;
|
||||||
|
xtensa_tlb_entry tmp_entry;
|
||||||
int ret = xtensa_tlb_lookup(env, vaddr, dtlb, &wi, &ei, &ring);
|
int ret = xtensa_tlb_lookup(env, vaddr, dtlb, &wi, &ei, &ring);
|
||||||
|
|
||||||
if ((ret == INST_TLB_MISS_CAUSE || ret == LOAD_STORE_TLB_MISS_CAUSE) &&
|
if ((ret == INST_TLB_MISS_CAUSE || ret == LOAD_STORE_TLB_MISS_CAUSE) &&
|
||||||
(mmu_idx != 0 || ((vaddr ^ env->sregs[PTEVADDR]) & 0xffc00000)) &&
|
may_lookup_pt && get_pte(env, vaddr, &pte) == 0) {
|
||||||
autorefill_mmu(env, vaddr, dtlb, &wi, &ei, &ring) == 0) {
|
ring = (pte >> 4) & 0x3;
|
||||||
|
wi = 0;
|
||||||
|
split_tlb_entry_spec_way(env, vaddr, dtlb, &vpn, wi, &ei);
|
||||||
|
|
||||||
|
if (update_tlb) {
|
||||||
|
wi = ++env->autorefill_idx & 0x3;
|
||||||
|
xtensa_tlb_set_entry(env, dtlb, wi, ei, vpn, pte);
|
||||||
|
env->sregs[EXCVADDR] = vaddr;
|
||||||
|
qemu_log("%s: autorefill(%08x): %08x -> %08x\n",
|
||||||
|
__func__, vaddr, vpn, pte);
|
||||||
|
} else {
|
||||||
|
xtensa_tlb_set_entry_mmu(env, &tmp_entry, dtlb, wi, ei, vpn, pte);
|
||||||
|
entry = &tmp_entry;
|
||||||
|
}
|
||||||
ret = 0;
|
ret = 0;
|
||||||
}
|
}
|
||||||
if (ret != 0) {
|
if (ret != 0) {
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
const xtensa_tlb_entry *entry =
|
if (entry == NULL) {
|
||||||
xtensa_tlb_get_entry(env, dtlb, wi, ei);
|
entry = xtensa_tlb_get_entry(env, dtlb, wi, ei);
|
||||||
|
}
|
||||||
|
|
||||||
if (ring < mmu_idx) {
|
if (ring < mmu_idx) {
|
||||||
return dtlb ?
|
return dtlb ?
|
||||||
@@ -494,30 +512,21 @@ static int get_physical_addr_mmu(CPUXtensaState *env,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int autorefill_mmu(CPUXtensaState *env, uint32_t vaddr, bool dtlb,
|
static int get_pte(CPUXtensaState *env, uint32_t vaddr, uint32_t *pte)
|
||||||
uint32_t *wi, uint32_t *ei, uint8_t *ring)
|
|
||||||
{
|
{
|
||||||
uint32_t paddr;
|
uint32_t paddr;
|
||||||
uint32_t page_size;
|
uint32_t page_size;
|
||||||
unsigned access;
|
unsigned access;
|
||||||
uint32_t pt_vaddr =
|
uint32_t pt_vaddr =
|
||||||
(env->sregs[PTEVADDR] | (vaddr >> 10)) & 0xfffffffc;
|
(env->sregs[PTEVADDR] | (vaddr >> 10)) & 0xfffffffc;
|
||||||
int ret = get_physical_addr_mmu(env, pt_vaddr, 0, 0,
|
int ret = get_physical_addr_mmu(env, false, pt_vaddr, 0, 0,
|
||||||
&paddr, &page_size, &access);
|
&paddr, &page_size, &access, false);
|
||||||
|
|
||||||
qemu_log("%s: trying autorefill(%08x) -> %08x\n", __func__,
|
qemu_log("%s: trying autorefill(%08x) -> %08x\n", __func__,
|
||||||
vaddr, ret ? ~0 : paddr);
|
vaddr, ret ? ~0 : paddr);
|
||||||
|
|
||||||
if (ret == 0) {
|
if (ret == 0) {
|
||||||
uint32_t vpn;
|
*pte = ldl_phys(paddr);
|
||||||
uint32_t pte = ldl_phys(paddr);
|
|
||||||
|
|
||||||
*ring = (pte >> 4) & 0x3;
|
|
||||||
*wi = (++env->autorefill_idx) & 0x3;
|
|
||||||
split_tlb_entry_spec_way(env, vaddr, dtlb, &vpn, *wi, ei);
|
|
||||||
xtensa_tlb_set_entry(env, dtlb, *wi, *ei, vpn, pte);
|
|
||||||
qemu_log("%s: autorefill(%08x): %08x -> %08x\n",
|
|
||||||
__func__, vaddr, vpn, pte);
|
|
||||||
}
|
}
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
@@ -553,13 +562,13 @@ static int get_physical_addr_region(CPUXtensaState *env,
|
|||||||
*
|
*
|
||||||
* \return 0 if ok, exception cause code otherwise
|
* \return 0 if ok, exception cause code otherwise
|
||||||
*/
|
*/
|
||||||
int xtensa_get_physical_addr(CPUXtensaState *env,
|
int xtensa_get_physical_addr(CPUXtensaState *env, bool update_tlb,
|
||||||
uint32_t vaddr, int is_write, int mmu_idx,
|
uint32_t vaddr, int is_write, int mmu_idx,
|
||||||
uint32_t *paddr, uint32_t *page_size, unsigned *access)
|
uint32_t *paddr, uint32_t *page_size, unsigned *access)
|
||||||
{
|
{
|
||||||
if (xtensa_option_enabled(env->config, XTENSA_OPTION_MMU)) {
|
if (xtensa_option_enabled(env->config, XTENSA_OPTION_MMU)) {
|
||||||
return get_physical_addr_mmu(env, vaddr, is_write, mmu_idx,
|
return get_physical_addr_mmu(env, update_tlb,
|
||||||
paddr, page_size, access);
|
vaddr, is_write, mmu_idx, paddr, page_size, access, true);
|
||||||
} else if (xtensa_option_bits_enabled(env->config,
|
} else if (xtensa_option_bits_enabled(env->config,
|
||||||
XTENSA_OPTION_BIT(XTENSA_OPTION_REGION_PROTECTION) |
|
XTENSA_OPTION_BIT(XTENSA_OPTION_REGION_PROTECTION) |
|
||||||
XTENSA_OPTION_BIT(XTENSA_OPTION_REGION_TRANSLATION))) {
|
XTENSA_OPTION_BIT(XTENSA_OPTION_REGION_TRANSLATION))) {
|
||||||
|
@@ -79,7 +79,7 @@ void tlb_fill(CPUXtensaState *env1, target_ulong vaddr, int is_write, int mmu_id
|
|||||||
uint32_t paddr;
|
uint32_t paddr;
|
||||||
uint32_t page_size;
|
uint32_t page_size;
|
||||||
unsigned access;
|
unsigned access;
|
||||||
int ret = xtensa_get_physical_addr(env, vaddr, is_write, mmu_idx,
|
int ret = xtensa_get_physical_addr(env, true, vaddr, is_write, mmu_idx,
|
||||||
&paddr, &page_size, &access);
|
&paddr, &page_size, &access);
|
||||||
|
|
||||||
qemu_log("%s(%08x, %d, %d) -> %08x, ret = %d\n", __func__,
|
qemu_log("%s(%08x, %d, %d) -> %08x, ret = %d\n", __func__,
|
||||||
@@ -103,7 +103,7 @@ static void tb_invalidate_virtual_addr(CPUXtensaState *env, uint32_t vaddr)
|
|||||||
uint32_t paddr;
|
uint32_t paddr;
|
||||||
uint32_t page_size;
|
uint32_t page_size;
|
||||||
unsigned access;
|
unsigned access;
|
||||||
int ret = xtensa_get_physical_addr(env, vaddr, 2, 0,
|
int ret = xtensa_get_physical_addr(env, false, vaddr, 2, 0,
|
||||||
&paddr, &page_size, &access);
|
&paddr, &page_size, &access);
|
||||||
if (ret == 0) {
|
if (ret == 0) {
|
||||||
tb_invalidate_phys_addr(paddr);
|
tb_invalidate_phys_addr(paddr);
|
||||||
@@ -655,6 +655,16 @@ uint32_t HELPER(ptlb)(uint32_t v, uint32_t dtlb)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void xtensa_tlb_set_entry_mmu(const CPUXtensaState *env,
|
||||||
|
xtensa_tlb_entry *entry, bool dtlb,
|
||||||
|
unsigned wi, unsigned ei, uint32_t vpn, uint32_t pte)
|
||||||
|
{
|
||||||
|
entry->vaddr = vpn;
|
||||||
|
entry->paddr = pte & xtensa_tlb_get_addr_mask(env, dtlb, wi);
|
||||||
|
entry->asid = (env->sregs[RASID] >> ((pte >> 1) & 0x18)) & 0xff;
|
||||||
|
entry->attr = pte & 0xf;
|
||||||
|
}
|
||||||
|
|
||||||
void xtensa_tlb_set_entry(CPUXtensaState *env, bool dtlb,
|
void xtensa_tlb_set_entry(CPUXtensaState *env, bool dtlb,
|
||||||
unsigned wi, unsigned ei, uint32_t vpn, uint32_t pte)
|
unsigned wi, unsigned ei, uint32_t vpn, uint32_t pte)
|
||||||
{
|
{
|
||||||
@@ -665,10 +675,8 @@ void xtensa_tlb_set_entry(CPUXtensaState *env, bool dtlb,
|
|||||||
if (entry->asid) {
|
if (entry->asid) {
|
||||||
tlb_flush_page(env, entry->vaddr);
|
tlb_flush_page(env, entry->vaddr);
|
||||||
}
|
}
|
||||||
entry->vaddr = vpn;
|
xtensa_tlb_set_entry_mmu(env, entry, dtlb, wi, ei, vpn, pte);
|
||||||
entry->paddr = pte & xtensa_tlb_get_addr_mask(env, dtlb, wi);
|
tlb_flush_page(env, entry->vaddr);
|
||||||
entry->asid = (env->sregs[RASID] >> ((pte >> 1) & 0x18)) & 0xff;
|
|
||||||
entry->attr = pte & 0xf;
|
|
||||||
} else {
|
} else {
|
||||||
qemu_log("%s %d, %d, %d trying to set immutable entry\n",
|
qemu_log("%s %d, %d, %d trying to set immutable entry\n",
|
||||||
__func__, dtlb, wi, ei);
|
__func__, dtlb, wi, ei);
|
||||||
|
@@ -388,6 +388,7 @@ static bool gen_check_loop_end(DisasContext *dc, int slot)
|
|||||||
dc->next_pc == dc->lend) {
|
dc->next_pc == dc->lend) {
|
||||||
int label = gen_new_label();
|
int label = gen_new_label();
|
||||||
|
|
||||||
|
gen_advance_ccount(dc);
|
||||||
tcg_gen_brcondi_i32(TCG_COND_EQ, cpu_SR[LCOUNT], 0, label);
|
tcg_gen_brcondi_i32(TCG_COND_EQ, cpu_SR[LCOUNT], 0, label);
|
||||||
tcg_gen_subi_i32(cpu_SR[LCOUNT], cpu_SR[LCOUNT], 1);
|
tcg_gen_subi_i32(cpu_SR[LCOUNT], cpu_SR[LCOUNT], 1);
|
||||||
gen_jumpi(dc, dc->lbeg, slot);
|
gen_jumpi(dc, dc->lbeg, slot);
|
||||||
@@ -410,6 +411,7 @@ static void gen_brcond(DisasContext *dc, TCGCond cond,
|
|||||||
{
|
{
|
||||||
int label = gen_new_label();
|
int label = gen_new_label();
|
||||||
|
|
||||||
|
gen_advance_ccount(dc);
|
||||||
tcg_gen_brcond_i32(cond, t0, t1, label);
|
tcg_gen_brcond_i32(cond, t0, t1, label);
|
||||||
gen_jumpi_check_loop_end(dc, 0);
|
gen_jumpi_check_loop_end(dc, 0);
|
||||||
gen_set_label(label);
|
gen_set_label(label);
|
||||||
|
@@ -293,26 +293,219 @@ test store_prohibited
|
|||||||
assert eq, a2, a3
|
assert eq, a2, a3
|
||||||
test_end
|
test_end
|
||||||
|
|
||||||
test dtlb_autoload
|
/* Set up page table entry vaddr->paddr, ring=pte_ring, attr=pte_attr
|
||||||
set_vector kernel, 0
|
* and DTLB way 7 to cover this PTE, ring=pt_ring, attr=pt_attr
|
||||||
|
*/
|
||||||
movi a2, 0xd4000000
|
.macro pt_setup pt_ring, pt_attr, pte_ring, vaddr, paddr, pte_attr
|
||||||
|
movi a2, 0x80000000
|
||||||
wsr a2, ptevaddr
|
wsr a2, ptevaddr
|
||||||
movi a3, 0x00001013
|
|
||||||
s32i a3, a2, 4
|
movi a3, 0x80000007 | (((\vaddr) >> 10) & 0xfffff000) /* way 7 */
|
||||||
|
movi a4, 0x04000003 | ((\pt_ring) << 4) /* PADDR 64M */
|
||||||
|
wdtlb a4, a3
|
||||||
|
isync
|
||||||
|
|
||||||
|
movi a3, ((\paddr) & 0xfffff000) | ((\pte_ring) << 4) | (\pte_attr)
|
||||||
|
movi a1, ((\vaddr) >> 12) << 2
|
||||||
|
add a2, a1, a2
|
||||||
|
s32i a3, a2, 0
|
||||||
|
|
||||||
|
movi a3, 0x80000007 | (((\vaddr) >> 10) & 0xfffff000) /* way 7 */
|
||||||
|
movi a4, 0x04000000 | ((\pt_ring) << 4) | (\pt_attr) /* PADDR 64M */
|
||||||
|
wdtlb a4, a3
|
||||||
|
isync
|
||||||
|
|
||||||
|
movi a3, (\vaddr)
|
||||||
|
.endm
|
||||||
|
|
||||||
|
/* out: PS.RING=ring, PS.EXCM=excm, a3=vaddr */
|
||||||
|
.macro go_ring ring, excm, vaddr
|
||||||
|
movi a3, 10f
|
||||||
|
pitlb a3, a3
|
||||||
|
ritlb1 a2, a3
|
||||||
|
movi a1, 0x10
|
||||||
|
or a2, a2, a1
|
||||||
|
movi a1, 0x000ff000
|
||||||
|
and a3, a3, a1
|
||||||
|
movi a1, 4
|
||||||
|
or a3, a3, a1
|
||||||
|
witlb a2, a3
|
||||||
|
movi a3, 10f
|
||||||
|
movi a1, 0x000fffff
|
||||||
|
and a1, a3, a1
|
||||||
|
|
||||||
|
movi a2, 0
|
||||||
|
wsr a2, excvaddr
|
||||||
|
|
||||||
|
movi a3, \vaddr
|
||||||
|
movi a2, 0x4000f | ((\ring) << 6) | ((\excm) << 4)
|
||||||
|
jx a1
|
||||||
|
10:
|
||||||
|
wsr a2, ps
|
||||||
|
isync
|
||||||
|
.endm
|
||||||
|
|
||||||
|
/* in: a3 -- virtual address to test */
|
||||||
|
.macro assert_auto_tlb
|
||||||
|
movi a2, 0x4000f
|
||||||
|
wsr a2, ps
|
||||||
|
isync
|
||||||
|
pdtlb a2, a3
|
||||||
|
movi a1, 0xfffff01f
|
||||||
|
and a2, a2, a1
|
||||||
|
movi a1, 0xfffff000
|
||||||
|
and a1, a1, a3
|
||||||
|
xor a1, a1, a2
|
||||||
|
assert gei, a1, 0x10
|
||||||
|
movi a2, 0x14
|
||||||
|
assert lt, a1, a2
|
||||||
|
.endm
|
||||||
|
|
||||||
|
/* in: a3 -- virtual address to test */
|
||||||
|
.macro assert_no_auto_tlb
|
||||||
|
movi a2, 0x4000f
|
||||||
|
wsr a2, ps
|
||||||
|
isync
|
||||||
pdtlb a2, a3
|
pdtlb a2, a3
|
||||||
movi a1, 0x10
|
movi a1, 0x10
|
||||||
and a1, a1, a2
|
and a1, a1, a2
|
||||||
assert eqi, a1, 0
|
assert eqi, a1, 0
|
||||||
|
.endm
|
||||||
|
|
||||||
|
.macro assert_sr sr, v
|
||||||
|
rsr a2, \sr
|
||||||
|
movi a1, (\v)
|
||||||
|
assert eq, a1, a2
|
||||||
|
.endm
|
||||||
|
|
||||||
|
.macro assert_epc1_1m vaddr
|
||||||
|
movi a2, (\vaddr)
|
||||||
|
movi a1, 0xfffff
|
||||||
|
and a1, a1, a2
|
||||||
|
rsr a2, epc1
|
||||||
|
assert eq, a1, a2
|
||||||
|
.endm
|
||||||
|
|
||||||
|
test dtlb_autoload
|
||||||
|
set_vector kernel, 0
|
||||||
|
|
||||||
|
pt_setup 0, 3, 1, 0x1000, 0x1000, 3
|
||||||
|
assert_no_auto_tlb
|
||||||
|
|
||||||
l8ui a1, a3, 0
|
l8ui a1, a3, 0
|
||||||
pdtlb a2, a3
|
|
||||||
movi a1, 0xfffff010
|
rsr a2, excvaddr
|
||||||
and a1, a1, a2
|
assert eq, a2, a3
|
||||||
movi a3, 0x00001010
|
|
||||||
assert eq, a1, a3
|
assert_auto_tlb
|
||||||
movi a1, 0xf
|
test_end
|
||||||
and a1, a1, a2
|
|
||||||
assert lti, a1, 4
|
test autoload_load_store_privilege
|
||||||
|
set_vector kernel, 0
|
||||||
|
set_vector double, 2f
|
||||||
|
|
||||||
|
pt_setup 0, 3, 0, 0x2000, 0x2000, 3
|
||||||
|
movi a3, 0x2004
|
||||||
|
assert_no_auto_tlb
|
||||||
|
|
||||||
|
movi a2, 0x4005f /* ring 1 + excm => cring == 0 */
|
||||||
|
wsr a2, ps
|
||||||
|
isync
|
||||||
|
1:
|
||||||
|
l32e a2, a3, -4 /* ring used */
|
||||||
|
test_fail
|
||||||
|
2:
|
||||||
|
rsr a2, excvaddr
|
||||||
|
addi a1, a3, -4
|
||||||
|
assert eq, a1, a2
|
||||||
|
|
||||||
|
assert_auto_tlb
|
||||||
|
assert_sr depc, 1b
|
||||||
|
assert_sr exccause, 26
|
||||||
|
test_end
|
||||||
|
|
||||||
|
test autoload_pte_load_prohibited
|
||||||
|
set_vector kernel, 2f
|
||||||
|
|
||||||
|
pt_setup 0, 3, 0, 0x3000, 0, 0xc
|
||||||
|
assert_no_auto_tlb
|
||||||
|
1:
|
||||||
|
l32i a2, a3, 0
|
||||||
|
test_fail
|
||||||
|
2:
|
||||||
|
rsr a2, excvaddr
|
||||||
|
assert eq, a2, a3
|
||||||
|
|
||||||
|
assert_auto_tlb
|
||||||
|
assert_sr epc1, 1b
|
||||||
|
assert_sr exccause, 28
|
||||||
|
test_end
|
||||||
|
|
||||||
|
test autoload_pt_load_prohibited
|
||||||
|
set_vector kernel, 2f
|
||||||
|
|
||||||
|
pt_setup 0, 0xc, 0, 0x4000, 0x4000, 3
|
||||||
|
assert_no_auto_tlb
|
||||||
|
1:
|
||||||
|
l32i a2, a3, 0
|
||||||
|
test_fail
|
||||||
|
2:
|
||||||
|
rsr a2, excvaddr
|
||||||
|
assert eq, a2, a3
|
||||||
|
|
||||||
|
assert_no_auto_tlb
|
||||||
|
assert_sr epc1, 1b
|
||||||
|
assert_sr exccause, 24
|
||||||
|
test_end
|
||||||
|
|
||||||
|
test autoload_pt_privilege
|
||||||
|
set_vector kernel, 2f
|
||||||
|
pt_setup 0, 3, 1, 0x5000, 0, 3
|
||||||
|
go_ring 1, 0, 0x5001
|
||||||
|
|
||||||
|
l8ui a2, a3, 0
|
||||||
|
1:
|
||||||
|
syscall
|
||||||
|
2:
|
||||||
|
rsr a2, excvaddr
|
||||||
|
assert eq, a2, a3
|
||||||
|
|
||||||
|
assert_auto_tlb
|
||||||
|
assert_epc1_1m 1b
|
||||||
|
assert_sr exccause, 1
|
||||||
|
test_end
|
||||||
|
|
||||||
|
test autoload_pte_privilege
|
||||||
|
set_vector kernel, 2f
|
||||||
|
pt_setup 0, 3, 0, 0x6000, 0, 3
|
||||||
|
go_ring 1, 0, 0x6001
|
||||||
|
1:
|
||||||
|
l8ui a2, a3, 0
|
||||||
|
syscall
|
||||||
|
2:
|
||||||
|
rsr a2, excvaddr
|
||||||
|
assert eq, a2, a3
|
||||||
|
|
||||||
|
assert_auto_tlb
|
||||||
|
assert_epc1_1m 1b
|
||||||
|
assert_sr exccause, 26
|
||||||
|
test_end
|
||||||
|
|
||||||
|
test autoload_3_level_pt
|
||||||
|
set_vector kernel, 2f
|
||||||
|
pt_setup 1, 3, 1, 0x00400000, 0, 3
|
||||||
|
pt_setup 1, 3, 1, 0x80001000, 0x2000000, 3
|
||||||
|
go_ring 1, 0, 0x00400001
|
||||||
|
1:
|
||||||
|
l8ui a2, a3, 0
|
||||||
|
syscall
|
||||||
|
2:
|
||||||
|
rsr a2, excvaddr
|
||||||
|
assert eq, a2, a3
|
||||||
|
|
||||||
|
assert_no_auto_tlb
|
||||||
|
assert_epc1_1m 1b
|
||||||
|
assert_sr exccause, 24
|
||||||
test_end
|
test_end
|
||||||
|
|
||||||
test_suite_end
|
test_suite_end
|
||||||
|
@@ -161,8 +161,11 @@ static void trace(TraceEventID event, uint64_t x1, uint64_t x2, uint64_t x3,
|
|||||||
}
|
}
|
||||||
|
|
||||||
timestamp = get_clock();
|
timestamp = get_clock();
|
||||||
|
#if GLIB_CHECK_VERSION(2, 30, 0)
|
||||||
|
idx = g_atomic_int_add((gint *)&trace_idx, 1) % TRACE_BUF_LEN;
|
||||||
|
#else
|
||||||
idx = g_atomic_int_exchange_and_add((gint *)&trace_idx, 1) % TRACE_BUF_LEN;
|
idx = g_atomic_int_exchange_and_add((gint *)&trace_idx, 1) % TRACE_BUF_LEN;
|
||||||
|
#endif
|
||||||
trace_buf[idx] = (TraceRecord){
|
trace_buf[idx] = (TraceRecord){
|
||||||
.event = event,
|
.event = event,
|
||||||
.timestamp_ns = timestamp,
|
.timestamp_ns = timestamp,
|
||||||
|
Reference in New Issue
Block a user