mirror of https://github.com/xqemu/xqemu.git
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1 iQEcBAABAgAGBQJWMmDMAAoJEJykq7OBq3PIHkIIAKyL9iY4EipKrtdMoWZu/Kfm I9g4NVVqPF4QmTfYpZVxWglvBy0g0+2p1h4DQ5KheUNr7DV2uchSSsN38MWnEgH/ XTRpY858jcWx4sSAvYpz+kUVRBEtJJL8a/1aTBvYRxcbNE1X1lm72m7mm4KXGGud PZ0fdj/UODHeoTOnMHddbs8Rs0kdHhlckl2Mfkz2dUgYAuZMK7xR7OIE7kOqWBcR p5/I1Jq3wgmp267ZPVNS17u8Cff2PIElv0Z3Ouubixhhf+k5kvLBtgTbTJ81h7/4 NfmIRwsmAPhtnDSDXqFJ8KgwUYpGYYtPrK8DIXIWYwPdSjkIIdl1gNtc2CGyV3w= =nA50 -----END PGP SIGNATURE----- Merge remote-tracking branch 'remotes/stefanha/tags/block-pull-request' into staging # gpg: Signature made Thu 29 Oct 2015 18:09:16 GMT using RSA key ID 81AB73C8 # gpg: Good signature from "Stefan Hajnoczi <stefanha@redhat.com>" # gpg: aka "Stefan Hajnoczi <stefanha@gmail.com>" * remotes/stefanha/tags/block-pull-request: block: Consider all child nodes in bdrv_requests_pending() target-arm: xlnx-zynqmp: Add sdhci support. sdhci: Split sdhci.h for public and internal device usage sd.h: Move sd.h to include/hw/sd/ virtio: sync the dataplane vring state to the virtqueue before virtio_save gdb command: qemu handlers virtio-blk: switch off scsi-passthrough by default ppc/spapr: add 2.4 compat props s390x: include HW_COMPAT_* props qemu-gdb: add $qemu_coroutine_sp and $qemu_coroutine_pc qemu-gdb: extract parts of "qemu coroutine" implementation qemu-gdb: allow using glibc_pointer_guard() on core dumps Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
commit
3a958f559e
13
block/io.c
13
block/io.c
|
@ -216,6 +216,8 @@ void bdrv_disable_copy_on_read(BlockDriverState *bs)
|
|||
/* Check if any requests are in-flight (including throttled requests) */
|
||||
bool bdrv_requests_pending(BlockDriverState *bs)
|
||||
{
|
||||
BdrvChild *child;
|
||||
|
||||
if (!QLIST_EMPTY(&bs->tracked_requests)) {
|
||||
return true;
|
||||
}
|
||||
|
@ -225,12 +227,13 @@ bool bdrv_requests_pending(BlockDriverState *bs)
|
|||
if (!qemu_co_queue_empty(&bs->throttled_reqs[1])) {
|
||||
return true;
|
||||
}
|
||||
if (bs->file && bdrv_requests_pending(bs->file->bs)) {
|
||||
return true;
|
||||
}
|
||||
if (bs->backing && bdrv_requests_pending(bs->backing->bs)) {
|
||||
return true;
|
||||
|
||||
QLIST_FOREACH(child, &bs->children, next) {
|
||||
if (bdrv_requests_pending(child->bs)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
|
@ -48,6 +48,14 @@ static const int uart_intr[XLNX_ZYNQMP_NUM_UARTS] = {
|
|||
21, 22,
|
||||
};
|
||||
|
||||
static const uint64_t sdhci_addr[XLNX_ZYNQMP_NUM_SDHCI] = {
|
||||
0xFF160000, 0xFF170000,
|
||||
};
|
||||
|
||||
static const int sdhci_intr[XLNX_ZYNQMP_NUM_SDHCI] = {
|
||||
48, 49,
|
||||
};
|
||||
|
||||
typedef struct XlnxZynqMPGICRegion {
|
||||
int region_index;
|
||||
uint32_t address;
|
||||
|
@ -97,6 +105,13 @@ static void xlnx_zynqmp_init(Object *obj)
|
|||
|
||||
object_initialize(&s->sata, sizeof(s->sata), TYPE_SYSBUS_AHCI);
|
||||
qdev_set_parent_bus(DEVICE(&s->sata), sysbus_get_default());
|
||||
|
||||
for (i = 0; i < XLNX_ZYNQMP_NUM_SDHCI; i++) {
|
||||
object_initialize(&s->sdhci[i], sizeof(s->sdhci[i]),
|
||||
TYPE_SYSBUS_SDHCI);
|
||||
qdev_set_parent_bus(DEVICE(&s->sdhci[i]),
|
||||
sysbus_get_default());
|
||||
}
|
||||
}
|
||||
|
||||
static void xlnx_zynqmp_realize(DeviceState *dev, Error **errp)
|
||||
|
@ -258,6 +273,19 @@ static void xlnx_zynqmp_realize(DeviceState *dev, Error **errp)
|
|||
|
||||
sysbus_mmio_map(SYS_BUS_DEVICE(&s->sata), 0, SATA_ADDR);
|
||||
sysbus_connect_irq(SYS_BUS_DEVICE(&s->sata), 0, gic_spi[SATA_INTR]);
|
||||
|
||||
for (i = 0; i < XLNX_ZYNQMP_NUM_SDHCI; i++) {
|
||||
object_property_set_bool(OBJECT(&s->sdhci[i]), true,
|
||||
"realized", &err);
|
||||
if (err) {
|
||||
error_propagate(errp, err);
|
||||
return;
|
||||
}
|
||||
sysbus_mmio_map(SYS_BUS_DEVICE(&s->sdhci[i]), 0,
|
||||
sdhci_addr[i]);
|
||||
sysbus_connect_irq(SYS_BUS_DEVICE(&s->sdhci[i]), 0,
|
||||
gic_spi[sdhci_intr[i]]);
|
||||
}
|
||||
}
|
||||
|
||||
static Property xlnx_zynqmp_props[] = {
|
||||
|
|
|
@ -798,6 +798,11 @@ static void virtio_blk_set_status(VirtIODevice *vdev, uint8_t status)
|
|||
static void virtio_blk_save(QEMUFile *f, void *opaque)
|
||||
{
|
||||
VirtIODevice *vdev = VIRTIO_DEVICE(opaque);
|
||||
VirtIOBlock *s = VIRTIO_BLK(vdev);
|
||||
|
||||
if (s->dataplane) {
|
||||
virtio_blk_data_plane_stop(s->dataplane);
|
||||
}
|
||||
|
||||
virtio_save(vdev, f);
|
||||
}
|
||||
|
@ -972,7 +977,7 @@ static Property virtio_blk_properties[] = {
|
|||
DEFINE_PROP_STRING("serial", VirtIOBlock, conf.serial),
|
||||
DEFINE_PROP_BIT("config-wce", VirtIOBlock, conf.config_wce, 0, true),
|
||||
#ifdef __linux__
|
||||
DEFINE_PROP_BIT("scsi", VirtIOBlock, conf.scsi, 0, true),
|
||||
DEFINE_PROP_BIT("scsi", VirtIOBlock, conf.scsi, 0, false),
|
||||
#endif
|
||||
DEFINE_PROP_BIT("request-merging", VirtIOBlock, conf.request_merging, 0,
|
||||
true),
|
||||
|
|
|
@ -2285,7 +2285,11 @@ static const TypeInfo spapr_machine_info = {
|
|||
},
|
||||
};
|
||||
|
||||
#define SPAPR_COMPAT_2_4 \
|
||||
HW_COMPAT_2_4
|
||||
|
||||
#define SPAPR_COMPAT_2_3 \
|
||||
SPAPR_COMPAT_2_4 \
|
||||
HW_COMPAT_2_3 \
|
||||
{\
|
||||
.driver = "spapr-pci-host-bridge",\
|
||||
|
@ -2399,11 +2403,16 @@ static const TypeInfo spapr_machine_2_3_info = {
|
|||
|
||||
static void spapr_machine_2_4_class_init(ObjectClass *oc, void *data)
|
||||
{
|
||||
static GlobalProperty compat_props[] = {
|
||||
SPAPR_COMPAT_2_4
|
||||
{ /* end of list */ }
|
||||
};
|
||||
MachineClass *mc = MACHINE_CLASS(oc);
|
||||
|
||||
mc->desc = "pSeries Logical Partition (PAPR compliant) v2.4";
|
||||
mc->alias = "pseries";
|
||||
mc->is_default = 0;
|
||||
mc->compat_props = compat_props;
|
||||
}
|
||||
|
||||
static const TypeInfo spapr_machine_2_4_info = {
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
#include "qemu/config-file.h"
|
||||
#include "s390-pci-bus.h"
|
||||
#include "hw/s390x/storage-keys.h"
|
||||
#include "hw/compat.h"
|
||||
|
||||
#define TYPE_S390_CCW_MACHINE "s390-ccw-machine"
|
||||
|
||||
|
@ -236,6 +237,7 @@ static const TypeInfo ccw_machine_info = {
|
|||
};
|
||||
|
||||
#define CCW_COMPAT_2_4 \
|
||||
HW_COMPAT_2_4 \
|
||||
{\
|
||||
.driver = TYPE_S390_SKEYS,\
|
||||
.property = "migration-enabled",\
|
||||
|
|
|
@ -653,6 +653,11 @@ static void virtio_scsi_reset(VirtIODevice *vdev)
|
|||
static void virtio_scsi_save(QEMUFile *f, void *opaque)
|
||||
{
|
||||
VirtIODevice *vdev = VIRTIO_DEVICE(opaque);
|
||||
VirtIOSCSI *s = VIRTIO_SCSI(vdev);
|
||||
|
||||
if (s->dataplane_started) {
|
||||
virtio_scsi_dataplane_stop(s);
|
||||
}
|
||||
virtio_save(vdev, f);
|
||||
}
|
||||
|
||||
|
|
|
@ -28,7 +28,7 @@
|
|||
#include "qemu/error-report.h"
|
||||
#include "sysemu/block-backend.h"
|
||||
#include "sysemu/blockdev.h"
|
||||
#include "hw/sd.h"
|
||||
#include "hw/sd/sd.h"
|
||||
|
||||
enum {
|
||||
ENABLE_CMD_TX = (1<<0),
|
||||
|
|
|
@ -18,7 +18,7 @@
|
|||
*/
|
||||
#include "hw/hw.h"
|
||||
#include "hw/arm/omap.h"
|
||||
#include "hw/sd.h"
|
||||
#include "hw/sd/sd.h"
|
||||
|
||||
struct omap_mmc_s {
|
||||
qemu_irq irq;
|
||||
|
|
|
@ -10,7 +10,7 @@
|
|||
#include "sysemu/block-backend.h"
|
||||
#include "sysemu/blockdev.h"
|
||||
#include "hw/sysbus.h"
|
||||
#include "hw/sd.h"
|
||||
#include "hw/sd/sd.h"
|
||||
|
||||
//#define DEBUG_PL181 1
|
||||
|
||||
|
|
|
@ -12,7 +12,7 @@
|
|||
|
||||
#include "hw/hw.h"
|
||||
#include "hw/arm/pxa.h"
|
||||
#include "hw/sd.h"
|
||||
#include "hw/sd/sd.h"
|
||||
#include "hw/qdev.h"
|
||||
|
||||
struct PXA2xxMMCIState {
|
||||
|
|
|
@ -31,7 +31,7 @@
|
|||
|
||||
#include "hw/hw.h"
|
||||
#include "sysemu/block-backend.h"
|
||||
#include "hw/sd.h"
|
||||
#include "hw/sd/sd.h"
|
||||
#include "qemu/bitmap.h"
|
||||
|
||||
//#define DEBUG_SD 1
|
||||
|
|
|
@ -21,15 +21,10 @@
|
|||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#ifndef SDHCI_INTERNAL_H
|
||||
#define SDHCI_INTERNAL_H
|
||||
|
||||
#ifndef SDHCI_H
|
||||
#define SDHCI_H
|
||||
|
||||
#include "qemu-common.h"
|
||||
#include "hw/block/block.h"
|
||||
#include "hw/pci/pci.h"
|
||||
#include "hw/sysbus.h"
|
||||
#include "hw/sd.h"
|
||||
#include "hw/sd/sdhci.h"
|
||||
|
||||
/* R/W SDMA System Address register 0x0 */
|
||||
#define SDHC_SYSAD 0x00
|
||||
|
@ -232,66 +227,6 @@ enum {
|
|||
sdhc_gap_write = 2 /* SDHC stopped at block gap during write operation */
|
||||
};
|
||||
|
||||
/* SD/MMC host controller state */
|
||||
typedef struct SDHCIState {
|
||||
union {
|
||||
PCIDevice pcidev;
|
||||
SysBusDevice busdev;
|
||||
};
|
||||
SDState *card;
|
||||
MemoryRegion iomem;
|
||||
BlockConf conf;
|
||||
|
||||
QEMUTimer *insert_timer; /* timer for 'changing' sd card. */
|
||||
QEMUTimer *transfer_timer;
|
||||
qemu_irq eject_cb;
|
||||
qemu_irq ro_cb;
|
||||
qemu_irq irq;
|
||||
|
||||
uint32_t sdmasysad; /* SDMA System Address register */
|
||||
uint16_t blksize; /* Host DMA Buff Boundary and Transfer BlkSize Reg */
|
||||
uint16_t blkcnt; /* Blocks count for current transfer */
|
||||
uint32_t argument; /* Command Argument Register */
|
||||
uint16_t trnmod; /* Transfer Mode Setting Register */
|
||||
uint16_t cmdreg; /* Command Register */
|
||||
uint32_t rspreg[4]; /* Response Registers 0-3 */
|
||||
uint32_t prnsts; /* Present State Register */
|
||||
uint8_t hostctl; /* Host Control Register */
|
||||
uint8_t pwrcon; /* Power control Register */
|
||||
uint8_t blkgap; /* Block Gap Control Register */
|
||||
uint8_t wakcon; /* WakeUp Control Register */
|
||||
uint16_t clkcon; /* Clock control Register */
|
||||
uint8_t timeoutcon; /* Timeout Control Register */
|
||||
uint8_t admaerr; /* ADMA Error Status Register */
|
||||
uint16_t norintsts; /* Normal Interrupt Status Register */
|
||||
uint16_t errintsts; /* Error Interrupt Status Register */
|
||||
uint16_t norintstsen; /* Normal Interrupt Status Enable Register */
|
||||
uint16_t errintstsen; /* Error Interrupt Status Enable Register */
|
||||
uint16_t norintsigen; /* Normal Interrupt Signal Enable Register */
|
||||
uint16_t errintsigen; /* Error Interrupt Signal Enable Register */
|
||||
uint16_t acmd12errsts; /* Auto CMD12 error status register */
|
||||
uint64_t admasysaddr; /* ADMA System Address Register */
|
||||
|
||||
uint32_t capareg; /* Capabilities Register */
|
||||
uint32_t maxcurr; /* Maximum Current Capabilities Register */
|
||||
uint8_t *fifo_buffer; /* SD host i/o FIFO buffer */
|
||||
uint32_t buf_maxsz;
|
||||
uint16_t data_count; /* current element in FIFO buffer */
|
||||
uint8_t stopped_state;/* Current SDHC state */
|
||||
/* Buffer Data Port Register - virtual access point to R and W buffers */
|
||||
/* Software Reset Register - always reads as 0 */
|
||||
/* Force Event Auto CMD12 Error Interrupt Reg - write only */
|
||||
/* Force Event Error Interrupt Register- write only */
|
||||
/* RO Host Controller Version Register always reads as 0x2401 */
|
||||
} SDHCIState;
|
||||
|
||||
extern const VMStateDescription sdhci_vmstate;
|
||||
|
||||
#define TYPE_PCI_SDHCI "sdhci-pci"
|
||||
#define PCI_SDHCI(obj) OBJECT_CHECK(SDHCIState, (obj), TYPE_PCI_SDHCI)
|
||||
|
||||
#define TYPE_SYSBUS_SDHCI "generic-sdhci"
|
||||
#define SYSBUS_SDHCI(obj) \
|
||||
OBJECT_CHECK(SDHCIState, (obj), TYPE_SYSBUS_SDHCI)
|
||||
|
||||
#endif /* SDHCI_H */
|
||||
#endif
|
|
@ -29,8 +29,7 @@
|
|||
#include "sysemu/dma.h"
|
||||
#include "qemu/timer.h"
|
||||
#include "qemu/bitops.h"
|
||||
|
||||
#include "sdhci.h"
|
||||
#include "sdhci-internal.h"
|
||||
|
||||
/* host controller debug messages */
|
||||
#ifndef SDHC_DEBUG
|
||||
|
|
|
@ -13,7 +13,7 @@
|
|||
#include "sysemu/block-backend.h"
|
||||
#include "sysemu/blockdev.h"
|
||||
#include "hw/ssi.h"
|
||||
#include "hw/sd.h"
|
||||
#include "hw/sd/sd.h"
|
||||
|
||||
//#define DEBUG_SSI_SD 1
|
||||
|
||||
|
|
|
@ -24,6 +24,7 @@
|
|||
#include "hw/char/cadence_uart.h"
|
||||
#include "hw/ide/pci.h"
|
||||
#include "hw/ide/ahci.h"
|
||||
#include "hw/sd/sdhci.h"
|
||||
|
||||
#define TYPE_XLNX_ZYNQMP "xlnx,zynqmp"
|
||||
#define XLNX_ZYNQMP(obj) OBJECT_CHECK(XlnxZynqMPState, (obj), \
|
||||
|
@ -33,6 +34,7 @@
|
|||
#define XLNX_ZYNQMP_NUM_RPU_CPUS 2
|
||||
#define XLNX_ZYNQMP_NUM_GEMS 4
|
||||
#define XLNX_ZYNQMP_NUM_UARTS 2
|
||||
#define XLNX_ZYNQMP_NUM_SDHCI 2
|
||||
|
||||
#define XLNX_ZYNQMP_NUM_OCM_BANKS 4
|
||||
#define XLNX_ZYNQMP_OCM_RAM_0_ADDRESS 0xFFFC0000
|
||||
|
@ -63,6 +65,7 @@ typedef struct XlnxZynqMPState {
|
|||
CadenceGEMState gem[XLNX_ZYNQMP_NUM_GEMS];
|
||||
CadenceUARTState uart[XLNX_ZYNQMP_NUM_UARTS];
|
||||
SysbusAHCIState sata;
|
||||
SDHCIState sdhci[XLNX_ZYNQMP_NUM_SDHCI];
|
||||
|
||||
char *boot_cpu;
|
||||
ARMCPU *boot_cpu_ptr;
|
||||
|
|
|
@ -2,7 +2,11 @@
|
|||
#define HW_COMPAT_H
|
||||
|
||||
#define HW_COMPAT_2_4 \
|
||||
/* empty */
|
||||
{\
|
||||
.driver = "virtio-blk-device",\
|
||||
.property = "scsi",\
|
||||
.value = "true",\
|
||||
},
|
||||
|
||||
#define HW_COMPAT_2_3 \
|
||||
{\
|
||||
|
|
|
@ -0,0 +1,94 @@
|
|||
/*
|
||||
* SD Association Host Standard Specification v2.0 controller emulation
|
||||
*
|
||||
* Copyright (c) 2011 Samsung Electronics Co., Ltd.
|
||||
* Mitsyanko Igor <i.mitsyanko@samsung.com>
|
||||
* Peter A.G. Crosthwaite <peter.crosthwaite@petalogix.com>
|
||||
*
|
||||
* Based on MMC controller for Samsung S5PC1xx-based board emulation
|
||||
* by Alexey Merkulov and Vladimir Monakhov.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
* See the GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU _General Public License along
|
||||
* with this program; if not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef SDHCI_H
|
||||
#define SDHCI_H
|
||||
|
||||
#include "qemu-common.h"
|
||||
#include "hw/block/block.h"
|
||||
#include "hw/pci/pci.h"
|
||||
#include "hw/sysbus.h"
|
||||
#include "hw/sd/sd.h"
|
||||
|
||||
/* SD/MMC host controller state */
|
||||
typedef struct SDHCIState {
|
||||
union {
|
||||
PCIDevice pcidev;
|
||||
SysBusDevice busdev;
|
||||
};
|
||||
SDState *card;
|
||||
MemoryRegion iomem;
|
||||
BlockConf conf;
|
||||
|
||||
QEMUTimer *insert_timer; /* timer for 'changing' sd card. */
|
||||
QEMUTimer *transfer_timer;
|
||||
qemu_irq eject_cb;
|
||||
qemu_irq ro_cb;
|
||||
qemu_irq irq;
|
||||
|
||||
uint32_t sdmasysad; /* SDMA System Address register */
|
||||
uint16_t blksize; /* Host DMA Buff Boundary and Transfer BlkSize Reg */
|
||||
uint16_t blkcnt; /* Blocks count for current transfer */
|
||||
uint32_t argument; /* Command Argument Register */
|
||||
uint16_t trnmod; /* Transfer Mode Setting Register */
|
||||
uint16_t cmdreg; /* Command Register */
|
||||
uint32_t rspreg[4]; /* Response Registers 0-3 */
|
||||
uint32_t prnsts; /* Present State Register */
|
||||
uint8_t hostctl; /* Host Control Register */
|
||||
uint8_t pwrcon; /* Power control Register */
|
||||
uint8_t blkgap; /* Block Gap Control Register */
|
||||
uint8_t wakcon; /* WakeUp Control Register */
|
||||
uint16_t clkcon; /* Clock control Register */
|
||||
uint8_t timeoutcon; /* Timeout Control Register */
|
||||
uint8_t admaerr; /* ADMA Error Status Register */
|
||||
uint16_t norintsts; /* Normal Interrupt Status Register */
|
||||
uint16_t errintsts; /* Error Interrupt Status Register */
|
||||
uint16_t norintstsen; /* Normal Interrupt Status Enable Register */
|
||||
uint16_t errintstsen; /* Error Interrupt Status Enable Register */
|
||||
uint16_t norintsigen; /* Normal Interrupt Signal Enable Register */
|
||||
uint16_t errintsigen; /* Error Interrupt Signal Enable Register */
|
||||
uint16_t acmd12errsts; /* Auto CMD12 error status register */
|
||||
uint64_t admasysaddr; /* ADMA System Address Register */
|
||||
|
||||
uint32_t capareg; /* Capabilities Register */
|
||||
uint32_t maxcurr; /* Maximum Current Capabilities Register */
|
||||
uint8_t *fifo_buffer; /* SD host i/o FIFO buffer */
|
||||
uint32_t buf_maxsz;
|
||||
uint16_t data_count; /* current element in FIFO buffer */
|
||||
uint8_t stopped_state;/* Current SDHC state */
|
||||
/* Buffer Data Port Register - virtual access point to R and W buffers */
|
||||
/* Software Reset Register - always reads as 0 */
|
||||
/* Force Event Auto CMD12 Error Interrupt Reg - write only */
|
||||
/* Force Event Error Interrupt Register- write only */
|
||||
/* RO Host Controller Version Register always reads as 0x2401 */
|
||||
} SDHCIState;
|
||||
|
||||
#define TYPE_PCI_SDHCI "sdhci-pci"
|
||||
#define PCI_SDHCI(obj) OBJECT_CHECK(SDHCIState, (obj), TYPE_PCI_SDHCI)
|
||||
|
||||
#define TYPE_SYSBUS_SDHCI "generic-sdhci"
|
||||
#define SYSBUS_SDHCI(obj) \
|
||||
OBJECT_CHECK(SDHCIState, (obj), TYPE_SYSBUS_SDHCI)
|
||||
|
||||
#endif /* SDHCI_H */
|
|
@ -26,7 +26,7 @@ import os, sys
|
|||
|
||||
sys.path.append(os.path.dirname(__file__))
|
||||
|
||||
from qemugdb import mtree, coroutine
|
||||
from qemugdb import aio, mtree, coroutine
|
||||
|
||||
class QemuCommand(gdb.Command):
|
||||
'''Prefix for QEMU debug support commands'''
|
||||
|
@ -37,6 +37,10 @@ class QemuCommand(gdb.Command):
|
|||
QemuCommand()
|
||||
coroutine.CoroutineCommand()
|
||||
mtree.MtreeCommand()
|
||||
aio.HandlersCommand()
|
||||
|
||||
coroutine.CoroutineSPFunction()
|
||||
coroutine.CoroutinePCFunction()
|
||||
|
||||
# Default to silently passing through SIGUSR1, because QEMU sends it
|
||||
# to itself a lot.
|
||||
|
|
|
@ -0,0 +1,58 @@
|
|||
#!/usr/bin/python
|
||||
|
||||
# GDB debugging support: aio/iohandler debug
|
||||
#
|
||||
# Copyright (c) 2015 Red Hat, Inc.
|
||||
#
|
||||
# Author: Dr. David Alan Gilbert <dgilbert@redhat.com>
|
||||
#
|
||||
# This work is licensed under the terms of the GNU GPL, version 2 or
|
||||
# later. See the COPYING file in the top-level directory.
|
||||
#
|
||||
|
||||
import gdb
|
||||
from qemugdb import coroutine
|
||||
|
||||
def isnull(ptr):
|
||||
return ptr == gdb.Value(0).cast(ptr.type)
|
||||
|
||||
def dump_aiocontext(context, verbose):
|
||||
'''Display a dump and backtrace for an aiocontext'''
|
||||
cur = context['aio_handlers']['lh_first']
|
||||
# Get pointers to functions we're going to process specially
|
||||
sym_fd_coroutine_enter = gdb.parse_and_eval('fd_coroutine_enter')
|
||||
|
||||
while not isnull(cur):
|
||||
entry = cur.dereference()
|
||||
gdb.write('----\n%s\n' % entry)
|
||||
if verbose and cur['io_read'] == sym_fd_coroutine_enter:
|
||||
coptr = (cur['opaque'].cast(gdb.lookup_type('FDYieldUntilData').pointer()))['co']
|
||||
coptr = coptr.cast(gdb.lookup_type('CoroutineUContext').pointer())
|
||||
coroutine.bt_jmpbuf(coptr['env']['__jmpbuf'])
|
||||
cur = cur['node']['le_next'];
|
||||
|
||||
gdb.write('----\n')
|
||||
|
||||
class HandlersCommand(gdb.Command):
|
||||
'''Display aio handlers'''
|
||||
def __init__(self):
|
||||
gdb.Command.__init__(self, 'qemu handlers', gdb.COMMAND_DATA,
|
||||
gdb.COMPLETE_NONE)
|
||||
|
||||
def invoke(self, arg, from_tty):
|
||||
verbose = False
|
||||
argv = gdb.string_to_argv(arg)
|
||||
|
||||
if len(argv) > 0 and argv[0] == '--verbose':
|
||||
verbose = True
|
||||
argv.pop(0)
|
||||
|
||||
if len(argv) > 1:
|
||||
gdb.write('usage: qemu handlers [--verbose] [handler]\n')
|
||||
return
|
||||
|
||||
if len(argv) == 1:
|
||||
handlers_name = argv[0]
|
||||
else:
|
||||
handlers_name = 'qemu_aio_context'
|
||||
dump_aiocontext(gdb.parse_and_eval(handlers_name), verbose)
|
|
@ -15,8 +15,11 @@
|
|||
|
||||
import gdb
|
||||
|
||||
VOID_PTR = gdb.lookup_type('void').pointer()
|
||||
|
||||
def get_fs_base():
|
||||
'''Fetch %fs base value using arch_prctl(ARCH_GET_FS)'''
|
||||
'''Fetch %fs base value using arch_prctl(ARCH_GET_FS). This is
|
||||
pthread_self().'''
|
||||
# %rsp - 120 is scratch space according to the SystemV ABI
|
||||
old = gdb.parse_and_eval('*(uint64_t*)($rsp - 120)')
|
||||
gdb.execute('call arch_prctl(0x1003, $rsp - 120)', False, True)
|
||||
|
@ -24,17 +27,29 @@ def get_fs_base():
|
|||
gdb.execute('set *(uint64_t*)($rsp - 120) = %s' % old, False, True)
|
||||
return fs_base
|
||||
|
||||
def pthread_self():
|
||||
'''Fetch pthread_self() from the glibc start_thread function.'''
|
||||
f = gdb.newest_frame()
|
||||
while f.name() != 'start_thread':
|
||||
f = f.older()
|
||||
if f is None:
|
||||
return get_fs_base()
|
||||
|
||||
try:
|
||||
return f.read_var("arg")
|
||||
except ValueError:
|
||||
return get_fs_base()
|
||||
|
||||
def get_glibc_pointer_guard():
|
||||
'''Fetch glibc pointer guard value'''
|
||||
fs_base = get_fs_base()
|
||||
fs_base = pthread_self()
|
||||
return gdb.parse_and_eval('*(uint64_t*)((uint64_t)%s + 0x30)' % fs_base)
|
||||
|
||||
def glibc_ptr_demangle(val, pointer_guard):
|
||||
'''Undo effect of glibc's PTR_MANGLE()'''
|
||||
return gdb.parse_and_eval('(((uint64_t)%s >> 0x11) | ((uint64_t)%s << (64 - 0x11))) ^ (uint64_t)%s' % (val, val, pointer_guard))
|
||||
|
||||
def bt_jmpbuf(jmpbuf):
|
||||
'''Backtrace a jmpbuf'''
|
||||
def get_jmpbuf_regs(jmpbuf):
|
||||
JB_RBX = 0
|
||||
JB_RBP = 1
|
||||
JB_R12 = 2
|
||||
|
@ -44,35 +59,35 @@ def bt_jmpbuf(jmpbuf):
|
|||
JB_RSP = 6
|
||||
JB_PC = 7
|
||||
|
||||
old_rbx = gdb.parse_and_eval('(uint64_t)$rbx')
|
||||
old_rbp = gdb.parse_and_eval('(uint64_t)$rbp')
|
||||
old_rsp = gdb.parse_and_eval('(uint64_t)$rsp')
|
||||
old_r12 = gdb.parse_and_eval('(uint64_t)$r12')
|
||||
old_r13 = gdb.parse_and_eval('(uint64_t)$r13')
|
||||
old_r14 = gdb.parse_and_eval('(uint64_t)$r14')
|
||||
old_r15 = gdb.parse_and_eval('(uint64_t)$r15')
|
||||
old_rip = gdb.parse_and_eval('(uint64_t)$rip')
|
||||
|
||||
pointer_guard = get_glibc_pointer_guard()
|
||||
gdb.execute('set $rbx = %s' % jmpbuf[JB_RBX])
|
||||
gdb.execute('set $rbp = %s' % glibc_ptr_demangle(jmpbuf[JB_RBP], pointer_guard))
|
||||
gdb.execute('set $rsp = %s' % glibc_ptr_demangle(jmpbuf[JB_RSP], pointer_guard))
|
||||
gdb.execute('set $r12 = %s' % jmpbuf[JB_R12])
|
||||
gdb.execute('set $r13 = %s' % jmpbuf[JB_R13])
|
||||
gdb.execute('set $r14 = %s' % jmpbuf[JB_R14])
|
||||
gdb.execute('set $r15 = %s' % jmpbuf[JB_R15])
|
||||
gdb.execute('set $rip = %s' % glibc_ptr_demangle(jmpbuf[JB_PC], pointer_guard))
|
||||
return {'rbx': jmpbuf[JB_RBX],
|
||||
'rbp': glibc_ptr_demangle(jmpbuf[JB_RBP], pointer_guard),
|
||||
'rsp': glibc_ptr_demangle(jmpbuf[JB_RSP], pointer_guard),
|
||||
'r12': jmpbuf[JB_R12],
|
||||
'r13': jmpbuf[JB_R13],
|
||||
'r14': jmpbuf[JB_R14],
|
||||
'r15': jmpbuf[JB_R15],
|
||||
'rip': glibc_ptr_demangle(jmpbuf[JB_PC], pointer_guard) }
|
||||
|
||||
def bt_jmpbuf(jmpbuf):
|
||||
'''Backtrace a jmpbuf'''
|
||||
regs = get_jmpbuf_regs(jmpbuf)
|
||||
old = dict()
|
||||
|
||||
for i in regs:
|
||||
old[i] = gdb.parse_and_eval('(uint64_t)$%s' % i)
|
||||
|
||||
for i in regs:
|
||||
gdb.execute('set $%s = %s' % (i, regs[i]))
|
||||
|
||||
gdb.execute('bt')
|
||||
|
||||
gdb.execute('set $rbx = %s' % old_rbx)
|
||||
gdb.execute('set $rbp = %s' % old_rbp)
|
||||
gdb.execute('set $rsp = %s' % old_rsp)
|
||||
gdb.execute('set $r12 = %s' % old_r12)
|
||||
gdb.execute('set $r13 = %s' % old_r13)
|
||||
gdb.execute('set $r14 = %s' % old_r14)
|
||||
gdb.execute('set $r15 = %s' % old_r15)
|
||||
gdb.execute('set $rip = %s' % old_rip)
|
||||
for i in regs:
|
||||
gdb.execute('set $%s = %s' % (i, old[i]))
|
||||
|
||||
def coroutine_to_jmpbuf(co):
|
||||
coroutine_pointer = co.cast(gdb.lookup_type('CoroutineUContext').pointer())
|
||||
return coroutine_pointer['env']['__jmpbuf']
|
||||
|
||||
|
||||
class CoroutineCommand(gdb.Command):
|
||||
|
@ -87,5 +102,18 @@ class CoroutineCommand(gdb.Command):
|
|||
gdb.write('usage: qemu coroutine <coroutine-pointer>\n')
|
||||
return
|
||||
|
||||
coroutine_pointer = gdb.parse_and_eval(argv[0]).cast(gdb.lookup_type('CoroutineUContext').pointer())
|
||||
bt_jmpbuf(coroutine_pointer['env']['__jmpbuf'])
|
||||
bt_jmpbuf(coroutine_to_jmpbuf(gdb.parse_and_eval(argv[0])))
|
||||
|
||||
class CoroutineSPFunction(gdb.Function):
|
||||
def __init__(self):
|
||||
gdb.Function.__init__(self, 'qemu_coroutine_sp')
|
||||
|
||||
def invoke(self, addr):
|
||||
return get_jmpbuf_regs(coroutine_to_jmpbuf(addr))['rsp'].cast(VOID_PTR)
|
||||
|
||||
class CoroutinePCFunction(gdb.Function):
|
||||
def __init__(self):
|
||||
gdb.Function.__init__(self, 'qemu_coroutine_pc')
|
||||
|
||||
def invoke(self, addr):
|
||||
return get_jmpbuf_regs(coroutine_to_jmpbuf(addr))['rip'].cast(VOID_PTR)
|
||||
|
|
Loading…
Reference in New Issue